Fix format-security warnings when building with trace-sync
[lttv.git] / lttv / lttv / state.c
... / ...
CommitLineData
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19#define _GNU_SOURCE
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <glib.h>
25#include <lttv/lttv.h>
26#include <lttv/module.h>
27#include <lttv/state.h>
28#include <ltt/trace.h>
29#include <ltt/event.h>
30#include <ltt/ltt.h>
31#include <ltt/marker-desc.h>
32#include <stdio.h>
33#include <string.h>
34#include <ltt/ltt-private.h>
35#include <inttypes.h>
36
37/* Comment :
38 * Mathieu Desnoyers
39 * usertrace is there only to be able to update the current CPU of the
40 * usertraces when there is a schedchange. it is a way to link the ProcessState
41 * to the associated usertrace. Link only created upon thread creation.
42 *
43 * The cpu id is necessary : it gives us back the current ProcessState when we
44 * are considering data from the usertrace.
45 */
46
47#define PREALLOCATED_EXECUTION_STACK 10
48
49/* Channel Quarks */
50
51GQuark
52 LTT_CHANNEL_FD_STATE,
53 LTT_CHANNEL_GLOBAL_STATE,
54 LTT_CHANNEL_IRQ_STATE,
55 LTT_CHANNEL_MODULE_STATE,
56 LTT_CHANNEL_NETIF_STATE,
57 LTT_CHANNEL_SOFTIRQ_STATE,
58 LTT_CHANNEL_SWAP_STATE,
59 LTT_CHANNEL_SYSCALL_STATE,
60 LTT_CHANNEL_TASK_STATE,
61 LTT_CHANNEL_VM_STATE,
62 LTT_CHANNEL_KPROBE_STATE,
63 LTT_CHANNEL_FS,
64 LTT_CHANNEL_KERNEL,
65 LTT_CHANNEL_MM,
66 LTT_CHANNEL_USERSPACE,
67 LTT_CHANNEL_BLOCK;
68
69/* Events Quarks */
70
71GQuark
72 LTT_EVENT_SYSCALL_ENTRY,
73 LTT_EVENT_SYSCALL_EXIT,
74 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
75 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
76 LTT_EVENT_PAGE_FAULT_ENTRY,
77 LTT_EVENT_PAGE_FAULT_EXIT,
78 LTT_EVENT_TRAP_ENTRY,
79 LTT_EVENT_TRAP_EXIT,
80 LTT_EVENT_IRQ_ENTRY,
81 LTT_EVENT_IRQ_EXIT,
82 LTT_EVENT_SOFT_IRQ_RAISE,
83 LTT_EVENT_SOFT_IRQ_ENTRY,
84 LTT_EVENT_SOFT_IRQ_EXIT,
85 LTT_EVENT_SCHED_SCHEDULE,
86 LTT_EVENT_SCHED_TRY_WAKEUP,
87 LTT_EVENT_PROCESS_FORK,
88 LTT_EVENT_KTHREAD_CREATE,
89 LTT_EVENT_PROCESS_EXIT,
90 LTT_EVENT_PROCESS_FREE,
91 LTT_EVENT_EXEC,
92 LTT_EVENT_PROCESS_STATE,
93 LTT_EVENT_STATEDUMP_END,
94 LTT_EVENT_FUNCTION_ENTRY,
95 LTT_EVENT_FUNCTION_EXIT,
96 LTT_EVENT_THREAD_BRAND,
97 LTT_EVENT_REQUEST_ISSUE,
98 LTT_EVENT_REQUEST_COMPLETE,
99 LTT_EVENT_LIST_INTERRUPT,
100 LTT_EVENT_SYS_CALL_TABLE,
101 LTT_EVENT_SOFTIRQ_VEC,
102 LTT_EVENT_KPROBE_TABLE,
103 LTT_EVENT_KPROBE,
104 LTT_EVENT_OPEN,
105 LTT_EVENT_READ,
106 LTT_EVENT_POLL_EVENT;
107
108/* Fields Quarks */
109
110GQuark
111 LTT_FIELD_SYSCALL_ID,
112 LTT_FIELD_TRAP_ID,
113 LTT_FIELD_IRQ_ID,
114 LTT_FIELD_SOFT_IRQ_ID,
115 LTT_FIELD_PREV_PID,
116 LTT_FIELD_NEXT_PID,
117 LTT_FIELD_PREV_STATE,
118 LTT_FIELD_PARENT_PID,
119 LTT_FIELD_CHILD_PID,
120 LTT_FIELD_PID,
121 LTT_FIELD_TGID,
122 LTT_FIELD_CHILD_TGID,
123 LTT_FIELD_FILENAME,
124 LTT_FIELD_NAME,
125 LTT_FIELD_TYPE,
126 LTT_FIELD_MODE,
127 LTT_FIELD_SUBMODE,
128 LTT_FIELD_STATUS,
129 LTT_FIELD_THIS_FN,
130 LTT_FIELD_CALL_SITE,
131 LTT_FIELD_MINOR,
132 LTT_FIELD_MAJOR,
133 LTT_FIELD_OPERATION,
134 LTT_FIELD_ACTION,
135 LTT_FIELD_ID,
136 LTT_FIELD_ADDRESS,
137 LTT_FIELD_SYMBOL,
138 LTT_FIELD_IP,
139 LTT_FIELD_FD,
140 LTT_FIELD_STATE,
141 LTT_FIELD_CPU_ID;
142
143LttvExecutionMode
144 LTTV_STATE_MODE_UNKNOWN,
145 LTTV_STATE_USER_MODE,
146 LTTV_STATE_MAYBE_USER_MODE,
147 LTTV_STATE_SYSCALL,
148 LTTV_STATE_MAYBE_SYSCALL,
149 LTTV_STATE_TRAP,
150 LTTV_STATE_MAYBE_TRAP,
151 LTTV_STATE_IRQ,
152 LTTV_STATE_SOFT_IRQ;
153
154LttvExecutionSubmode
155 LTTV_STATE_SUBMODE_UNKNOWN,
156 LTTV_STATE_SUBMODE_NONE;
157
158LttvProcessStatus
159 LTTV_STATE_UNNAMED,
160 LTTV_STATE_WAIT_FORK,
161 LTTV_STATE_WAIT_CPU,
162 LTTV_STATE_EXIT,
163 LTTV_STATE_ZOMBIE,
164 LTTV_STATE_WAIT,
165 LTTV_STATE_RUN,
166 LTTV_STATE_DEAD;
167
168GQuark
169 LTTV_STATE_UNBRANDED;
170
171LttvProcessType
172 LTTV_STATE_USER_THREAD,
173 LTTV_STATE_KERNEL_THREAD;
174
175LttvCPUMode
176 LTTV_CPU_UNKNOWN,
177 LTTV_CPU_IDLE,
178 LTTV_CPU_BUSY,
179 LTTV_CPU_IRQ,
180 LTTV_CPU_SOFT_IRQ,
181 LTTV_CPU_TRAP;
182
183LttvIRQMode
184 LTTV_IRQ_UNKNOWN,
185 LTTV_IRQ_IDLE,
186 LTTV_IRQ_BUSY;
187
188LttvBdevMode
189 LTTV_BDEV_UNKNOWN,
190 LTTV_BDEV_IDLE,
191 LTTV_BDEV_BUSY_READING,
192 LTTV_BDEV_BUSY_WRITING;
193
194static GQuark
195 LTTV_STATE_TRACEFILES,
196 LTTV_STATE_PROCESSES,
197 LTTV_STATE_PROCESS,
198 LTTV_STATE_RUNNING_PROCESS,
199 LTTV_STATE_EVENT,
200 LTTV_STATE_SAVED_STATES,
201 LTTV_STATE_SAVED_STATES_TIME,
202 LTTV_STATE_TIME,
203 LTTV_STATE_HOOKS,
204 LTTV_STATE_NAME_TABLES,
205 LTTV_STATE_TRACE_STATE_USE_COUNT,
206 LTTV_STATE_RESOURCE_CPUS,
207 LTTV_STATE_RESOURCE_CPUS_COUNT,
208 LTTV_STATE_RESOURCE_IRQS,
209 LTTV_STATE_RESOURCE_SOFT_IRQS,
210 LTTV_STATE_RESOURCE_TRAPS,
211 LTTV_STATE_RESOURCE_BLKDEVS;
212
213static void create_max_time(LttvTraceState *tcs);
214
215static void get_max_time(LttvTraceState *tcs);
216
217static void free_max_time(LttvTraceState *tcs);
218
219static void create_name_tables(LttvTraceState *tcs);
220
221static void get_name_tables(LttvTraceState *tcs);
222
223static void free_name_tables(LttvTraceState *tcs);
224
225static void free_saved_state(LttvTraceState *tcs);
226
227static void lttv_state_free_process_table(GHashTable *processes);
228
229static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
230 GPtrArray *quarktable);
231
232/* Resource function prototypes */
233static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint32 devcode);
234static LttvBdevState *bdevstate_new(void);
235static void bdevstate_free(LttvBdevState *);
236static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data);
237static LttvBdevState *bdevstate_copy(LttvBdevState *bds);
238
239
240#if (__WORDSIZE == 32)
241guint guint64_hash(gconstpointer key)
242{
243 guint64 ukey = *(const guint64 *)key;
244
245 return (guint)ukey ^ (guint)(ukey >> 32);
246}
247
248gboolean guint64_equal(gconstpointer a, gconstpointer b)
249{
250 guint64 ua = *(const guint64 *)a;
251 guint64 ub = *(const guint64 *)b;
252
253 return ua == ub;
254}
255#endif
256
257void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
258{
259 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
260}
261
262
263void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
264{
265 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
266}
267
268
269void lttv_state_state_saved_free(LttvTraceState *self,
270 LttvAttribute *container)
271{
272 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
273}
274
275
276guint process_hash(gconstpointer key)
277{
278 guint pid = ((const LttvProcessState *)key)->pid;
279 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
280}
281
282
283/* If the hash table hash function is well distributed,
284 * the process_equal should compare different pid */
285gboolean process_equal(gconstpointer a, gconstpointer b)
286{
287 const LttvProcessState *process_a, *process_b;
288 gboolean ret = TRUE;
289
290 process_a = (const LttvProcessState *)a;
291 process_b = (const LttvProcessState *)b;
292
293 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
294 else if(likely(process_a->pid == 0 &&
295 process_a->cpu != process_b->cpu)) ret = FALSE;
296
297 return ret;
298}
299
300static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
301{
302 g_tree_destroy((GTree*)value);
303}
304
305static void lttv_state_free_usertraces(GHashTable *usertraces)
306{
307 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
308 g_hash_table_destroy(usertraces);
309}
310
311gboolean rettrue(gpointer key, gpointer value, gpointer user_data)
312{
313 return TRUE;
314}
315
316static guint check_expand(nb, id)
317{
318 if(likely(nb > id))
319 return nb;
320 else
321 return max(id + 1, nb * 2);
322}
323
324static void expand_name_table(LttvTraceState *ts, GQuark **table,
325 guint nb, guint new_nb)
326{
327 /* Expand an incomplete table */
328 GQuark *old_table = *table;
329 *table = g_new(GQuark, new_nb);
330 memcpy(*table, old_table, nb * sizeof(GQuark));
331 g_free(old_table);
332}
333
334static void fill_name_table(LttvTraceState *ts, GQuark *table, guint nb,
335 guint new_nb, const char *def_string)
336{
337 guint i;
338 GString *fe_name = g_string_new("");
339 for(i = nb; i < new_nb; i++) {
340 g_string_printf(fe_name, "%s %d", def_string, i);
341 table[i] = g_quark_from_string(fe_name->str);
342 }
343 g_string_free(fe_name, TRUE);
344}
345
346static void expand_syscall_table(LttvTraceState *ts, int id)
347{
348 LttvNameTables *nt = ts->name_tables;
349 guint new_nb;
350
351 new_nb = check_expand(nt->nb_syscalls, id);
352 if(likely(new_nb == nt->nb_syscalls))
353 return;
354 expand_name_table(ts, &nt->syscall_names, nt->nb_syscalls, new_nb);
355 fill_name_table(ts, nt->syscall_names, nt->nb_syscalls, new_nb, "syscall");
356 /* Update the table size */
357 nt->nb_syscalls = new_nb;
358}
359
360static void expand_kprobe_table(LttvTraceState *ts, guint64 ip, char *symbol)
361{
362 LttvNameTables *nt = ts->name_tables;
363#if (__WORDSIZE == 32)
364 guint64 *ip_ptr = g_new(guint64, 1);
365 g_hash_table_insert(nt->kprobe_hash, ip_ptr,
366 (gpointer)(glong)g_quark_from_string(symbol));
367#else
368 g_hash_table_insert(nt->kprobe_hash, (gpointer)ip,
369 (gpointer)(glong)g_quark_from_string(symbol));
370#endif
371}
372
373static void expand_trap_table(LttvTraceState *ts, int id)
374{
375 LttvNameTables *nt = ts->name_tables;
376 LttvTrapState *old_table;
377 guint new_nb, i;
378
379 new_nb = check_expand(nt->nb_traps, id);
380 if(likely(new_nb == nt->nb_traps))
381 return;
382
383 expand_name_table(ts, &nt->trap_names, nt->nb_traps, new_nb);
384 fill_name_table(ts, nt->trap_names, nt->nb_traps, new_nb, "trap");
385
386 old_table = ts->trap_states;
387 ts->trap_states = g_new(LttvTrapState, new_nb);
388 memcpy(ts->trap_states, old_table, nt->nb_traps * sizeof(LttvTrapState));
389 g_free(old_table);
390 for(i = nt->nb_traps; i < new_nb; i++)
391 ts->trap_states[i].running = 0;
392
393 /* Update the table size */
394 nt->nb_traps = new_nb;
395}
396
397static void expand_irq_table(LttvTraceState *ts, int id)
398{
399 LttvNameTables *nt = ts->name_tables;
400 LttvIRQState *old_table;
401 guint new_nb, i;
402
403 new_nb = check_expand(nt->nb_irqs, id);
404 if(likely(new_nb == nt->nb_irqs))
405 return;
406
407 expand_name_table(ts, &nt->irq_names, nt->nb_irqs, new_nb);
408 fill_name_table(ts, nt->irq_names, nt->nb_irqs, new_nb, "irq");
409
410 old_table = ts->irq_states;
411 ts->irq_states = g_new(LttvIRQState, new_nb);
412 memcpy(ts->irq_states, old_table, nt->nb_irqs * sizeof(LttvIRQState));
413 g_free(old_table);
414 for(i = nt->nb_irqs; i < new_nb; i++)
415 ts->irq_states[i].mode_stack =
416 g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
417
418 /* Update the table size */
419 nt->nb_irqs = new_nb;
420}
421
422static void expand_soft_irq_table(LttvTraceState *ts, int id)
423{
424 LttvNameTables *nt = ts->name_tables;
425 LttvSoftIRQState *old_table;
426 guint new_nb, i;
427
428 new_nb = check_expand(nt->nb_soft_irqs, id);
429 if(likely(new_nb == nt->nb_soft_irqs))
430 return;
431
432 expand_name_table(ts, &nt->soft_irq_names, nt->nb_soft_irqs, new_nb);
433 fill_name_table(ts, nt->soft_irq_names, nt->nb_soft_irqs, new_nb, "softirq");
434
435 old_table = ts->soft_irq_states;
436 ts->soft_irq_states = g_new(LttvSoftIRQState, new_nb);
437 memcpy(ts->soft_irq_states, old_table,
438 nt->nb_soft_irqs * sizeof(LttvSoftIRQState));
439 g_free(old_table);
440 for(i = nt->nb_soft_irqs; i < new_nb; i++)
441 ts->soft_irq_states[i].running = 0;
442
443 /* Update the table size */
444 nt->nb_soft_irqs = new_nb;
445}
446
447static void restore_init_state(LttvTraceState *self)
448{
449 guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
450
451 //LttvTracefileState *tfcs;
452
453 LttTime start_time, end_time;
454
455 /* Free the process tables */
456 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
457 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
458 self->processes = g_hash_table_new(process_hash, process_equal);
459 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
460 self->nb_event = 0;
461
462 /* Seek time to beginning */
463 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
464 // closest. It's the tracecontext job to seek the trace to the beginning
465 // anyway : the init state might be used at the middle of the trace as well...
466 //g_tree_destroy(self->parent.ts_context->pqueue);
467 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
468
469 ltt_trace_time_span_get(self->parent.t, &start_time, &end_time);
470
471 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
472
473 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
474 nb_irqs = self->name_tables->nb_irqs;
475 nb_soft_irqs = self->name_tables->nb_soft_irqs;
476 nb_traps = self->name_tables->nb_traps;
477
478 /* Put the per cpu running_process to beginning state : process 0. */
479 for(i=0; i< nb_cpus; i++) {
480 LttvExecutionState *es;
481 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
482 LTTV_STATE_UNNAMED, &start_time);
483 /* We are not sure is it's a kernel thread or normal thread, put the
484 * bottom stack state to unknown */
485 self->running_process[i]->execution_stack =
486 g_array_set_size(self->running_process[i]->execution_stack, 1);
487 es = self->running_process[i]->state =
488 &g_array_index(self->running_process[i]->execution_stack,
489 LttvExecutionState, 0);
490 es->t = LTTV_STATE_MODE_UNKNOWN;
491 es->s = LTTV_STATE_UNNAMED;
492
493 //self->running_process[i]->state->s = LTTV_STATE_RUN;
494 self->running_process[i]->cpu = i;
495
496 /* reset cpu states */
497 if(self->cpu_states[i].mode_stack->len > 0) {
498 g_array_remove_range(self->cpu_states[i].mode_stack, 0,
499 self->cpu_states[i].mode_stack->len);
500 if(self->cpu_states[i].irq_stack->len)
501 g_array_remove_range(self->cpu_states[i].irq_stack, 0,
502 self->cpu_states[i].irq_stack->len);
503 if(self->cpu_states[i].softirq_stack->len)
504 g_array_remove_range(self->cpu_states[i].softirq_stack, 0,
505 self->cpu_states[i].softirq_stack->len);
506 if(self->cpu_states[i].trap_stack->len)
507 g_array_remove_range(self->cpu_states[i].trap_stack, 0,
508 self->cpu_states[i].trap_stack->len);
509 }
510 }
511
512 /* reset irq states */
513 for(i=0; i<nb_irqs; i++) {
514 if(self->irq_states[i].mode_stack->len > 0)
515 g_array_remove_range(self->irq_states[i].mode_stack, 0,
516 self->irq_states[i].mode_stack->len);
517 }
518
519 /* reset softirq states */
520 for(i=0; i<nb_soft_irqs; i++) {
521 self->soft_irq_states[i].pending = 0;
522 self->soft_irq_states[i].running = 0;
523 }
524
525 /* reset trap states */
526 for(i=0; i<nb_traps; i++) {
527 self->trap_states[i].running = 0;
528 }
529
530 /* reset bdev states */
531 g_hash_table_foreach(self->bdev_states, bdevstate_free_cb, NULL);
532 //g_hash_table_steal_all(self->bdev_states);
533 g_hash_table_foreach_steal(self->bdev_states, rettrue, NULL);
534
535#if 0
536 nb_tracefile = self->parent.tracefiles->len;
537
538 for(i = 0 ; i < nb_tracefile ; i++) {
539 tfcs =
540 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
541 LttvTracefileContext*, i));
542 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
543// tfcs->saved_position = 0;
544 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
545 tfcs->process->state->s = LTTV_STATE_RUN;
546 tfcs->process->last_cpu = tfcs->cpu_name;
547 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
548 }
549#endif //0
550}
551
552//static LttTime time_zero = {0,0};
553
554static gint compare_usertraces(gconstpointer a, gconstpointer b,
555 gpointer user_data)
556{
557 const LttTime *t1 = (const LttTime *)a;
558 const LttTime *t2 = (const LttTime *)b;
559
560 return ltt_time_compare(*t1, *t2);
561}
562
563static void free_usertrace_key(gpointer data)
564{
565 g_free(data);
566}
567
568#define MAX_STRING_LEN 4096
569
570static void state_load_saved_states(LttvTraceState *tcs)
571{
572 FILE *fp;
573 GPtrArray *quarktable;
574 const char *trace_path;
575 char path[PATH_MAX];
576 guint count;
577 guint i;
578 tcs->has_precomputed_states = FALSE;
579 GQuark q;
580 gchar *string;
581 gint hdr;
582 gchar buf[MAX_STRING_LEN];
583 guint len;
584 size_t res;
585
586 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
587 strncpy(path, trace_path, PATH_MAX-1);
588 count = strnlen(trace_path, PATH_MAX-1);
589 // quarktable : open, test
590 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
591 fp = fopen(path, "r");
592 if(!fp) return;
593 quarktable = g_ptr_array_sized_new(4096);
594
595 /* Index 0 is null */
596 hdr = fgetc(fp);
597 if(hdr == EOF) return;
598 g_assert(hdr == HDR_QUARKS);
599 q = 1;
600 do {
601 hdr = fgetc(fp);
602 if(hdr == EOF) break;
603 g_assert(hdr == HDR_QUARK);
604 g_ptr_array_set_size(quarktable, q+1);
605 i=0;
606 while(1) {
607 res = fread(&buf[i], sizeof(gchar), 1, fp);
608 g_assert(res == 1);
609 if(buf[i] == '\0' || feof(fp)) break;
610 i++;
611 }
612 len = strnlen(buf, MAX_STRING_LEN-1);
613 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
614 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
615 q++;
616 } while(1);
617
618 fclose(fp);
619
620 // saved_states : open, test
621 strncpy(path, trace_path, PATH_MAX-1);
622 count = strnlen(trace_path, PATH_MAX-1);
623 strncat(path, "/precomputed/states", PATH_MAX-count-1);
624 fp = fopen(path, "r");
625 if(!fp) return;
626
627 hdr = fgetc(fp);
628 if(hdr != HDR_TRACE) goto end;
629
630 lttv_trace_states_read_raw(tcs, fp, quarktable);
631
632 tcs->has_precomputed_states = TRUE;
633
634end:
635 fclose(fp);
636
637 /* Free the quarktable */
638 for(i=0; i<quarktable->len; i++) {
639 string = g_ptr_array_index (quarktable, i);
640 g_free(string);
641 }
642 g_ptr_array_free(quarktable, TRUE);
643 return;
644}
645
646static void init(LttvTracesetState *self, LttvTraceset *ts)
647{
648 guint i, j, nb_trace, nb_tracefile, nb_cpu;
649 guint64 nb_irq;
650
651 LttvTraceContext *tc;
652
653 LttvTraceState *tcs;
654
655 LttvTracefileState *tfcs;
656
657 LttvAttributeValue v;
658
659 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
660 init((LttvTracesetContext *)self, ts);
661
662 nb_trace = lttv_traceset_number(ts);
663 for(i = 0 ; i < nb_trace ; i++) {
664 tc = self->parent.traces[i];
665 tcs = LTTV_TRACE_STATE(tc);
666 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
667 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
668 LTTV_UINT, &v);
669 (*v.v_uint)++;
670
671 if(*(v.v_uint) == 1) {
672 create_name_tables(tcs);
673 create_max_time(tcs);
674 }
675 get_name_tables(tcs);
676 get_max_time(tcs);
677
678 nb_tracefile = tc->tracefiles->len;
679 nb_cpu = ltt_trace_get_num_cpu(tc->t);
680 nb_irq = tcs->name_tables->nb_irqs;
681 tcs->processes = NULL;
682 tcs->usertraces = NULL;
683 tcs->running_process = g_new(LttvProcessState*, nb_cpu);
684
685 /* init cpu resource stuff */
686 tcs->cpu_states = g_new(LttvCPUState, nb_cpu);
687 for(j = 0; j<nb_cpu; j++) {
688 tcs->cpu_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
689 tcs->cpu_states[j].irq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
690 tcs->cpu_states[j].softirq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
691 tcs->cpu_states[j].trap_stack = g_array_new(FALSE, FALSE, sizeof(gint));
692 g_assert(tcs->cpu_states[j].mode_stack != NULL);
693 }
694
695 /* init irq resource stuff */
696 tcs->irq_states = g_new(LttvIRQState, nb_irq);
697 for(j = 0; j<nb_irq; j++) {
698 tcs->irq_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
699 g_assert(tcs->irq_states[j].mode_stack != NULL);
700 }
701
702 /* init soft irq stuff */
703 /* the kernel has a statically fixed max of 32 softirqs */
704 tcs->soft_irq_states = g_new(LttvSoftIRQState, tcs->name_tables->nb_soft_irqs);
705
706 /* init trap stuff */
707 tcs->trap_states = g_new(LttvTrapState, tcs->name_tables->nb_traps);
708
709 /* init bdev resource stuff */
710 tcs->bdev_states = g_hash_table_new(g_int_hash, g_int_equal);
711
712 restore_init_state(tcs);
713 for(j = 0 ; j < nb_tracefile ; j++) {
714 tfcs =
715 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
716 LttvTracefileContext*, j));
717 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
718 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
719 tfcs->cpu_state = &(tcs->cpu_states[tfcs->cpu]);
720 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
721 /* It's a Usertrace */
722 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
723 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
724 GUINT_TO_POINTER(tid));
725 if(!usertrace_tree) {
726 usertrace_tree = g_tree_new_full(compare_usertraces,
727 NULL, free_usertrace_key, NULL);
728 g_hash_table_insert(tcs->usertraces,
729 GUINT_TO_POINTER(tid), usertrace_tree);
730 }
731 LttTime *timestamp = g_new(LttTime, 1);
732 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
733 ltt_tracefile_creation(tfcs->parent.tf));
734 g_tree_insert(usertrace_tree, timestamp, tfcs);
735 }
736 }
737
738 /* See if the trace has saved states */
739 state_load_saved_states(tcs);
740 }
741}
742
743static void fini(LttvTracesetState *self)
744{
745 guint i, nb_trace;
746
747 LttvTraceState *tcs;
748
749 //LttvTracefileState *tfcs;
750
751 LttvAttributeValue v;
752
753 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
754 for(i = 0 ; i < nb_trace ; i++) {
755 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
756 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
757 LTTV_UINT, &v);
758
759 g_assert(*(v.v_uint) != 0);
760 (*v.v_uint)--;
761
762 if(*(v.v_uint) == 0) {
763 free_name_tables(tcs);
764 free_max_time(tcs);
765 free_saved_state(tcs);
766 }
767 g_free(tcs->running_process);
768 tcs->running_process = NULL;
769 lttv_state_free_process_table(tcs->processes);
770 lttv_state_free_usertraces(tcs->usertraces);
771 tcs->processes = NULL;
772 tcs->usertraces = NULL;
773 }
774 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
775 fini((LttvTracesetContext *)self);
776}
777
778
779static LttvTracesetContext *new_traceset_context(LttvTracesetContext *self)
780{
781 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
782}
783
784
785static LttvTraceContext *new_trace_context(LttvTracesetContext *self)
786{
787 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
788}
789
790
791static LttvTracefileContext *new_tracefile_context(LttvTracesetContext *self)
792{
793 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
794}
795
796
797/* Write the process state of the trace */
798
799static void write_process_state(gpointer key, gpointer value,
800 gpointer user_data)
801{
802 LttvProcessState *process;
803
804 LttvExecutionState *es;
805
806 FILE *fp = (FILE *)user_data;
807
808 guint i;
809 guint64 address;
810
811 process = (LttvProcessState *)value;
812 fprintf(fp," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" FREE_EVENTS=\"%u\">\n",
813 process, process->pid, process->tgid, process->ppid,
814 g_quark_to_string(process->type),
815 process->creation_time.tv_sec,
816 process->creation_time.tv_nsec,
817 process->insertion_time.tv_sec,
818 process->insertion_time.tv_nsec,
819 g_quark_to_string(process->name),
820 g_quark_to_string(process->brand),
821 process->cpu, process->free_events);
822
823 for(i = 0 ; i < process->execution_stack->len; i++) {
824 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
825 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
826 g_quark_to_string(es->t), g_quark_to_string(es->n),
827 es->entry.tv_sec, es->entry.tv_nsec);
828 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
829 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
830 }
831
832 for(i = 0 ; i < process->user_stack->len; i++) {
833 address = g_array_index(process->user_stack, guint64, i);
834 fprintf(fp, " <USER_STACK ADDRESS=\"%" PRIu64 "\"/>\n", address);
835 }
836
837 if(process->usertrace) {
838 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
839 g_quark_to_string(process->usertrace->tracefile_name),
840 process->usertrace->cpu);
841 }
842
843
844 fprintf(fp, " </PROCESS>\n");
845}
846
847
848void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
849{
850 guint i, nb_tracefile, nb_block, offset;
851 guint64 tsc;
852
853 LttvTracefileState *tfcs;
854
855 LttTracefile *tf;
856
857 LttEventPosition *ep;
858
859 guint nb_cpus;
860
861 ep = ltt_event_position_new();
862
863 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
864
865 g_hash_table_foreach(self->processes, write_process_state, fp);
866
867 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
868 for(i=0;i<nb_cpus;i++) {
869 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
870 i, self->running_process[i]->pid);
871 }
872
873 nb_tracefile = self->parent.tracefiles->len;
874
875 for(i = 0 ; i < nb_tracefile ; i++) {
876 tfcs =
877 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
878 LttvTracefileContext*, i));
879 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
880 tfcs->parent.timestamp.tv_sec,
881 tfcs->parent.timestamp.tv_nsec);
882 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
883 if(e == NULL) fprintf(fp,"/>\n");
884 else {
885 ltt_event_position(e, ep);
886 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
887 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%" PRIu64 "/>\n", nb_block, offset,
888 tsc);
889 }
890 }
891 g_free(ep);
892 fprintf(fp,"</PROCESS_STATE>\n");
893}
894
895
896static void write_process_state_raw(gpointer key, gpointer value,
897 gpointer user_data)
898{
899 LttvProcessState *process;
900
901 LttvExecutionState *es;
902
903 FILE *fp = (FILE *)user_data;
904
905 guint i;
906 guint64 address;
907
908 process = (LttvProcessState *)value;
909 fputc(HDR_PROCESS, fp);
910 //fwrite(&header, sizeof(header), 1, fp);
911 //fprintf(fp, "%s", g_quark_to_string(process->type));
912 //fputc('\0', fp);
913 fwrite(&process->type, sizeof(process->type), 1, fp);
914 //fprintf(fp, "%s", g_quark_to_string(process->name));
915 //fputc('\0', fp);
916 fwrite(&process->name, sizeof(process->name), 1, fp);
917 //fprintf(fp, "%s", g_quark_to_string(process->brand));
918 //fputc('\0', fp);
919 fwrite(&process->brand, sizeof(process->brand), 1, fp);
920 fwrite(&process->pid, sizeof(process->pid), 1, fp);
921 fwrite(&process->free_events, sizeof(process->free_events), 1, fp);
922 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
923 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
924 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
925 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
926 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
927
928#if 0
929 fprintf(fp," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
930 process, process->pid, process->tgid, process->ppid,
931 g_quark_to_string(process->type),
932 process->creation_time.tv_sec,
933 process->creation_time.tv_nsec,
934 process->insertion_time.tv_sec,
935 process->insertion_time.tv_nsec,
936 g_quark_to_string(process->name),
937 g_quark_to_string(process->brand),
938 process->cpu);
939#endif //0
940
941 for(i = 0 ; i < process->execution_stack->len; i++) {
942 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
943
944 fputc(HDR_ES, fp);
945 //fprintf(fp, "%s", g_quark_to_string(es->t));
946 //fputc('\0', fp);
947 fwrite(&es->t, sizeof(es->t), 1, fp);
948 //fprintf(fp, "%s", g_quark_to_string(es->n));
949 //fputc('\0', fp);
950 fwrite(&es->n, sizeof(es->n), 1, fp);
951 //fprintf(fp, "%s", g_quark_to_string(es->s));
952 //fputc('\0', fp);
953 fwrite(&es->s, sizeof(es->s), 1, fp);
954 fwrite(&es->entry, sizeof(es->entry), 1, fp);
955 fwrite(&es->change, sizeof(es->change), 1, fp);
956 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
957#if 0
958 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
959 g_quark_to_string(es->t), g_quark_to_string(es->n),
960 es->entry.tv_sec, es->entry.tv_nsec);
961 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
962 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
963#endif //0
964 }
965
966 for(i = 0 ; i < process->user_stack->len; i++) {
967 address = g_array_index(process->user_stack, guint64, i);
968 fputc(HDR_USER_STACK, fp);
969 fwrite(&address, sizeof(address), 1, fp);
970#if 0
971 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n", address);
972#endif //0
973 }
974
975 if(process->usertrace) {
976 fputc(HDR_USERTRACE, fp);
977 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
978 //fputc('\0', fp);
979 fwrite(&process->usertrace->tracefile_name,
980 sizeof(process->usertrace->tracefile_name), 1, fp);
981 fwrite(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
982#if 0
983 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
984 g_quark_to_string(process->usertrace->tracefile_name),
985 process->usertrace->cpu);
986#endif //0
987 }
988
989}
990
991
992void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
993{
994 guint i, nb_tracefile, nb_block, offset;
995 guint64 tsc;
996
997 LttvTracefileState *tfcs;
998
999 LttTracefile *tf;
1000
1001 LttEventPosition *ep;
1002
1003 guint nb_cpus;
1004
1005 ep = ltt_event_position_new();
1006
1007 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1008 fputc(HDR_PROCESS_STATE, fp);
1009 fwrite(&t, sizeof(t), 1, fp);
1010
1011 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
1012
1013 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1014 for(i=0;i<nb_cpus;i++) {
1015 fputc(HDR_CPU, fp);
1016 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
1017 fwrite(&self->running_process[i]->pid,
1018 sizeof(self->running_process[i]->pid), 1, fp);
1019 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1020 // i, self->running_process[i]->pid);
1021 }
1022
1023 nb_tracefile = self->parent.tracefiles->len;
1024
1025 for(i = 0 ; i < nb_tracefile ; i++) {
1026 tfcs =
1027 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1028 LttvTracefileContext*, i));
1029 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1030 // tfcs->parent.timestamp.tv_sec,
1031 // tfcs->parent.timestamp.tv_nsec);
1032 fputc(HDR_TRACEFILE, fp);
1033 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
1034 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1035 * position following : end of trace */
1036 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
1037 if(e != NULL) {
1038 ltt_event_position(e, ep);
1039 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
1040 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1041 // tsc);
1042 fwrite(&nb_block, sizeof(nb_block), 1, fp);
1043 fwrite(&offset, sizeof(offset), 1, fp);
1044 fwrite(&tsc, sizeof(tsc), 1, fp);
1045 }
1046 }
1047 g_free(ep);
1048}
1049
1050
1051/* Read process state from a file */
1052
1053/* Called because a HDR_PROCESS was found */
1054static void read_process_state_raw(LttvTraceState *self, FILE *fp,
1055 GPtrArray *quarktable)
1056{
1057 LttvExecutionState *es;
1058 LttvProcessState *process, *parent_process;
1059 LttvProcessState tmp;
1060 GQuark tmpq;
1061 size_t res;
1062
1063 guint64 *address;
1064
1065 res = fread(&tmp.type, sizeof(tmp.type), 1, fp);
1066 res += fread(&tmp.name, sizeof(tmp.name), 1, fp);
1067 res += fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
1068 res += fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
1069 res += fread(&tmp.free_events, sizeof(tmp.free_events), 1, fp);
1070 res += fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
1071 res += fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
1072 res += fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
1073 res += fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
1074 res += fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
1075 g_assert(res == 10);
1076
1077 if(tmp.pid == 0) {
1078 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
1079 } else {
1080 /* We must link to the parent */
1081 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
1082 &ltt_time_zero);
1083 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
1084 if(process == NULL) {
1085 process = lttv_state_create_process(self, parent_process, tmp.cpu,
1086 tmp.pid, tmp.tgid,
1087 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
1088 &tmp.creation_time);
1089 }
1090 }
1091 process->insertion_time = tmp.insertion_time;
1092 process->creation_time = tmp.creation_time;
1093 process->type = g_quark_from_string(
1094 (gchar*)g_ptr_array_index(quarktable, tmp.type));
1095 process->tgid = tmp.tgid;
1096 process->ppid = tmp.ppid;
1097 process->brand = g_quark_from_string(
1098 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
1099 process->name =
1100 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
1101 process->free_events = tmp.free_events;
1102
1103 do {
1104 if(feof(fp) || ferror(fp)) goto end_loop;
1105
1106 gint hdr = fgetc(fp);
1107 if(hdr == EOF) goto end_loop;
1108
1109 switch(hdr) {
1110 case HDR_ES:
1111 process->execution_stack =
1112 g_array_set_size(process->execution_stack,
1113 process->execution_stack->len + 1);
1114 es = &g_array_index(process->execution_stack, LttvExecutionState,
1115 process->execution_stack->len-1);
1116 process->state = es;
1117
1118 res = fread(&es->t, sizeof(es->t), 1, fp);
1119 g_assert(res == 1);
1120 es->t = g_quark_from_string(
1121 (gchar*)g_ptr_array_index(quarktable, es->t));
1122 res = fread(&es->n, sizeof(es->n), 1, fp);
1123 g_assert(res == 1);
1124 es->n = g_quark_from_string(
1125 (gchar*)g_ptr_array_index(quarktable, es->n));
1126 res = fread(&es->s, sizeof(es->s), 1, fp);
1127 g_assert(res == 1);
1128 es->s = g_quark_from_string(
1129 (gchar*)g_ptr_array_index(quarktable, es->s));
1130 res = fread(&es->entry, sizeof(es->entry), 1, fp);
1131 res += fread(&es->change, sizeof(es->change), 1, fp);
1132 res += fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
1133 g_assert(res == 3);
1134 break;
1135
1136 case HDR_USER_STACK:
1137 process->user_stack = g_array_set_size(process->user_stack,
1138 process->user_stack->len + 1);
1139 address = &g_array_index(process->user_stack, guint64,
1140 process->user_stack->len-1);
1141 res = fread(address, sizeof(address), 1, fp);
1142 g_assert(res == 1);
1143 process->current_function = *address;
1144 break;
1145
1146 case HDR_USERTRACE:
1147 res = fread(&tmpq, sizeof(tmpq), 1, fp);
1148 res += fread(&process->usertrace->cpu,
1149 sizeof(process->usertrace->cpu), 1, fp);
1150 g_assert(res == 2);
1151 break;
1152
1153 default:
1154 ungetc(hdr, fp);
1155 goto end_loop;
1156 };
1157 } while(1);
1158end_loop:
1159 return;
1160}
1161
1162
1163/* Called because a HDR_PROCESS_STATE was found */
1164/* Append a saved state to the trace states */
1165void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
1166{
1167 guint i, nb_tracefile, nb_block, offset;
1168 guint64 tsc;
1169 LttvTracefileState *tfcs;
1170
1171 LttEventPosition *ep;
1172
1173 guint nb_cpus;
1174
1175 int hdr;
1176 size_t res;
1177
1178 LttTime t;
1179
1180 LttvAttribute *saved_states_tree, *saved_state_tree;
1181
1182 LttvAttributeValue value;
1183 GTree *pqueue = self->parent.ts_context->pqueue;
1184 ep = ltt_event_position_new();
1185
1186 restore_init_state(self);
1187
1188 res = fread(&t, sizeof(t), 1, fp);
1189 g_assert(res == 1);
1190
1191 do {
1192 if(feof(fp) || ferror(fp)) goto end_loop;
1193 hdr = fgetc(fp);
1194 if(hdr == EOF) goto end_loop;
1195
1196 switch(hdr) {
1197 case HDR_PROCESS:
1198 /* Call read_process_state_raw */
1199 read_process_state_raw(self, fp, quarktable);
1200 break;
1201 case HDR_TRACEFILE:
1202 case HDR_TRACESET:
1203 case HDR_TRACE:
1204 case HDR_QUARKS:
1205 case HDR_QUARK:
1206 case HDR_ES:
1207 case HDR_USER_STACK:
1208 case HDR_USERTRACE:
1209 case HDR_PROCESS_STATE:
1210 case HDR_CPU:
1211 ungetc(hdr, fp);
1212 goto end_loop;
1213 break;
1214 default:
1215 g_error("Error while parsing saved state file : unknown data header %d",
1216 hdr);
1217 };
1218 } while(1);
1219end_loop:
1220
1221 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1222 for(i=0;i<nb_cpus;i++) {
1223 int cpu_num;
1224 hdr = fgetc(fp);
1225 g_assert(hdr == HDR_CPU);
1226 res = fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
1227 g_assert(res == 1);
1228 g_assert(i == cpu_num);
1229 res = fread(&self->running_process[i]->pid,
1230 sizeof(self->running_process[i]->pid), 1, fp);
1231 g_assert(res == 1);
1232 }
1233
1234 nb_tracefile = self->parent.tracefiles->len;
1235
1236 for(i = 0 ; i < nb_tracefile ; i++) {
1237 tfcs =
1238 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1239 LttvTracefileContext*, i));
1240 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1241 // tfcs->parent.timestamp.tv_sec,
1242 // tfcs->parent.timestamp.tv_nsec);
1243 g_tree_remove(pqueue, &tfcs->parent);
1244 hdr = fgetc(fp);
1245 g_assert(hdr == HDR_TRACEFILE);
1246 res = fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
1247 g_assert(res == 1);
1248 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1249 * position following : end of trace */
1250 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
1251 res = fread(&nb_block, sizeof(nb_block), 1, fp);
1252 res += fread(&offset, sizeof(offset), 1, fp);
1253 res += fread(&tsc, sizeof(tsc), 1, fp);
1254 g_assert(res == 3);
1255 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
1256 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
1257 g_assert(ret == 0);
1258 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
1259 }
1260 }
1261 g_free(ep);
1262
1263 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
1264 LTTV_STATE_SAVED_STATES);
1265 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1266 value = lttv_attribute_add(saved_states_tree,
1267 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1268 *(value.v_gobject) = (GObject *)saved_state_tree;
1269 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1270 *(value.v_time) = t;
1271 lttv_state_save(self, saved_state_tree);
1272 g_debug("Saving state at time %lu.%lu", t.tv_sec,
1273 t.tv_nsec);
1274
1275 *(self->max_time_state_recomputed_in_seek) = t;
1276
1277}
1278
1279/* Called when a HDR_TRACE is found */
1280void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
1281 GPtrArray *quarktable)
1282{
1283 int hdr;
1284
1285 do {
1286 if(feof(fp) || ferror(fp)) goto end_loop;
1287 hdr = fgetc(fp);
1288 if(hdr == EOF) goto end_loop;
1289
1290 switch(hdr) {
1291 case HDR_PROCESS_STATE:
1292 /* Call read_process_state_raw */
1293 lttv_state_read_raw(tcs, fp, quarktable);
1294 break;
1295 case HDR_TRACEFILE:
1296 case HDR_TRACESET:
1297 case HDR_TRACE:
1298 case HDR_QUARKS:
1299 case HDR_QUARK:
1300 case HDR_ES:
1301 case HDR_USER_STACK:
1302 case HDR_USERTRACE:
1303 case HDR_PROCESS:
1304 case HDR_CPU:
1305 g_error("Error while parsing saved state file :"
1306 " unexpected data header %d",
1307 hdr);
1308 break;
1309 default:
1310 g_error("Error while parsing saved state file : unknown data header %d",
1311 hdr);
1312 };
1313 } while(1);
1314end_loop:
1315 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1316 restore_init_state(tcs);
1317 lttv_process_trace_seek_time(&tcs->parent, ltt_time_zero);
1318 return;
1319}
1320
1321
1322
1323/* Copy each process from an existing hash table to a new one */
1324
1325static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
1326{
1327 LttvProcessState *process, *new_process;
1328
1329 GHashTable *new_processes = (GHashTable *)user_data;
1330
1331 guint i;
1332
1333 process = (LttvProcessState *)value;
1334 new_process = g_new(LttvProcessState, 1);
1335 *new_process = *process;
1336 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1337 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1338 new_process->execution_stack =
1339 g_array_set_size(new_process->execution_stack,
1340 process->execution_stack->len);
1341 for(i = 0 ; i < process->execution_stack->len; i++) {
1342 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1343 g_array_index(process->execution_stack, LttvExecutionState, i);
1344 }
1345 new_process->state = &g_array_index(new_process->execution_stack,
1346 LttvExecutionState, new_process->execution_stack->len - 1);
1347 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1348 sizeof(guint64), 0);
1349 new_process->user_stack = g_array_set_size(new_process->user_stack,
1350 process->user_stack->len);
1351 for(i = 0 ; i < process->user_stack->len; i++) {
1352 g_array_index(new_process->user_stack, guint64, i) =
1353 g_array_index(process->user_stack, guint64, i);
1354 }
1355 new_process->current_function = process->current_function;
1356
1357 /* fd hash table stuff */
1358 {
1359 GHashTableIter it;
1360 gpointer key;
1361 gpointer value;
1362
1363 /* copy every item in the hash table */
1364 new_process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
1365
1366 g_hash_table_iter_init(&it, process->fds);
1367 while (g_hash_table_iter_next (&it, (void *)&key, (void *)&value)) {
1368 g_hash_table_insert(new_process->fds, key, value);
1369 }
1370 }
1371
1372 /* When done creating the new process state, insert it in the
1373 * hash table */
1374 g_hash_table_insert(new_processes, new_process, new_process);
1375}
1376
1377
1378static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
1379{
1380 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
1381
1382 g_hash_table_foreach(processes, copy_process_state, new_processes);
1383 return new_processes;
1384}
1385
1386static LttvCPUState *lttv_state_copy_cpu_states(LttvCPUState *states, guint n)
1387{
1388 guint i,j;
1389 LttvCPUState *retval;
1390
1391 retval = g_new(LttvCPUState, n);
1392
1393 for(i=0; i<n; i++) {
1394 retval[i].irq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1395 g_array_set_size(retval[i].irq_stack, states[i].irq_stack->len);
1396 for(j=0; j<states[i].irq_stack->len; j++) {
1397 g_array_index(retval[i].irq_stack, gint, j) =
1398 g_array_index(states[i].irq_stack, gint, j);
1399 }
1400
1401 retval[i].softirq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1402 g_array_set_size(retval[i].softirq_stack, states[i].softirq_stack->len);
1403 for(j=0; j<states[i].softirq_stack->len; j++) {
1404 g_array_index(retval[i].softirq_stack, gint, j) =
1405 g_array_index(states[i].softirq_stack, gint, j);
1406 }
1407
1408 retval[i].trap_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1409 g_array_set_size(retval[i].trap_stack, states[i].trap_stack->len);
1410 for(j=0; j<states[i].trap_stack->len; j++) {
1411 g_array_index(retval[i].trap_stack, gint, j) =
1412 g_array_index(states[i].trap_stack, gint, j);
1413 }
1414
1415 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
1416 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1417 for(j=0; j<states[i].mode_stack->len; j++) {
1418 g_array_index(retval[i].mode_stack, GQuark, j) =
1419 g_array_index(states[i].mode_stack, GQuark, j);
1420 }
1421 }
1422
1423 return retval;
1424}
1425
1426static void lttv_state_free_cpu_states(LttvCPUState *states, guint n)
1427{
1428 guint i;
1429
1430 for(i=0; i<n; i++) {
1431 g_array_free(states[i].mode_stack, TRUE);
1432 g_array_free(states[i].irq_stack, TRUE);
1433 g_array_free(states[i].softirq_stack, TRUE);
1434 g_array_free(states[i].trap_stack, TRUE);
1435 }
1436
1437 g_free(states);
1438}
1439
1440static LttvIRQState *lttv_state_copy_irq_states(LttvIRQState *states, guint n)
1441{
1442 guint i,j;
1443 LttvIRQState *retval;
1444
1445 retval = g_new(LttvIRQState, n);
1446
1447 for(i=0; i<n; i++) {
1448 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
1449 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1450 for(j=0; j<states[i].mode_stack->len; j++) {
1451 g_array_index(retval[i].mode_stack, GQuark, j) =
1452 g_array_index(states[i].mode_stack, GQuark, j);
1453 }
1454 }
1455
1456 return retval;
1457}
1458
1459static void lttv_state_free_irq_states(LttvIRQState *states, guint n)
1460{
1461 guint i;
1462
1463 for(i=0; i<n; i++) {
1464 g_array_free(states[i].mode_stack, TRUE);
1465 }
1466
1467 g_free(states);
1468}
1469
1470static LttvSoftIRQState *
1471lttv_state_copy_soft_irq_states(LttvSoftIRQState *states, guint n)
1472{
1473 guint i;
1474 LttvSoftIRQState *retval;
1475
1476 retval = g_new(LttvSoftIRQState, n);
1477
1478 for(i=0; i<n; i++) {
1479 retval[i].pending = states[i].pending;
1480 retval[i].running = states[i].running;
1481 }
1482
1483 return retval;
1484}
1485
1486static void lttv_state_free_soft_irq_states(LttvSoftIRQState *states, guint n)
1487{
1488 g_free(states);
1489}
1490
1491static LttvTrapState *
1492lttv_state_copy_trap_states(LttvTrapState *states, guint n)
1493{
1494 guint i;
1495 LttvTrapState *retval;
1496
1497 retval = g_new(LttvTrapState, n);
1498
1499 for(i=0; i<n; i++) {
1500 retval[i].running = states[i].running;
1501 }
1502
1503 return retval;
1504}
1505
1506static void lttv_state_free_trap_states(LttvTrapState *states, guint n)
1507{
1508 g_free(states);
1509}
1510
1511/* bdevstate stuff */
1512
1513static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint32 devcode)
1514{
1515 gint devcode_gint = devcode;
1516 gpointer bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
1517 if(bdev == NULL) {
1518 LttvBdevState *bdevstate = g_new(LttvBdevState, 1);
1519 bdevstate->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1520
1521 gint * key = g_new(gint, 1);
1522 *key = devcode;
1523 g_hash_table_insert(ts->bdev_states, key, bdevstate);
1524
1525 bdev = bdevstate;
1526 }
1527
1528 return bdev;
1529}
1530
1531static LttvBdevState *bdevstate_new(void)
1532{
1533 LttvBdevState *retval;
1534 retval = g_new(LttvBdevState, 1);
1535 retval->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1536
1537 return retval;
1538}
1539
1540static void bdevstate_free(LttvBdevState *bds)
1541{
1542 g_array_free(bds->mode_stack, TRUE);
1543 g_free(bds);
1544}
1545
1546static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data)
1547{
1548 LttvBdevState *bds = (LttvBdevState *) value;
1549
1550 bdevstate_free(bds);
1551}
1552
1553static LttvBdevState *bdevstate_copy(LttvBdevState *bds)
1554{
1555 LttvBdevState *retval;
1556
1557 retval = bdevstate_new();
1558 g_array_insert_vals(retval->mode_stack, 0, bds->mode_stack->data,
1559 bds->mode_stack->len);
1560
1561 return retval;
1562}
1563
1564static void insert_and_copy_bdev_state(gpointer k, gpointer v, gpointer u)
1565{
1566 //GHashTable *ht = (GHashTable *)u;
1567 LttvBdevState *bds = (LttvBdevState *)v;
1568 LttvBdevState *newbds;
1569
1570 newbds = bdevstate_copy(bds);
1571
1572 g_hash_table_insert(u, k, newbds);
1573}
1574
1575static GHashTable *lttv_state_copy_blkdev_hashtable(GHashTable *ht)
1576{
1577 GHashTable *retval;
1578
1579 retval = g_hash_table_new(g_int_hash, g_int_equal);
1580
1581 g_hash_table_foreach(ht, insert_and_copy_bdev_state, retval);
1582
1583 return retval;
1584}
1585
1586/* Free a hashtable and the LttvBdevState structures its values
1587 * point to. */
1588
1589static void lttv_state_free_blkdev_hashtable(GHashTable *ht)
1590{
1591 g_hash_table_foreach(ht, bdevstate_free_cb, NULL);
1592 g_hash_table_destroy(ht);
1593}
1594
1595/* The saved state for each trace contains a member "processes", which
1596 stores a copy of the process table, and a member "tracefiles" with
1597 one entry per tracefile. Each tracefile has a "process" member pointing
1598 to the current process and a "position" member storing the tracefile
1599 position (needed to seek to the current "next" event. */
1600
1601static void state_save(LttvTraceState *self, LttvAttribute *container)
1602{
1603 guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1604
1605 LttvTracefileState *tfcs;
1606
1607 LttvAttribute *tracefiles_tree, *tracefile_tree;
1608
1609 guint *running_process;
1610
1611 LttvAttributeValue value;
1612
1613 LttEventPosition *ep;
1614
1615 tracefiles_tree = lttv_attribute_find_subdir(container,
1616 LTTV_STATE_TRACEFILES);
1617
1618 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1619 LTTV_POINTER);
1620 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1621
1622 /* Add the currently running processes array */
1623 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1624 running_process = g_new(guint, nb_cpus);
1625 for(i=0;i<nb_cpus;i++) {
1626 running_process[i] = self->running_process[i]->pid;
1627 }
1628 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1629 LTTV_POINTER);
1630 *(value.v_pointer) = running_process;
1631
1632 g_info("State save");
1633
1634 nb_tracefile = self->parent.tracefiles->len;
1635
1636 for(i = 0 ; i < nb_tracefile ; i++) {
1637 tfcs =
1638 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1639 LttvTracefileContext*, i));
1640 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1641 value = lttv_attribute_add(tracefiles_tree, i,
1642 LTTV_GOBJECT);
1643 *(value.v_gobject) = (GObject *)tracefile_tree;
1644#if 0
1645 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1646 LTTV_UINT);
1647 *(value.v_uint) = tfcs->process->pid;
1648#endif //0
1649 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1650 LTTV_POINTER);
1651 /* Only save the position if the tfs has not infinite time. */
1652 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1653 // && current_tfcs != tfcs) {
1654 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1655 *(value.v_pointer) = NULL;
1656 } else {
1657 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
1658 ep = ltt_event_position_new();
1659 ltt_event_position(e, ep);
1660 *(value.v_pointer) = ep;
1661
1662 guint nb_block, offset;
1663 guint64 tsc;
1664 LttTracefile *tf;
1665 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
1666 g_info("Block %u offset %u tsc %" PRIu64 " time %lu.%lu", nb_block,
1667 offset, tsc, tfcs->parent.timestamp.tv_sec,
1668 tfcs->parent.timestamp.tv_nsec);
1669 }
1670 }
1671
1672 /* save the cpu state */
1673 {
1674 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS_COUNT,
1675 LTTV_UINT);
1676 *(value.v_uint) = nb_cpus;
1677
1678 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS,
1679 LTTV_POINTER);
1680 *(value.v_pointer) = lttv_state_copy_cpu_states(self->cpu_states, nb_cpus);
1681 }
1682
1683 /* save the irq state */
1684 nb_irqs = self->name_tables->nb_irqs;
1685 {
1686 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_IRQS,
1687 LTTV_POINTER);
1688 *(value.v_pointer) = lttv_state_copy_irq_states(self->irq_states, nb_irqs);
1689 }
1690
1691 /* save the soft irq state */
1692 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1693 {
1694 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_SOFT_IRQS,
1695 LTTV_POINTER);
1696 *(value.v_pointer) = lttv_state_copy_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1697 }
1698
1699 /* save the trap state */
1700 nb_traps = self->name_tables->nb_traps;
1701 {
1702 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_TRAPS,
1703 LTTV_POINTER);
1704 *(value.v_pointer) = lttv_state_copy_trap_states(self->trap_states, nb_traps);
1705 }
1706
1707 /* save the blkdev states */
1708 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_BLKDEVS,
1709 LTTV_POINTER);
1710 *(value.v_pointer) = lttv_state_copy_blkdev_hashtable(self->bdev_states);
1711}
1712
1713
1714static void state_restore(LttvTraceState *self, LttvAttribute *container)
1715{
1716 guint i, nb_tracefile, pid, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1717
1718 LttvTracefileState *tfcs;
1719
1720 LttvAttribute *tracefiles_tree, *tracefile_tree;
1721
1722 guint *running_process;
1723
1724 LttvAttributeType type;
1725
1726 LttvAttributeValue value;
1727
1728 LttvAttributeName name;
1729
1730 gboolean is_named;
1731
1732 LttEventPosition *ep;
1733
1734 LttvTracesetContext *tsc = self->parent.ts_context;
1735 int retval;
1736
1737 tracefiles_tree = lttv_attribute_find_subdir(container,
1738 LTTV_STATE_TRACEFILES);
1739
1740 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1741 &value);
1742 g_assert(type == LTTV_POINTER);
1743 lttv_state_free_process_table(self->processes);
1744 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1745
1746 /* Add the currently running processes array */
1747 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1748 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1749 &value);
1750 g_assert(type == LTTV_POINTER);
1751 running_process = *(value.v_pointer);
1752 for(i=0;i<nb_cpus;i++) {
1753 pid = running_process[i];
1754 self->running_process[i] = lttv_state_find_process(self, i, pid);
1755 g_assert(self->running_process[i] != NULL);
1756 }
1757
1758 nb_tracefile = self->parent.tracefiles->len;
1759
1760 //g_tree_destroy(tsc->pqueue);
1761 //tsc->pqueue = g_tree_new(compare_tracefile);
1762
1763 /* restore cpu resource states */
1764 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1765 g_assert(type == LTTV_POINTER);
1766 lttv_state_free_cpu_states(self->cpu_states, nb_cpus);
1767 self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus);
1768
1769 /* restore irq resource states */
1770 nb_irqs = self->name_tables->nb_irqs;
1771 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1772 g_assert(type == LTTV_POINTER);
1773 lttv_state_free_irq_states(self->irq_states, nb_irqs);
1774 self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs);
1775
1776 /* restore soft irq resource states */
1777 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1778 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1779 g_assert(type == LTTV_POINTER);
1780 lttv_state_free_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1781 self->soft_irq_states = lttv_state_copy_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1782
1783 /* restore trap resource states */
1784 nb_traps = self->name_tables->nb_traps;
1785 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_TRAPS, &value);
1786 g_assert(type == LTTV_POINTER);
1787 lttv_state_free_trap_states(self->trap_states, nb_traps);
1788 self->trap_states = lttv_state_copy_trap_states(*(value.v_pointer), nb_traps);
1789
1790 /* restore the blkdev states */
1791 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1792 g_assert(type == LTTV_POINTER);
1793 lttv_state_free_blkdev_hashtable(self->bdev_states);
1794 self->bdev_states = lttv_state_copy_blkdev_hashtable(*(value.v_pointer));
1795
1796 for(i = 0 ; i < nb_tracefile ; i++) {
1797 tfcs =
1798 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1799 LttvTracefileContext*, i));
1800 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1801 g_assert(type == LTTV_GOBJECT);
1802 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1803#if 0
1804 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1805 &value);
1806 g_assert(type == LTTV_UINT);
1807 pid = *(value.v_uint);
1808 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
1809#endif //0
1810 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1811 &value);
1812 g_assert(type == LTTV_POINTER);
1813 //g_assert(*(value.v_pointer) != NULL);
1814 ep = *(value.v_pointer);
1815 g_assert(tfcs->parent.t_context != NULL);
1816
1817 tfcs->cpu_state = &self->cpu_states[tfcs->cpu];
1818
1819 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
1820 g_tree_remove(tsc->pqueue, tfc);
1821
1822 if(ep != NULL) {
1823 retval= ltt_tracefile_seek_position(tfc->tf, ep);
1824 g_assert_cmpint(retval, ==, 0);
1825 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
1826 g_assert_cmpint(ltt_time_compare(tfc->timestamp, ltt_time_infinite),
1827 !=, 0);
1828 g_tree_insert(tsc->pqueue, tfc, tfc);
1829 g_info("Restoring state for a tf at time %lu.%lu",
1830 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1831 } else {
1832 tfc->timestamp = ltt_time_infinite;
1833 }
1834 }
1835}
1836
1837
1838static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
1839{
1840 guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs;
1841
1842 LttvTracefileState *tfcs;
1843
1844 LttvAttribute *tracefiles_tree, *tracefile_tree;
1845
1846 guint *running_process;
1847
1848 LttvAttributeType type;
1849
1850 LttvAttributeValue value;
1851
1852 LttvAttributeName name;
1853
1854 gboolean is_named;
1855
1856 tracefiles_tree = lttv_attribute_find_subdir(container,
1857 LTTV_STATE_TRACEFILES);
1858 g_object_ref(G_OBJECT(tracefiles_tree));
1859 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
1860
1861 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1862 &value);
1863 g_assert(type == LTTV_POINTER);
1864 lttv_state_free_process_table(*(value.v_pointer));
1865 *(value.v_pointer) = NULL;
1866 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1867
1868 /* Free running processes array */
1869 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1870 &value);
1871 g_assert(type == LTTV_POINTER);
1872 running_process = *(value.v_pointer);
1873 g_free(running_process);
1874
1875 /* free cpu resource states */
1876 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS_COUNT, &value);
1877 g_assert(type == LTTV_UINT);
1878 nb_cpus = *value.v_uint;
1879 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1880 g_assert(type == LTTV_POINTER);
1881 lttv_state_free_cpu_states(*(value.v_pointer), nb_cpus);
1882
1883 /* free irq resource states */
1884 nb_irqs = self->name_tables->nb_irqs;
1885 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1886 g_assert(type == LTTV_POINTER);
1887 lttv_state_free_irq_states(*(value.v_pointer), nb_irqs);
1888
1889 /* free softirq resource states */
1890 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1891 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1892 g_assert(type == LTTV_POINTER);
1893 lttv_state_free_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1894
1895 /* free the blkdev states */
1896 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1897 g_assert(type == LTTV_POINTER);
1898 lttv_state_free_blkdev_hashtable(*(value.v_pointer));
1899
1900 nb_tracefile = self->parent.tracefiles->len;
1901
1902 for(i = 0 ; i < nb_tracefile ; i++) {
1903 tfcs =
1904 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1905 LttvTracefileContext*, i));
1906 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1907 g_assert(type == LTTV_GOBJECT);
1908 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1909
1910 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1911 &value);
1912 g_assert(type == LTTV_POINTER);
1913 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
1914 }
1915 g_object_unref(G_OBJECT(tracefiles_tree));
1916}
1917
1918
1919static void free_saved_state(LttvTraceState *self)
1920{
1921 guint i, nb;
1922
1923 LttvAttributeType type;
1924
1925 LttvAttributeValue value;
1926
1927 LttvAttributeName name;
1928
1929 gboolean is_named;
1930
1931 LttvAttribute *saved_states;
1932
1933 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1934 LTTV_STATE_SAVED_STATES);
1935
1936 nb = lttv_attribute_get_number(saved_states);
1937 for(i = 0 ; i < nb ; i++) {
1938 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
1939 g_assert(type == LTTV_GOBJECT);
1940 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1941 }
1942
1943 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
1944}
1945
1946
1947static void create_max_time(LttvTraceState *tcs)
1948{
1949 LttvAttributeValue v;
1950
1951 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1952 LTTV_POINTER, &v);
1953 g_assert(*(v.v_pointer) == NULL);
1954 *(v.v_pointer) = g_new(LttTime,1);
1955 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
1956}
1957
1958
1959static void get_max_time(LttvTraceState *tcs)
1960{
1961 LttvAttributeValue v;
1962
1963 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1964 LTTV_POINTER, &v);
1965 g_assert(*(v.v_pointer) != NULL);
1966 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1967}
1968
1969
1970static void free_max_time(LttvTraceState *tcs)
1971{
1972 LttvAttributeValue v;
1973
1974 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1975 LTTV_POINTER, &v);
1976 g_free(*(v.v_pointer));
1977 *(v.v_pointer) = NULL;
1978}
1979
1980static void create_name_tables(LttvTraceState *tcs)
1981{
1982 int i;
1983
1984 GString *fe_name = g_string_new("");
1985
1986 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1987
1988 LttvAttributeValue v;
1989
1990 GArray *hooks;
1991
1992 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1993 LTTV_POINTER, &v);
1994 g_assert(*(v.v_pointer) == NULL);
1995 *(v.v_pointer) = name_tables;
1996
1997 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1);
1998
1999 if(!lttv_trace_find_hook(tcs->parent.t,
2000 LTT_CHANNEL_KERNEL,
2001 LTT_EVENT_SYSCALL_ENTRY,
2002 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
2003 NULL, NULL, &hooks)) {
2004
2005// th = lttv_trace_hook_get_first(&th);
2006//
2007// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2008// nb = ltt_type_element_number(t);
2009//
2010// name_tables->syscall_names = g_new(GQuark, nb);
2011// name_tables->nb_syscalls = nb;
2012//
2013// for(i = 0 ; i < nb ; i++) {
2014// name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
2015// if(!name_tables->syscall_names[i]) {
2016// GString *string = g_string_new("");
2017// g_string_printf(string, "syscall %u", i);
2018// name_tables->syscall_names[i] = g_quark_from_string(string->str);
2019// g_string_free(string, TRUE);
2020// }
2021// }
2022
2023 name_tables->nb_syscalls = PREALLOC_NB_SYSCALLS;
2024 name_tables->syscall_names = g_new(GQuark, name_tables->nb_syscalls);
2025 for(i = 0 ; i < name_tables->nb_syscalls; i++) {
2026 g_string_printf(fe_name, "syscall %d", i);
2027 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
2028 }
2029 } else {
2030 name_tables->syscall_names = NULL;
2031 name_tables->nb_syscalls = 0;
2032 }
2033 lttv_trace_hook_remove_all(&hooks);
2034
2035 if(!lttv_trace_find_hook(tcs->parent.t,
2036 LTT_CHANNEL_KERNEL,
2037 LTT_EVENT_TRAP_ENTRY,
2038 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
2039 NULL, NULL, &hooks) ||
2040 !lttv_trace_find_hook(tcs->parent.t,
2041 LTT_CHANNEL_KERNEL,
2042 LTT_EVENT_PAGE_FAULT_ENTRY,
2043 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
2044 NULL, NULL, &hooks)) {
2045
2046// th = lttv_trace_hook_get_first(&th);
2047//
2048// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2049// //nb = ltt_type_element_number(t);
2050//
2051// name_tables->trap_names = g_new(GQuark, nb);
2052// for(i = 0 ; i < nb ; i++) {
2053// name_tables->trap_names[i] = g_quark_from_string(
2054// ltt_enum_string_get(t, i));
2055// }
2056
2057 name_tables->nb_traps = PREALLOC_NB_TRAPS;
2058 name_tables->trap_names = g_new(GQuark, name_tables->nb_traps);
2059 for(i = 0 ; i < name_tables->nb_traps; i++) {
2060 g_string_printf(fe_name, "trap %d", i);
2061 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
2062 }
2063 } else {
2064 name_tables->trap_names = NULL;
2065 name_tables->nb_traps = 0;
2066 }
2067 lttv_trace_hook_remove_all(&hooks);
2068
2069 if(!lttv_trace_find_hook(tcs->parent.t,
2070 LTT_CHANNEL_KERNEL,
2071 LTT_EVENT_IRQ_ENTRY,
2072 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
2073 NULL, NULL, &hooks)) {
2074
2075 /*
2076 name_tables->irq_names = g_new(GQuark, nb);
2077 for(i = 0 ; i < nb ; i++) {
2078 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2079 }
2080 */
2081 /* FIXME: LttvIRQState *irq_states should become a g_array */
2082
2083 name_tables->nb_irqs = PREALLOC_NB_IRQS;
2084 name_tables->irq_names = g_new(GQuark, name_tables->nb_irqs);
2085 for(i = 0 ; i < name_tables->nb_irqs; i++) {
2086 g_string_printf(fe_name, "irq %d", i);
2087 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
2088 }
2089 } else {
2090 name_tables->nb_irqs = 0;
2091 name_tables->irq_names = NULL;
2092 }
2093 lttv_trace_hook_remove_all(&hooks);
2094 /*
2095 name_tables->soft_irq_names = g_new(GQuark, nb);
2096 for(i = 0 ; i < nb ; i++) {
2097 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2098 }
2099 */
2100
2101 name_tables->nb_soft_irqs = PREALLOC_NB_SOFT_IRQS;
2102 name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_soft_irqs);
2103 for(i = 0 ; i < name_tables->nb_soft_irqs ; i++) {
2104 g_string_printf(fe_name, "softirq %d", i);
2105 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
2106 }
2107 g_array_free(hooks, TRUE);
2108
2109 g_string_free(fe_name, TRUE);
2110
2111#if (__WORDSIZE == 32)
2112 name_tables->kprobe_hash = g_hash_table_new_full(guint64_hash, guint64_equal,
2113 g_free, NULL);
2114#else
2115 name_tables->kprobe_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
2116#endif
2117}
2118
2119
2120static void get_name_tables(LttvTraceState *tcs)
2121{
2122 LttvAttributeValue v;
2123
2124 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
2125 LTTV_POINTER, &v);
2126 g_assert(*(v.v_pointer) != NULL);
2127 tcs->name_tables = (LttvNameTables *)*(v.v_pointer);
2128}
2129
2130
2131static void free_name_tables(LttvTraceState *tcs)
2132{
2133 LttvNameTables *name_tables;
2134
2135 LttvAttributeValue v;
2136
2137 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
2138 LTTV_POINTER, &v);
2139 name_tables = (LttvNameTables *)*(v.v_pointer);
2140 *(v.v_pointer) = NULL;
2141
2142 // g_free(name_tables->eventtype_names);
2143 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
2144 if(name_tables->trap_names) g_free(name_tables->trap_names);
2145 if(name_tables->irq_names) g_free(name_tables->irq_names);
2146 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
2147 g_hash_table_destroy(name_tables->kprobe_hash);
2148 g_free(name_tables);
2149}
2150
2151#ifdef HASH_TABLE_DEBUG
2152
2153static void test_process(gpointer key, gpointer value, gpointer user_data)
2154{
2155 LttvProcessState *process = (LttvProcessState *)value;
2156
2157 /* Test for process corruption */
2158 guint stack_len = process->execution_stack->len;
2159}
2160
2161static void hash_table_check(GHashTable *table)
2162{
2163 g_hash_table_foreach(table, test_process, NULL);
2164}
2165
2166
2167#endif
2168
2169/* clears the stack and sets the state passed as argument */
2170static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
2171{
2172 g_array_set_size(cpust->mode_stack, 1);
2173 ((GQuark *)cpust->mode_stack->data)[0] = state;
2174}
2175
2176static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
2177{
2178 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
2179 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
2180}
2181
2182static void cpu_pop_mode(LttvCPUState *cpust)
2183{
2184 if(cpust->mode_stack->len <= 1)
2185 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
2186 else
2187 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
2188}
2189
2190/* clears the stack and sets the state passed as argument */
2191static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
2192{
2193 g_array_set_size(bdevst->mode_stack, 1);
2194 ((GQuark *)bdevst->mode_stack->data)[0] = state;
2195}
2196
2197static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
2198{
2199 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
2200 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
2201}
2202
2203static void bdev_pop_mode(LttvBdevState *bdevst)
2204{
2205 if(bdevst->mode_stack->len <= 1)
2206 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
2207 else
2208 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
2209}
2210
2211static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
2212{
2213 g_array_set_size(irqst->mode_stack, 1);
2214 ((GQuark *)irqst->mode_stack->data)[0] = state;
2215}
2216
2217static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
2218{
2219 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
2220 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
2221}
2222
2223static void irq_pop_mode(LttvIRQState *irqst)
2224{
2225 if(irqst->mode_stack->len <= 1)
2226 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
2227 else
2228 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
2229}
2230
2231static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
2232 guint state_id)
2233{
2234 LttvExecutionState *es;
2235
2236 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2237 guint cpu = tfs->cpu;
2238
2239#ifdef HASH_TABLE_DEBUG
2240 hash_table_check(ts->processes);
2241#endif
2242 LttvProcessState *process = ts->running_process[cpu];
2243
2244 guint depth = process->execution_stack->len;
2245
2246 process->execution_stack =
2247 g_array_set_size(process->execution_stack, depth + 1);
2248 /* Keep in sync */
2249 process->state =
2250 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
2251
2252 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
2253 es->t = t;
2254 es->n = state_id;
2255 es->entry = es->change = tfs->parent.timestamp;
2256 es->cum_cpu_time = ltt_time_zero;
2257 es->s = process->state->s;
2258 process->state = es;
2259}
2260
2261/* pop state
2262 * return 1 when empty, else 0 */
2263int
2264lttv_state_pop_state_cleanup(LttvProcessState *process, LttvTracefileState *tfs)
2265{
2266 guint depth = process->execution_stack->len;
2267
2268 if(depth == 1){
2269 return 1;
2270 }
2271
2272 process->execution_stack =
2273 g_array_set_size(process->execution_stack, depth - 1);
2274 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2275 depth - 2);
2276 process->state->change = tfs->parent.timestamp;
2277
2278 return 0;
2279}
2280
2281static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
2282{
2283 guint cpu = tfs->cpu;
2284 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2285 LttvProcessState *process = ts->running_process[cpu];
2286
2287 guint depth = process->execution_stack->len;
2288
2289 if(process->state->t != t){
2290 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2291 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2292 g_info("process state has %s when pop_int is %s\n",
2293 g_quark_to_string(process->state->t),
2294 g_quark_to_string(t));
2295 g_info("{ %u, %u, %s, %s, %s }\n",
2296 process->pid,
2297 process->ppid,
2298 g_quark_to_string(process->name),
2299 g_quark_to_string(process->brand),
2300 g_quark_to_string(process->state->s));
2301 return;
2302 }
2303
2304 if(depth == 1){
2305 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2306 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2307 return;
2308 }
2309
2310 process->execution_stack =
2311 g_array_set_size(process->execution_stack, depth - 1);
2312 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2313 depth - 2);
2314 process->state->change = tfs->parent.timestamp;
2315}
2316
2317struct search_result {
2318 const LttTime *time; /* Requested time */
2319 LttTime *best; /* Best result */
2320};
2321
2322static gint search_usertrace(gconstpointer a, gconstpointer b)
2323{
2324 const LttTime *elem_time = (const LttTime*)a;
2325 /* Explicit non const cast */
2326 struct search_result *res = (struct search_result *)b;
2327
2328 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
2329 /* The usertrace was created before the schedchange */
2330 /* Get larger keys */
2331 return 1;
2332 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
2333 /* The usertrace was created after the schedchange time */
2334 /* Get smaller keys */
2335 if(res->best) {
2336 if(ltt_time_compare(*elem_time, *res->best) < 0) {
2337 res->best = (LttTime *)elem_time;
2338 }
2339 } else {
2340 res->best = (LttTime *)elem_time;
2341 }
2342 return -1;
2343 }
2344 return 0;
2345}
2346
2347static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
2348 guint pid, const LttTime *timestamp)
2349{
2350 LttvTracefileState *tfs = NULL;
2351 struct search_result res;
2352 /* Find the usertrace associated with a pid and time interval.
2353 * Search in the usertraces by PID (within a hash) and then, for each
2354 * corresponding element of the array, find the first one with creation
2355 * timestamp the lowest, but higher or equal to "timestamp". */
2356 res.time = timestamp;
2357 res.best = NULL;
2358 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces,
2359 GUINT_TO_POINTER(pid));
2360 if(usertrace_tree) {
2361 g_tree_search(usertrace_tree, search_usertrace, &res);
2362 if(res.best)
2363 tfs = g_tree_lookup(usertrace_tree, res.best);
2364 }
2365
2366 return tfs;
2367}
2368
2369/* Return a new and initialized LttvProcessState structure */
2370
2371LttvProcessState *lttv_state_create_process(LttvTraceState *tcs,
2372 LttvProcessState *parent, guint cpu, guint pid,
2373 guint tgid, GQuark name, const LttTime *timestamp)
2374{
2375 LttvProcessState *process = g_new(LttvProcessState, 1);
2376
2377 LttvExecutionState *es;
2378
2379 char buffer[128];
2380
2381 process->pid = pid;
2382 process->tgid = tgid;
2383 process->cpu = cpu;
2384 process->name = name;
2385 process->brand = LTTV_STATE_UNBRANDED;
2386 //process->last_cpu = tfs->cpu_name;
2387 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2388 process->type = LTTV_STATE_USER_THREAD;
2389 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2390 process->current_function = 0; //function 0x0 by default.
2391
2392 g_info("Process %u, core %p", process->pid, process);
2393 g_hash_table_insert(tcs->processes, process, process);
2394
2395 if(parent) {
2396 process->ppid = parent->pid;
2397 process->creation_time = *timestamp;
2398 }
2399
2400 /* No parent. This process exists but we are missing all information about
2401 its creation. The birth time is set to zero but we remember the time of
2402 insertion */
2403
2404 else {
2405 process->ppid = 0;
2406 process->creation_time = ltt_time_zero;
2407 }
2408
2409 process->insertion_time = *timestamp;
2410 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2411 process->creation_time.tv_nsec);
2412 process->pid_time = g_quark_from_string(buffer);
2413 process->cpu = cpu;
2414 process->free_events = 0;
2415 //process->last_cpu = tfs->cpu_name;
2416 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2417 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2418 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2419 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2420 es = process->state = &g_array_index(process->execution_stack,
2421 LttvExecutionState, 0);
2422 es->t = LTTV_STATE_USER_MODE;
2423 es->n = LTTV_STATE_SUBMODE_NONE;
2424 es->entry = *timestamp;
2425 //g_assert(timestamp->tv_sec != 0);
2426 es->change = *timestamp;
2427 es->cum_cpu_time = ltt_time_zero;
2428 es->s = LTTV_STATE_RUN;
2429
2430 es = process->state = &g_array_index(process->execution_stack,
2431 LttvExecutionState, 1);
2432 es->t = LTTV_STATE_SYSCALL;
2433 es->n = LTTV_STATE_SUBMODE_NONE;
2434 es->entry = *timestamp;
2435 //g_assert(timestamp->tv_sec != 0);
2436 es->change = *timestamp;
2437 es->cum_cpu_time = ltt_time_zero;
2438 es->s = LTTV_STATE_WAIT_FORK;
2439
2440 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2441 process->user_stack = g_array_sized_new(FALSE, FALSE,
2442 sizeof(guint64), 0);
2443
2444 process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
2445
2446 return process;
2447}
2448
2449LttvProcessState *
2450lttv_state_find_process(LttvTraceState *ts, guint cpu, guint pid)
2451{
2452 LttvProcessState key;
2453 LttvProcessState *process;
2454
2455 key.pid = pid;
2456 key.cpu = cpu;
2457 process = g_hash_table_lookup(ts->processes, &key);
2458 return process;
2459}
2460
2461LttvProcessState *lttv_state_find_process_or_create(LttvTraceState *ts,
2462 guint cpu, guint pid, const LttTime *timestamp)
2463{
2464 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2465 LttvExecutionState *es;
2466
2467 /* Put ltt_time_zero creation time for unexisting processes */
2468 if(unlikely(process == NULL)) {
2469 process = lttv_state_create_process(ts,
2470 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2471 /* We are not sure is it's a kernel thread or normal thread, put the
2472 * bottom stack state to unknown */
2473 process->execution_stack =
2474 g_array_set_size(process->execution_stack, 1);
2475 process->state = es =
2476 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2477 es->t = LTTV_STATE_MODE_UNKNOWN;
2478 es->s = LTTV_STATE_UNNAMED;
2479 }
2480 return process;
2481}
2482
2483/* FIXME : this function should be called when we receive an event telling that
2484 * release_task has been called in the kernel. In happens generally when
2485 * the parent waits for its child termination, but may also happens in special
2486 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2487 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2488 * of a killed thread group, but isn't the leader.
2489 */
2490static int exit_process(LttvTracefileState *tfs, LttvProcessState *process)
2491{
2492 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2493 LttvProcessState key;
2494
2495 /* Wait for both schedule with exit dead and process free to happen.
2496 * They can happen in any order. */
2497 if (++(process->free_events) < 2)
2498 return 0;
2499
2500 key.pid = process->pid;
2501 key.cpu = process->cpu;
2502 g_hash_table_remove(ts->processes, &key);
2503 g_array_free(process->execution_stack, TRUE);
2504 g_array_free(process->user_stack, TRUE);
2505
2506 /* the following also clears the content */
2507 g_hash_table_destroy(process->fds);
2508
2509 g_free(process);
2510 return 1;
2511}
2512
2513
2514static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2515{
2516 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2517 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
2518
2519 /* the following also clears the content */
2520 g_hash_table_destroy(((LttvProcessState *)value)->fds);
2521
2522 g_free(value);
2523}
2524
2525
2526static void lttv_state_free_process_table(GHashTable *processes)
2527{
2528 g_hash_table_foreach(processes, free_process_state, NULL);
2529 g_hash_table_destroy(processes);
2530}
2531
2532
2533static gboolean syscall_entry(void *hook_data, void *call_data)
2534{
2535 LttvTracefileState *s = (LttvTracefileState *)call_data;
2536 guint cpu = s->cpu;
2537 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2538 LttvProcessState *process = ts->running_process[cpu];
2539 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2540 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2541 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2542 LttvExecutionSubmode submode;
2543 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2544
2545 guint syscall = ltt_event_get_unsigned(e, f);
2546 expand_syscall_table(ts, syscall);
2547 submode = nt->syscall_names[syscall];
2548 /* There can be no system call from PID 0 : unknown state */
2549 if(process->pid != 0)
2550 push_state(s, LTTV_STATE_SYSCALL, submode);
2551 return FALSE;
2552}
2553
2554
2555static gboolean syscall_exit(void *hook_data, void *call_data)
2556{
2557 LttvTracefileState *s = (LttvTracefileState *)call_data;
2558 guint cpu = s->cpu;
2559 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2560 LttvProcessState *process = ts->running_process[cpu];
2561
2562 /* There can be no system call from PID 0 : unknown state */
2563 if(process->pid != 0)
2564 pop_state(s, LTTV_STATE_SYSCALL);
2565 return FALSE;
2566}
2567
2568
2569static gboolean trap_entry(void *hook_data, void *call_data)
2570{
2571 LttvTracefileState *s = (LttvTracefileState *)call_data;
2572 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2573 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2574 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2575 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2576 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2577
2578 LttvExecutionSubmode submode;
2579
2580 guint64 trap = ltt_event_get_long_unsigned(e, f);
2581
2582 expand_trap_table(ts, trap);
2583
2584 submode = nt->trap_names[trap];
2585
2586 push_state(s, LTTV_STATE_TRAP, submode);
2587
2588 /* update cpu status */
2589 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2590
2591 /* update trap status */
2592 g_array_append_val(s->cpu_state->trap_stack, trap);
2593 ts->trap_states[trap].running++;
2594
2595 return FALSE;
2596}
2597
2598static gboolean trap_exit(void *hook_data, void *call_data)
2599{
2600 LttvTracefileState *s = (LttvTracefileState *)call_data;
2601 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2602
2603 pop_state(s, LTTV_STATE_TRAP);
2604
2605 /* update cpu status */
2606 cpu_pop_mode(s->cpu_state);
2607
2608 /* update trap status */
2609 if (s->cpu_state->trap_stack->len > 0) {
2610 gint last = g_array_index(s->cpu_state->trap_stack, gint,
2611 s->cpu_state->trap_stack->len-1);
2612 if(ts->trap_states[last].running)
2613 ts->trap_states[last].running--;
2614 g_array_remove_index(s->cpu_state->trap_stack,
2615 s->cpu_state->trap_stack->len-1);
2616 }
2617 return FALSE;
2618}
2619
2620static gboolean irq_entry(void *hook_data, void *call_data)
2621{
2622 LttvTracefileState *s = (LttvTracefileState *)call_data;
2623 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2624 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2625 //guint8 ev_id = ltt_event_eventtype_id(e);
2626 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2627 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2628 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2629
2630 LttvExecutionSubmode submode;
2631 guint64 irq = ltt_event_get_long_unsigned(e, f);
2632
2633 expand_irq_table(ts, irq);
2634
2635 submode = nt->irq_names[irq];
2636
2637 /* Do something with the info about being in user or system mode when int? */
2638 push_state(s, LTTV_STATE_IRQ, submode);
2639
2640 /* update cpu status */
2641 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2642
2643 /* update irq status */
2644 g_array_append_val(s->cpu_state->irq_stack, irq);
2645 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2646
2647 return FALSE;
2648}
2649
2650static gboolean soft_irq_exit(void *hook_data, void *call_data)
2651{
2652 LttvTracefileState *s = (LttvTracefileState *)call_data;
2653 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2654
2655 pop_state(s, LTTV_STATE_SOFT_IRQ);
2656
2657 /* update cpu status */
2658 cpu_pop_mode(s->cpu_state);
2659
2660 /* update softirq status */
2661 if (s->cpu_state->softirq_stack->len > 0) {
2662 gint last = g_array_index(s->cpu_state->softirq_stack, gint, s->cpu_state->softirq_stack->len-1);
2663 if(ts->soft_irq_states[last].running)
2664 ts->soft_irq_states[last].running--;
2665 g_array_remove_index(s->cpu_state->softirq_stack, s->cpu_state->softirq_stack->len-1);
2666 }
2667 return FALSE;
2668}
2669
2670static gboolean irq_exit(void *hook_data, void *call_data)
2671{
2672 LttvTracefileState *s = (LttvTracefileState *)call_data;
2673 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2674
2675 pop_state(s, LTTV_STATE_IRQ);
2676
2677 /* update cpu status */
2678 cpu_pop_mode(s->cpu_state);
2679
2680 /* update irq status */
2681 if (s->cpu_state->irq_stack->len > 0) {
2682 gint last = g_array_index(s->cpu_state->irq_stack, gint, s->cpu_state->irq_stack->len-1);
2683 g_array_remove_index(s->cpu_state->irq_stack, s->cpu_state->irq_stack->len-1);
2684 irq_pop_mode(&ts->irq_states[last]);
2685 }
2686
2687 return FALSE;
2688}
2689
2690static gboolean soft_irq_raise(void *hook_data, void *call_data)
2691{
2692 LttvTracefileState *s = (LttvTracefileState *)call_data;
2693 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2694 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2695 //guint8 ev_id = ltt_event_eventtype_id(e);
2696 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2697 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2698 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2699 LttvExecutionSubmode submode;
2700 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2701
2702 expand_soft_irq_table(ts, softirq);
2703
2704 submode = nt->soft_irq_names[softirq];
2705
2706 /* update softirq status */
2707 /* a soft irq raises are not cumulative */
2708 ts->soft_irq_states[softirq].pending=1;
2709
2710 return FALSE;
2711}
2712
2713static gboolean soft_irq_entry(void *hook_data, void *call_data)
2714{
2715 LttvTracefileState *s = (LttvTracefileState *)call_data;
2716 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2717 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2718 //guint8 ev_id = ltt_event_eventtype_id(e);
2719 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2720 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2721 LttvExecutionSubmode submode;
2722 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2723 expand_soft_irq_table(ts, softirq);
2724 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2725 submode = nt->soft_irq_names[softirq];
2726
2727 /* Do something with the info about being in user or system mode when int? */
2728 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2729
2730 /* update cpu status */
2731 cpu_push_mode(s->cpu_state, LTTV_CPU_SOFT_IRQ);
2732
2733 /* update softirq status */
2734 g_array_append_val(s->cpu_state->softirq_stack, softirq);
2735 if(ts->soft_irq_states[softirq].pending)
2736 ts->soft_irq_states[softirq].pending--;
2737 ts->soft_irq_states[softirq].running++;
2738
2739 return FALSE;
2740}
2741
2742static gboolean enum_interrupt(void *hook_data, void *call_data)
2743{
2744 LttvTracefileState *s = (LttvTracefileState *)call_data;
2745 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2746 LttvNameTables *nt = ts->name_tables;
2747 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2748 //guint8 ev_id = ltt_event_eventtype_id(e);
2749 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2750
2751 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2752 lttv_trace_get_hook_field(th, 0)));
2753 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2754
2755 expand_irq_table(ts, irq);
2756 nt->irq_names[irq] = action;
2757
2758 return FALSE;
2759}
2760
2761
2762static gboolean bdev_request_issue(void *hook_data, void *call_data)
2763{
2764 LttvTracefileState *s = (LttvTracefileState *)call_data;
2765 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2766 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2767 //guint8 ev_id = ltt_event_eventtype_id(e);
2768 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2769
2770 guint major = ltt_event_get_long_unsigned(e,
2771 lttv_trace_get_hook_field(th, 0));
2772 guint minor = ltt_event_get_long_unsigned(e,
2773 lttv_trace_get_hook_field(th, 1));
2774 guint oper = ltt_event_get_long_unsigned(e,
2775 lttv_trace_get_hook_field(th, 2));
2776 guint32 devcode = MKDEV(major,minor);
2777
2778 /* have we seen this block device before? */
2779 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2780
2781 if(oper == 0)
2782 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2783 else
2784 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2785
2786 return FALSE;
2787}
2788
2789static gboolean bdev_request_complete(void *hook_data, void *call_data)
2790{
2791 LttvTracefileState *s = (LttvTracefileState *)call_data;
2792 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2793 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2794 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2795
2796 guint major = ltt_event_get_long_unsigned(e,
2797 lttv_trace_get_hook_field(th, 0));
2798 guint minor = ltt_event_get_long_unsigned(e,
2799 lttv_trace_get_hook_field(th, 1));
2800 //guint oper = ltt_event_get_long_unsigned(e,
2801 // lttv_trace_get_hook_field(th, 2));
2802 guint32 devcode = MKDEV(major,minor);
2803
2804 /* have we seen this block device before? */
2805 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2806
2807 /* update block device */
2808 bdev_pop_mode(bdev);
2809
2810 return FALSE;
2811}
2812
2813static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2814{
2815 guint64 *new_func;
2816
2817 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2818 guint cpu = tfs->cpu;
2819 LttvProcessState *process = ts->running_process[cpu];
2820
2821 guint depth = process->user_stack->len;
2822
2823 process->user_stack =
2824 g_array_set_size(process->user_stack, depth + 1);
2825
2826 new_func = &g_array_index(process->user_stack, guint64, depth);
2827 *new_func = funcptr;
2828 process->current_function = funcptr;
2829}
2830
2831static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2832{
2833 guint cpu = tfs->cpu;
2834 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2835 LttvProcessState *process = ts->running_process[cpu];
2836
2837 if(process->current_function != funcptr){
2838 g_info("Different functions (%lu.%09lu): ignore it\n",
2839 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2840 g_info("process state has %" PRIu64 " when pop_function is %" PRIu64 "\n",
2841 process->current_function, funcptr);
2842 g_info("{ %u, %u, %s, %s, %s }\n",
2843 process->pid,
2844 process->ppid,
2845 g_quark_to_string(process->name),
2846 g_quark_to_string(process->brand),
2847 g_quark_to_string(process->state->s));
2848 return;
2849 }
2850 guint depth = process->user_stack->len;
2851
2852 if(depth == 0){
2853 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2854 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2855 return;
2856 }
2857
2858 process->user_stack =
2859 g_array_set_size(process->user_stack, depth - 1);
2860 process->current_function =
2861 g_array_index(process->user_stack, guint64, depth - 2);
2862}
2863
2864
2865static gboolean function_entry(void *hook_data, void *call_data)
2866{
2867 LttvTracefileState *s = (LttvTracefileState *)call_data;
2868 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2869 //guint8 ev_id = ltt_event_eventtype_id(e);
2870 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2871 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2872 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2873
2874 push_function(s, funcptr);
2875 return FALSE;
2876}
2877
2878static gboolean function_exit(void *hook_data, void *call_data)
2879{
2880 LttvTracefileState *s = (LttvTracefileState *)call_data;
2881 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2882 //guint8 ev_id = ltt_event_eventtype_id(e);
2883 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2884 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2885 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2886
2887 pop_function(s, funcptr);
2888 return FALSE;
2889}
2890
2891static gboolean dump_syscall(void *hook_data, void *call_data)
2892{
2893 LttvTracefileState *s = (LttvTracefileState *)call_data;
2894 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2895 LttvNameTables *nt = ts->name_tables;
2896 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2897 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2898 guint id;
2899 guint64 address;
2900 char *symbol;
2901
2902 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2903 address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2904 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2905
2906 expand_syscall_table(ts, id);
2907 nt->syscall_names[id] = g_quark_from_string(symbol);
2908
2909 return FALSE;
2910}
2911
2912static gboolean dump_kprobe(void *hook_data, void *call_data)
2913{
2914 LttvTracefileState *s = (LttvTracefileState *)call_data;
2915 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2916 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2917 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2918 guint64 ip;
2919 char *symbol;
2920
2921 ip = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2922 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 1));
2923
2924 expand_kprobe_table(ts, ip, symbol);
2925
2926 return FALSE;
2927}
2928
2929static gboolean dump_softirq(void *hook_data, void *call_data)
2930{
2931 LttvTracefileState *s = (LttvTracefileState *)call_data;
2932 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2933 LttvNameTables *nt = ts->name_tables;
2934 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2935 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2936 guint id;
2937 guint64 address;
2938 char *symbol;
2939
2940 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2941 address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2942 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2943
2944 expand_soft_irq_table(ts, id);
2945 nt->soft_irq_names[id] = g_quark_from_string(symbol);
2946
2947 return FALSE;
2948}
2949
2950static gboolean sched_try_wakeup(void *hook_data, void *call_data)
2951{
2952 LttvTracefileState *s = (LttvTracefileState *)call_data;
2953 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2954 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2955 LttvProcessState *process;
2956 gint woken_pid;
2957 guint woken_cpu;
2958
2959 woken_pid = ltt_event_get_int(e, lttv_trace_get_hook_field(th, 0));
2960 woken_cpu = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2961
2962 process = lttv_state_find_process_or_create(
2963 (LttvTraceState*)s->parent.t_context,
2964 woken_cpu, woken_pid,
2965 &s->parent.timestamp);
2966
2967 if (process->state->s == LTTV_STATE_WAIT || process->state->s == LTTV_STATE_WAIT_FORK)
2968 {
2969 process->state->s = LTTV_STATE_WAIT_CPU;
2970 process->state->change = s->parent.timestamp;
2971 }
2972
2973 g_debug("Wakeup: process %d on CPU %u\n", woken_pid, woken_cpu);
2974
2975 return FALSE;
2976}
2977
2978static gboolean schedchange(void *hook_data, void *call_data)
2979{
2980 LttvTracefileState *s = (LttvTracefileState *)call_data;
2981 guint cpu = s->cpu;
2982 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2983 LttvProcessState *process = ts->running_process[cpu];
2984 //LttvProcessState *old_process = ts->running_process[cpu];
2985
2986 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2987 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2988 guint pid_in, pid_out;
2989 gint64 state_out;
2990
2991 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2992 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2993 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
2994
2995 if(likely(process != NULL)) {
2996
2997 /* We could not know but it was not the idle process executing.
2998 This should only happen at the beginning, before the first schedule
2999 event, and when the initial information (current process for each CPU)
3000 is missing. It is not obvious how we could, after the fact, compensate
3001 the wrongly attributed statistics. */
3002
3003 //This test only makes sense once the state is known and if there is no
3004 //missing events. We need to silently ignore schedchange coming after a
3005 //process_free, or it causes glitches. (FIXME)
3006 //if(unlikely(process->pid != pid_out)) {
3007 // g_assert(process->pid == 0);
3008 //}
3009 if(process->pid == 0
3010 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
3011 if(pid_out == 0) {
3012 /*
3013 * Scheduling out of pid 0 at beginning of the trace.
3014 * We are typically in system call mode at this point although
3015 * (FIXME) we might be in a trap handler.
3016 */
3017 g_assert(process->execution_stack->len == 1);
3018 process->state->t = LTTV_STATE_SYSCALL;
3019 process->state->s = LTTV_STATE_WAIT;
3020 process->state->change = s->parent.timestamp;
3021 process->state->entry = s->parent.timestamp;
3022 }
3023 } else {
3024 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
3025 process->state->s = LTTV_STATE_ZOMBIE;
3026 process->state->change = s->parent.timestamp;
3027 } else {
3028 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
3029 else process->state->s = LTTV_STATE_WAIT;
3030 process->state->change = s->parent.timestamp;
3031 }
3032
3033 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
3034 /* see sched.h for states */
3035 if (!exit_process(s, process)) {
3036 process->state->s = LTTV_STATE_DEAD;
3037 process->state->change = s->parent.timestamp;
3038 }
3039 }
3040 }
3041 }
3042 process = ts->running_process[cpu] = lttv_state_find_process_or_create(
3043 (LttvTraceState*)s->parent.t_context,
3044 cpu, pid_in,
3045 &s->parent.timestamp);
3046 process->state->s = LTTV_STATE_RUN;
3047 process->cpu = cpu;
3048 if(process->usertrace)
3049 process->usertrace->cpu = cpu;
3050 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3051 process->state->change = s->parent.timestamp;
3052
3053 /* update cpu status */
3054 if(pid_in == 0)
3055 /* going to idle task */
3056 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
3057 else {
3058 /* scheduling a real task.
3059 * we must be careful here:
3060 * if we just schedule()'ed to a process that is
3061 * in a trap, we must put the cpu in trap mode
3062 */
3063 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
3064 if(process->state->t == LTTV_STATE_TRAP)
3065 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
3066 }
3067
3068 return FALSE;
3069}
3070
3071static gboolean process_fork(void *hook_data, void *call_data)
3072{
3073 LttvTracefileState *s = (LttvTracefileState *)call_data;
3074 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3075 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3076 guint parent_pid;
3077 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
3078 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
3079 //LttvProcessState *zombie_process;
3080 guint cpu = s->cpu;
3081 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3082 LttvProcessState *process = ts->running_process[cpu];
3083 LttvProcessState *child_process;
3084 struct marker_field *f;
3085
3086 /* Parent PID */
3087 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3088
3089 /* Child PID */
3090 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
3091 s->parent.target_pid = child_pid;
3092
3093 /* Child TGID */
3094 f = lttv_trace_get_hook_field(th, 2);
3095 if (likely(f))
3096 child_tgid = ltt_event_get_unsigned(e, f);
3097 else
3098 child_tgid = 0;
3099
3100 /* Mathieu : it seems like the process might have been scheduled in before the
3101 * fork, and, in a rare case, might be the current process. This might happen
3102 * in a SMP case where we don't have enough precision on the clocks.
3103 *
3104 * Test reenabled after precision fixes on time. (Mathieu) */
3105#if 0
3106 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
3107
3108 if(unlikely(zombie_process != NULL)) {
3109 /* Reutilisation of PID. Only now we are sure that the old PID
3110 * has been released. FIXME : should know when release_task happens instead.
3111 */
3112 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3113 guint i;
3114 for(i=0; i< num_cpus; i++) {
3115 g_assert(zombie_process != ts->running_process[i]);
3116 }
3117
3118 exit_process(s, zombie_process);
3119 }
3120#endif //0
3121 g_assert(process->pid != child_pid);
3122 // FIXME : Add this test in the "known state" section
3123 // g_assert(process->pid == parent_pid);
3124 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
3125 if(child_process == NULL) {
3126 child_process = lttv_state_create_process(ts, process, cpu,
3127 child_pid, child_tgid,
3128 LTTV_STATE_UNNAMED, &s->parent.timestamp);
3129 } else {
3130 /* The process has already been created : due to time imprecision between
3131 * multiple CPUs : it has been scheduled in before creation. Note that we
3132 * shouldn't have this kind of imprecision.
3133 *
3134 * Simply put a correct parent.
3135 */
3136 g_error("Process %u has been created at [%lu.%09lu] "
3137 "and inserted at [%lu.%09lu] before \n"
3138 "fork on cpu %u[%lu.%09lu].\n"
3139 "Probably an unsynchronized TSC problem on the traced machine.",
3140 child_pid,
3141 child_process->creation_time.tv_sec,
3142 child_process->creation_time.tv_nsec,
3143 child_process->insertion_time.tv_sec,
3144 child_process->insertion_time.tv_nsec,
3145 cpu, ltt_event_time(e).tv_sec, ltt_event_time(e).tv_nsec);
3146 //g_assert(0); /* This is a problematic case : the process has been created
3147 // before the fork event */
3148 child_process->ppid = process->pid;
3149 child_process->tgid = child_tgid;
3150 }
3151 g_assert(child_process->name == LTTV_STATE_UNNAMED);
3152 child_process->name = process->name;
3153 child_process->brand = process->brand;
3154
3155 return FALSE;
3156}
3157
3158/* We stamp a newly created process as kernel_thread.
3159 * The thread should not be running yet. */
3160static gboolean process_kernel_thread(void *hook_data, void *call_data)
3161{
3162 LttvTracefileState *s = (LttvTracefileState *)call_data;
3163 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3164 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3165 guint pid;
3166 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3167 LttvProcessState *process;
3168 LttvExecutionState *es;
3169
3170 /* PID */
3171 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
3172 s->parent.target_pid = pid;
3173
3174 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
3175 &ltt_time_zero);
3176 if (process->state->s != LTTV_STATE_DEAD) {
3177 process->execution_stack =
3178 g_array_set_size(process->execution_stack, 1);
3179 es = process->state =
3180 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3181 es->t = LTTV_STATE_SYSCALL;
3182 }
3183 process->type = LTTV_STATE_KERNEL_THREAD;
3184
3185 return FALSE;
3186}
3187
3188static gboolean process_exit(void *hook_data, void *call_data)
3189{
3190 LttvTracefileState *s = (LttvTracefileState *)call_data;
3191 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3192 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3193 guint pid;
3194 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3195 LttvProcessState *process; // = ts->running_process[cpu];
3196
3197 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3198 s->parent.target_pid = pid;
3199
3200 // FIXME : Add this test in the "known state" section
3201 // g_assert(process->pid == pid);
3202
3203 process = lttv_state_find_process(ts, ANY_CPU, pid);
3204 if(likely(process != NULL)) {
3205 process->state->s = LTTV_STATE_EXIT;
3206 }
3207 return FALSE;
3208}
3209
3210static gboolean process_free(void *hook_data, void *call_data)
3211{
3212 LttvTracefileState *s = (LttvTracefileState *)call_data;
3213 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3214 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3215 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3216 guint release_pid;
3217 LttvProcessState *process;
3218
3219 /* PID of the process to release */
3220 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3221 s->parent.target_pid = release_pid;
3222
3223 g_assert(release_pid != 0);
3224
3225 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
3226 if(likely(process != NULL))
3227 exit_process(s, process);
3228 return FALSE;
3229//DISABLED
3230 if(likely(process != NULL)) {
3231 /* release_task is happening at kernel level : we can now safely release
3232 * the data structure of the process */
3233 //This test is fun, though, as it may happen that
3234 //at time t : CPU 0 : process_free
3235 //at time t+150ns : CPU 1 : schedule out
3236 //Clearly due to time imprecision, we disable it. (Mathieu)
3237 //If this weird case happen, we have no choice but to put the
3238 //Currently running process on the cpu to 0.
3239 //I re-enable it following time precision fixes. (Mathieu)
3240 //Well, in the case where an process is freed by a process on another CPU
3241 //and still scheduled, it happens that this is the schedchange that will
3242 //drop the last reference count. Do not free it here!
3243 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3244 guint i;
3245 for(i=0; i< num_cpus; i++) {
3246 //g_assert(process != ts->running_process[i]);
3247 if(process == ts->running_process[i]) {
3248 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3249 break;
3250 }
3251 }
3252 if(i == num_cpus) /* process is not scheduled */
3253 exit_process(s, process);
3254 }
3255
3256 return FALSE;
3257}
3258
3259
3260static gboolean process_exec(void *hook_data, void *call_data)
3261{
3262 LttvTracefileState *s = (LttvTracefileState *)call_data;
3263 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3264 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3265 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3266 //gchar *name;
3267 guint cpu = s->cpu;
3268 LttvProcessState *process = ts->running_process[cpu];
3269
3270#if 0//how to use a sequence that must be transformed in a string
3271 /* PID of the process to release */
3272 guint64 name_len = ltt_event_field_element_number(e,
3273 lttv_trace_get_hook_field(th, 0));
3274 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3275 LttField *child = ltt_event_field_element_select(e,
3276 lttv_trace_get_hook_field(th, 0), 0);
3277 gchar *name_begin =
3278 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
3279 gchar *null_term_name = g_new(gchar, name_len+1);
3280 memcpy(null_term_name, name_begin, name_len);
3281 null_term_name[name_len] = '\0';
3282 process->name = g_quark_from_string(null_term_name);
3283#endif //0
3284
3285 process->name = g_quark_from_string(ltt_event_get_string(e,
3286 lttv_trace_get_hook_field(th, 0)));
3287 process->brand = LTTV_STATE_UNBRANDED;
3288 //g_free(null_term_name);
3289 return FALSE;
3290}
3291
3292static gboolean thread_brand(void *hook_data, void *call_data)
3293{
3294 LttvTracefileState *s = (LttvTracefileState *)call_data;
3295 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3296 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3297 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3298 gchar *name;
3299 guint cpu = s->cpu;
3300 LttvProcessState *process = ts->running_process[cpu];
3301
3302 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3303 process->brand = g_quark_from_string(name);
3304
3305 return FALSE;
3306}
3307
3308static gboolean fs_open(void *hook_data, void *call_data)
3309{
3310 LttvTracefileState *s = (LttvTracefileState *)call_data;
3311 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
3312 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3313 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3314 struct marker_field *f;
3315 guint cpu = s->cpu;
3316 int fd;
3317 char *filename;
3318 LttvProcessState *process = ts->running_process[cpu];
3319
3320 f = lttv_trace_get_hook_field(th, 0);
3321 fd = ltt_event_get_int(e, f);
3322
3323 f = lttv_trace_get_hook_field(th, 1);
3324 filename = ltt_event_get_string(e, f);
3325
3326 g_hash_table_insert(process->fds, (gpointer)(long)fd,
3327 (gpointer)(unsigned long)g_quark_from_string(filename));
3328
3329 return FALSE;
3330}
3331
3332static void print_stack(LttvProcessState *process)
3333{
3334 LttvExecutionState *es;
3335 int i;
3336
3337 g_debug("Execution stack for process %u %s:\n",
3338 process->pid, g_quark_to_string(process->name));
3339
3340 for (i = 0; i < process->execution_stack->len; i++) {
3341 es = &g_array_index(process->execution_stack,
3342 LttvExecutionState, i);
3343 g_debug("Depth %d mode %s submode %s status %s\n",
3344 i, g_quark_to_string(es->t),
3345 g_quark_to_string(es->n),
3346 g_quark_to_string(es->s));
3347 }
3348
3349}
3350
3351static void fix_process(gpointer key, gpointer value, gpointer user_data)
3352{
3353 LttvProcessState *process;
3354 LttvExecutionState *es;
3355 process = (LttvProcessState *)value;
3356 LttTime *timestamp = (LttTime*)user_data;
3357
3358 print_stack(process);
3359
3360 if(process->type == LTTV_STATE_KERNEL_THREAD) {
3361 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3362 if(es->t == LTTV_STATE_MAYBE_SYSCALL) {
3363 es->t = LTTV_STATE_SYSCALL;
3364 es->n = LTTV_STATE_SUBMODE_NONE;
3365 es->entry = *timestamp;
3366 es->change = *timestamp;
3367 es->cum_cpu_time = ltt_time_zero;
3368 if(es->s == LTTV_STATE_UNNAMED)
3369 es->s = LTTV_STATE_WAIT;
3370 }
3371 } else {
3372 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3373 if(es->t == LTTV_STATE_MAYBE_USER_MODE) {
3374 es->t = LTTV_STATE_USER_MODE;
3375 es->n = LTTV_STATE_SUBMODE_NONE;
3376 es->entry = *timestamp;
3377 //g_assert(timestamp->tv_sec != 0);
3378 es->change = *timestamp;
3379 es->cum_cpu_time = ltt_time_zero;
3380 if(es->s == LTTV_STATE_UNNAMED)
3381 es->s = LTTV_STATE_RUN;
3382
3383 if(process->execution_stack->len == 1) {
3384 /* Still in bottom unknown mode, means we either:
3385 * - never did a system call
3386 * - are scheduled out from user mode.
3387 * May be either in user mode, syscall mode, running or waiting.*/
3388 /* CHECK : we may be tagging syscall mode when being user mode
3389 * (should be fixed now) */
3390 if (es->s == LTTV_STATE_WAIT_CPU) {
3391 /* nothing to do: scheduled out from userspace */
3392 } else {
3393 process->execution_stack =
3394 g_array_set_size(process->execution_stack, 2);
3395 es = process->state = &g_array_index(process->execution_stack,
3396 LttvExecutionState, 1);
3397 es->t = LTTV_STATE_SYSCALL;
3398 es->n = LTTV_STATE_SUBMODE_NONE;
3399 es->entry = *timestamp;
3400 //g_assert(timestamp->tv_sec != 0);
3401 es->change = *timestamp;
3402 es->cum_cpu_time = ltt_time_zero;
3403 if(es->s == LTTV_STATE_WAIT_FORK)
3404 es->s = LTTV_STATE_WAIT;
3405 }
3406 }
3407 }
3408 }
3409}
3410
3411static gboolean statedump_end(void *hook_data, void *call_data)
3412{
3413 LttvTracefileState *s = (LttvTracefileState *)call_data;
3414 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3415 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
3416 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3417 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3418
3419 /* For all processes */
3420 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3421 /* else, if stack[0] is unknown, set to user mode, running */
3422
3423 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
3424
3425 return FALSE;
3426}
3427
3428static gboolean enum_process_state(void *hook_data, void *call_data)
3429{
3430 LttvTracefileState *s = (LttvTracefileState *)call_data;
3431 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3432 //It's slow : optimise later by doing this before reading trace.
3433 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3434 guint parent_pid;
3435 guint pid;
3436 guint tgid;
3437 gchar * command;
3438 guint cpu = s->cpu;
3439 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3440 LttvProcessState *process = ts->running_process[cpu];
3441 LttvProcessState *parent_process;
3442 struct marker_field *f;
3443 GQuark type, mode, submode, status;
3444 LttvExecutionState *es;
3445 guint i, nb_cpus;
3446
3447 /* PID */
3448 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3449 s->parent.target_pid = pid;
3450
3451 /* Parent PID */
3452 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
3453
3454 /* Command name */
3455 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
3456
3457 /* type */
3458 f = lttv_trace_get_hook_field(th, 3);
3459 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3460
3461 //FIXME: type is rarely used, enum must match possible types.
3462
3463 /* mode */
3464 f = lttv_trace_get_hook_field(th, 4);
3465 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
3466
3467 /* submode */
3468 f = lttv_trace_get_hook_field(th, 5);
3469 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3470
3471 /* status */
3472 f = lttv_trace_get_hook_field(th, 6);
3473 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3474
3475 /* TGID */
3476 f = lttv_trace_get_hook_field(th, 7);
3477 if(f)
3478 tgid = ltt_event_get_unsigned(e, f);
3479 else
3480 tgid = 0;
3481
3482 if(pid == 0) {
3483 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3484 for(i=0; i<nb_cpus; i++) {
3485 process = lttv_state_find_process(ts, i, pid);
3486 g_assert(process != NULL);
3487
3488 process->ppid = parent_pid;
3489 process->tgid = tgid;
3490 process->name = g_quark_from_string(command);
3491 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3492 process->type = LTTV_STATE_KERNEL_THREAD;
3493 }
3494
3495 } else {
3496 /* The process might exist if a process was forked while performing the
3497 * state dump. */
3498 process = lttv_state_find_process(ts, ANY_CPU, pid);
3499 if(process == NULL) {
3500 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3501 process = lttv_state_create_process(ts, parent_process, cpu,
3502 pid, tgid, g_quark_from_string(command),
3503 &s->parent.timestamp);
3504
3505 /* Keep the stack bottom : a running user mode */
3506 /* Disabled because of inconsistencies in the current statedump states. */
3507 if(type == LTTV_STATE_KERNEL_THREAD) {
3508 /* Only keep the bottom
3509 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3510 /* Will cause expected trap when in fact being syscall (even after end of
3511 * statedump event)
3512 * Will cause expected interrupt when being syscall. (only before end of
3513 * statedump event) */
3514 // This will cause a "popping last state on stack, ignoring it."
3515 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3516 es = process->state = &g_array_index(process->execution_stack,
3517 LttvExecutionState, 0);
3518 process->type = LTTV_STATE_KERNEL_THREAD;
3519 es->t = LTTV_STATE_MAYBE_SYSCALL;
3520 es->s = LTTV_STATE_UNNAMED;
3521 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3522 //es->s = status;
3523 //es->n = submode;
3524 } else {
3525 /* User space process :
3526 * bottom : user mode
3527 * either currently running or scheduled out.
3528 * can be scheduled out because interrupted in (user mode or in syscall)
3529 * or because of an explicit call to the scheduler in syscall. Note that
3530 * the scheduler call comes after the irq_exit, so never in interrupt
3531 * context. */
3532 // temp workaround : set size to 1 : only have user mode bottom of stack.
3533 // will cause g_info message of expected syscall mode when in fact being
3534 // in user mode. Can also cause expected trap when in fact being user
3535 // mode in the event of a page fault reenabling interrupts in the handler.
3536 // Expected syscall and trap can also happen after the end of statedump
3537 // This will cause a "popping last state on stack, ignoring it."
3538 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3539 es = process->state = &g_array_index(process->execution_stack,
3540 LttvExecutionState, 0);
3541 es->t = LTTV_STATE_MAYBE_USER_MODE;
3542 es->s = LTTV_STATE_UNNAMED;
3543 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3544 //es->s = status;
3545 //es->n = submode;
3546 }
3547 #if 0
3548 /* UNKNOWN STATE */
3549 {
3550 es = process->state = &g_array_index(process->execution_stack,
3551 LttvExecutionState, 1);
3552 es->t = LTTV_STATE_MODE_UNKNOWN;
3553 es->s = LTTV_STATE_UNNAMED;
3554 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3555 }
3556 #endif //0
3557 } else {
3558 /* The process has already been created :
3559 * Probably was forked while dumping the process state or
3560 * was simply scheduled in prior to get the state dump event.
3561 */
3562 process->ppid = parent_pid;
3563 process->tgid = tgid;
3564 process->name = g_quark_from_string(command);
3565 process->type = type;
3566 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3567#if 0
3568 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3569 if(type == LTTV_STATE_KERNEL_THREAD)
3570 es->t = LTTV_STATE_SYSCALL;
3571 else
3572 es->t = LTTV_STATE_USER_MODE;
3573 }
3574#endif //0
3575 /* Don't mess around with the stack, it will eventually become
3576 * ok after the end of state dump. */
3577 }
3578 }
3579
3580 return FALSE;
3581}
3582
3583gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3584{
3585 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3586
3587 lttv_state_add_event_hooks(tss);
3588
3589 return 0;
3590}
3591
3592void lttv_state_add_event_hooks(LttvTracesetState *self)
3593{
3594 LttvTraceset *traceset = self->parent.ts;
3595
3596 guint i, j, k, nb_trace, nb_tracefile;
3597
3598 LttvTraceState *ts;
3599
3600 LttvTracefileState *tfs;
3601
3602 GArray *hooks;
3603
3604 LttvTraceHook *th;
3605
3606 LttvAttributeValue val;
3607
3608 nb_trace = lttv_traceset_number(traceset);
3609 for(i = 0 ; i < nb_trace ; i++) {
3610 ts = (LttvTraceState *)self->parent.traces[i];
3611
3612 /* Find the eventtype id for the following events and register the
3613 associated by id hooks. */
3614
3615 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 20);
3616 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3617 //hn = 0;
3618
3619 lttv_trace_find_hook(ts->parent.t,
3620 LTT_CHANNEL_KERNEL,
3621 LTT_EVENT_SYSCALL_ENTRY,
3622 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3623 syscall_entry, NULL, &hooks);
3624
3625 lttv_trace_find_hook(ts->parent.t,
3626 LTT_CHANNEL_KERNEL,
3627 LTT_EVENT_SYSCALL_EXIT,
3628 NULL,
3629 syscall_exit, NULL, &hooks);
3630
3631 lttv_trace_find_hook(ts->parent.t,
3632 LTT_CHANNEL_KERNEL,
3633 LTT_EVENT_TRAP_ENTRY,
3634 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3635 trap_entry, NULL, &hooks);
3636
3637 lttv_trace_find_hook(ts->parent.t,
3638 LTT_CHANNEL_KERNEL,
3639 LTT_EVENT_TRAP_EXIT,
3640 NULL,
3641 trap_exit, NULL, &hooks);
3642
3643 lttv_trace_find_hook(ts->parent.t,
3644 LTT_CHANNEL_KERNEL,
3645 LTT_EVENT_PAGE_FAULT_ENTRY,
3646 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3647 trap_entry, NULL, &hooks);
3648
3649 lttv_trace_find_hook(ts->parent.t,
3650 LTT_CHANNEL_KERNEL,
3651 LTT_EVENT_PAGE_FAULT_EXIT,
3652 NULL,
3653 trap_exit, NULL, &hooks);
3654
3655 lttv_trace_find_hook(ts->parent.t,
3656 LTT_CHANNEL_KERNEL,
3657 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
3658 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3659 trap_entry, NULL, &hooks);
3660
3661 lttv_trace_find_hook(ts->parent.t,
3662 LTT_CHANNEL_KERNEL,
3663 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
3664 NULL,
3665 trap_exit, NULL, &hooks);
3666
3667 lttv_trace_find_hook(ts->parent.t,
3668 LTT_CHANNEL_KERNEL,
3669 LTT_EVENT_IRQ_ENTRY,
3670 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3671 irq_entry, NULL, &hooks);
3672
3673 lttv_trace_find_hook(ts->parent.t,
3674 LTT_CHANNEL_KERNEL,
3675 LTT_EVENT_IRQ_EXIT,
3676 NULL,
3677 irq_exit, NULL, &hooks);
3678
3679 lttv_trace_find_hook(ts->parent.t,
3680 LTT_CHANNEL_KERNEL,
3681 LTT_EVENT_SOFT_IRQ_RAISE,
3682 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3683 soft_irq_raise, NULL, &hooks);
3684
3685 lttv_trace_find_hook(ts->parent.t,
3686 LTT_CHANNEL_KERNEL,
3687 LTT_EVENT_SOFT_IRQ_ENTRY,
3688 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3689 soft_irq_entry, NULL, &hooks);
3690
3691 lttv_trace_find_hook(ts->parent.t,
3692 LTT_CHANNEL_KERNEL,
3693 LTT_EVENT_SOFT_IRQ_EXIT,
3694 NULL,
3695 soft_irq_exit, NULL, &hooks);
3696
3697 lttv_trace_find_hook(ts->parent.t,
3698 LTT_CHANNEL_KERNEL,
3699 LTT_EVENT_SCHED_SCHEDULE,
3700 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3701 LTT_FIELD_PREV_STATE),
3702 schedchange, NULL, &hooks);
3703
3704 lttv_trace_find_hook(ts->parent.t,
3705 LTT_CHANNEL_KERNEL,
3706 LTT_EVENT_SCHED_TRY_WAKEUP,
3707 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_CPU_ID, LTT_FIELD_STATE),
3708 sched_try_wakeup, NULL, &hooks);
3709
3710 lttv_trace_find_hook(ts->parent.t,
3711 LTT_CHANNEL_KERNEL,
3712 LTT_EVENT_PROCESS_FORK,
3713 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3714 LTT_FIELD_CHILD_TGID),
3715 process_fork, NULL, &hooks);
3716
3717 lttv_trace_find_hook(ts->parent.t,
3718 LTT_CHANNEL_KERNEL,
3719 LTT_EVENT_KTHREAD_CREATE,
3720 FIELD_ARRAY(LTT_FIELD_PID),
3721 process_kernel_thread, NULL, &hooks);
3722
3723 lttv_trace_find_hook(ts->parent.t,
3724 LTT_CHANNEL_KERNEL,
3725 LTT_EVENT_PROCESS_EXIT,
3726 FIELD_ARRAY(LTT_FIELD_PID),
3727 process_exit, NULL, &hooks);
3728
3729 lttv_trace_find_hook(ts->parent.t,
3730 LTT_CHANNEL_KERNEL,
3731 LTT_EVENT_PROCESS_FREE,
3732 FIELD_ARRAY(LTT_FIELD_PID),
3733 process_free, NULL, &hooks);
3734
3735 lttv_trace_find_hook(ts->parent.t,
3736 LTT_CHANNEL_FS,
3737 LTT_EVENT_EXEC,
3738 FIELD_ARRAY(LTT_FIELD_FILENAME),
3739 process_exec, NULL, &hooks);
3740
3741 lttv_trace_find_hook(ts->parent.t,
3742 LTT_CHANNEL_USERSPACE,
3743 LTT_EVENT_THREAD_BRAND,
3744 FIELD_ARRAY(LTT_FIELD_NAME),
3745 thread_brand, NULL, &hooks);
3746
3747 /* statedump-related hooks */
3748 lttv_trace_find_hook(ts->parent.t,
3749 LTT_CHANNEL_TASK_STATE,
3750 LTT_EVENT_PROCESS_STATE,
3751 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3752 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3753 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3754 enum_process_state, NULL, &hooks);
3755
3756 lttv_trace_find_hook(ts->parent.t,
3757 LTT_CHANNEL_GLOBAL_STATE,
3758 LTT_EVENT_STATEDUMP_END,
3759 NULL,
3760 statedump_end, NULL, &hooks);
3761
3762 lttv_trace_find_hook(ts->parent.t,
3763 LTT_CHANNEL_IRQ_STATE,
3764 LTT_EVENT_LIST_INTERRUPT,
3765 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3766 enum_interrupt, NULL, &hooks);
3767
3768 lttv_trace_find_hook(ts->parent.t,
3769 LTT_CHANNEL_BLOCK,
3770 LTT_EVENT_REQUEST_ISSUE,
3771 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3772 bdev_request_issue, NULL, &hooks);
3773
3774 lttv_trace_find_hook(ts->parent.t,
3775 LTT_CHANNEL_BLOCK,
3776 LTT_EVENT_REQUEST_COMPLETE,
3777 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3778 bdev_request_complete, NULL, &hooks);
3779
3780 lttv_trace_find_hook(ts->parent.t,
3781 LTT_CHANNEL_USERSPACE,
3782 LTT_EVENT_FUNCTION_ENTRY,
3783 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3784 function_entry, NULL, &hooks);
3785
3786 lttv_trace_find_hook(ts->parent.t,
3787 LTT_CHANNEL_USERSPACE,
3788 LTT_EVENT_FUNCTION_EXIT,
3789 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3790 function_exit, NULL, &hooks);
3791
3792 lttv_trace_find_hook(ts->parent.t,
3793 LTT_CHANNEL_SYSCALL_STATE,
3794 LTT_EVENT_SYS_CALL_TABLE,
3795 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3796 dump_syscall, NULL, &hooks);
3797
3798 lttv_trace_find_hook(ts->parent.t,
3799 LTT_CHANNEL_KPROBE_STATE,
3800 LTT_EVENT_KPROBE_TABLE,
3801 FIELD_ARRAY(LTT_FIELD_IP, LTT_FIELD_SYMBOL),
3802 dump_kprobe, NULL, &hooks);
3803
3804 lttv_trace_find_hook(ts->parent.t,
3805 LTT_CHANNEL_SOFTIRQ_STATE,
3806 LTT_EVENT_SOFTIRQ_VEC,
3807 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3808 dump_softirq, NULL, &hooks);
3809
3810 lttv_trace_find_hook(ts->parent.t,
3811 LTT_CHANNEL_FS,
3812 LTT_EVENT_OPEN,
3813 FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME),
3814 fs_open, NULL, &hooks);
3815
3816 /* Add these hooks to each event_by_id hooks list */
3817
3818 nb_tracefile = ts->parent.tracefiles->len;
3819
3820 for(j = 0 ; j < nb_tracefile ; j++) {
3821 tfs =
3822 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3823 LttvTracefileContext*, j));
3824
3825 for(k = 0 ; k < hooks->len ; k++) {
3826 th = &g_array_index(hooks, LttvTraceHook, k);
3827 if (th->mdata == tfs->parent.tf->mdata)
3828 lttv_hooks_add(
3829 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3830 th->h,
3831 th,
3832 LTTV_PRIO_STATE);
3833 }
3834 }
3835 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3836 *(val.v_pointer) = hooks;
3837 }
3838}
3839
3840gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3841{
3842 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3843
3844 lttv_state_remove_event_hooks(tss);
3845
3846 return 0;
3847}
3848
3849void lttv_state_remove_event_hooks(LttvTracesetState *self)
3850{
3851 LttvTraceset *traceset = self->parent.ts;
3852
3853 guint i, j, k, nb_trace, nb_tracefile;
3854
3855 LttvTraceState *ts;
3856
3857 LttvTracefileState *tfs;
3858
3859 GArray *hooks;
3860
3861 LttvTraceHook *th;
3862
3863 LttvAttributeValue val;
3864
3865 nb_trace = lttv_traceset_number(traceset);
3866 for(i = 0 ; i < nb_trace ; i++) {
3867 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3868
3869 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3870 hooks = *(val.v_pointer);
3871
3872 /* Remove these hooks from each event_by_id hooks list */
3873
3874 nb_tracefile = ts->parent.tracefiles->len;
3875
3876 for(j = 0 ; j < nb_tracefile ; j++) {
3877 tfs =
3878 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3879 LttvTracefileContext*, j));
3880
3881 for(k = 0 ; k < hooks->len ; k++) {
3882 th = &g_array_index(hooks, LttvTraceHook, k);
3883 if (th->mdata == tfs->parent.tf->mdata)
3884 lttv_hooks_remove_data(
3885 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3886 th->h,
3887 th);
3888 }
3889 }
3890 lttv_trace_hook_remove_all(&hooks);
3891 g_array_free(hooks, TRUE);
3892 }
3893}
3894
3895static gboolean state_save_event_hook(void *hook_data, void *call_data)
3896{
3897 guint *event_count = (guint*)hook_data;
3898
3899 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3900 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3901 return FALSE;
3902 else
3903 *event_count = 0;
3904
3905 LttvTracefileState *self = (LttvTracefileState *)call_data;
3906
3907 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3908
3909 LttvAttribute *saved_states_tree, *saved_state_tree;
3910
3911 LttvAttributeValue value;
3912
3913 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3914 LTTV_STATE_SAVED_STATES);
3915 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3916 value = lttv_attribute_add(saved_states_tree,
3917 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3918 *(value.v_gobject) = (GObject *)saved_state_tree;
3919 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3920 *(value.v_time) = self->parent.timestamp;
3921 lttv_state_save(tcs, saved_state_tree);
3922 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3923 self->parent.timestamp.tv_nsec);
3924
3925 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3926
3927 return FALSE;
3928}
3929
3930static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3931{
3932 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3933
3934 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3935
3936 return FALSE;
3937}
3938
3939guint lttv_state_current_cpu(LttvTracefileState *tfs)
3940{
3941 return tfs->cpu;
3942}
3943
3944
3945
3946#if 0
3947static gboolean block_start(void *hook_data, void *call_data)
3948{
3949 LttvTracefileState *self = (LttvTracefileState *)call_data;
3950
3951 LttvTracefileState *tfcs;
3952
3953 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3954
3955 LttEventPosition *ep;
3956
3957 guint i, nb_block, nb_event, nb_tracefile;
3958
3959 LttTracefile *tf;
3960
3961 LttvAttribute *saved_states_tree, *saved_state_tree;
3962
3963 LttvAttributeValue value;
3964
3965 ep = ltt_event_position_new();
3966
3967 nb_tracefile = tcs->parent.tracefiles->len;
3968
3969 /* Count the number of events added since the last block end in any
3970 tracefile. */
3971
3972 for(i = 0 ; i < nb_tracefile ; i++) {
3973 tfcs =
3974 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3975 LttvTracefileContext, i));
3976 ltt_event_position(tfcs->parent.e, ep);
3977 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3978 tcs->nb_event += nb_event - tfcs->saved_position;
3979 tfcs->saved_position = nb_event;
3980 }
3981 g_free(ep);
3982
3983 if(tcs->nb_event >= tcs->save_interval) {
3984 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3985 LTTV_STATE_SAVED_STATES);
3986 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3987 value = lttv_attribute_add(saved_states_tree,
3988 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3989 *(value.v_gobject) = (GObject *)saved_state_tree;
3990 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3991 *(value.v_time) = self->parent.timestamp;
3992 lttv_state_save(tcs, saved_state_tree);
3993 tcs->nb_event = 0;
3994 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3995 self->parent.timestamp.tv_nsec);
3996 }
3997 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3998 return FALSE;
3999}
4000#endif //0
4001
4002#if 0
4003static gboolean block_end(void *hook_data, void *call_data)
4004{
4005 LttvTracefileState *self = (LttvTracefileState *)call_data;
4006
4007 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
4008
4009 LttTracefile *tf;
4010
4011 LttEventPosition *ep;
4012
4013 guint nb_block, nb_event;
4014
4015 ep = ltt_event_position_new();
4016 ltt_event_position(self->parent.e, ep);
4017 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
4018 tcs->nb_event += nb_event - self->saved_position + 1;
4019 self->saved_position = 0;
4020 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
4021 g_free(ep);
4022
4023 return FALSE;
4024}
4025#endif //0
4026#if 0
4027void lttv_state_save_add_event_hooks(LttvTracesetState *self)
4028{
4029 LttvTraceset *traceset = self->parent.ts;
4030
4031 guint i, j, nb_trace, nb_tracefile;
4032
4033 LttvTraceState *ts;
4034
4035 LttvTracefileState *tfs;
4036
4037 LttvTraceHook hook_start, hook_end;
4038
4039 nb_trace = lttv_traceset_number(traceset);
4040 for(i = 0 ; i < nb_trace ; i++) {
4041 ts = (LttvTraceState *)self->parent.traces[i];
4042
4043 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
4044 NULL, NULL, block_start, &hook_start);
4045 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
4046 NULL, NULL, block_end, &hook_end);
4047
4048 nb_tracefile = ts->parent.tracefiles->len;
4049
4050 for(j = 0 ; j < nb_tracefile ; j++) {
4051 tfs =
4052 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
4053 LttvTracefileContext, j));
4054 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
4055 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
4056 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
4057 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
4058 }
4059 }
4060}
4061#endif //0
4062
4063void lttv_state_save_add_event_hooks(LttvTracesetState *self)
4064{
4065 LttvTraceset *traceset = self->parent.ts;
4066
4067 guint i, j, nb_trace, nb_tracefile;
4068
4069 LttvTraceState *ts;
4070
4071 LttvTracefileState *tfs;
4072
4073
4074 nb_trace = lttv_traceset_number(traceset);
4075 for(i = 0 ; i < nb_trace ; i++) {
4076
4077 ts = (LttvTraceState *)self->parent.traces[i];
4078 nb_tracefile = ts->parent.tracefiles->len;
4079
4080 if(ts->has_precomputed_states) continue;
4081
4082 guint *event_count = g_new(guint, 1);
4083 *event_count = 0;
4084
4085 for(j = 0 ; j < nb_tracefile ; j++) {
4086 tfs =
4087 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4088 LttvTracefileContext*, j));
4089 lttv_hooks_add(tfs->parent.event,
4090 state_save_event_hook,
4091 event_count,
4092 LTTV_PRIO_STATE);
4093
4094 }
4095 }
4096
4097 lttv_process_traceset_begin(&self->parent,
4098 NULL, NULL, NULL, NULL, NULL);
4099
4100}
4101
4102gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
4103{
4104 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
4105
4106 lttv_state_save_add_event_hooks(tss);
4107
4108 return 0;
4109}
4110
4111
4112#if 0
4113void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4114{
4115 LttvTraceset *traceset = self->parent.ts;
4116
4117 guint i, j, nb_trace, nb_tracefile;
4118
4119 LttvTraceState *ts;
4120
4121 LttvTracefileState *tfs;
4122
4123 LttvTraceHook hook_start, hook_end;
4124
4125 nb_trace = lttv_traceset_number(traceset);
4126 for(i = 0 ; i < nb_trace ; i++) {
4127 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
4128
4129 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
4130 NULL, NULL, block_start, &hook_start);
4131
4132 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
4133 NULL, NULL, block_end, &hook_end);
4134
4135 nb_tracefile = ts->parent.tracefiles->len;
4136
4137 for(j = 0 ; j < nb_tracefile ; j++) {
4138 tfs =
4139 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
4140 LttvTracefileContext, j));
4141 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4142 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
4143 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4144 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
4145 }
4146 }
4147}
4148#endif //0
4149
4150void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4151{
4152 LttvTraceset *traceset = self->parent.ts;
4153
4154 guint i, j, nb_trace, nb_tracefile;
4155
4156 LttvTraceState *ts;
4157
4158 LttvTracefileState *tfs;
4159
4160 LttvHooks *after_trace = lttv_hooks_new();
4161
4162 lttv_hooks_add(after_trace,
4163 state_save_after_trace_hook,
4164 NULL,
4165 LTTV_PRIO_STATE);
4166
4167
4168 lttv_process_traceset_end(&self->parent,
4169 NULL, after_trace, NULL, NULL, NULL);
4170
4171 lttv_hooks_destroy(after_trace);
4172
4173 nb_trace = lttv_traceset_number(traceset);
4174 for(i = 0 ; i < nb_trace ; i++) {
4175
4176 ts = (LttvTraceState *)self->parent.traces[i];
4177 nb_tracefile = ts->parent.tracefiles->len;
4178
4179 if(ts->has_precomputed_states) continue;
4180
4181 guint *event_count = NULL;
4182
4183 for(j = 0 ; j < nb_tracefile ; j++) {
4184 tfs =
4185 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4186 LttvTracefileContext*, j));
4187 event_count = lttv_hooks_remove(tfs->parent.event,
4188 state_save_event_hook);
4189 }
4190 if(event_count) g_free(event_count);
4191 }
4192}
4193
4194gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
4195{
4196 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
4197
4198 lttv_state_save_remove_event_hooks(tss);
4199
4200 return 0;
4201}
4202
4203void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
4204{
4205 LttvTraceset *traceset = self->parent.ts;
4206
4207 guint i, nb_trace;
4208
4209 int min_pos, mid_pos, max_pos;
4210
4211 guint call_rest = 0;
4212
4213 LttvTraceState *tcs;
4214
4215 LttvAttributeValue value;
4216
4217 LttvAttributeType type;
4218
4219 LttvAttributeName name;
4220
4221 gboolean is_named;
4222
4223 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree = NULL;
4224
4225 //g_tree_destroy(self->parent.pqueue);
4226 //self->parent.pqueue = g_tree_new(compare_tracefile);
4227
4228 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
4229
4230 nb_trace = lttv_traceset_number(traceset);
4231 for(i = 0 ; i < nb_trace ; i++) {
4232 tcs = (LttvTraceState *)self->parent.traces[i];
4233
4234 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
4235 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
4236 LTTV_STATE_SAVED_STATES);
4237 min_pos = -1;
4238
4239 if(saved_states_tree) {
4240 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
4241 mid_pos = max_pos / 2;
4242 while(min_pos < max_pos) {
4243 type = lttv_attribute_get(saved_states_tree, mid_pos,
4244 &name, &value, &is_named);
4245 g_assert(type == LTTV_GOBJECT);
4246 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
4247 type = lttv_attribute_get_by_name(saved_state_tree,
4248 LTTV_STATE_TIME, &value);
4249 g_assert(type == LTTV_TIME);
4250 if(ltt_time_compare(*(value.v_time), t) < 0) {
4251 min_pos = mid_pos;
4252 closest_tree = saved_state_tree;
4253 }
4254 else max_pos = mid_pos - 1;
4255
4256 mid_pos = (min_pos + max_pos + 1) / 2;
4257 }
4258 }
4259
4260 /* restore the closest earlier saved state */
4261 if(min_pos != -1) {
4262 lttv_state_restore(tcs, closest_tree);
4263 call_rest = 1;
4264 }
4265
4266 /* There is no saved state, yet we want to have it. Restart at T0 */
4267 else {
4268 restore_init_state(tcs);
4269 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
4270 }
4271 }
4272 /* We want to seek quickly without restoring/updating the state */
4273 else {
4274 restore_init_state(tcs);
4275 lttv_process_trace_seek_time(&(tcs->parent), t);
4276 }
4277 }
4278 if(!call_rest) g_info("NOT Calling restore");
4279}
4280
4281
4282static void traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
4283{
4284}
4285
4286
4287static void traceset_state_finalize (LttvTracesetState *self)
4288{
4289 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
4290 finalize(G_OBJECT(self));
4291}
4292
4293
4294static void traceset_state_class_init (LttvTracesetContextClass *klass)
4295{
4296 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4297
4298 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
4299 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
4300 klass->fini = (void (*)(LttvTracesetContext *self))fini;
4301 klass->new_traceset_context = new_traceset_context;
4302 klass->new_trace_context = new_trace_context;
4303 klass->new_tracefile_context = new_tracefile_context;
4304}
4305
4306
4307GType lttv_traceset_state_get_type(void)
4308{
4309 static GType type = 0;
4310 if (type == 0) {
4311 static const GTypeInfo info = {
4312 sizeof (LttvTracesetStateClass),
4313 NULL, /* base_init */
4314 NULL, /* base_finalize */
4315 (GClassInitFunc) traceset_state_class_init, /* class_init */
4316 NULL, /* class_finalize */
4317 NULL, /* class_data */
4318 sizeof (LttvTracesetState),
4319 0, /* n_preallocs */
4320 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
4321 NULL /* value handling */
4322 };
4323
4324 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
4325 &info, 0);
4326 }
4327 return type;
4328}
4329
4330
4331static void trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
4332{
4333}
4334
4335
4336static void trace_state_finalize (LttvTraceState *self)
4337{
4338 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
4339 finalize(G_OBJECT(self));
4340}
4341
4342
4343static void trace_state_class_init (LttvTraceStateClass *klass)
4344{
4345 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4346
4347 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
4348 klass->state_save = state_save;
4349 klass->state_restore = state_restore;
4350 klass->state_saved_free = state_saved_free;
4351}
4352
4353
4354GType lttv_trace_state_get_type(void)
4355{
4356 static GType type = 0;
4357 if (type == 0) {
4358 static const GTypeInfo info = {
4359 sizeof (LttvTraceStateClass),
4360 NULL, /* base_init */
4361 NULL, /* base_finalize */
4362 (GClassInitFunc) trace_state_class_init, /* class_init */
4363 NULL, /* class_finalize */
4364 NULL, /* class_data */
4365 sizeof (LttvTraceState),
4366 0, /* n_preallocs */
4367 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
4368 NULL /* value handling */
4369 };
4370
4371 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
4372 "LttvTraceStateType", &info, 0);
4373 }
4374 return type;
4375}
4376
4377
4378static void tracefile_state_instance_init (GTypeInstance *instance,
4379 gpointer g_class)
4380{
4381}
4382
4383
4384static void tracefile_state_finalize (LttvTracefileState *self)
4385{
4386 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
4387 finalize(G_OBJECT(self));
4388}
4389
4390
4391static void tracefile_state_class_init (LttvTracefileStateClass *klass)
4392{
4393 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4394
4395 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
4396}
4397
4398
4399GType lttv_tracefile_state_get_type(void)
4400{
4401 static GType type = 0;
4402 if (type == 0) {
4403 static const GTypeInfo info = {
4404 sizeof (LttvTracefileStateClass),
4405 NULL, /* base_init */
4406 NULL, /* base_finalize */
4407 (GClassInitFunc) tracefile_state_class_init, /* class_init */
4408 NULL, /* class_finalize */
4409 NULL, /* class_data */
4410 sizeof (LttvTracefileState),
4411 0, /* n_preallocs */
4412 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
4413 NULL /* value handling */
4414 };
4415
4416 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
4417 "LttvTracefileStateType", &info, 0);
4418 }
4419 return type;
4420}
4421
4422
4423static void module_init()
4424{
4425 LTTV_STATE_UNNAMED = g_quark_from_string("");
4426 LTTV_STATE_UNBRANDED = g_quark_from_string("");
4427 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
4428 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
4429 LTTV_STATE_MAYBE_USER_MODE = g_quark_from_string("MAYBE_USER_MODE");
4430 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
4431 LTTV_STATE_MAYBE_SYSCALL = g_quark_from_string("MAYBE_SYSCALL");
4432 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
4433 LTTV_STATE_MAYBE_TRAP = g_quark_from_string("MAYBE_TRAP");
4434 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
4435 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
4436 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
4437 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
4438 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
4439 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
4440 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
4441 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
4442 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
4443 LTTV_STATE_RUN = g_quark_from_string("RUN");
4444 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
4445 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
4446 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
4447 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
4448 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
4449 LTTV_STATE_PROCESS = g_quark_from_string("process");
4450 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
4451 LTTV_STATE_EVENT = g_quark_from_string("event");
4452 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
4453 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
4454 LTTV_STATE_TIME = g_quark_from_string("time");
4455 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
4456 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
4457 LTTV_STATE_TRACE_STATE_USE_COUNT =
4458 g_quark_from_string("trace_state_use_count");
4459 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
4460 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
4461 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
4462 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
4463 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
4464 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
4465
4466 LTT_CHANNEL_FD_STATE = g_quark_from_string("fd_state");
4467 LTT_CHANNEL_GLOBAL_STATE = g_quark_from_string("global_state");
4468 LTT_CHANNEL_IRQ_STATE = g_quark_from_string("irq_state");
4469 LTT_CHANNEL_MODULE_STATE = g_quark_from_string("module_state");
4470 LTT_CHANNEL_NETIF_STATE = g_quark_from_string("netif_state");
4471 LTT_CHANNEL_SOFTIRQ_STATE = g_quark_from_string("softirq_state");
4472 LTT_CHANNEL_SWAP_STATE = g_quark_from_string("swap_state");
4473 LTT_CHANNEL_SYSCALL_STATE = g_quark_from_string("syscall_state");
4474 LTT_CHANNEL_TASK_STATE = g_quark_from_string("task_state");
4475 LTT_CHANNEL_VM_STATE = g_quark_from_string("vm_state");
4476 LTT_CHANNEL_KPROBE_STATE = g_quark_from_string("kprobe_state");
4477 LTT_CHANNEL_FS = g_quark_from_string("fs");
4478 LTT_CHANNEL_KERNEL = g_quark_from_string("kernel");
4479 LTT_CHANNEL_MM = g_quark_from_string("mm");
4480 LTT_CHANNEL_USERSPACE = g_quark_from_string("userspace");
4481 LTT_CHANNEL_BLOCK = g_quark_from_string("block");
4482
4483 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
4484 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
4485 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
4486 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
4487 LTT_EVENT_PAGE_FAULT_ENTRY = g_quark_from_string("page_fault_entry");
4488 LTT_EVENT_PAGE_FAULT_EXIT = g_quark_from_string("page_fault_exit");
4489 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY = g_quark_from_string("page_fault_nosem_entry");
4490 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT = g_quark_from_string("page_fault_nosem_exit");
4491 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
4492 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
4493 LTT_EVENT_SOFT_IRQ_RAISE = g_quark_from_string("softirq_raise");
4494 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
4495 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
4496 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
4497 LTT_EVENT_SCHED_TRY_WAKEUP = g_quark_from_string("sched_try_wakeup");
4498 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
4499 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
4500 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
4501 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
4502 LTT_EVENT_EXEC = g_quark_from_string("exec");
4503 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
4504 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
4505 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4506 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
4507 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
4508 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4509 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
4510 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");
4511 LTT_EVENT_SYS_CALL_TABLE = g_quark_from_string("sys_call_table");
4512 LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec");
4513 LTT_EVENT_KPROBE_TABLE = g_quark_from_string("kprobe_table");
4514 LTT_EVENT_KPROBE = g_quark_from_string("kprobe");
4515 LTT_EVENT_OPEN = g_quark_from_string("open");
4516 LTT_EVENT_READ = g_quark_from_string("read");
4517 LTT_EVENT_POLL_EVENT = g_quark_from_string("poll_event");
4518
4519 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4520 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4521 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
4522 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
4523 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4524 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4525 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
4526 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4527 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4528 LTT_FIELD_PID = g_quark_from_string("pid");
4529 LTT_FIELD_TGID = g_quark_from_string("tgid");
4530 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
4531 LTT_FIELD_FILENAME = g_quark_from_string("filename");
4532 LTT_FIELD_NAME = g_quark_from_string("name");
4533 LTT_FIELD_TYPE = g_quark_from_string("type");
4534 LTT_FIELD_MODE = g_quark_from_string("mode");
4535 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4536 LTT_FIELD_STATUS = g_quark_from_string("status");
4537 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4538 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
4539 LTT_FIELD_MAJOR = g_quark_from_string("major");
4540 LTT_FIELD_MINOR = g_quark_from_string("minor");
4541 LTT_FIELD_OPERATION = g_quark_from_string("direction");
4542 LTT_FIELD_ACTION = g_quark_from_string("action");
4543 LTT_FIELD_ID = g_quark_from_string("id");
4544 LTT_FIELD_ADDRESS = g_quark_from_string("address");
4545 LTT_FIELD_SYMBOL = g_quark_from_string("symbol");
4546 LTT_FIELD_IP = g_quark_from_string("ip");
4547 LTT_FIELD_FD = g_quark_from_string("fd");
4548 LTT_FIELD_STATE = g_quark_from_string("state");
4549 LTT_FIELD_CPU_ID = g_quark_from_string("cpu_id");
4550
4551 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4552 LTTV_CPU_IDLE = g_quark_from_string("idle");
4553 LTTV_CPU_BUSY = g_quark_from_string("busy");
4554 LTTV_CPU_IRQ = g_quark_from_string("irq");
4555 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
4556 LTTV_CPU_TRAP = g_quark_from_string("trap");
4557
4558 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4559 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4560 LTTV_IRQ_BUSY = g_quark_from_string("busy");
4561
4562 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4563 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4564 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4565 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
4566}
4567
4568static void module_destroy()
4569{
4570}
4571
4572
4573LTTV_MODULE("state", "State computation", \
4574 "Update the system state, possibly saving it at intervals", \
4575 module_init, module_destroy)
4576
4577
4578
This page took 0.038309 seconds and 4 git commands to generate.