1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
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>
32 #define PREALLOCATED_EXECUTION_STACK 10
34 /* Facilities Quarks */
44 LTT_EVENT_SYSCALL_ENTRY
,
45 LTT_EVENT_SYSCALL_EXIT
,
50 LTT_EVENT_SCHEDCHANGE
,
71 LTTV_STATE_MODE_UNKNOWN
,
78 LTTV_STATE_SUBMODE_UNKNOWN
,
79 LTTV_STATE_SUBMODE_NONE
;
91 LTTV_STATE_TRACEFILES
,
94 LTTV_STATE_RUNNING_PROCESS
,
96 LTTV_STATE_SAVED_STATES
,
97 LTTV_STATE_SAVED_STATES_TIME
,
100 LTTV_STATE_NAME_TABLES
,
101 LTTV_STATE_TRACE_STATE_USE_COUNT
;
103 static void create_max_time(LttvTraceState
*tcs
);
105 static void get_max_time(LttvTraceState
*tcs
);
107 static void free_max_time(LttvTraceState
*tcs
);
109 static void create_name_tables(LttvTraceState
*tcs
);
111 static void get_name_tables(LttvTraceState
*tcs
);
113 static void free_name_tables(LttvTraceState
*tcs
);
115 static void free_saved_state(LttvTraceState
*tcs
);
117 static void lttv_state_free_process_table(GHashTable
*processes
);
120 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
122 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
126 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
128 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
132 void lttv_state_state_saved_free(LttvTraceState
*self
,
133 LttvAttribute
*container
)
135 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
139 guint
process_hash(gconstpointer key
)
141 guint pid
= ((const LttvProcessState
*)key
)->pid
;
142 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
146 /* If the hash table hash function is well distributed,
147 * the process_equal should compare different pid */
148 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
150 const LttvProcessState
*process_a
, *process_b
;
153 process_a
= (const LttvProcessState
*)a
;
154 process_b
= (const LttvProcessState
*)b
;
156 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
157 else if(likely(process_a
->pid
== 0 &&
158 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
165 restore_init_state(LttvTraceState
*self
)
169 LttvTracefileState
*tfcs
;
171 /* Free the process tables */
172 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
173 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
176 /* Seek time to beginning */
177 g_tree_destroy(self
->parent
.ts_context
->pqueue
);
178 self
->parent
.ts_context
->pqueue
= g_tree_new(compare_tracefile
);
180 lttv_process_trace_seek_time(&self
->parent
, ltt_time_zero
);
182 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
184 /* Put the per cpu running_process to beginning state : process 0. */
185 for(i
=0; i
< nb_cpus
; i
++) {
186 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
188 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
189 self
->running_process
[i
]->cpu
= i
;
193 nb_tracefile
= self
->parent
.tracefiles
->len
;
195 for(i
= 0 ; i
< nb_tracefile
; i
++) {
197 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
198 LttvTracefileContext
*, i
));
199 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
200 // tfcs->saved_position = 0;
201 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
202 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
203 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
204 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
209 //static LttTime time_zero = {0,0};
212 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
214 guint i
, j
, nb_trace
, nb_tracefile
;
216 LttvTraceContext
*tc
;
220 LttvTracefileState
*tfcs
;
222 LttvAttributeValue v
;
224 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
225 init((LttvTracesetContext
*)self
, ts
);
227 nb_trace
= lttv_traceset_number(ts
);
228 for(i
= 0 ; i
< nb_trace
; i
++) {
229 tc
= self
->parent
.traces
[i
];
230 tcs
= LTTV_TRACE_STATE(tc
);
231 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
232 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
236 if(*(v
.v_uint
) == 1) {
237 create_name_tables(tcs
);
238 create_max_time(tcs
);
240 get_name_tables(tcs
);
243 nb_tracefile
= tc
->tracefiles
->len
;
245 for(j
= 0 ; j
< nb_tracefile
; j
++) {
247 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
248 LttvTracefileContext
*, j
));
249 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
252 tcs
->processes
= NULL
;
253 tcs
->running_process
= g_new(LttvProcessState
*,
254 ltt_trace_get_num_cpu(tc
->t
));
255 restore_init_state(tcs
);
261 fini(LttvTracesetState
*self
)
267 LttvTracefileState
*tfcs
;
269 LttvAttributeValue v
;
271 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
272 for(i
= 0 ; i
< nb_trace
; i
++) {
273 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
274 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
277 g_assert(*(v
.v_uint
) != 0);
280 if(*(v
.v_uint
) == 0) {
281 free_name_tables(tcs
);
283 free_saved_state(tcs
);
285 g_free(tcs
->running_process
);
286 tcs
->running_process
= NULL
;
287 lttv_state_free_process_table(tcs
->processes
);
288 tcs
->processes
= NULL
;
290 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
291 fini((LttvTracesetContext
*)self
);
295 static LttvTracesetContext
*
296 new_traceset_context(LttvTracesetContext
*self
)
298 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
302 static LttvTraceContext
*
303 new_trace_context(LttvTracesetContext
*self
)
305 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
309 static LttvTracefileContext
*
310 new_tracefile_context(LttvTracesetContext
*self
)
312 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
316 /* Write the process state of the trace */
318 static void write_process_state(gpointer key
, gpointer value
,
321 LttvProcessState
*process
;
323 LttvExecutionState
*es
;
325 FILE *fp
= (FILE *)user_data
;
329 process
= (LttvProcessState
*)value
;
331 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
332 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
333 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
336 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
337 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
338 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
339 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
340 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
341 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
342 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
344 fprintf(fp
, " </PROCESS>\n");
348 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
350 guint i
, nb_tracefile
, nb_block
, offset
;
353 LttvTracefileState
*tfcs
;
357 LttEventPosition
*ep
;
361 ep
= ltt_event_position_new();
363 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
365 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
367 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
368 for(i
=0;i
<nb_cpus
;i
++) {
369 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
370 i
, self
->running_process
[i
]->pid
);
373 nb_tracefile
= self
->parent
.tracefiles
->len
;
375 for(i
= 0 ; i
< nb_tracefile
; i
++) {
377 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
378 LttvTracefileContext
*, i
));
379 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
380 tfcs
->parent
.timestamp
.tv_sec
,
381 tfcs
->parent
.timestamp
.tv_nsec
);
382 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
383 if(e
== NULL
) fprintf(fp
,"/>\n");
385 ltt_event_position(e
, ep
);
386 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
387 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
392 fprintf(fp
,"</PROCESS_STATE>");
396 /* Copy each process from an existing hash table to a new one */
398 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
400 LttvProcessState
*process
, *new_process
;
402 GHashTable
*new_processes
= (GHashTable
*)user_data
;
406 process
= (LttvProcessState
*)value
;
407 new_process
= g_new(LttvProcessState
, 1);
408 *new_process
= *process
;
409 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
410 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
411 new_process
->execution_stack
=
412 g_array_set_size(new_process
->execution_stack
,
413 process
->execution_stack
->len
);
414 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
415 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
416 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
418 new_process
->state
= &g_array_index(new_process
->execution_stack
,
419 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
420 g_hash_table_insert(new_processes
, new_process
, new_process
);
424 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
426 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
428 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
429 return new_processes
;
433 /* The saved state for each trace contains a member "processes", which
434 stores a copy of the process table, and a member "tracefiles" with
435 one entry per tracefile. Each tracefile has a "process" member pointing
436 to the current process and a "position" member storing the tracefile
437 position (needed to seek to the current "next" event. */
439 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
441 guint i
, nb_tracefile
, nb_cpus
;
443 LttvTracefileState
*tfcs
;
445 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
447 guint
*running_process
;
449 LttvAttributeType type
;
451 LttvAttributeValue value
;
453 LttvAttributeName name
;
455 LttEventPosition
*ep
;
457 tracefiles_tree
= lttv_attribute_find_subdir(container
,
458 LTTV_STATE_TRACEFILES
);
460 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
462 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
464 /* Add the currently running processes array */
465 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
466 running_process
= g_new(guint
, nb_cpus
);
467 for(i
=0;i
<nb_cpus
;i
++) {
468 running_process
[i
] = self
->running_process
[i
]->pid
;
470 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
472 *(value
.v_pointer
) = running_process
;
474 g_info("State save");
476 nb_tracefile
= self
->parent
.tracefiles
->len
;
478 for(i
= 0 ; i
< nb_tracefile
; i
++) {
480 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
481 LttvTracefileContext
*, i
));
482 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
483 value
= lttv_attribute_add(tracefiles_tree
, i
,
485 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
487 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
489 *(value
.v_uint
) = tfcs
->process
->pid
;
491 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
493 /* Only save the position if the tfs has not infinite time. */
494 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
495 // && current_tfcs != tfcs) {
496 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
497 *(value
.v_pointer
) = NULL
;
499 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
500 ep
= ltt_event_position_new();
501 ltt_event_position(e
, ep
);
502 *(value
.v_pointer
) = ep
;
504 guint nb_block
, offset
;
507 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
508 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
510 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
516 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
518 guint i
, nb_tracefile
, pid
, nb_cpus
;
520 LttvTracefileState
*tfcs
;
522 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
524 guint
*running_process
;
526 LttvAttributeType type
;
528 LttvAttributeValue value
;
530 LttvAttributeName name
;
532 LttEventPosition
*ep
;
534 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
536 tracefiles_tree
= lttv_attribute_find_subdir(container
,
537 LTTV_STATE_TRACEFILES
);
539 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
541 g_assert(type
== LTTV_POINTER
);
542 lttv_state_free_process_table(self
->processes
);
543 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
545 /* Add the currently running processes array */
546 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
547 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
549 g_assert(type
== LTTV_POINTER
);
550 running_process
= *(value
.v_pointer
);
551 for(i
=0;i
<nb_cpus
;i
++) {
552 pid
= running_process
[i
];
553 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
554 g_assert(self
->running_process
[i
] != NULL
);
558 nb_tracefile
= self
->parent
.tracefiles
->len
;
560 g_tree_destroy(tsc
->pqueue
);
561 tsc
->pqueue
= g_tree_new(compare_tracefile
);
563 for(i
= 0 ; i
< nb_tracefile
; i
++) {
565 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
566 LttvTracefileContext
*, i
));
567 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
568 g_assert(type
== LTTV_GOBJECT
);
569 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
571 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
573 g_assert(type
== LTTV_UINT
);
574 pid
= *(value
.v_uint
);
575 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
577 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
579 g_assert(type
== LTTV_POINTER
);
580 //g_assert(*(value.v_pointer) != NULL);
581 ep
= *(value
.v_pointer
);
582 g_assert(tfcs
->parent
.t_context
!= NULL
);
584 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
587 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
588 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
589 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
590 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
591 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
593 tfc
->timestamp
= ltt_time_infinite
;
599 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
601 guint i
, nb_tracefile
, nb_cpus
;
603 LttvTracefileState
*tfcs
;
605 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
607 guint
*running_process
;
609 LttvAttributeType type
;
611 LttvAttributeValue value
;
613 LttvAttributeName name
;
615 LttEventPosition
*ep
;
617 tracefiles_tree
= lttv_attribute_find_subdir(container
,
618 LTTV_STATE_TRACEFILES
);
619 g_object_ref(G_OBJECT(tracefiles_tree
));
620 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
622 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
624 g_assert(type
== LTTV_POINTER
);
625 lttv_state_free_process_table(*(value
.v_pointer
));
626 *(value
.v_pointer
) = NULL
;
627 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
629 /* Free running processes array */
630 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
631 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
633 g_assert(type
== LTTV_POINTER
);
634 running_process
= *(value
.v_pointer
);
635 g_free(running_process
);
637 nb_tracefile
= self
->parent
.tracefiles
->len
;
639 for(i
= 0 ; i
< nb_tracefile
; i
++) {
641 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
642 LttvTracefileContext
*, i
));
643 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
644 g_assert(type
== LTTV_GOBJECT
);
645 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
647 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
649 g_assert(type
== LTTV_POINTER
);
650 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
652 g_object_unref(G_OBJECT(tracefiles_tree
));
656 static void free_saved_state(LttvTraceState
*self
)
660 LttvAttributeType type
;
662 LttvAttributeValue value
;
664 LttvAttributeName name
;
666 LttvAttribute
*saved_states
;
668 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
669 LTTV_STATE_SAVED_STATES
);
671 nb
= lttv_attribute_get_number(saved_states
);
672 for(i
= 0 ; i
< nb
; i
++) {
673 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
674 g_assert(type
== LTTV_GOBJECT
);
675 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
678 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
683 create_max_time(LttvTraceState
*tcs
)
685 LttvAttributeValue v
;
687 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
689 g_assert(*(v
.v_pointer
) == NULL
);
690 *(v
.v_pointer
) = g_new(LttTime
,1);
691 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
696 get_max_time(LttvTraceState
*tcs
)
698 LttvAttributeValue v
;
700 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
702 g_assert(*(v
.v_pointer
) != NULL
);
703 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
708 free_max_time(LttvTraceState
*tcs
)
710 LttvAttributeValue v
;
712 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
714 g_free(*(v
.v_pointer
));
715 *(v
.v_pointer
) = NULL
;
719 typedef struct _LttvNameTables
{
720 // FIXME GQuark *eventtype_names;
721 GQuark
*syscall_names
;
728 create_name_tables(LttvTraceState
*tcs
)
732 GQuark f_name
, e_name
;
736 LttvTraceHookByFacility
*thf
;
742 GString
*fe_name
= g_string_new("");
744 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
746 LttvAttributeValue v
;
748 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
750 g_assert(*(v
.v_pointer
) == NULL
);
751 *(v
.v_pointer
) = name_tables
;
752 #if 0 // Use iteration over the facilities_by_name and then list all event
753 // types of each facility
754 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
755 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
756 for(i
= 0 ; i
< nb
; i
++) {
757 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
758 e_name
= ltt_eventtype_name(et
);
759 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
760 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
761 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
764 if(lttv_trace_find_hook(tcs
->parent
.t
,
765 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
766 LTT_FIELD_SYSCALL_ID
, 0, 0,
770 thf
= lttv_trace_hook_get_first(&h
);
772 t
= ltt_field_type(thf
->f1
);
773 nb
= ltt_type_element_number(t
);
775 lttv_trace_hook_destroy(&h
);
777 /* CHECK syscalls should be an enum but currently are not!
778 name_tables->syscall_names = g_new(GQuark, nb);
780 for(i = 0 ; i < nb ; i++) {
781 name_tables->syscall_names[i] = g_quark_from_string(
782 ltt_enum_string_get(t, i));
786 name_tables
->syscall_names
= g_new(GQuark
, 256);
787 for(i
= 0 ; i
< 256 ; i
++) {
788 g_string_printf(fe_name
, "syscall %d", i
);
789 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
792 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
793 LTT_EVENT_TRAP_ENTRY
,
794 LTT_FIELD_TRAP_ID
, 0, 0,
798 thf
= lttv_trace_hook_get_first(&h
);
800 t
= ltt_field_type(thf
->f1
);
801 nb
= ltt_type_element_number(t
);
803 lttv_trace_hook_destroy(&h
);
806 name_tables->trap_names = g_new(GQuark, nb);
807 for(i = 0 ; i < nb ; i++) {
808 name_tables->trap_names[i] = g_quark_from_string(
809 ltt_enum_string_get(t, i));
813 name_tables
->trap_names
= g_new(GQuark
, 256);
814 for(i
= 0 ; i
< 256 ; i
++) {
815 g_string_printf(fe_name
, "trap %d", i
);
816 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
819 if(lttv_trace_find_hook(tcs
->parent
.t
,
820 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
821 LTT_FIELD_IRQ_ID
, 0, 0,
825 thf
= lttv_trace_hook_get_first(&h
);
827 t
= ltt_field_type(thf
->f1
);
828 nb
= ltt_type_element_number(t
);
830 lttv_trace_hook_destroy(&h
);
833 name_tables->irq_names = g_new(GQuark, nb);
834 for(i = 0 ; i < nb ; i++) {
835 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
839 name_tables
->irq_names
= g_new(GQuark
, 256);
840 for(i
= 0 ; i
< 256 ; i
++) {
841 g_string_printf(fe_name
, "irq %d", i
);
842 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
845 g_string_free(fe_name
, TRUE
);
850 get_name_tables(LttvTraceState
*tcs
)
852 LttvNameTables
*name_tables
;
854 LttvAttributeValue v
;
856 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
858 g_assert(*(v
.v_pointer
) != NULL
);
859 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
860 //tcs->eventtype_names = name_tables->eventtype_names;
861 tcs
->syscall_names
= name_tables
->syscall_names
;
862 tcs
->trap_names
= name_tables
->trap_names
;
863 tcs
->irq_names
= name_tables
->irq_names
;
868 free_name_tables(LttvTraceState
*tcs
)
870 LttvNameTables
*name_tables
;
872 LttvAttributeValue v
;
874 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
876 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
877 *(v
.v_pointer
) = NULL
;
879 // g_free(name_tables->eventtype_names);
880 g_free(name_tables
->syscall_names
);
881 g_free(name_tables
->trap_names
);
882 g_free(name_tables
->irq_names
);
886 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
889 LttvExecutionState
*es
;
891 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
892 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
893 LttvProcessState
*process
= ts
->running_process
[cpu
];
895 guint depth
= process
->execution_stack
->len
;
897 process
->execution_stack
=
898 g_array_set_size(process
->execution_stack
, depth
+ 1);
901 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
903 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
906 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
907 es
->s
= process
->state
->s
;
912 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
914 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
915 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
916 LttvProcessState
*process
= ts
->running_process
[cpu
];
918 guint depth
= process
->execution_stack
->len
;
920 if(process
->state
->t
!= t
){
921 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
922 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
923 g_info("process state has %s when pop_int is %s\n",
924 g_quark_to_string(process
->state
->t
),
925 g_quark_to_string(t
));
926 g_info("{ %u, %u, %s, %s }\n",
929 g_quark_to_string(process
->name
),
930 g_quark_to_string(process
->state
->s
));
935 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
936 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
940 process
->execution_stack
=
941 g_array_set_size(process
->execution_stack
, depth
- 1);
942 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
944 process
->state
->change
= tfs
->parent
.timestamp
;
949 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
950 guint cpu
, guint pid
, const LttTime
*timestamp
)
952 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
954 LttvExecutionState
*es
;
956 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
962 //process->last_cpu = tfs->cpu_name;
963 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
964 g_info("Process %u, core %p", process
->pid
, process
);
965 g_hash_table_insert(tcs
->processes
, process
, process
);
968 process
->ppid
= parent
->pid
;
969 process
->name
= parent
->name
;
970 process
->creation_time
= *timestamp
;
973 /* No parent. This process exists but we are missing all information about
974 its creation. The birth time is set to zero but we remember the time of
979 process
->name
= LTTV_STATE_UNNAMED
;
980 process
->creation_time
= ltt_time_zero
;
983 process
->insertion_time
= *timestamp
;
984 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
985 process
->creation_time
.tv_nsec
);
986 process
->pid_time
= g_quark_from_string(buffer
);
988 //process->last_cpu = tfs->cpu_name;
989 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
990 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
991 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
992 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
993 es
= process
->state
= &g_array_index(process
->execution_stack
,
994 LttvExecutionState
, 0);
995 es
->t
= LTTV_STATE_USER_MODE
;
996 es
->n
= LTTV_STATE_SUBMODE_NONE
;
997 es
->entry
= *timestamp
;
998 //g_assert(timestamp->tv_sec != 0);
999 es
->change
= *timestamp
;
1000 es
->s
= LTTV_STATE_WAIT_FORK
;
1005 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1008 LttvProcessState key
;
1009 LttvProcessState
*process
;
1013 process
= g_hash_table_lookup(ts
->processes
, &key
);
1018 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1021 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1023 /* Put ltt_time_zero creation time for unexisting processes */
1024 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1025 NULL
, cpu
, pid
, timestamp
);
1029 /* FIXME : this function should be called when we receive an event telling that
1030 * release_task has been called in the kernel. In happens generally when
1031 * the parent waits for its child terminaison, but may also happen in special
1032 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1033 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1034 * of a killed thread ground, but isn't the leader.
1036 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1038 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1039 LttvProcessState key
;
1041 key
.pid
= process
->pid
;
1042 key
.cpu
= process
->cpu
;
1043 g_hash_table_remove(ts
->processes
, &key
);
1044 g_array_free(process
->execution_stack
, TRUE
);
1049 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1051 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1056 static void lttv_state_free_process_table(GHashTable
*processes
)
1058 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1059 g_hash_table_destroy(processes
);
1063 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1065 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1066 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1067 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1068 LttField
*f
= thf
->f1
;
1070 LttvExecutionSubmode submode
;
1072 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1073 ltt_event_get_unsigned(e
, f
)];
1074 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1079 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1081 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1083 pop_state(s
, LTTV_STATE_SYSCALL
);
1088 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1090 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1091 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1092 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1093 LttField
*f
= thf
->f1
;
1095 LttvExecutionSubmode submode
;
1097 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1098 ltt_event_get_unsigned(e
, f
)];
1099 push_state(s
, LTTV_STATE_TRAP
, submode
);
1104 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1106 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1108 pop_state(s
, LTTV_STATE_TRAP
);
1113 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1115 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1116 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1117 guint8 fac_id
= ltt_event_facility_id(e
);
1118 guint8 ev_id
= ltt_event_eventtype_id(e
);
1119 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1120 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1121 g_assert(thf
->f1
!= NULL
);
1122 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1123 LttField
*f
= thf
->f1
;
1125 LttvExecutionSubmode submode
;
1127 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1128 ltt_event_get_unsigned(e
, f
)];
1130 /* Do something with the info about being in user or system mode when int? */
1131 push_state(s
, LTTV_STATE_IRQ
, submode
);
1136 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1138 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1140 pop_state(s
, LTTV_STATE_IRQ
);
1145 static gboolean
schedchange(void *hook_data
, void *call_data
)
1147 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1148 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1149 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1150 LttvProcessState
*process
= ts
->running_process
[cpu
];
1152 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1153 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1154 guint pid_in
, pid_out
;
1157 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1158 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1159 state_out
= ltt_event_get_int(e
, thf
->f3
);
1161 if(likely(process
!= NULL
)) {
1163 /* We could not know but it was not the idle process executing.
1164 This should only happen at the beginning, before the first schedule
1165 event, and when the initial information (current process for each CPU)
1166 is missing. It is not obvious how we could, after the fact, compensate
1167 the wrongly attributed statistics. */
1169 //This test only makes sense once the state is known and if there is no
1171 //if(unlikely(process->pid != pid_out)) {
1172 // g_assert(process->pid == 0);
1175 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1176 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1178 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1179 else process
->state
->s
= LTTV_STATE_WAIT
;
1180 } /* FIXME : we do not remove process here, because the kernel
1181 * still has them : they may be zombies. We need to know
1182 * exactly when release_task is executed on the PID to
1183 * know when the zombie is destroyed.
1186 // exit_process(s, process);
1188 process
->state
->change
= s
->parent
.timestamp
;
1190 process
= ts
->running_process
[cpu
] =
1191 lttv_state_find_process_or_create(
1192 (LttvTraceState
*)s
->parent
.t_context
,
1194 &s
->parent
.timestamp
);
1195 process
->state
->s
= LTTV_STATE_RUN
;
1197 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1198 process
->state
->change
= s
->parent
.timestamp
;
1202 static gboolean
process_fork(void *hook_data
, void *call_data
)
1204 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1205 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1206 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1210 LttvProcessState
*zombie_process
;
1211 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1212 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1213 LttvProcessState
*process
= ts
->running_process
[cpu
];
1217 parent_pid
= ltt_event_get_unsigned(e
, f
);
1221 child_pid
= ltt_event_get_unsigned(e
, f
);
1223 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1225 if(unlikely(zombie_process
!= NULL
)) {
1226 /* Reutilisation of PID. Only now we are sure that the old PID
1227 * has been released. FIXME : should know when release_task happens instead.
1229 exit_process(s
, zombie_process
);
1231 g_assert(process
->pid
!= child_pid
);
1232 // FIXME : Add this test in the "known state" section
1233 // g_assert(process->pid == parent_pid);
1234 lttv_state_create_process(ts
, process
, cpu
, child_pid
, &s
->parent
.timestamp
);
1240 static gboolean
process_exit(void *hook_data
, void *call_data
)
1242 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1243 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1244 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1247 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1248 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1249 LttvProcessState
*process
= ts
->running_process
[cpu
];
1251 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1253 // FIXME : Add this test in the "known state" section
1254 // g_assert(process->pid == pid);
1256 if(likely(process
!= NULL
)) {
1257 process
->state
->s
= LTTV_STATE_EXIT
;
1262 static gboolean
process_free(void *hook_data
, void *call_data
)
1264 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1265 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1266 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1267 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1269 LttvProcessState
*process
;
1271 /* PID of the process to release */
1272 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1274 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1276 if(likely(process
!= NULL
)) {
1277 /* release_task is happening at kernel level : we can now safely release
1278 * the data structure of the process */
1279 exit_process(s
, process
);
1286 static gboolean
process_exec(void *hook_data
, void *call_data
)
1288 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1289 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1290 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1291 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1293 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1294 LttvProcessState
*process
= ts
->running_process
[cpu
];
1296 /* PID of the process to release */
1297 name
= ltt_event_get_string(e
, thf
->f1
);
1299 process
->name
= g_quark_from_string(name
);
1307 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1309 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1311 lttv_state_add_event_hooks(tss
);
1316 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1318 LttvTraceset
*traceset
= self
->parent
.ts
;
1320 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1324 LttvTracefileState
*tfs
;
1328 LttvTraceHookByFacility
*thf
;
1330 LttvTraceHook
*hook
;
1332 LttvAttributeValue val
;
1336 nb_trace
= lttv_traceset_number(traceset
);
1337 for(i
= 0 ; i
< nb_trace
; i
++) {
1338 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1340 /* Find the eventtype id for the following events and register the
1341 associated by id hooks. */
1343 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 11);
1344 hooks
= g_array_set_size(hooks
, 11);
1346 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1347 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1348 LTT_FIELD_SYSCALL_ID
, 0, 0,
1349 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1352 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1353 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1355 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1358 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1359 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1360 LTT_FIELD_TRAP_ID
, 0, 0,
1361 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1364 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1365 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1367 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1370 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1371 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1372 LTT_FIELD_IRQ_ID
, 0, 0,
1373 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1376 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1377 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1379 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1382 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1383 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1384 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1385 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1388 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1389 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1390 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1391 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1394 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1395 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1396 LTT_FIELD_PID
, 0, 0,
1397 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1400 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1401 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1402 LTT_FIELD_PID
, 0, 0,
1403 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1406 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1407 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1408 LTT_FIELD_FILENAME
, 0, 0,
1409 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1414 /* Add these hooks to each event_by_id hooks list */
1416 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1418 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1420 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1421 LttvTracefileContext
*, j
));
1423 for(k
= 0 ; k
< hooks
->len
; k
++) {
1424 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1425 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1426 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1428 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1435 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1436 *(val
.v_pointer
) = hooks
;
1440 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1442 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1444 lttv_state_remove_event_hooks(tss
);
1449 static guint test_event_count
= 0;
1450 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1452 LttvTraceset
*traceset
= self
->parent
.ts
;
1454 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1458 LttvTracefileState
*tfs
;
1462 LttvTraceHook
*hook
;
1464 LttvTraceHookByFacility
*thf
;
1466 LttvAttributeValue val
;
1468 nb_trace
= lttv_traceset_number(traceset
);
1469 for(i
= 0 ; i
< nb_trace
; i
++) {
1470 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1471 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1472 hooks
= *(val
.v_pointer
);
1474 /* Remove these hooks from each event_by_id hooks list */
1476 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1478 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1480 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1481 LttvTracefileContext
*, j
));
1483 for(k
= 0 ; k
< hooks
->len
; k
++) {
1484 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1485 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1486 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1488 lttv_hooks_remove_data(
1489 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1495 for(k
= 0 ; k
< hooks
->len
; k
++)
1496 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1497 g_array_free(hooks
, TRUE
);
1499 g_info("EVENT COUNT TEST : %u", test_event_count
);
1502 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1504 guint
*event_count
= (guint
*)hook_data
;
1507 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1508 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1513 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1515 LttvTracefileState
*tfcs
;
1517 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1519 LttEventPosition
*ep
;
1525 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1527 LttvAttributeValue value
;
1529 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1530 LTTV_STATE_SAVED_STATES
);
1531 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1532 value
= lttv_attribute_add(saved_states_tree
,
1533 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1534 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1535 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1536 *(value
.v_time
) = self
->parent
.timestamp
;
1537 lttv_state_save(tcs
, saved_state_tree
);
1538 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1539 self
->parent
.timestamp
.tv_nsec
);
1541 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1547 static gboolean
block_start(void *hook_data
, void *call_data
)
1549 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1551 LttvTracefileState
*tfcs
;
1553 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1555 LttEventPosition
*ep
;
1557 guint i
, nb_block
, nb_event
, nb_tracefile
;
1561 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1563 LttvAttributeValue value
;
1565 ep
= ltt_event_position_new();
1567 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1569 /* Count the number of events added since the last block end in any
1572 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1574 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1575 LttvTracefileContext
, i
));
1576 ltt_event_position(tfcs
->parent
.e
, ep
);
1577 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1578 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1579 tfcs
->saved_position
= nb_event
;
1583 if(tcs
->nb_event
>= tcs
->save_interval
) {
1584 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1585 LTTV_STATE_SAVED_STATES
);
1586 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1587 value
= lttv_attribute_add(saved_states_tree
,
1588 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1589 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1590 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1591 *(value
.v_time
) = self
->parent
.timestamp
;
1592 lttv_state_save(tcs
, saved_state_tree
);
1594 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1595 self
->parent
.timestamp
.tv_nsec
);
1597 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1603 static gboolean
block_end(void *hook_data
, void *call_data
)
1605 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1607 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1611 LttEventPosition
*ep
;
1613 guint nb_block
, nb_event
;
1615 ep
= ltt_event_position_new();
1616 ltt_event_position(self
->parent
.e
, ep
);
1617 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1618 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1619 self
->saved_position
= 0;
1620 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1627 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1629 LttvTraceset
*traceset
= self
->parent
.ts
;
1631 guint i
, j
, nb_trace
, nb_tracefile
;
1635 LttvTracefileState
*tfs
;
1637 LttvTraceHook hook_start
, hook_end
;
1639 nb_trace
= lttv_traceset_number(traceset
);
1640 for(i
= 0 ; i
< nb_trace
; i
++) {
1641 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1643 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1644 NULL
, NULL
, block_start
, &hook_start
);
1645 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1646 NULL
, NULL
, block_end
, &hook_end
);
1648 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1650 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1652 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1653 LttvTracefileContext
, j
));
1654 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1655 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1656 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1657 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1663 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1665 LttvTraceset
*traceset
= self
->parent
.ts
;
1667 guint i
, j
, nb_trace
, nb_tracefile
;
1671 LttvTracefileState
*tfs
;
1674 nb_trace
= lttv_traceset_number(traceset
);
1675 for(i
= 0 ; i
< nb_trace
; i
++) {
1677 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1678 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1680 guint
*event_count
= g_new(guint
, 1);
1683 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1685 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1686 LttvTracefileContext
*, j
));
1687 lttv_hooks_add(tfs
->parent
.event
,
1688 state_save_event_hook
,
1696 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1698 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1700 lttv_state_save_add_event_hooks(tss
);
1707 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1709 LttvTraceset
*traceset
= self
->parent
.ts
;
1711 guint i
, j
, nb_trace
, nb_tracefile
;
1715 LttvTracefileState
*tfs
;
1717 LttvTraceHook hook_start
, hook_end
;
1719 nb_trace
= lttv_traceset_number(traceset
);
1720 for(i
= 0 ; i
< nb_trace
; i
++) {
1721 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1723 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1724 NULL
, NULL
, block_start
, &hook_start
);
1726 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1727 NULL
, NULL
, block_end
, &hook_end
);
1729 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1731 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1733 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1734 LttvTracefileContext
, j
));
1735 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1736 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1737 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1738 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1744 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1746 LttvTraceset
*traceset
= self
->parent
.ts
;
1748 guint i
, j
, nb_trace
, nb_tracefile
;
1752 LttvTracefileState
*tfs
;
1755 nb_trace
= lttv_traceset_number(traceset
);
1756 for(i
= 0 ; i
< nb_trace
; i
++) {
1758 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1759 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1763 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1765 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1766 LttvTracefileContext
*, j
));
1767 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1768 state_save_event_hook
);
1771 g_free(event_count
);
1775 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1777 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1779 lttv_state_save_remove_event_hooks(tss
);
1784 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1786 LttvTraceset
*traceset
= self
->parent
.ts
;
1790 int min_pos
, mid_pos
, max_pos
;
1792 guint call_rest
= 0;
1794 LttvTraceState
*tcs
;
1796 LttvAttributeValue value
;
1798 LttvAttributeType type
;
1800 LttvAttributeName name
;
1802 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1804 g_tree_destroy(self
->parent
.pqueue
);
1805 self
->parent
.pqueue
= g_tree_new(compare_tracefile
);
1807 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
1809 nb_trace
= lttv_traceset_number(traceset
);
1810 for(i
= 0 ; i
< nb_trace
; i
++) {
1811 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1813 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1814 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1815 LTTV_STATE_SAVED_STATES
);
1818 if(saved_states_tree
) {
1819 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1820 mid_pos
= max_pos
/ 2;
1821 while(min_pos
< max_pos
) {
1822 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1823 g_assert(type
== LTTV_GOBJECT
);
1824 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1825 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1827 g_assert(type
== LTTV_TIME
);
1828 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1830 closest_tree
= saved_state_tree
;
1832 else max_pos
= mid_pos
- 1;
1834 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1838 /* restore the closest earlier saved state */
1840 lttv_state_restore(tcs
, closest_tree
);
1844 /* There is no saved state, yet we want to have it. Restart at T0 */
1846 restore_init_state(tcs
);
1847 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1850 /* We want to seek quickly without restoring/updating the state */
1852 restore_init_state(tcs
);
1853 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1856 if(!call_rest
) g_info("NOT Calling restore");
1861 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1867 traceset_state_finalize (LttvTracesetState
*self
)
1869 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1870 finalize(G_OBJECT(self
));
1875 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1877 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1879 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1880 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1881 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1882 klass
->new_traceset_context
= new_traceset_context
;
1883 klass
->new_trace_context
= new_trace_context
;
1884 klass
->new_tracefile_context
= new_tracefile_context
;
1889 lttv_traceset_state_get_type(void)
1891 static GType type
= 0;
1893 static const GTypeInfo info
= {
1894 sizeof (LttvTracesetStateClass
),
1895 NULL
, /* base_init */
1896 NULL
, /* base_finalize */
1897 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1898 NULL
, /* class_finalize */
1899 NULL
, /* class_data */
1900 sizeof (LttvTracesetState
),
1901 0, /* n_preallocs */
1902 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1903 NULL
/* value handling */
1906 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1914 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1920 trace_state_finalize (LttvTraceState
*self
)
1922 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1923 finalize(G_OBJECT(self
));
1928 trace_state_class_init (LttvTraceStateClass
*klass
)
1930 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1932 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1933 klass
->state_save
= state_save
;
1934 klass
->state_restore
= state_restore
;
1935 klass
->state_saved_free
= state_saved_free
;
1940 lttv_trace_state_get_type(void)
1942 static GType type
= 0;
1944 static const GTypeInfo info
= {
1945 sizeof (LttvTraceStateClass
),
1946 NULL
, /* base_init */
1947 NULL
, /* base_finalize */
1948 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1949 NULL
, /* class_finalize */
1950 NULL
, /* class_data */
1951 sizeof (LttvTraceState
),
1952 0, /* n_preallocs */
1953 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1954 NULL
/* value handling */
1957 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1958 "LttvTraceStateType", &info
, 0);
1965 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1971 tracefile_state_finalize (LttvTracefileState
*self
)
1973 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1974 finalize(G_OBJECT(self
));
1979 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1981 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1983 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1988 lttv_tracefile_state_get_type(void)
1990 static GType type
= 0;
1992 static const GTypeInfo info
= {
1993 sizeof (LttvTracefileStateClass
),
1994 NULL
, /* base_init */
1995 NULL
, /* base_finalize */
1996 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1997 NULL
, /* class_finalize */
1998 NULL
, /* class_data */
1999 sizeof (LttvTracefileState
),
2000 0, /* n_preallocs */
2001 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2002 NULL
/* value handling */
2005 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2006 "LttvTracefileStateType", &info
, 0);
2012 static void module_init()
2014 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2015 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
2016 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
2017 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
2018 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
2019 LTTV_STATE_TRAP
= g_quark_from_string("trap");
2020 LTTV_STATE_IRQ
= g_quark_from_string("irq");
2021 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
2022 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
2023 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
2024 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
2025 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
2026 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
2027 LTTV_STATE_RUN
= g_quark_from_string("running");
2028 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2029 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2030 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2031 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2032 LTTV_STATE_EVENT
= g_quark_from_string("event");
2033 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2034 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2035 LTTV_STATE_TIME
= g_quark_from_string("time");
2036 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2037 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2038 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2039 g_quark_from_string("trace_state_use_count");
2042 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2043 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2044 LTT_FACILITY_FS
= g_quark_from_string("fs");
2047 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2048 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2049 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2050 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2051 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2052 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2053 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2054 LTT_EVENT_FORK
= g_quark_from_string("fork");
2055 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2056 LTT_EVENT_FREE
= g_quark_from_string("free");
2057 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2060 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2061 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2062 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2063 LTT_FIELD_OUT
= g_quark_from_string("out");
2064 LTT_FIELD_IN
= g_quark_from_string("in");
2065 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2066 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2067 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2068 LTT_FIELD_PID
= g_quark_from_string("pid");
2069 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2073 static void module_destroy()
2078 LTTV_MODULE("state", "State computation", \
2079 "Update the system state, possibly saving it at intervals", \
2080 module_init
, module_destroy
)