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>
33 #define PREALLOCATED_EXECUTION_STACK 10
35 /* Facilities Quarks */
39 LTT_FACILITY_KERNEL_ARCH
,
42 LTT_FACILITY_STATEDUMP
,
43 LTT_FACILITY_USER_GENERIC
;
48 LTT_EVENT_SYSCALL_ENTRY
,
49 LTT_EVENT_SYSCALL_EXIT
,
54 LTT_EVENT_SOFT_IRQ_ENTRY
,
55 LTT_EVENT_SOFT_IRQ_EXIT
,
56 LTT_EVENT_SCHEDCHANGE
,
58 LTT_EVENT_KERNEL_THREAD
,
62 LTT_EVENT_ENUM_PROCESS_STATE
,
63 LTT_EVENT_FUNCTION_ENTRY
,
64 LTT_EVENT_FUNCTION_EXIT
;
72 LTT_FIELD_SOFT_IRQ_ID
,
88 LTTV_STATE_MODE_UNKNOWN
,
96 LTTV_STATE_SUBMODE_UNKNOWN
,
97 LTTV_STATE_SUBMODE_NONE
;
101 LTTV_STATE_WAIT_FORK
,
110 LTTV_STATE_TRACEFILES
,
111 LTTV_STATE_PROCESSES
,
113 LTTV_STATE_RUNNING_PROCESS
,
115 LTTV_STATE_SAVED_STATES
,
116 LTTV_STATE_SAVED_STATES_TIME
,
119 LTTV_STATE_NAME_TABLES
,
120 LTTV_STATE_TRACE_STATE_USE_COUNT
;
122 static void create_max_time(LttvTraceState
*tcs
);
124 static void get_max_time(LttvTraceState
*tcs
);
126 static void free_max_time(LttvTraceState
*tcs
);
128 static void create_name_tables(LttvTraceState
*tcs
);
130 static void get_name_tables(LttvTraceState
*tcs
);
132 static void free_name_tables(LttvTraceState
*tcs
);
134 static void free_saved_state(LttvTraceState
*tcs
);
136 static void lttv_state_free_process_table(GHashTable
*processes
);
139 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
141 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
145 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
147 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
151 void lttv_state_state_saved_free(LttvTraceState
*self
,
152 LttvAttribute
*container
)
154 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
158 guint
process_hash(gconstpointer key
)
160 guint pid
= ((const LttvProcessState
*)key
)->pid
;
161 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
165 /* If the hash table hash function is well distributed,
166 * the process_equal should compare different pid */
167 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
169 const LttvProcessState
*process_a
, *process_b
;
172 process_a
= (const LttvProcessState
*)a
;
173 process_b
= (const LttvProcessState
*)b
;
175 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
176 else if(likely(process_a
->pid
== 0 &&
177 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
182 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
184 g_tree_destroy((GTree
*)value
);
187 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
189 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
190 g_hash_table_destroy(usertraces
);
196 restore_init_state(LttvTraceState
*self
)
200 LttvTracefileState
*tfcs
;
202 /* Free the process tables */
203 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
204 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
205 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
206 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
209 /* Seek time to beginning */
210 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
211 // closest. It's the tracecontext job to seek the trace to the beginning
212 // anyway : the init state might be used at the middle of the trace as well...
213 //g_tree_destroy(self->parent.ts_context->pqueue);
214 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
217 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
219 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
221 /* Put the per cpu running_process to beginning state : process 0. */
222 for(i
=0; i
< nb_cpus
; i
++) {
223 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
224 LTTV_STATE_UNNAMED
, <t_time_zero
);
225 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
226 self
->running_process
[i
]->cpu
= i
;
230 nb_tracefile
= self
->parent
.tracefiles
->len
;
232 for(i
= 0 ; i
< nb_tracefile
; i
++) {
234 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
235 LttvTracefileContext
*, i
));
236 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
237 // tfcs->saved_position = 0;
238 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
239 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
240 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
241 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
246 //static LttTime time_zero = {0,0};
248 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
251 const LttTime
*t1
= (const LttTime
*)a
;
252 const LttTime
*t2
= (const LttTime
*)b
;
254 return ltt_time_compare(*t1
, *t2
);
257 static void free_usertrace_key(gpointer data
)
263 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
265 guint i
, j
, nb_trace
, nb_tracefile
;
267 LttvTraceContext
*tc
;
271 LttvTracefileState
*tfcs
;
273 LttvAttributeValue v
;
275 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
276 init((LttvTracesetContext
*)self
, ts
);
278 nb_trace
= lttv_traceset_number(ts
);
279 for(i
= 0 ; i
< nb_trace
; i
++) {
280 tc
= self
->parent
.traces
[i
];
281 tcs
= LTTV_TRACE_STATE(tc
);
282 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
283 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
287 if(*(v
.v_uint
) == 1) {
288 create_name_tables(tcs
);
289 create_max_time(tcs
);
291 get_name_tables(tcs
);
294 nb_tracefile
= tc
->tracefiles
->len
;
295 tcs
->processes
= NULL
;
296 tcs
->usertraces
= NULL
;
297 tcs
->running_process
= g_new(LttvProcessState
*,
298 ltt_trace_get_num_cpu(tc
->t
));
299 restore_init_state(tcs
);
300 for(j
= 0 ; j
< nb_tracefile
; j
++) {
302 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
303 LttvTracefileContext
*, j
));
304 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
305 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
307 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
308 /* It's a Usertrace */
309 LttvProcessState
*process
;
311 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
312 ltt_tracefile_creation(tfcs
->parent
.tf
));
313 process
= lttv_state_find_process_or_create(
315 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
317 process
->usertrace
= tfcs
;
321 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
322 /* It's a Usertrace */
323 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
324 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
326 if(!usertrace_tree
) {
327 usertrace_tree
= g_tree_new_full(compare_usertraces
,
328 NULL
, free_usertrace_key
, NULL
);
329 g_hash_table_insert(tcs
->usertraces
,
330 (gpointer
)tid
, usertrace_tree
);
332 LttTime
*timestamp
= g_new(LttTime
, 1);
333 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
334 ltt_tracefile_creation(tfcs
->parent
.tf
));
335 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
343 fini(LttvTracesetState
*self
)
349 LttvTracefileState
*tfcs
;
351 LttvAttributeValue v
;
353 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
354 for(i
= 0 ; i
< nb_trace
; i
++) {
355 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
356 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
359 g_assert(*(v
.v_uint
) != 0);
362 if(*(v
.v_uint
) == 0) {
363 free_name_tables(tcs
);
365 free_saved_state(tcs
);
367 g_free(tcs
->running_process
);
368 tcs
->running_process
= NULL
;
369 lttv_state_free_process_table(tcs
->processes
);
370 lttv_state_free_usertraces(tcs
->usertraces
);
371 tcs
->processes
= NULL
;
372 tcs
->usertraces
= NULL
;
374 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
375 fini((LttvTracesetContext
*)self
);
379 static LttvTracesetContext
*
380 new_traceset_context(LttvTracesetContext
*self
)
382 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
386 static LttvTraceContext
*
387 new_trace_context(LttvTracesetContext
*self
)
389 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
393 static LttvTracefileContext
*
394 new_tracefile_context(LttvTracesetContext
*self
)
396 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
400 /* Write the process state of the trace */
402 static void write_process_state(gpointer key
, gpointer value
,
405 LttvProcessState
*process
;
407 LttvExecutionState
*es
;
409 FILE *fp
= (FILE *)user_data
;
413 process
= (LttvProcessState
*)value
;
415 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
416 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
417 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
420 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
421 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
422 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
423 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
424 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
425 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
426 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
428 fprintf(fp
, " </PROCESS>\n");
432 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
434 guint i
, nb_tracefile
, nb_block
, offset
;
437 LttvTracefileState
*tfcs
;
441 LttEventPosition
*ep
;
445 ep
= ltt_event_position_new();
447 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
449 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
451 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
452 for(i
=0;i
<nb_cpus
;i
++) {
453 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
454 i
, self
->running_process
[i
]->pid
);
457 nb_tracefile
= self
->parent
.tracefiles
->len
;
459 for(i
= 0 ; i
< nb_tracefile
; i
++) {
461 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
462 LttvTracefileContext
*, i
));
463 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
464 tfcs
->parent
.timestamp
.tv_sec
,
465 tfcs
->parent
.timestamp
.tv_nsec
);
466 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
467 if(e
== NULL
) fprintf(fp
,"/>\n");
469 ltt_event_position(e
, ep
);
470 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
471 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
476 fprintf(fp
,"</PROCESS_STATE>");
480 /* Copy each process from an existing hash table to a new one */
482 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
484 LttvProcessState
*process
, *new_process
;
486 GHashTable
*new_processes
= (GHashTable
*)user_data
;
490 process
= (LttvProcessState
*)value
;
491 new_process
= g_new(LttvProcessState
, 1);
492 *new_process
= *process
;
493 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
494 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
495 new_process
->execution_stack
=
496 g_array_set_size(new_process
->execution_stack
,
497 process
->execution_stack
->len
);
498 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
499 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
500 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
502 new_process
->state
= &g_array_index(new_process
->execution_stack
,
503 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
504 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
506 new_process
->user_stack
=
507 g_array_set_size(new_process
->user_stack
,
508 process
->user_stack
->len
);
509 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
510 g_array_index(new_process
->user_stack
, guint64
, i
) =
511 g_array_index(process
->user_stack
, guint64
, i
);
513 new_process
->current_function
= &g_array_index(new_process
->user_stack
,
514 guint64
, new_process
->user_stack
->len
- 1);
515 g_hash_table_insert(new_processes
, new_process
, new_process
);
519 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
521 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
523 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
524 return new_processes
;
528 /* The saved state for each trace contains a member "processes", which
529 stores a copy of the process table, and a member "tracefiles" with
530 one entry per tracefile. Each tracefile has a "process" member pointing
531 to the current process and a "position" member storing the tracefile
532 position (needed to seek to the current "next" event. */
534 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
536 guint i
, nb_tracefile
, nb_cpus
;
538 LttvTracefileState
*tfcs
;
540 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
542 guint
*running_process
;
544 LttvAttributeType type
;
546 LttvAttributeValue value
;
548 LttvAttributeName name
;
550 LttEventPosition
*ep
;
552 tracefiles_tree
= lttv_attribute_find_subdir(container
,
553 LTTV_STATE_TRACEFILES
);
555 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
557 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
559 /* Add the currently running processes array */
560 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
561 running_process
= g_new(guint
, nb_cpus
);
562 for(i
=0;i
<nb_cpus
;i
++) {
563 running_process
[i
] = self
->running_process
[i
]->pid
;
565 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
567 *(value
.v_pointer
) = running_process
;
569 g_info("State save");
571 nb_tracefile
= self
->parent
.tracefiles
->len
;
573 for(i
= 0 ; i
< nb_tracefile
; i
++) {
575 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
576 LttvTracefileContext
*, i
));
577 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
578 value
= lttv_attribute_add(tracefiles_tree
, i
,
580 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
582 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
584 *(value
.v_uint
) = tfcs
->process
->pid
;
586 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
588 /* Only save the position if the tfs has not infinite time. */
589 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
590 // && current_tfcs != tfcs) {
591 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
592 *(value
.v_pointer
) = NULL
;
594 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
595 ep
= ltt_event_position_new();
596 ltt_event_position(e
, ep
);
597 *(value
.v_pointer
) = ep
;
599 guint nb_block
, offset
;
602 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
603 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
605 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
611 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
613 guint i
, nb_tracefile
, pid
, nb_cpus
;
615 LttvTracefileState
*tfcs
;
617 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
619 guint
*running_process
;
621 LttvAttributeType type
;
623 LttvAttributeValue value
;
625 LttvAttributeName name
;
629 LttEventPosition
*ep
;
631 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
633 tracefiles_tree
= lttv_attribute_find_subdir(container
,
634 LTTV_STATE_TRACEFILES
);
636 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
638 g_assert(type
== LTTV_POINTER
);
639 lttv_state_free_process_table(self
->processes
);
640 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
642 /* Add the currently running processes array */
643 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
644 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
646 g_assert(type
== LTTV_POINTER
);
647 running_process
= *(value
.v_pointer
);
648 for(i
=0;i
<nb_cpus
;i
++) {
649 pid
= running_process
[i
];
650 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
651 g_assert(self
->running_process
[i
] != NULL
);
655 nb_tracefile
= self
->parent
.tracefiles
->len
;
657 //g_tree_destroy(tsc->pqueue);
658 //tsc->pqueue = g_tree_new(compare_tracefile);
660 for(i
= 0 ; i
< nb_tracefile
; i
++) {
662 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
663 LttvTracefileContext
*, i
));
664 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
665 g_assert(type
== LTTV_GOBJECT
);
666 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
668 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
670 g_assert(type
== LTTV_UINT
);
671 pid
= *(value
.v_uint
);
672 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
674 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
676 g_assert(type
== LTTV_POINTER
);
677 //g_assert(*(value.v_pointer) != NULL);
678 ep
= *(value
.v_pointer
);
679 g_assert(tfcs
->parent
.t_context
!= NULL
);
681 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
682 g_tree_remove(tsc
->pqueue
, tfc
);
685 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
686 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
687 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
688 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
689 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
691 tfc
->timestamp
= ltt_time_infinite
;
697 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
699 guint i
, nb_tracefile
, nb_cpus
;
701 LttvTracefileState
*tfcs
;
703 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
705 guint
*running_process
;
707 LttvAttributeType type
;
709 LttvAttributeValue value
;
711 LttvAttributeName name
;
715 LttEventPosition
*ep
;
717 tracefiles_tree
= lttv_attribute_find_subdir(container
,
718 LTTV_STATE_TRACEFILES
);
719 g_object_ref(G_OBJECT(tracefiles_tree
));
720 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
722 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
724 g_assert(type
== LTTV_POINTER
);
725 lttv_state_free_process_table(*(value
.v_pointer
));
726 *(value
.v_pointer
) = NULL
;
727 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
729 /* Free running processes array */
730 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
731 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
733 g_assert(type
== LTTV_POINTER
);
734 running_process
= *(value
.v_pointer
);
735 g_free(running_process
);
737 nb_tracefile
= self
->parent
.tracefiles
->len
;
739 for(i
= 0 ; i
< nb_tracefile
; i
++) {
741 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
742 LttvTracefileContext
*, i
));
743 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
744 g_assert(type
== LTTV_GOBJECT
);
745 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
747 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
749 g_assert(type
== LTTV_POINTER
);
750 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
752 g_object_unref(G_OBJECT(tracefiles_tree
));
756 static void free_saved_state(LttvTraceState
*self
)
760 LttvAttributeType type
;
762 LttvAttributeValue value
;
764 LttvAttributeName name
;
768 LttvAttribute
*saved_states
;
770 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
771 LTTV_STATE_SAVED_STATES
);
773 nb
= lttv_attribute_get_number(saved_states
);
774 for(i
= 0 ; i
< nb
; i
++) {
775 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
776 g_assert(type
== LTTV_GOBJECT
);
777 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
780 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
785 create_max_time(LttvTraceState
*tcs
)
787 LttvAttributeValue v
;
789 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
791 g_assert(*(v
.v_pointer
) == NULL
);
792 *(v
.v_pointer
) = g_new(LttTime
,1);
793 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
798 get_max_time(LttvTraceState
*tcs
)
800 LttvAttributeValue v
;
802 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
804 g_assert(*(v
.v_pointer
) != NULL
);
805 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
810 free_max_time(LttvTraceState
*tcs
)
812 LttvAttributeValue v
;
814 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
816 g_free(*(v
.v_pointer
));
817 *(v
.v_pointer
) = NULL
;
821 typedef struct _LttvNameTables
{
822 // FIXME GQuark *eventtype_names;
823 GQuark
*syscall_names
;
827 GQuark
*soft_irq_names
;
832 create_name_tables(LttvTraceState
*tcs
)
836 GQuark f_name
, e_name
;
840 LttvTraceHookByFacility
*thf
;
846 GString
*fe_name
= g_string_new("");
848 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
850 LttvAttributeValue v
;
852 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
854 g_assert(*(v
.v_pointer
) == NULL
);
855 *(v
.v_pointer
) = name_tables
;
856 #if 0 // Use iteration over the facilities_by_name and then list all event
857 // types of each facility
858 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
859 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
860 for(i
= 0 ; i
< nb
; i
++) {
861 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
862 e_name
= ltt_eventtype_name(et
);
863 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
864 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
865 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
868 if(lttv_trace_find_hook(tcs
->parent
.t
,
869 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
870 LTT_FIELD_SYSCALL_ID
, 0, 0,
874 thf
= lttv_trace_hook_get_first(&h
);
876 t
= ltt_field_type(thf
->f1
);
877 nb
= ltt_type_element_number(t
);
879 lttv_trace_hook_destroy(&h
);
881 name_tables
->syscall_names
= g_new(GQuark
, nb
);
882 name_tables
->nb_syscalls
= nb
;
884 for(i
= 0 ; i
< nb
; i
++) {
885 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
888 //name_tables->syscall_names = g_new(GQuark, 256);
889 //for(i = 0 ; i < 256 ; i++) {
890 // g_string_printf(fe_name, "syscall %d", i);
891 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
894 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
895 LTT_EVENT_TRAP_ENTRY
,
896 LTT_FIELD_TRAP_ID
, 0, 0,
900 thf
= lttv_trace_hook_get_first(&h
);
902 t
= ltt_field_type(thf
->f1
);
903 //nb = ltt_type_element_number(t);
905 lttv_trace_hook_destroy(&h
);
908 name_tables->trap_names = g_new(GQuark, nb);
909 for(i = 0 ; i < nb ; i++) {
910 name_tables->trap_names[i] = g_quark_from_string(
911 ltt_enum_string_get(t, i));
915 name_tables
->trap_names
= g_new(GQuark
, 256);
916 for(i
= 0 ; i
< 256 ; i
++) {
917 g_string_printf(fe_name
, "trap %d", i
);
918 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
921 if(lttv_trace_find_hook(tcs
->parent
.t
,
922 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
923 LTT_FIELD_IRQ_ID
, 0, 0,
927 thf
= lttv_trace_hook_get_first(&h
);
929 t
= ltt_field_type(thf
->f1
);
930 //nb = ltt_type_element_number(t);
932 lttv_trace_hook_destroy(&h
);
935 name_tables->irq_names = g_new(GQuark, nb);
936 for(i = 0 ; i < nb ; i++) {
937 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
941 name_tables
->irq_names
= g_new(GQuark
, 256);
942 for(i
= 0 ; i
< 256 ; i
++) {
943 g_string_printf(fe_name
, "irq %d", i
);
944 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
948 name_tables->soft_irq_names = g_new(GQuark, nb);
949 for(i = 0 ; i < nb ; i++) {
950 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
954 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
955 for(i
= 0 ; i
< 256 ; i
++) {
956 g_string_printf(fe_name
, "softirq %d", i
);
957 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
961 g_string_free(fe_name
, TRUE
);
966 get_name_tables(LttvTraceState
*tcs
)
968 LttvNameTables
*name_tables
;
970 LttvAttributeValue v
;
972 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
974 g_assert(*(v
.v_pointer
) != NULL
);
975 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
976 //tcs->eventtype_names = name_tables->eventtype_names;
977 tcs
->syscall_names
= name_tables
->syscall_names
;
978 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
979 tcs
->trap_names
= name_tables
->trap_names
;
980 tcs
->irq_names
= name_tables
->irq_names
;
981 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
986 free_name_tables(LttvTraceState
*tcs
)
988 LttvNameTables
*name_tables
;
990 LttvAttributeValue v
;
992 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
994 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
995 *(v
.v_pointer
) = NULL
;
997 // g_free(name_tables->eventtype_names);
998 g_free(name_tables
->syscall_names
);
999 g_free(name_tables
->trap_names
);
1000 g_free(name_tables
->irq_names
);
1001 g_free(name_tables
->soft_irq_names
);
1002 g_free(name_tables
);
1005 #ifdef HASH_TABLE_DEBUG
1007 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1009 LttvProcessState
*process
= (LttvProcessState
*)value
;
1011 /* Test for process corruption */
1012 guint stack_len
= process
->execution_stack
->len
;
1015 static void hash_table_check(GHashTable
*table
)
1017 g_hash_table_foreach(table
, test_process
, NULL
);
1024 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1027 LttvExecutionState
*es
;
1029 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1030 guint cpu
= tfs
->cpu
;
1032 #ifdef HASH_TABLE_DEBUG
1033 hash_table_check(ts
->processes
);
1035 LttvProcessState
*process
= ts
->running_process
[cpu
];
1037 guint depth
= process
->execution_stack
->len
;
1039 process
->execution_stack
=
1040 g_array_set_size(process
->execution_stack
, depth
+ 1);
1043 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1045 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1048 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1049 es
->s
= process
->state
->s
;
1050 process
->state
= es
;
1054 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1056 guint cpu
= tfs
->cpu
;
1057 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1058 LttvProcessState
*process
= ts
->running_process
[cpu
];
1060 guint depth
= process
->execution_stack
->len
;
1062 if(process
->state
->t
!= t
){
1063 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1064 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1065 g_info("process state has %s when pop_int is %s\n",
1066 g_quark_to_string(process
->state
->t
),
1067 g_quark_to_string(t
));
1068 g_info("{ %u, %u, %s, %s }\n",
1071 g_quark_to_string(process
->name
),
1072 g_quark_to_string(process
->state
->s
));
1077 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1078 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1082 process
->execution_stack
=
1083 g_array_set_size(process
->execution_stack
, depth
- 1);
1084 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1086 process
->state
->change
= tfs
->parent
.timestamp
;
1089 struct search_result
{
1090 const LttTime
*time
; /* Requested time */
1091 LttTime
*best
; /* Best result */
1094 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1096 const LttTime
*elem_time
= (const LttTime
*)a
;
1097 /* Explicit non const cast */
1098 struct search_result
*res
= (struct search_result
*)b
;
1100 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1101 /* The usertrace was created before the schedchange */
1102 /* Get larger keys */
1104 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1105 /* The usertrace was created after the schedchange time */
1106 /* Get smaller keys */
1108 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1109 res
->best
= elem_time
;
1112 res
->best
= elem_time
;
1119 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1120 guint pid
, const LttTime
*timestamp
)
1122 LttvTracefileState
*tfs
= NULL
;
1123 struct search_result res
;
1124 /* Find the usertrace associated with a pid and time interval.
1125 * Search in the usertraces by PID (within a hash) and then, for each
1126 * corresponding element of the array, find the first one with creation
1127 * timestamp the lowest, but higher or equal to "timestamp". */
1128 res
.time
= timestamp
;
1130 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1131 if(usertrace_tree
) {
1132 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1134 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1142 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1143 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1145 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1147 LttvExecutionState
*es
;
1149 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1155 process
->name
= name
;
1156 //process->last_cpu = tfs->cpu_name;
1157 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1158 process
->kernel_thread
= 0;
1159 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1160 process
->current_function
= 0; //function 0x0 by default.
1162 g_info("Process %u, core %p", process
->pid
, process
);
1163 g_hash_table_insert(tcs
->processes
, process
, process
);
1166 process
->ppid
= parent
->pid
;
1167 process
->creation_time
= *timestamp
;
1170 /* No parent. This process exists but we are missing all information about
1171 its creation. The birth time is set to zero but we remember the time of
1176 process
->creation_time
= ltt_time_zero
;
1179 process
->insertion_time
= *timestamp
;
1180 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1181 process
->creation_time
.tv_nsec
);
1182 process
->pid_time
= g_quark_from_string(buffer
);
1184 //process->last_cpu = tfs->cpu_name;
1185 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1186 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1187 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1188 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1189 es
= process
->state
= &g_array_index(process
->execution_stack
,
1190 LttvExecutionState
, 0);
1191 es
->t
= LTTV_STATE_USER_MODE
;
1192 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1193 es
->entry
= *timestamp
;
1194 //g_assert(timestamp->tv_sec != 0);
1195 es
->change
= *timestamp
;
1196 es
->s
= LTTV_STATE_RUN
;
1198 es
= process
->state
= &g_array_index(process
->execution_stack
,
1199 LttvExecutionState
, 1);
1200 es
->t
= LTTV_STATE_SYSCALL
;
1201 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1202 es
->entry
= *timestamp
;
1203 //g_assert(timestamp->tv_sec != 0);
1204 es
->change
= *timestamp
;
1205 es
->s
= LTTV_STATE_WAIT_FORK
;
1207 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1208 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1209 sizeof(guint64
), 0);
1214 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1217 LttvProcessState key
;
1218 LttvProcessState
*process
;
1222 process
= g_hash_table_lookup(ts
->processes
, &key
);
1227 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1230 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1231 LttvExecutionState
*es
;
1233 /* Put ltt_time_zero creation time for unexisting processes */
1234 if(unlikely(process
== NULL
)) {
1235 process
= lttv_state_create_process(ts
,
1236 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1237 /* We are not sure is it's a kernel thread or normal thread, put the
1238 * bottom stack state to unknown */
1239 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1240 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1245 /* FIXME : this function should be called when we receive an event telling that
1246 * release_task has been called in the kernel. In happens generally when
1247 * the parent waits for its child terminaison, but may also happen in special
1248 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1249 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1250 * of a killed thread ground, but isn't the leader.
1252 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1254 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1255 LttvProcessState key
;
1257 key
.pid
= process
->pid
;
1258 key
.cpu
= process
->cpu
;
1259 g_hash_table_remove(ts
->processes
, &key
);
1260 g_array_free(process
->execution_stack
, TRUE
);
1261 g_array_free(process
->user_stack
, TRUE
);
1266 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1268 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1269 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1274 static void lttv_state_free_process_table(GHashTable
*processes
)
1276 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1277 g_hash_table_destroy(processes
);
1281 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1283 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1284 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1285 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1286 LttField
*f
= thf
->f1
;
1288 LttvExecutionSubmode submode
;
1290 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1291 guint syscall
= ltt_event_get_unsigned(e
, f
);
1293 if(syscall
< nb_syscalls
) {
1294 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1297 /* Fixup an incomplete syscall table */
1298 GString
*string
= g_string_new("");
1299 g_string_printf(string
, "syscall %u", syscall
);
1300 submode
= g_quark_from_string(string
->str
);
1301 g_string_free(string
, TRUE
);
1303 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1308 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1310 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1312 pop_state(s
, LTTV_STATE_SYSCALL
);
1317 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1319 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1320 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1321 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1322 LttField
*f
= thf
->f1
;
1324 LttvExecutionSubmode submode
;
1326 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1327 ltt_event_get_unsigned(e
, f
)];
1328 push_state(s
, LTTV_STATE_TRAP
, submode
);
1333 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1335 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1337 pop_state(s
, LTTV_STATE_TRAP
);
1342 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1344 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1345 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1346 guint8 fac_id
= ltt_event_facility_id(e
);
1347 guint8 ev_id
= ltt_event_eventtype_id(e
);
1348 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1349 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1350 g_assert(thf
->f1
!= NULL
);
1351 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1352 LttField
*f
= thf
->f1
;
1354 LttvExecutionSubmode submode
;
1356 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1357 ltt_event_get_unsigned(e
, f
)];
1359 /* Do something with the info about being in user or system mode when int? */
1360 push_state(s
, LTTV_STATE_IRQ
, submode
);
1364 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1366 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1368 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1374 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1376 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1378 pop_state(s
, LTTV_STATE_IRQ
);
1382 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1384 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1385 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1386 guint8 fac_id
= ltt_event_facility_id(e
);
1387 guint8 ev_id
= ltt_event_eventtype_id(e
);
1388 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1389 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1390 g_assert(thf
->f1
!= NULL
);
1391 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1392 LttField
*f
= thf
->f1
;
1394 LttvExecutionSubmode submode
;
1396 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1397 ltt_event_get_unsigned(e
, f
)];
1399 /* Do something with the info about being in user or system mode when int? */
1400 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1404 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1408 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1409 guint cpu
= tfs
->cpu
;
1410 LttvProcessState
*process
= ts
->running_process
[cpu
];
1412 guint depth
= process
->user_stack
->len
;
1414 process
->user_stack
=
1415 g_array_set_size(process
->user_stack
, depth
+ 1);
1417 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1418 *new_func
= funcptr
;
1419 process
->current_function
=
1420 g_array_index(process
->user_stack
, guint64
, depth
- 1);
1423 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1425 guint cpu
= tfs
->cpu
;
1426 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1427 LttvProcessState
*process
= ts
->running_process
[cpu
];
1429 guint depth
= process
->user_stack
->len
;
1430 if(process
->current_function
!= funcptr
){
1431 g_info("Different functions (%lu.%09lu): ignore it\n",
1432 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1433 g_info("process state has %llu when pop_function is %llu\n",
1434 process
->current_function
, funcptr
);
1435 g_info("{ %u, %u, %s, %s }\n",
1438 g_quark_to_string(process
->name
),
1439 g_quark_to_string(process
->state
->s
));
1444 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1445 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1449 process
->user_stack
=
1450 g_array_set_size(process
->user_stack
, depth
- 1);
1451 process
->current_function
=
1452 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1456 static gboolean
function_entry(void *hook_data
, void *call_data
)
1458 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1459 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1460 guint8 fac_id
= ltt_event_facility_id(e
);
1461 guint8 ev_id
= ltt_event_eventtype_id(e
);
1462 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1463 g_assert(thf
->f1
!= NULL
);
1464 LttField
*f
= thf
->f1
;
1465 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1467 push_function(s
, funcptr
);
1471 static gboolean
function_exit(void *hook_data
, void *call_data
)
1473 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1474 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1475 guint8 fac_id
= ltt_event_facility_id(e
);
1476 guint8 ev_id
= ltt_event_eventtype_id(e
);
1477 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1478 g_assert(thf
->f1
!= NULL
);
1479 LttField
*f
= thf
->f1
;
1480 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1482 LttvExecutionSubmode submode
;
1484 pop_function(s
, funcptr
);
1488 static gboolean
schedchange(void *hook_data
, void *call_data
)
1490 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1492 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1493 LttvProcessState
*process
= ts
->running_process
[cpu
];
1494 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1496 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1497 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1498 guint pid_in
, pid_out
;
1501 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1502 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1503 state_out
= ltt_event_get_int(e
, thf
->f3
);
1505 if(likely(process
!= NULL
)) {
1507 /* We could not know but it was not the idle process executing.
1508 This should only happen at the beginning, before the first schedule
1509 event, and when the initial information (current process for each CPU)
1510 is missing. It is not obvious how we could, after the fact, compensate
1511 the wrongly attributed statistics. */
1513 //This test only makes sense once the state is known and if there is no
1514 //missing events. We need to silently ignore schedchange coming after a
1515 //process_free, or it causes glitches. (FIXME)
1516 //if(unlikely(process->pid != pid_out)) {
1517 // g_assert(process->pid == 0);
1520 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1521 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1522 process
->state
->change
= s
->parent
.timestamp
;
1524 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1525 else process
->state
->s
= LTTV_STATE_WAIT
;
1526 process
->state
->change
= s
->parent
.timestamp
;
1530 exit_process(s
, process
); /* EXIT_DEAD */
1531 /* see sched.h for states */
1533 process
= ts
->running_process
[cpu
] =
1534 lttv_state_find_process_or_create(
1535 (LttvTraceState
*)s
->parent
.t_context
,
1537 &s
->parent
.timestamp
);
1538 process
->state
->s
= LTTV_STATE_RUN
;
1540 if(process
->usertrace
)
1541 process
->usertrace
->cpu
= cpu
;
1542 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1543 process
->state
->change
= s
->parent
.timestamp
;
1547 static gboolean
process_fork(void *hook_data
, void *call_data
)
1549 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1550 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1551 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1554 LttvProcessState
*zombie_process
;
1556 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1557 LttvProcessState
*process
= ts
->running_process
[cpu
];
1558 LttvProcessState
*child_process
;
1561 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1564 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1566 /* Mathieu : it seems like the process might have been scheduled in before the
1567 * fork, and, in a rare case, might be the current process. This might happen
1568 * in a SMP case where we don't have enough precision on the clocks.
1570 * Test reenabled after precision fixes on time. (Mathieu) */
1572 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1574 if(unlikely(zombie_process
!= NULL
)) {
1575 /* Reutilisation of PID. Only now we are sure that the old PID
1576 * has been released. FIXME : should know when release_task happens instead.
1578 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1580 for(i
=0; i
< num_cpus
; i
++) {
1581 g_assert(zombie_process
!= ts
->running_process
[i
]);
1584 exit_process(s
, zombie_process
);
1587 g_assert(process
->pid
!= child_pid
);
1588 // FIXME : Add this test in the "known state" section
1589 // g_assert(process->pid == parent_pid);
1590 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1591 if(child_process
== NULL
) {
1592 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1593 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1595 /* The process has already been created : due to time imprecision between
1596 * multiple CPUs : it has been scheduled in before creation. Note that we
1597 * shouldn't have this kind of imprecision.
1599 * Simply put a correct parent.
1601 g_assert(0); /* This is a problematic case : the process has been created
1602 before the fork event */
1603 child_process
->ppid
= process
->pid
;
1605 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1606 child_process
->name
= process
->name
;
1611 /* We stamp a newly created process as kernel_thread */
1612 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1614 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1615 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1616 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1619 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1620 LttvProcessState
*process
;
1621 LttvExecutionState
*es
;
1624 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1626 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1627 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1628 es
->t
= LTTV_STATE_SYSCALL
;
1629 process
->kernel_thread
= 1;
1634 static gboolean
process_exit(void *hook_data
, void *call_data
)
1636 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1637 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1638 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1642 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1643 LttvProcessState
*process
= ts
->running_process
[cpu
];
1645 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1647 // FIXME : Add this test in the "known state" section
1648 // g_assert(process->pid == pid);
1650 if(likely(process
!= NULL
)) {
1651 process
->state
->s
= LTTV_STATE_EXIT
;
1656 static gboolean
process_free(void *hook_data
, void *call_data
)
1658 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1659 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1660 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1661 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1663 LttvProcessState
*process
;
1665 /* PID of the process to release */
1666 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1668 g_assert(release_pid
!= 0);
1670 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1672 if(likely(process
!= NULL
)) {
1673 /* release_task is happening at kernel level : we can now safely release
1674 * the data structure of the process */
1675 //This test is fun, though, as it may happen that
1676 //at time t : CPU 0 : process_free
1677 //at time t+150ns : CPU 1 : schedule out
1678 //Clearly due to time imprecision, we disable it. (Mathieu)
1679 //If this weird case happen, we have no choice but to put the
1680 //Currently running process on the cpu to 0.
1681 //I re-enable it following time precision fixes. (Mathieu)
1682 //Well, in the case where an process is freed by a process on another CPU
1683 //and still scheduled, it happens that this is the schedchange that will
1684 //drop the last reference count. Do not free it here!
1685 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1687 for(i
=0; i
< num_cpus
; i
++) {
1688 //g_assert(process != ts->running_process[i]);
1689 if(process
== ts
->running_process
[i
]) {
1690 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1694 //if(i == num_cpus) /* process is not scheduled */
1695 //exit_process(s, process); // do nothing : wait for the schedchange to
1696 //delete the process.
1703 static gboolean
process_exec(void *hook_data
, void *call_data
)
1705 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1706 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1707 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1708 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1711 LttvProcessState
*process
= ts
->running_process
[cpu
];
1713 /* PID of the process to release */
1714 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1715 //name = ltt_event_get_string(e, thf->f1);
1716 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1718 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1719 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1720 memcpy(null_term_name
, name_begin
, name_len
);
1721 null_term_name
[name_len
] = '\0';
1723 process
->name
= g_quark_from_string(null_term_name
);
1724 g_free(null_term_name
);
1728 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1731 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1732 //It's slow : optimise later by doing this before reading trace.
1733 LttEventType
*et
= ltt_event_eventtype(e
);
1735 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1740 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1741 LttvProcessState
*process
= ts
->running_process
[cpu
];
1742 LttvProcessState
*parent_process
;
1743 LttField
*f4
, *f5
, *f6
;
1744 GQuark mode
, submode
, status
;
1747 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1750 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1753 command
= ltt_event_get_string(e
, thf
->f3
);
1756 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1757 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1758 ltt_event_get_unsigned(e
, f4
));
1761 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1762 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1763 ltt_event_get_unsigned(e
, f5
));
1766 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1767 status
= ltt_enum_string_get(ltt_field_type(f6
),
1768 ltt_event_get_unsigned(e
, f6
));
1770 /* The process might exist if a process was forked while performing the sate dump. */
1771 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1772 if(process
== NULL
) {
1773 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1774 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1775 pid
, g_quark_from_string(command
),
1776 &s
->parent
.timestamp
);
1778 /* Keep the stack bottom : a running user mode */
1780 /* Disabled because of inconsistencies in the current statedump states. */
1781 if(mode
== LTTV_STATE_USER_MODE
) {
1782 /* Only keep the bottom */
1783 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1785 /* On top of it : */
1786 LttvExecutionState
*es
;
1787 es
= process
->state
= &g_array_index(process
->execution_stack
,
1788 LttvExecutionState
, 1);
1797 LttvExecutionState
*es
;
1798 es
= process
->state
= &g_array_index(process
->execution_stack
,
1799 LttvExecutionState
, 1);
1800 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1801 es
->s
= LTTV_STATE_UNNAMED
;
1802 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1805 /* The process has already been created :
1806 * Probably was forked while dumping the process state or
1807 * was simply scheduled in prior to get the state dump event.
1809 process
->ppid
= parent_pid
;
1810 process
->name
= g_quark_from_string(command
);
1811 /* Don't mess around with the stack, it will eventually become
1812 * ok after the end of state dump. */
1818 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1820 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1822 lttv_state_add_event_hooks(tss
);
1827 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1829 LttvTraceset
*traceset
= self
->parent
.ts
;
1831 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1835 LttvTracefileState
*tfs
;
1839 LttvTraceHookByFacility
*thf
;
1841 LttvTraceHook
*hook
;
1843 LttvAttributeValue val
;
1848 nb_trace
= lttv_traceset_number(traceset
);
1849 for(i
= 0 ; i
< nb_trace
; i
++) {
1850 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1852 /* Find the eventtype id for the following events and register the
1853 associated by id hooks. */
1855 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1856 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1859 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1860 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1861 LTT_FIELD_SYSCALL_ID
, 0, 0,
1862 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1865 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1866 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1868 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1871 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1872 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1873 LTT_FIELD_TRAP_ID
, 0, 0,
1874 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1877 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1878 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1880 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1883 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1884 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1885 LTT_FIELD_IRQ_ID
, 0, 0,
1886 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1889 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1890 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1892 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1895 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1896 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1897 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1898 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1901 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1902 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1904 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1907 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1908 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1909 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1910 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1913 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1914 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1915 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1916 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1919 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1920 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1921 LTT_FIELD_PID
, 0, 0,
1922 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1926 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1927 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1928 LTT_FIELD_PID
, 0, 0,
1929 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1932 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1933 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1934 LTT_FIELD_PID
, 0, 0,
1935 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1938 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1939 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1940 LTT_FIELD_FILENAME
, 0, 0,
1941 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1944 /* statedump-related hooks */
1945 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1946 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1947 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1948 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1951 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1952 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1953 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1954 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1957 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1958 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1959 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1960 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1963 hooks
= g_array_set_size(hooks
, hn
);
1965 /* Add these hooks to each event_by_id hooks list */
1967 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1969 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1971 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1972 LttvTracefileContext
*, j
));
1974 for(k
= 0 ; k
< hooks
->len
; k
++) {
1975 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1976 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1977 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1979 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1986 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1987 *(val
.v_pointer
) = hooks
;
1991 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1993 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1995 lttv_state_remove_event_hooks(tss
);
2000 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2002 LttvTraceset
*traceset
= self
->parent
.ts
;
2004 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2008 LttvTracefileState
*tfs
;
2012 LttvTraceHook
*hook
;
2014 LttvTraceHookByFacility
*thf
;
2016 LttvAttributeValue val
;
2018 nb_trace
= lttv_traceset_number(traceset
);
2019 for(i
= 0 ; i
< nb_trace
; i
++) {
2020 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2021 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2022 hooks
= *(val
.v_pointer
);
2024 /* Remove these hooks from each event_by_id hooks list */
2026 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2028 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2030 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2031 LttvTracefileContext
*, j
));
2033 for(k
= 0 ; k
< hooks
->len
; k
++) {
2034 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2035 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2036 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2038 lttv_hooks_remove_data(
2039 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2045 for(k
= 0 ; k
< hooks
->len
; k
++)
2046 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2047 g_array_free(hooks
, TRUE
);
2051 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2053 guint
*event_count
= (guint
*)hook_data
;
2055 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2056 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2061 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2063 LttvTracefileState
*tfcs
;
2065 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2067 LttEventPosition
*ep
;
2073 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2075 LttvAttributeValue value
;
2077 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2078 LTTV_STATE_SAVED_STATES
);
2079 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2080 value
= lttv_attribute_add(saved_states_tree
,
2081 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2082 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2083 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2084 *(value
.v_time
) = self
->parent
.timestamp
;
2085 lttv_state_save(tcs
, saved_state_tree
);
2086 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2087 self
->parent
.timestamp
.tv_nsec
);
2089 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2094 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2096 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2098 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2103 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2111 static gboolean
block_start(void *hook_data
, void *call_data
)
2113 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2115 LttvTracefileState
*tfcs
;
2117 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2119 LttEventPosition
*ep
;
2121 guint i
, nb_block
, nb_event
, nb_tracefile
;
2125 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2127 LttvAttributeValue value
;
2129 ep
= ltt_event_position_new();
2131 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2133 /* Count the number of events added since the last block end in any
2136 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2138 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2139 LttvTracefileContext
, i
));
2140 ltt_event_position(tfcs
->parent
.e
, ep
);
2141 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2142 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2143 tfcs
->saved_position
= nb_event
;
2147 if(tcs
->nb_event
>= tcs
->save_interval
) {
2148 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2149 LTTV_STATE_SAVED_STATES
);
2150 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2151 value
= lttv_attribute_add(saved_states_tree
,
2152 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2153 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2154 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2155 *(value
.v_time
) = self
->parent
.timestamp
;
2156 lttv_state_save(tcs
, saved_state_tree
);
2158 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2159 self
->parent
.timestamp
.tv_nsec
);
2161 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2167 static gboolean
block_end(void *hook_data
, void *call_data
)
2169 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2171 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2175 LttEventPosition
*ep
;
2177 guint nb_block
, nb_event
;
2179 ep
= ltt_event_position_new();
2180 ltt_event_position(self
->parent
.e
, ep
);
2181 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2182 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2183 self
->saved_position
= 0;
2184 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2191 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2193 LttvTraceset
*traceset
= self
->parent
.ts
;
2195 guint i
, j
, nb_trace
, nb_tracefile
;
2199 LttvTracefileState
*tfs
;
2201 LttvTraceHook hook_start
, hook_end
;
2203 nb_trace
= lttv_traceset_number(traceset
);
2204 for(i
= 0 ; i
< nb_trace
; i
++) {
2205 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2207 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2208 NULL
, NULL
, block_start
, &hook_start
);
2209 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2210 NULL
, NULL
, block_end
, &hook_end
);
2212 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2214 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2216 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2217 LttvTracefileContext
, j
));
2218 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2219 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2220 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2221 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2227 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2229 LttvTraceset
*traceset
= self
->parent
.ts
;
2231 guint i
, j
, nb_trace
, nb_tracefile
;
2235 LttvTracefileState
*tfs
;
2238 nb_trace
= lttv_traceset_number(traceset
);
2239 for(i
= 0 ; i
< nb_trace
; i
++) {
2241 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2242 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2244 guint
*event_count
= g_new(guint
, 1);
2247 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2249 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2250 LttvTracefileContext
*, j
));
2251 lttv_hooks_add(tfs
->parent
.event
,
2252 state_save_event_hook
,
2259 lttv_process_traceset_begin(&self
->parent
,
2260 NULL
, NULL
, NULL
, NULL
, NULL
);
2264 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2266 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2268 lttv_state_save_add_event_hooks(tss
);
2275 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2277 LttvTraceset
*traceset
= self
->parent
.ts
;
2279 guint i
, j
, nb_trace
, nb_tracefile
;
2283 LttvTracefileState
*tfs
;
2285 LttvTraceHook hook_start
, hook_end
;
2287 nb_trace
= lttv_traceset_number(traceset
);
2288 for(i
= 0 ; i
< nb_trace
; i
++) {
2289 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2291 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2292 NULL
, NULL
, block_start
, &hook_start
);
2294 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2295 NULL
, NULL
, block_end
, &hook_end
);
2297 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2299 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2301 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2302 LttvTracefileContext
, j
));
2303 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2304 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2305 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2306 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2312 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2314 LttvTraceset
*traceset
= self
->parent
.ts
;
2316 guint i
, j
, nb_trace
, nb_tracefile
;
2320 LttvTracefileState
*tfs
;
2322 LttvHooks
*after_trace
= lttv_hooks_new();
2324 lttv_hooks_add(after_trace
,
2325 state_save_after_trace_hook
,
2330 lttv_process_traceset_end(&self
->parent
,
2331 NULL
, after_trace
, NULL
, NULL
, NULL
);
2333 lttv_hooks_destroy(after_trace
);
2335 nb_trace
= lttv_traceset_number(traceset
);
2336 for(i
= 0 ; i
< nb_trace
; i
++) {
2338 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2339 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2341 guint
*event_count
= NULL
;
2343 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2345 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2346 LttvTracefileContext
*, j
));
2347 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2348 state_save_event_hook
);
2350 if(event_count
) g_free(event_count
);
2354 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2356 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2358 lttv_state_save_remove_event_hooks(tss
);
2363 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2365 LttvTraceset
*traceset
= self
->parent
.ts
;
2369 int min_pos
, mid_pos
, max_pos
;
2371 guint call_rest
= 0;
2373 LttvTraceState
*tcs
;
2375 LttvAttributeValue value
;
2377 LttvAttributeType type
;
2379 LttvAttributeName name
;
2383 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2385 //g_tree_destroy(self->parent.pqueue);
2386 //self->parent.pqueue = g_tree_new(compare_tracefile);
2388 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2390 nb_trace
= lttv_traceset_number(traceset
);
2391 for(i
= 0 ; i
< nb_trace
; i
++) {
2392 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2394 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2395 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2396 LTTV_STATE_SAVED_STATES
);
2399 if(saved_states_tree
) {
2400 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2401 mid_pos
= max_pos
/ 2;
2402 while(min_pos
< max_pos
) {
2403 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2405 g_assert(type
== LTTV_GOBJECT
);
2406 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2407 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2409 g_assert(type
== LTTV_TIME
);
2410 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2412 closest_tree
= saved_state_tree
;
2414 else max_pos
= mid_pos
- 1;
2416 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2420 /* restore the closest earlier saved state */
2422 lttv_state_restore(tcs
, closest_tree
);
2426 /* There is no saved state, yet we want to have it. Restart at T0 */
2428 restore_init_state(tcs
);
2429 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2432 /* We want to seek quickly without restoring/updating the state */
2434 restore_init_state(tcs
);
2435 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2438 if(!call_rest
) g_info("NOT Calling restore");
2443 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2449 traceset_state_finalize (LttvTracesetState
*self
)
2451 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2452 finalize(G_OBJECT(self
));
2457 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2459 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2461 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2462 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2463 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2464 klass
->new_traceset_context
= new_traceset_context
;
2465 klass
->new_trace_context
= new_trace_context
;
2466 klass
->new_tracefile_context
= new_tracefile_context
;
2471 lttv_traceset_state_get_type(void)
2473 static GType type
= 0;
2475 static const GTypeInfo info
= {
2476 sizeof (LttvTracesetStateClass
),
2477 NULL
, /* base_init */
2478 NULL
, /* base_finalize */
2479 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2480 NULL
, /* class_finalize */
2481 NULL
, /* class_data */
2482 sizeof (LttvTracesetState
),
2483 0, /* n_preallocs */
2484 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2485 NULL
/* value handling */
2488 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2496 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2502 trace_state_finalize (LttvTraceState
*self
)
2504 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2505 finalize(G_OBJECT(self
));
2510 trace_state_class_init (LttvTraceStateClass
*klass
)
2512 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2514 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2515 klass
->state_save
= state_save
;
2516 klass
->state_restore
= state_restore
;
2517 klass
->state_saved_free
= state_saved_free
;
2522 lttv_trace_state_get_type(void)
2524 static GType type
= 0;
2526 static const GTypeInfo info
= {
2527 sizeof (LttvTraceStateClass
),
2528 NULL
, /* base_init */
2529 NULL
, /* base_finalize */
2530 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2531 NULL
, /* class_finalize */
2532 NULL
, /* class_data */
2533 sizeof (LttvTraceState
),
2534 0, /* n_preallocs */
2535 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2536 NULL
/* value handling */
2539 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2540 "LttvTraceStateType", &info
, 0);
2547 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2553 tracefile_state_finalize (LttvTracefileState
*self
)
2555 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2556 finalize(G_OBJECT(self
));
2561 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2563 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2565 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2570 lttv_tracefile_state_get_type(void)
2572 static GType type
= 0;
2574 static const GTypeInfo info
= {
2575 sizeof (LttvTracefileStateClass
),
2576 NULL
, /* base_init */
2577 NULL
, /* base_finalize */
2578 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2579 NULL
, /* class_finalize */
2580 NULL
, /* class_data */
2581 sizeof (LttvTracefileState
),
2582 0, /* n_preallocs */
2583 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2584 NULL
/* value handling */
2587 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2588 "LttvTracefileStateType", &info
, 0);
2594 static void module_init()
2596 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2597 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2598 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2599 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2600 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2601 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2602 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2603 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2604 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2605 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2606 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2607 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2608 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2609 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2610 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2611 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2612 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2613 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2614 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2615 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2616 LTTV_STATE_EVENT
= g_quark_from_string("event");
2617 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2618 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2619 LTTV_STATE_TIME
= g_quark_from_string("time");
2620 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2621 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2622 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2623 g_quark_from_string("trace_state_use_count");
2626 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2627 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2628 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2629 LTT_FACILITY_FS
= g_quark_from_string("fs");
2630 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2631 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2634 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2635 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2636 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2637 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2638 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2639 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2640 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2641 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2642 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2643 LTT_EVENT_FORK
= g_quark_from_string("fork");
2644 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2645 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2646 LTT_EVENT_FREE
= g_quark_from_string("free");
2647 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2648 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2649 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2650 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2653 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2654 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2655 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2656 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2657 LTT_FIELD_OUT
= g_quark_from_string("out");
2658 LTT_FIELD_IN
= g_quark_from_string("in");
2659 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2660 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2661 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2662 LTT_FIELD_PID
= g_quark_from_string("pid");
2663 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2664 LTT_FIELD_NAME
= g_quark_from_string("name");
2665 LTT_FIELD_MODE
= g_quark_from_string("mode");
2666 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2667 LTT_FIELD_STATUS
= g_quark_from_string("status");
2668 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2669 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2673 static void module_destroy()
2678 LTTV_MODULE("state", "State computation", \
2679 "Update the system state, possibly saving it at intervals", \
2680 module_init
, module_destroy
)