control flow view works (state computation disabled)
[lttv.git] / ltt / branches / poly / 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 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
29 #include <ltt/type.h>
30 #include <stdio.h>
31
32 #define PREALLOCATED_EXECUTION_STACK 10
33
34 /* Facilities Quarks */
35
36 GQuark
37 LTT_FACILITY_KERNEL,
38 LTT_FACILITY_PROCESS;
39
40 /* Events Quarks */
41
42 GQuark
43 LTT_EVENT_SYSCALL_ENTRY,
44 LTT_EVENT_SYSCALL_EXIT,
45 LTT_EVENT_TRAP_ENTRY,
46 LTT_EVENT_TRAP_EXIT,
47 LTT_EVENT_IRQ_ENTRY,
48 LTT_EVENT_IRQ_EXIT,
49 LTT_EVENT_SCHEDCHANGE,
50 LTT_EVENT_FORK,
51 LTT_EVENT_EXIT,
52 LTT_EVENT_FREE;
53
54 /* Fields Quarks */
55
56 GQuark
57 LTT_FIELD_SYSCALL_ID,
58 LTT_FIELD_TRAP_ID,
59 LTT_FIELD_IRQ_ID,
60 LTT_FIELD_OUT,
61 LTT_FIELD_IN,
62 LTT_FIELD_OUT_STATE,
63 LTT_FIELD_PARENT_PID,
64 LTT_FIELD_CHILD_PID,
65 LTT_FIELD_PID;
66
67 LttvExecutionMode
68 LTTV_STATE_MODE_UNKNOWN,
69 LTTV_STATE_USER_MODE,
70 LTTV_STATE_SYSCALL,
71 LTTV_STATE_TRAP,
72 LTTV_STATE_IRQ;
73
74 LttvExecutionSubmode
75 LTTV_STATE_SUBMODE_UNKNOWN,
76 LTTV_STATE_SUBMODE_NONE;
77
78 LttvProcessStatus
79 LTTV_STATE_UNNAMED,
80 LTTV_STATE_WAIT_FORK,
81 LTTV_STATE_WAIT_CPU,
82 LTTV_STATE_EXIT,
83 LTTV_STATE_ZOMBIE,
84 LTTV_STATE_WAIT,
85 LTTV_STATE_RUN;
86
87 static GQuark
88 LTTV_STATE_TRACEFILES,
89 LTTV_STATE_PROCESSES,
90 LTTV_STATE_PROCESS,
91 LTTV_STATE_EVENT,
92 LTTV_STATE_SAVED_STATES,
93 LTTV_STATE_SAVED_STATES_TIME,
94 LTTV_STATE_TIME,
95 LTTV_STATE_HOOKS,
96 LTTV_STATE_NAME_TABLES,
97 LTTV_STATE_TRACE_STATE_USE_COUNT;
98
99 static void create_max_time(LttvTraceState *tcs);
100
101 static void get_max_time(LttvTraceState *tcs);
102
103 static void free_max_time(LttvTraceState *tcs);
104
105 static void create_name_tables(LttvTraceState *tcs);
106
107 static void get_name_tables(LttvTraceState *tcs);
108
109 static void free_name_tables(LttvTraceState *tcs);
110
111 static void free_saved_state(LttvTraceState *tcs);
112
113 static void lttv_state_free_process_table(GHashTable *processes);
114
115
116 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
117 {
118 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
119 }
120
121
122 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
123 {
124 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
125 }
126
127
128 void lttv_state_state_saved_free(LttvTraceState *self,
129 LttvAttribute *container)
130 {
131 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
132 }
133
134
135 guint process_hash(gconstpointer key)
136 {
137 guint pid = ((const LttvProcessState *)key)->pid;
138 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
139 }
140
141
142 /* If the hash table hash function is well distributed,
143 * the process_equal should compare different pid */
144 gboolean process_equal(gconstpointer a, gconstpointer b)
145 {
146 const LttvProcessState *process_a, *process_b;
147 gboolean ret = TRUE;
148
149 process_a = (const LttvProcessState *)a;
150 process_b = (const LttvProcessState *)b;
151
152 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
153 else if(likely(process_a->pid == 0 &&
154 process_a->last_cpu != process_b->last_cpu)) ret = FALSE;
155
156 return ret;
157 }
158
159
160 static void
161 restore_init_state(LttvTraceState *self)
162 {
163 guint i, nb_tracefile;
164
165 LttvTracefileState *tfcs;
166
167 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
168 self->processes = g_hash_table_new(process_hash, process_equal);
169 self->nb_event = 0;
170
171 nb_tracefile = self->parent.tracefiles->len;
172
173 for(i = 0 ; i < nb_tracefile ; i++) {
174 tfcs =
175 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
176 LttvTracefileContext*, i));
177 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
178 // tfcs->saved_position = 0;
179 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
180 tfcs->process->state->s = LTTV_STATE_RUN;
181 tfcs->process->last_cpu = tfcs->cpu_name;
182 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
183 }
184 }
185
186 static LttTime time_zero = {0,0};
187
188 static void
189 init(LttvTracesetState *self, LttvTraceset *ts)
190 {
191 guint i, j, nb_trace, nb_tracefile;
192
193 LttvTraceContext *tc;
194
195 LttvTraceState *tcs;
196
197 LttvTracefileState *tfcs;
198
199 LttvAttributeValue v;
200
201 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
202 init((LttvTracesetContext *)self, ts);
203
204 nb_trace = lttv_traceset_number(ts);
205 for(i = 0 ; i < nb_trace ; i++) {
206 tc = self->parent.traces[i];
207 tcs = LTTV_TRACE_STATE(tc);
208 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
209 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
210 LTTV_UINT, &v);
211 (*v.v_uint)++;
212
213 if(*(v.v_uint) == 1) {
214 create_name_tables(tcs);
215 create_max_time(tcs);
216 }
217 get_name_tables(tcs);
218 get_max_time(tcs);
219
220 nb_tracefile = tc->tracefiles->len;
221
222 for(j = 0 ; j < nb_tracefile ; j++) {
223 tfcs =
224 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
225 LttvTracefileContext*, j));
226 tfcs->cpu_name = ltt_tracefile_name(tfcs->parent.tf);
227 }
228 tcs->processes = NULL;
229 restore_init_state(tcs);
230 }
231 }
232
233
234 static void
235 fini(LttvTracesetState *self)
236 {
237 guint i, nb_trace;
238
239 LttvTraceState *tcs;
240
241 LttvTracefileState *tfcs;
242
243 LttvAttributeValue v;
244
245 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
246 for(i = 0 ; i < nb_trace ; i++) {
247 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
248 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
249 LTTV_UINT, &v);
250
251 g_assert(*(v.v_uint) != 0);
252 (*v.v_uint)--;
253
254 if(*(v.v_uint) == 0) {
255 free_name_tables(tcs);
256 free_max_time(tcs);
257 free_saved_state(tcs);
258 }
259 lttv_state_free_process_table(tcs->processes);
260 tcs->processes = NULL;
261 }
262 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
263 fini((LttvTracesetContext *)self);
264 }
265
266
267 static LttvTracesetContext *
268 new_traceset_context(LttvTracesetContext *self)
269 {
270 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
271 }
272
273
274 static LttvTraceContext *
275 new_trace_context(LttvTracesetContext *self)
276 {
277 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
278 }
279
280
281 static LttvTracefileContext *
282 new_tracefile_context(LttvTracesetContext *self)
283 {
284 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
285 }
286
287
288 /* Write the process state of the trace */
289
290 static void write_process_state(gpointer key, gpointer value,
291 gpointer user_data)
292 {
293 LttvProcessState *process;
294
295 LttvExecutionState *es;
296
297 FILE *fp = (FILE *)user_data;
298
299 guint i;
300
301 process = (LttvProcessState *)value;
302 fprintf(fp,
303 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
304 process, process->pid, process->ppid, process->creation_time.tv_sec,
305 process->creation_time.tv_nsec, g_quark_to_string(process->name),
306 g_quark_to_string(process->last_cpu));
307
308 for(i = 0 ; i < process->execution_stack->len; i++) {
309 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
310 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
311 g_quark_to_string(es->t), g_quark_to_string(es->n),
312 es->entry.tv_sec, es->entry.tv_nsec);
313 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
314 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
315 }
316 fprintf(fp, " </PROCESS>\n");
317 }
318
319
320 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
321 {
322 guint i, nb_tracefile, nb_block, offset;
323 guint64 tsc;
324
325 LttvTracefileState *tfcs;
326
327 LttTracefile *tf;
328
329 LttEventPosition *ep;
330
331 ep = ltt_event_position_new();
332
333 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
334
335 g_hash_table_foreach(self->processes, write_process_state, fp);
336
337 nb_tracefile = self->parent.tracefiles->len;
338
339 for(i = 0 ; i < nb_tracefile ; i++) {
340 tfcs =
341 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
342 LttvTracefileContext*, i));
343 fprintf(fp, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
344 tfcs->process->pid, tfcs->parent.timestamp.tv_sec,
345 tfcs->parent.timestamp.tv_nsec);
346 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
347 if(e == NULL) fprintf(fp,"/>\n");
348 else {
349 ltt_event_position(e, ep);
350 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
351 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
352 tsc);
353 }
354 }
355 g_free(ep);
356 fprintf(fp,"</PROCESS_STATE>");
357 }
358
359
360 /* Copy each process from an existing hash table to a new one */
361
362 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
363 {
364 LttvProcessState *process, *new_process;
365
366 GHashTable *new_processes = (GHashTable *)user_data;
367
368 guint i;
369
370 process = (LttvProcessState *)value;
371 new_process = g_new(LttvProcessState, 1);
372 *new_process = *process;
373 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
374 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
375 new_process->execution_stack =
376 g_array_set_size(new_process->execution_stack,
377 process->execution_stack->len);
378 for(i = 0 ; i < process->execution_stack->len; i++) {
379 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
380 g_array_index(process->execution_stack, LttvExecutionState, i);
381 }
382 new_process->state = &g_array_index(new_process->execution_stack,
383 LttvExecutionState, new_process->execution_stack->len - 1);
384 g_hash_table_insert(new_processes, new_process, new_process);
385 }
386
387
388 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
389 {
390 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
391
392 g_hash_table_foreach(processes, copy_process_state, new_processes);
393 return new_processes;
394 }
395
396
397 /* The saved state for each trace contains a member "processes", which
398 stores a copy of the process table, and a member "tracefiles" with
399 one entry per tracefile. Each tracefile has a "process" member pointing
400 to the current process and a "position" member storing the tracefile
401 position (needed to seek to the current "next" event. */
402
403 static void state_save(LttvTraceState *self, LttvAttribute *container)
404 {
405 guint i, nb_tracefile;
406
407 LttvTracefileState *tfcs;
408
409 LttvAttribute *tracefiles_tree, *tracefile_tree;
410
411 LttvAttributeType type;
412
413 LttvAttributeValue value;
414
415 LttvAttributeName name;
416
417 LttEventPosition *ep;
418
419 tracefiles_tree = lttv_attribute_find_subdir(container,
420 LTTV_STATE_TRACEFILES);
421
422 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
423 LTTV_POINTER);
424 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
425
426 nb_tracefile = self->parent.tracefiles->len;
427
428 for(i = 0 ; i < nb_tracefile ; i++) {
429 tfcs =
430 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
431 LttvTracefileContext*, i));
432 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
433 value = lttv_attribute_add(tracefiles_tree, i,
434 LTTV_GOBJECT);
435 *(value.v_gobject) = (GObject *)tracefile_tree;
436 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
437 LTTV_UINT);
438 *(value.v_uint) = tfcs->process->pid;
439 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
440 LTTV_POINTER);
441 /* Only save the position of the tfs is in the pqueue */
442 if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)) {
443 *(value.v_pointer) = NULL;
444 } else {
445 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
446 ep = ltt_event_position_new();
447 ltt_event_position(e, ep);
448 *(value.v_pointer) = ep;
449
450 guint nb_block, offset;
451 guint64 tsc;
452 LttTracefile *tf;
453 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
454 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
455 tsc,
456 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
457 }
458 }
459 }
460
461
462 static void state_restore(LttvTraceState *self, LttvAttribute *container)
463 {
464 guint i, nb_tracefile, pid;
465
466 LttvTracefileState *tfcs;
467
468 LttvAttribute *tracefiles_tree, *tracefile_tree;
469
470 LttvAttributeType type;
471
472 LttvAttributeValue value;
473
474 LttvAttributeName name;
475
476 LttEventPosition *ep;
477
478 LttvTracesetContext *tsc = self->parent.ts_context;
479
480 tracefiles_tree = lttv_attribute_find_subdir(container,
481 LTTV_STATE_TRACEFILES);
482
483 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
484 &value);
485 g_assert(type == LTTV_POINTER);
486 lttv_state_free_process_table(self->processes);
487 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
488
489 nb_tracefile = self->parent.tracefiles->len;
490
491 g_tree_destroy(tsc->pqueue);
492 tsc->pqueue = g_tree_new(compare_tracefile);
493
494 for(i = 0 ; i < nb_tracefile ; i++) {
495 tfcs =
496 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
497 LttvTracefileContext*, i));
498 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
499 g_assert(type == LTTV_GOBJECT);
500 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
501
502 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
503 &value);
504 g_assert(type == LTTV_UINT);
505 pid = *(value.v_uint);
506 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
507
508 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
509 &value);
510 g_assert(type == LTTV_POINTER);
511 //g_assert(*(value.v_pointer) != NULL);
512 ep = *(value.v_pointer);
513 g_assert(tfcs->parent.t_context != NULL);
514
515 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
516
517 if(ep != NULL) {
518 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
519 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
520 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
521 g_tree_insert(tsc->pqueue, tfc, tfc);
522 } else {
523 tfc->timestamp = ltt_time_infinite;
524 }
525 }
526 }
527
528
529 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
530 {
531 guint i, nb_tracefile;
532
533 LttvTracefileState *tfcs;
534
535 LttvAttribute *tracefiles_tree, *tracefile_tree;
536
537 LttvAttributeType type;
538
539 LttvAttributeValue value;
540
541 LttvAttributeName name;
542
543 LttEventPosition *ep;
544
545 tracefiles_tree = lttv_attribute_find_subdir(container,
546 LTTV_STATE_TRACEFILES);
547 g_object_ref(G_OBJECT(tracefiles_tree));
548 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
549
550 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
551 &value);
552 g_assert(type == LTTV_POINTER);
553 lttv_state_free_process_table(*(value.v_pointer));
554 *(value.v_pointer) = NULL;
555 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
556
557 nb_tracefile = self->parent.tracefiles->len;
558
559 for(i = 0 ; i < nb_tracefile ; i++) {
560 tfcs =
561 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
562 LttvTracefileContext*, i));
563 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
564 g_assert(type == LTTV_GOBJECT);
565 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
566
567 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
568 &value);
569 g_assert(type == LTTV_POINTER);
570 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
571 }
572 g_object_unref(G_OBJECT(tracefiles_tree));
573 }
574
575
576 static void free_saved_state(LttvTraceState *self)
577 {
578 guint i, nb;
579
580 LttvAttributeType type;
581
582 LttvAttributeValue value;
583
584 LttvAttributeName name;
585
586 LttvAttribute *saved_states;
587
588 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
589 LTTV_STATE_SAVED_STATES);
590
591 nb = lttv_attribute_get_number(saved_states);
592 for(i = 0 ; i < nb ; i++) {
593 type = lttv_attribute_get(saved_states, i, &name, &value);
594 g_assert(type == LTTV_GOBJECT);
595 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
596 }
597
598 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
599 }
600
601
602 static void
603 create_max_time(LttvTraceState *tcs)
604 {
605 LttvAttributeValue v;
606
607 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
608 LTTV_POINTER, &v);
609 g_assert(*(v.v_pointer) == NULL);
610 *(v.v_pointer) = g_new(LttTime,1);
611 *((LttTime *)*(v.v_pointer)) = time_zero;
612 }
613
614
615 static void
616 get_max_time(LttvTraceState *tcs)
617 {
618 LttvAttributeValue v;
619
620 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
621 LTTV_POINTER, &v);
622 g_assert(*(v.v_pointer) != NULL);
623 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
624 }
625
626
627 static void
628 free_max_time(LttvTraceState *tcs)
629 {
630 LttvAttributeValue v;
631
632 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
633 LTTV_POINTER, &v);
634 g_free(*(v.v_pointer));
635 *(v.v_pointer) = NULL;
636 }
637
638
639 typedef struct _LttvNameTables {
640 // FIXME GQuark *eventtype_names;
641 GQuark *syscall_names;
642 GQuark *trap_names;
643 GQuark *irq_names;
644 } LttvNameTables;
645
646
647 static void
648 create_name_tables(LttvTraceState *tcs)
649 {
650 int i, nb;
651
652 GQuark f_name, e_name;
653
654 LttvTraceHook h;
655
656 LttvTraceHookByFacility *thf;
657
658 LttEventType *et;
659
660 LttType *t;
661
662 GString *fe_name = g_string_new("");
663
664 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
665
666 LttvAttributeValue v;
667
668 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
669 LTTV_POINTER, &v);
670 g_assert(*(v.v_pointer) == NULL);
671 *(v.v_pointer) = name_tables;
672 #if 0 // Use iteration over the facilities_by_name and then list all event
673 // types of each facility
674 nb = ltt_trace_eventtype_number(tcs->parent.t);
675 name_tables->eventtype_names = g_new(GQuark, nb);
676 for(i = 0 ; i < nb ; i++) {
677 et = ltt_trace_eventtype_get(tcs->parent.t, i);
678 e_name = ltt_eventtype_name(et);
679 f_name = ltt_facility_name(ltt_eventtype_facility(et));
680 g_string_printf(fe_name, "%s.%s", f_name, e_name);
681 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
682 }
683 #endif //0
684 if(lttv_trace_find_hook(tcs->parent.t,
685 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
686 LTT_FIELD_SYSCALL_ID, 0, 0,
687 NULL, NULL, &h))
688 return;
689
690 thf = lttv_trace_hook_get_first(&h);
691
692 t = ltt_field_type(thf->f1);
693 nb = ltt_type_element_number(t);
694
695 lttv_trace_hook_destroy(&h);
696
697 /* CHECK syscalls should be an enum but currently are not!
698 name_tables->syscall_names = g_new(GQuark, nb);
699
700 for(i = 0 ; i < nb ; i++) {
701 name_tables->syscall_names[i] = g_quark_from_string(
702 ltt_enum_string_get(t, i));
703 }
704 */
705
706 name_tables->syscall_names = g_new(GQuark, 256);
707 for(i = 0 ; i < 256 ; i++) {
708 g_string_printf(fe_name, "syscall %d", i);
709 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
710 }
711
712 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
713 LTT_EVENT_TRAP_ENTRY,
714 LTT_FIELD_TRAP_ID, 0, 0,
715 NULL, NULL, &h))
716 return;
717
718 thf = lttv_trace_hook_get_first(&h);
719
720 t = ltt_field_type(thf->f1);
721 nb = ltt_type_element_number(t);
722
723 lttv_trace_hook_destroy(&h);
724
725 /*
726 name_tables->trap_names = g_new(GQuark, nb);
727 for(i = 0 ; i < nb ; i++) {
728 name_tables->trap_names[i] = g_quark_from_string(
729 ltt_enum_string_get(t, i));
730 }
731 */
732
733 name_tables->trap_names = g_new(GQuark, 256);
734 for(i = 0 ; i < 256 ; i++) {
735 g_string_printf(fe_name, "trap %d", i);
736 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
737 }
738
739 if(lttv_trace_find_hook(tcs->parent.t,
740 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
741 LTT_FIELD_IRQ_ID, 0, 0,
742 NULL, NULL, &h))
743 return;
744
745 thf = lttv_trace_hook_get_first(&h);
746
747 t = ltt_field_type(thf->f1);
748 nb = ltt_type_element_number(t);
749
750 lttv_trace_hook_destroy(&h);
751
752 /*
753 name_tables->irq_names = g_new(GQuark, nb);
754 for(i = 0 ; i < nb ; i++) {
755 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
756 }
757 */
758
759 name_tables->irq_names = g_new(GQuark, 256);
760 for(i = 0 ; i < 256 ; i++) {
761 g_string_printf(fe_name, "irq %d", i);
762 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
763 }
764
765 g_string_free(fe_name, TRUE);
766 }
767
768
769 static void
770 get_name_tables(LttvTraceState *tcs)
771 {
772 LttvNameTables *name_tables;
773
774 LttvAttributeValue v;
775
776 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
777 LTTV_POINTER, &v);
778 g_assert(*(v.v_pointer) != NULL);
779 name_tables = (LttvNameTables *)*(v.v_pointer);
780 //tcs->eventtype_names = name_tables->eventtype_names;
781 tcs->syscall_names = name_tables->syscall_names;
782 tcs->trap_names = name_tables->trap_names;
783 tcs->irq_names = name_tables->irq_names;
784 }
785
786
787 static void
788 free_name_tables(LttvTraceState *tcs)
789 {
790 LttvNameTables *name_tables;
791
792 LttvAttributeValue v;
793
794 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
795 LTTV_POINTER, &v);
796 name_tables = (LttvNameTables *)*(v.v_pointer);
797 *(v.v_pointer) = NULL;
798
799 // g_free(name_tables->eventtype_names);
800 g_free(name_tables->syscall_names);
801 g_free(name_tables->trap_names);
802 g_free(name_tables->irq_names);
803 g_free(name_tables);
804 }
805
806 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
807 guint state_id)
808 {
809 LttvExecutionState *es;
810
811 LttvProcessState *process = tfs->process;
812
813 guint depth = process->execution_stack->len;
814
815 process->execution_stack =
816 g_array_set_size(process->execution_stack, depth + 1);
817 /* Keep in sync */
818 process->state =
819 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
820
821 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
822 es->t = t;
823 es->n = state_id;
824 es->entry = es->change = tfs->parent.timestamp;
825 es->s = process->state->s;
826 process->state = es;
827 }
828
829
830 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
831 {
832 LttvProcessState *process = tfs->process;
833
834 guint depth = process->execution_stack->len;
835
836 if(process->state->t != t){
837 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
838 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
839 g_info("process state has %s when pop_int is %s\n",
840 g_quark_to_string(process->state->t),
841 g_quark_to_string(t));
842 g_info("{ %u, %u, %s, %s }\n",
843 process->pid,
844 process->ppid,
845 g_quark_to_string(process->name),
846 g_quark_to_string(process->state->s));
847 return;
848 }
849
850 if(depth == 1){
851 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
852 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
853 return;
854 }
855
856 process->execution_stack =
857 g_array_set_size(process->execution_stack, depth - 1);
858 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
859 depth - 2);
860 process->state->change = tfs->parent.timestamp;
861 }
862
863
864 LttvProcessState *
865 lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
866 guint pid)
867 {
868 LttvProcessState *process = g_new(LttvProcessState, 1);
869
870 LttvExecutionState *es;
871
872 LttvTraceContext *tc;
873
874 LttvTraceState *tcs;
875
876 char buffer[128];
877
878 tc = tfs->parent.t_context;
879 tcs = (LttvTraceState *)tc;
880
881 process->pid = pid;
882 process->last_cpu = tfs->cpu_name;
883 process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
884 g_info("Process %u, core %p", process->pid, process);
885 g_hash_table_insert(tcs->processes, process, process);
886
887 if(parent) {
888 process->ppid = parent->pid;
889 process->name = parent->name;
890 process->creation_time = tfs->parent.timestamp;
891 }
892
893 /* No parent. This process exists but we are missing all information about
894 its creation. The birth time is set to zero but we remember the time of
895 insertion */
896
897 else {
898 process->ppid = 0;
899 process->name = LTTV_STATE_UNNAMED;
900 process->creation_time = ltt_time_zero;
901 }
902
903 process->insertion_time = tfs->parent.timestamp;
904 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
905 process->creation_time.tv_nsec);
906 process->pid_time = g_quark_from_string(buffer);
907 process->last_cpu = tfs->cpu_name;
908 process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
909 process->execution_stack = g_array_sized_new(FALSE, FALSE,
910 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
911 process->execution_stack = g_array_set_size(process->execution_stack, 1);
912 es = process->state = &g_array_index(process->execution_stack,
913 LttvExecutionState, 0);
914 es->t = LTTV_STATE_USER_MODE;
915 es->n = LTTV_STATE_SUBMODE_NONE;
916 es->entry = tfs->parent.timestamp;
917 g_assert(tfs->parent.timestamp.tv_sec != 0);
918 es->change = tfs->parent.timestamp;
919 es->s = LTTV_STATE_WAIT_FORK;
920
921 return process;
922 }
923
924 LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
925 guint pid)
926 {
927 LttvProcessState key;
928 LttvProcessState *process;
929
930 LttvTraceState* ts = (LttvTraceState*)tfs->parent.t_context;
931
932 key.pid = pid;
933 key.last_cpu = tfs->cpu_name;
934 process = g_hash_table_lookup(ts->processes, &key);
935 return process;
936 }
937
938 LttvProcessState *
939 lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
940 {
941 LttvProcessState *process = lttv_state_find_process(tfs, pid);
942
943 if(unlikely(process == NULL)) process = lttv_state_create_process(tfs, NULL, pid);
944 return process;
945 }
946
947 /* FIXME : this function should be called when we receive an event telling that
948 * release_task has been called in the kernel. In happens generally when
949 * the parent waits for its child terminaison, but may also happen in special
950 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
951 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
952 * of a killed thread ground, but isn't the leader.
953 */
954 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
955 {
956 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
957 LttvProcessState key;
958
959 key.pid = process->pid;
960 key.last_cpu = process->last_cpu;
961 g_hash_table_remove(ts->processes, &key);
962 g_array_free(process->execution_stack, TRUE);
963 g_free(process);
964 }
965
966
967 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
968 {
969 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
970 g_free(value);
971 }
972
973
974 static void lttv_state_free_process_table(GHashTable *processes)
975 {
976 g_hash_table_foreach(processes, free_process_state, NULL);
977 g_hash_table_destroy(processes);
978 }
979
980
981 static gboolean syscall_entry(void *hook_data, void *call_data)
982 {
983 LttvTracefileState *s = (LttvTracefileState *)call_data;
984 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
985 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
986 LttField *f = thf->f1;
987
988 LttvExecutionSubmode submode;
989
990 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
991 ltt_event_get_unsigned(e, f)];
992 push_state(s, LTTV_STATE_SYSCALL, submode);
993 return FALSE;
994 }
995
996
997 static gboolean syscall_exit(void *hook_data, void *call_data)
998 {
999 LttvTracefileState *s = (LttvTracefileState *)call_data;
1000
1001 pop_state(s, LTTV_STATE_SYSCALL);
1002 return FALSE;
1003 }
1004
1005
1006 static gboolean trap_entry(void *hook_data, void *call_data)
1007 {
1008 LttvTracefileState *s = (LttvTracefileState *)call_data;
1009 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1010 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1011 LttField *f = thf->f1;
1012
1013 LttvExecutionSubmode submode;
1014
1015 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1016 ltt_event_get_unsigned(e, f)];
1017 push_state(s, LTTV_STATE_TRAP, submode);
1018 return FALSE;
1019 }
1020
1021
1022 static gboolean trap_exit(void *hook_data, void *call_data)
1023 {
1024 LttvTracefileState *s = (LttvTracefileState *)call_data;
1025
1026 pop_state(s, LTTV_STATE_TRAP);
1027 return FALSE;
1028 }
1029
1030
1031 static gboolean irq_entry(void *hook_data, void *call_data)
1032 {
1033 LttvTracefileState *s = (LttvTracefileState *)call_data;
1034 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1035 guint8 fac_id = ltt_event_facility_id(e);
1036 guint8 ev_id = ltt_event_eventtype_id(e);
1037 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1038 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1039 g_assert(thf->f1 != NULL);
1040 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1041 LttField *f = thf->f1;
1042
1043 LttvExecutionSubmode submode;
1044
1045 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1046 ltt_event_get_unsigned(e, f)];
1047
1048 /* Do something with the info about being in user or system mode when int? */
1049 push_state(s, LTTV_STATE_IRQ, submode);
1050 return FALSE;
1051 }
1052
1053
1054 static gboolean irq_exit(void *hook_data, void *call_data)
1055 {
1056 LttvTracefileState *s = (LttvTracefileState *)call_data;
1057
1058 pop_state(s, LTTV_STATE_IRQ);
1059 return FALSE;
1060 }
1061
1062
1063 static gboolean schedchange(void *hook_data, void *call_data)
1064 {
1065 LttvTracefileState *s = (LttvTracefileState *)call_data;
1066 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1067 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1068 guint pid_in, pid_out;
1069 gint state_out;
1070
1071 pid_out = ltt_event_get_unsigned(e, thf->f1);
1072 pid_in = ltt_event_get_unsigned(e, thf->f2);
1073 state_out = ltt_event_get_int(e, thf->f3);
1074
1075 if(likely(s->process != NULL)) {
1076
1077 /* We could not know but it was not the idle process executing.
1078 This should only happen at the beginning, before the first schedule
1079 event, and when the initial information (current process for each CPU)
1080 is missing. It is not obvious how we could, after the fact, compensate
1081 the wrongly attributed statistics. */
1082
1083 //This test only makes sense once the state is known and if there is no
1084 //missing events.
1085 //if(unlikely(s->process->pid != pid_out)) {
1086 // g_assert(s->process->pid == 0);
1087 //}
1088
1089 if(unlikely(s->process->state->s == LTTV_STATE_EXIT)) {
1090 s->process->state->s = LTTV_STATE_ZOMBIE;
1091 } else {
1092 if(unlikely(state_out == 0)) s->process->state->s = LTTV_STATE_WAIT_CPU;
1093 else s->process->state->s = LTTV_STATE_WAIT;
1094 } /* FIXME : we do not remove process here, because the kernel
1095 * still has them : they may be zombies. We need to know
1096 * exactly when release_task is executed on the PID to
1097 * know when the zombie is destroyed.
1098 */
1099 //else
1100 // exit_process(s, s->process);
1101
1102 s->process->state->change = s->parent.timestamp;
1103 }
1104 s->process = lttv_state_find_process_or_create(s, pid_in);
1105 s->process->state->s = LTTV_STATE_RUN;
1106 s->process->last_cpu = s->cpu_name;
1107 s->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1108 s->process->state->change = s->parent.timestamp;
1109 return FALSE;
1110 }
1111
1112 static gboolean process_fork(void *hook_data, void *call_data)
1113 {
1114 LttvTracefileState *s = (LttvTracefileState *)call_data;
1115 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1116 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1117 LttField *f;
1118 guint parent_pid;
1119 guint child_pid;
1120 LttvProcessState *zombie_process;
1121
1122 /* Parent PID */
1123 f = thf->f1;
1124 parent_pid = ltt_event_get_unsigned(e, f);
1125
1126 /* Child PID */
1127 f = thf->f2;
1128 child_pid = ltt_event_get_unsigned(e, f);
1129
1130 zombie_process = lttv_state_find_process(s, child_pid);
1131
1132 if(unlikely(zombie_process != NULL)) {
1133 /* Reutilisation of PID. Only now we are sure that the old PID
1134 * has been released. FIXME : should know when release_task happens instead.
1135 */
1136 exit_process(s, zombie_process);
1137 }
1138 g_assert(s->process->pid != child_pid);
1139 // FIXME : Add this test in the "known state" section
1140 // g_assert(s->process->pid == parent_pid);
1141 lttv_state_create_process(s, s->process, child_pid);
1142
1143 return FALSE;
1144 }
1145
1146
1147 static gboolean process_exit(void *hook_data, void *call_data)
1148 {
1149 LttvTracefileState *s = (LttvTracefileState *)call_data;
1150 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1151 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1152 LttField *f;
1153 guint pid;
1154
1155 pid = ltt_event_get_unsigned(e, thf->f1);
1156
1157 // FIXME : Add this test in the "known state" section
1158 // g_assert(s->process->pid == pid);
1159
1160 if(likely(s->process != NULL)) {
1161 s->process->state->s = LTTV_STATE_EXIT;
1162 }
1163 return FALSE;
1164 }
1165
1166 static gboolean process_free(void *hook_data, void *call_data)
1167 {
1168 LttvTracefileState *s = (LttvTracefileState *)call_data;
1169 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1170 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1171 guint release_pid;
1172 LttvProcessState *process;
1173
1174 /* PID of the process to release */
1175 release_pid = ltt_event_get_unsigned(e, thf->f1);
1176
1177 process = lttv_state_find_process(s, release_pid);
1178
1179 if(likely(process != NULL)) {
1180 /* release_task is happening at kernel level : we can now safely release
1181 * the data structure of the process */
1182 exit_process(s, process);
1183 }
1184
1185 return FALSE;
1186 }
1187
1188 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1189 {
1190 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1191
1192 lttv_state_add_event_hooks(tss);
1193
1194 return 0;
1195 }
1196
1197 void lttv_state_add_event_hooks(LttvTracesetState *self)
1198 {
1199 LttvTraceset *traceset = self->parent.ts;
1200
1201 guint i, j, k, l, nb_trace, nb_tracefile;
1202
1203 LttvTraceState *ts;
1204
1205 LttvTracefileState *tfs;
1206
1207 GArray *hooks;
1208
1209 LttvTraceHookByFacility *thf;
1210
1211 LttvTraceHook *hook;
1212
1213 LttvAttributeValue val;
1214
1215 gint ret;
1216
1217 nb_trace = lttv_traceset_number(traceset);
1218 for(i = 0 ; i < nb_trace ; i++) {
1219 ts = (LttvTraceState *)self->parent.traces[i];
1220
1221 /* Find the eventtype id for the following events and register the
1222 associated by id hooks. */
1223
1224 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 10);
1225 hooks = g_array_set_size(hooks, 10);
1226
1227 ret = lttv_trace_find_hook(ts->parent.t,
1228 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1229 LTT_FIELD_SYSCALL_ID, 0, 0,
1230 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1231 g_assert(!ret);
1232
1233 ret = lttv_trace_find_hook(ts->parent.t,
1234 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1235 0, 0, 0,
1236 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1237 g_assert(!ret);
1238
1239 ret = lttv_trace_find_hook(ts->parent.t,
1240 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1241 LTT_FIELD_TRAP_ID, 0, 0,
1242 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1243 g_assert(!ret);
1244
1245 ret = lttv_trace_find_hook(ts->parent.t,
1246 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1247 0, 0, 0,
1248 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1249 g_assert(!ret);
1250
1251 ret = lttv_trace_find_hook(ts->parent.t,
1252 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1253 LTT_FIELD_IRQ_ID, 0, 0,
1254 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1255 g_assert(!ret);
1256
1257 ret = lttv_trace_find_hook(ts->parent.t,
1258 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1259 0, 0, 0,
1260 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1261 g_assert(!ret);
1262
1263 ret = lttv_trace_find_hook(ts->parent.t,
1264 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1265 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1266 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1267 g_assert(!ret);
1268
1269 ret = lttv_trace_find_hook(ts->parent.t,
1270 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1271 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1272 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1273 g_assert(!ret);
1274
1275 ret = lttv_trace_find_hook(ts->parent.t,
1276 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1277 LTT_FIELD_PID, 0, 0,
1278 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1279 g_assert(!ret);
1280
1281 ret = lttv_trace_find_hook(ts->parent.t,
1282 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1283 LTT_FIELD_PID, 0, 0,
1284 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1285 g_assert(!ret);
1286
1287
1288 /* Add these hooks to each event_by_id hooks list */
1289
1290 nb_tracefile = ts->parent.tracefiles->len;
1291
1292 for(j = 0 ; j < nb_tracefile ; j++) {
1293 tfs =
1294 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1295 LttvTracefileContext*, j));
1296
1297 for(k = 0 ; k < hooks->len ; k++) {
1298 hook = &g_array_index(hooks, LttvTraceHook, k);
1299 for(l=0;l<hook->fac_list->len;l++) {
1300 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1301 lttv_hooks_add(
1302 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1303 thf->h,
1304 thf,
1305 LTTV_PRIO_STATE);
1306 }
1307 }
1308 }
1309 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1310 *(val.v_pointer) = hooks;
1311 }
1312 }
1313
1314 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1315 {
1316 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1317
1318 lttv_state_remove_event_hooks(tss);
1319
1320 return 0;
1321 }
1322
1323 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1324 {
1325 LttvTraceset *traceset = self->parent.ts;
1326
1327 guint i, j, k, l, nb_trace, nb_tracefile;
1328
1329 LttvTraceState *ts;
1330
1331 LttvTracefileState *tfs;
1332
1333 GArray *hooks;
1334
1335 LttvTraceHook *hook;
1336
1337 LttvTraceHookByFacility *thf;
1338
1339 LttvAttributeValue val;
1340
1341 nb_trace = lttv_traceset_number(traceset);
1342 for(i = 0 ; i < nb_trace ; i++) {
1343 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1344 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1345 hooks = *(val.v_pointer);
1346
1347 /* Remove these hooks from each event_by_id hooks list */
1348
1349 nb_tracefile = ts->parent.tracefiles->len;
1350
1351 for(j = 0 ; j < nb_tracefile ; j++) {
1352 tfs =
1353 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1354 LttvTracefileContext*, j));
1355
1356 for(k = 0 ; k < hooks->len ; k++) {
1357 hook = &g_array_index(hooks, LttvTraceHook, k);
1358 for(l=0;l<hook->fac_list->len;l++) {
1359 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1360
1361 lttv_hooks_remove_data(
1362 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1363 thf->h,
1364 thf);
1365 }
1366 }
1367 }
1368 for(k = 0 ; k < hooks->len ; k++)
1369 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1370 g_array_free(hooks, TRUE);
1371 }
1372 }
1373
1374
1375 static gboolean state_save_event_hook(void *hook_data, void *call_data)
1376 {
1377 guint *event_count = (guint*)hook_data;
1378
1379 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1380 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1381 return FALSE;
1382 else
1383 *event_count = 0;
1384
1385 LttvTracefileState *self = (LttvTracefileState *)call_data;
1386
1387 LttvTracefileState *tfcs;
1388
1389 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1390
1391 LttEventPosition *ep;
1392
1393 guint i;
1394
1395 LttTracefile *tf;
1396
1397 LttvAttribute *saved_states_tree, *saved_state_tree;
1398
1399 LttvAttributeValue value;
1400
1401 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1402 LTTV_STATE_SAVED_STATES);
1403 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1404 value = lttv_attribute_add(saved_states_tree,
1405 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1406 *(value.v_gobject) = (GObject *)saved_state_tree;
1407 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1408 *(value.v_time) = self->parent.timestamp;
1409 lttv_state_save(tcs, saved_state_tree);
1410 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1411 self->parent.timestamp.tv_nsec);
1412
1413 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1414
1415 return FALSE;
1416 }
1417
1418 #if 0
1419 static gboolean block_start(void *hook_data, void *call_data)
1420 {
1421 LttvTracefileState *self = (LttvTracefileState *)call_data;
1422
1423 LttvTracefileState *tfcs;
1424
1425 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1426
1427 LttEventPosition *ep;
1428
1429 guint i, nb_block, nb_event, nb_tracefile;
1430
1431 LttTracefile *tf;
1432
1433 LttvAttribute *saved_states_tree, *saved_state_tree;
1434
1435 LttvAttributeValue value;
1436
1437 ep = ltt_event_position_new();
1438
1439 nb_tracefile = tcs->parent.tracefiles->len;
1440
1441 /* Count the number of events added since the last block end in any
1442 tracefile. */
1443
1444 for(i = 0 ; i < nb_tracefile ; i++) {
1445 tfcs =
1446 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1447 LttvTracefileContext, i));
1448 ltt_event_position(tfcs->parent.e, ep);
1449 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1450 tcs->nb_event += nb_event - tfcs->saved_position;
1451 tfcs->saved_position = nb_event;
1452 }
1453 g_free(ep);
1454
1455 if(tcs->nb_event >= tcs->save_interval) {
1456 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1457 LTTV_STATE_SAVED_STATES);
1458 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1459 value = lttv_attribute_add(saved_states_tree,
1460 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1461 *(value.v_gobject) = (GObject *)saved_state_tree;
1462 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1463 *(value.v_time) = self->parent.timestamp;
1464 lttv_state_save(tcs, saved_state_tree);
1465 tcs->nb_event = 0;
1466 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1467 self->parent.timestamp.tv_nsec);
1468 }
1469 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1470 return FALSE;
1471 }
1472 #endif //0
1473
1474 #if 0
1475 static gboolean block_end(void *hook_data, void *call_data)
1476 {
1477 LttvTracefileState *self = (LttvTracefileState *)call_data;
1478
1479 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1480
1481 LttTracefile *tf;
1482
1483 LttEventPosition *ep;
1484
1485 guint nb_block, nb_event;
1486
1487 ep = ltt_event_position_new();
1488 ltt_event_position(self->parent.e, ep);
1489 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1490 tcs->nb_event += nb_event - self->saved_position + 1;
1491 self->saved_position = 0;
1492 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1493 g_free(ep);
1494
1495 return FALSE;
1496 }
1497 #endif //0
1498 #if 0
1499 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1500 {
1501 LttvTraceset *traceset = self->parent.ts;
1502
1503 guint i, j, nb_trace, nb_tracefile;
1504
1505 LttvTraceState *ts;
1506
1507 LttvTracefileState *tfs;
1508
1509 LttvTraceHook hook_start, hook_end;
1510
1511 nb_trace = lttv_traceset_number(traceset);
1512 for(i = 0 ; i < nb_trace ; i++) {
1513 ts = (LttvTraceState *)self->parent.traces[i];
1514
1515 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1516 NULL, NULL, block_start, &hook_start);
1517 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1518 NULL, NULL, block_end, &hook_end);
1519
1520 nb_tracefile = ts->parent.tracefiles->len;
1521
1522 for(j = 0 ; j < nb_tracefile ; j++) {
1523 tfs =
1524 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1525 LttvTracefileContext, j));
1526 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1527 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1528 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1529 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1530 }
1531 }
1532 }
1533 #endif //0
1534
1535 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1536 {
1537 LttvTraceset *traceset = self->parent.ts;
1538
1539 guint i, j, nb_trace, nb_tracefile;
1540
1541 LttvTraceState *ts;
1542
1543 LttvTracefileState *tfs;
1544
1545
1546 nb_trace = lttv_traceset_number(traceset);
1547 for(i = 0 ; i < nb_trace ; i++) {
1548
1549 ts = (LttvTraceState *)self->parent.traces[i];
1550 nb_tracefile = ts->parent.tracefiles->len;
1551
1552 for(j = 0 ; j < nb_tracefile ; j++) {
1553 guint *event_count = g_new(guint, 1);
1554 *event_count = 0;
1555 tfs =
1556 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1557 LttvTracefileContext*, j));
1558 lttv_hooks_add(tfs->parent.event,
1559 state_save_event_hook,
1560 event_count,
1561 LTTV_PRIO_STATE);
1562
1563 }
1564 }
1565 }
1566
1567 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1568 {
1569 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1570
1571 lttv_state_save_add_event_hooks(tss);
1572
1573 return 0;
1574 }
1575
1576
1577 #if 0
1578 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1579 {
1580 LttvTraceset *traceset = self->parent.ts;
1581
1582 guint i, j, nb_trace, nb_tracefile;
1583
1584 LttvTraceState *ts;
1585
1586 LttvTracefileState *tfs;
1587
1588 LttvTraceHook hook_start, hook_end;
1589
1590 nb_trace = lttv_traceset_number(traceset);
1591 for(i = 0 ; i < nb_trace ; i++) {
1592 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1593
1594 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1595 NULL, NULL, block_start, &hook_start);
1596
1597 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1598 NULL, NULL, block_end, &hook_end);
1599
1600 nb_tracefile = ts->parent.tracefiles->len;
1601
1602 for(j = 0 ; j < nb_tracefile ; j++) {
1603 tfs =
1604 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1605 LttvTracefileContext, j));
1606 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1607 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1608 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1609 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1610 }
1611 }
1612 }
1613 #endif //0
1614
1615 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1616 {
1617 LttvTraceset *traceset = self->parent.ts;
1618
1619 guint i, j, nb_trace, nb_tracefile;
1620
1621 LttvTraceState *ts;
1622
1623 LttvTracefileState *tfs;
1624
1625
1626 nb_trace = lttv_traceset_number(traceset);
1627 for(i = 0 ; i < nb_trace ; i++) {
1628
1629 ts = (LttvTraceState *)self->parent.traces[i];
1630 nb_tracefile = ts->parent.tracefiles->len;
1631
1632 guint *event_count;
1633
1634 for(j = 0 ; j < nb_tracefile ; j++) {
1635 tfs =
1636 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1637 LttvTracefileContext*, j));
1638 event_count = lttv_hooks_remove(tfs->parent.event,
1639 state_save_event_hook);
1640 g_free(event_count);
1641
1642 }
1643 }
1644 }
1645
1646 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1647 {
1648 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1649
1650 lttv_state_save_remove_event_hooks(tss);
1651
1652 return 0;
1653 }
1654
1655 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1656 {
1657 LttvTraceset *traceset = self->parent.ts;
1658
1659 guint i, nb_trace;
1660
1661 int min_pos, mid_pos, max_pos;
1662
1663 LttvTraceState *tcs;
1664
1665 LttvAttributeValue value;
1666
1667 LttvAttributeType type;
1668
1669 LttvAttributeName name;
1670
1671 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1672
1673 nb_trace = lttv_traceset_number(traceset);
1674 for(i = 0 ; i < nb_trace ; i++) {
1675 tcs = (LttvTraceState *)self->parent.traces[i];
1676
1677 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1678 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1679 LTTV_STATE_SAVED_STATES);
1680 min_pos = -1;
1681
1682 if(saved_states_tree) {
1683 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1684 mid_pos = max_pos / 2;
1685 while(min_pos < max_pos) {
1686 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1687 g_assert(type == LTTV_GOBJECT);
1688 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1689 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1690 &value);
1691 g_assert(type == LTTV_TIME);
1692 if(ltt_time_compare(*(value.v_time), t) < 0) {
1693 min_pos = mid_pos;
1694 closest_tree = saved_state_tree;
1695 }
1696 else max_pos = mid_pos - 1;
1697
1698 mid_pos = (min_pos + max_pos + 1) / 2;
1699 }
1700 }
1701
1702 /* restore the closest earlier saved state */
1703 if(min_pos != -1) {
1704 lttv_state_restore(tcs, closest_tree);
1705 }
1706
1707 /* There is no saved state, yet we want to have it. Restart at T0 */
1708 else {
1709 restore_init_state(tcs);
1710 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1711 }
1712 }
1713 /* We want to seek quickly without restoring/updating the state */
1714 else {
1715 restore_init_state(tcs);
1716 lttv_process_trace_seek_time(&(tcs->parent), t);
1717 }
1718 }
1719 }
1720
1721
1722 static void
1723 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1724 {
1725 }
1726
1727
1728 static void
1729 traceset_state_finalize (LttvTracesetState *self)
1730 {
1731 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1732 finalize(G_OBJECT(self));
1733 }
1734
1735
1736 static void
1737 traceset_state_class_init (LttvTracesetContextClass *klass)
1738 {
1739 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1740
1741 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1742 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1743 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1744 klass->new_traceset_context = new_traceset_context;
1745 klass->new_trace_context = new_trace_context;
1746 klass->new_tracefile_context = new_tracefile_context;
1747 }
1748
1749
1750 GType
1751 lttv_traceset_state_get_type(void)
1752 {
1753 static GType type = 0;
1754 if (type == 0) {
1755 static const GTypeInfo info = {
1756 sizeof (LttvTracesetStateClass),
1757 NULL, /* base_init */
1758 NULL, /* base_finalize */
1759 (GClassInitFunc) traceset_state_class_init, /* class_init */
1760 NULL, /* class_finalize */
1761 NULL, /* class_data */
1762 sizeof (LttvTracesetState),
1763 0, /* n_preallocs */
1764 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1765 NULL /* value handling */
1766 };
1767
1768 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1769 &info, 0);
1770 }
1771 return type;
1772 }
1773
1774
1775 static void
1776 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1777 {
1778 }
1779
1780
1781 static void
1782 trace_state_finalize (LttvTraceState *self)
1783 {
1784 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1785 finalize(G_OBJECT(self));
1786 }
1787
1788
1789 static void
1790 trace_state_class_init (LttvTraceStateClass *klass)
1791 {
1792 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1793
1794 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1795 klass->state_save = state_save;
1796 klass->state_restore = state_restore;
1797 klass->state_saved_free = state_saved_free;
1798 }
1799
1800
1801 GType
1802 lttv_trace_state_get_type(void)
1803 {
1804 static GType type = 0;
1805 if (type == 0) {
1806 static const GTypeInfo info = {
1807 sizeof (LttvTraceStateClass),
1808 NULL, /* base_init */
1809 NULL, /* base_finalize */
1810 (GClassInitFunc) trace_state_class_init, /* class_init */
1811 NULL, /* class_finalize */
1812 NULL, /* class_data */
1813 sizeof (LttvTraceState),
1814 0, /* n_preallocs */
1815 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1816 NULL /* value handling */
1817 };
1818
1819 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1820 "LttvTraceStateType", &info, 0);
1821 }
1822 return type;
1823 }
1824
1825
1826 static void
1827 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1828 {
1829 }
1830
1831
1832 static void
1833 tracefile_state_finalize (LttvTracefileState *self)
1834 {
1835 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1836 finalize(G_OBJECT(self));
1837 }
1838
1839
1840 static void
1841 tracefile_state_class_init (LttvTracefileStateClass *klass)
1842 {
1843 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1844
1845 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1846 }
1847
1848
1849 GType
1850 lttv_tracefile_state_get_type(void)
1851 {
1852 static GType type = 0;
1853 if (type == 0) {
1854 static const GTypeInfo info = {
1855 sizeof (LttvTracefileStateClass),
1856 NULL, /* base_init */
1857 NULL, /* base_finalize */
1858 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1859 NULL, /* class_finalize */
1860 NULL, /* class_data */
1861 sizeof (LttvTracefileState),
1862 0, /* n_preallocs */
1863 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1864 NULL /* value handling */
1865 };
1866
1867 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1868 "LttvTracefileStateType", &info, 0);
1869 }
1870 return type;
1871 }
1872
1873
1874 static void module_init()
1875 {
1876 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1877 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1878 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1879 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1880 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1881 LTTV_STATE_TRAP = g_quark_from_string("trap");
1882 LTTV_STATE_IRQ = g_quark_from_string("irq");
1883 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1884 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1885 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1886 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1887 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
1888 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1889 LTTV_STATE_RUN = g_quark_from_string("running");
1890 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1891 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1892 LTTV_STATE_PROCESS = g_quark_from_string("process");
1893 LTTV_STATE_EVENT = g_quark_from_string("event");
1894 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1895 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1896 LTTV_STATE_TIME = g_quark_from_string("time");
1897 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1898 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1899 LTTV_STATE_TRACE_STATE_USE_COUNT =
1900 g_quark_from_string("trace_state_use_count");
1901
1902
1903 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
1904 LTT_FACILITY_PROCESS = g_quark_from_string("process");
1905
1906
1907 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
1908 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
1909 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
1910 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
1911 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
1912 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
1913 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
1914 LTT_EVENT_FORK = g_quark_from_string("fork");
1915 LTT_EVENT_EXIT = g_quark_from_string("exit");
1916 LTT_EVENT_FREE = g_quark_from_string("free");
1917
1918
1919 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
1920 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
1921 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
1922 LTT_FIELD_OUT = g_quark_from_string("out");
1923 LTT_FIELD_IN = g_quark_from_string("in");
1924 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
1925 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
1926 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
1927 LTT_FIELD_PID = g_quark_from_string("pid");
1928
1929 }
1930
1931 static void module_destroy()
1932 {
1933 }
1934
1935
1936 LTTV_MODULE("state", "State computation", \
1937 "Update the system state, possibly saving it at intervals", \
1938 module_init, module_destroy)
1939
1940
1941
This page took 0.0692 seconds and 4 git commands to generate.