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