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
= process
->current_function
;
514 g_hash_table_insert(new_processes
, new_process
, new_process
);
518 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
520 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
522 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
523 return new_processes
;
527 /* The saved state for each trace contains a member "processes", which
528 stores a copy of the process table, and a member "tracefiles" with
529 one entry per tracefile. Each tracefile has a "process" member pointing
530 to the current process and a "position" member storing the tracefile
531 position (needed to seek to the current "next" event. */
533 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
535 guint i
, nb_tracefile
, nb_cpus
;
537 LttvTracefileState
*tfcs
;
539 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
541 guint
*running_process
;
543 LttvAttributeType type
;
545 LttvAttributeValue value
;
547 LttvAttributeName name
;
549 LttEventPosition
*ep
;
551 tracefiles_tree
= lttv_attribute_find_subdir(container
,
552 LTTV_STATE_TRACEFILES
);
554 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
556 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
558 /* Add the currently running processes array */
559 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
560 running_process
= g_new(guint
, nb_cpus
);
561 for(i
=0;i
<nb_cpus
;i
++) {
562 running_process
[i
] = self
->running_process
[i
]->pid
;
564 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
566 *(value
.v_pointer
) = running_process
;
568 g_info("State save");
570 nb_tracefile
= self
->parent
.tracefiles
->len
;
572 for(i
= 0 ; i
< nb_tracefile
; i
++) {
574 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
575 LttvTracefileContext
*, i
));
576 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
577 value
= lttv_attribute_add(tracefiles_tree
, i
,
579 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
581 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
583 *(value
.v_uint
) = tfcs
->process
->pid
;
585 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
587 /* Only save the position if the tfs has not infinite time. */
588 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
589 // && current_tfcs != tfcs) {
590 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
591 *(value
.v_pointer
) = NULL
;
593 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
594 ep
= ltt_event_position_new();
595 ltt_event_position(e
, ep
);
596 *(value
.v_pointer
) = ep
;
598 guint nb_block
, offset
;
601 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
602 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
604 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
610 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
612 guint i
, nb_tracefile
, pid
, nb_cpus
;
614 LttvTracefileState
*tfcs
;
616 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
618 guint
*running_process
;
620 LttvAttributeType type
;
622 LttvAttributeValue value
;
624 LttvAttributeName name
;
628 LttEventPosition
*ep
;
630 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
632 tracefiles_tree
= lttv_attribute_find_subdir(container
,
633 LTTV_STATE_TRACEFILES
);
635 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
637 g_assert(type
== LTTV_POINTER
);
638 lttv_state_free_process_table(self
->processes
);
639 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
641 /* Add the currently running processes array */
642 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
643 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
645 g_assert(type
== LTTV_POINTER
);
646 running_process
= *(value
.v_pointer
);
647 for(i
=0;i
<nb_cpus
;i
++) {
648 pid
= running_process
[i
];
649 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
650 g_assert(self
->running_process
[i
] != NULL
);
654 nb_tracefile
= self
->parent
.tracefiles
->len
;
656 //g_tree_destroy(tsc->pqueue);
657 //tsc->pqueue = g_tree_new(compare_tracefile);
659 for(i
= 0 ; i
< nb_tracefile
; i
++) {
661 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
662 LttvTracefileContext
*, i
));
663 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
664 g_assert(type
== LTTV_GOBJECT
);
665 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
667 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
669 g_assert(type
== LTTV_UINT
);
670 pid
= *(value
.v_uint
);
671 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
673 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
675 g_assert(type
== LTTV_POINTER
);
676 //g_assert(*(value.v_pointer) != NULL);
677 ep
= *(value
.v_pointer
);
678 g_assert(tfcs
->parent
.t_context
!= NULL
);
680 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
681 g_tree_remove(tsc
->pqueue
, tfc
);
684 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
685 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
686 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
687 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
688 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
690 tfc
->timestamp
= ltt_time_infinite
;
696 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
698 guint i
, nb_tracefile
, nb_cpus
;
700 LttvTracefileState
*tfcs
;
702 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
704 guint
*running_process
;
706 LttvAttributeType type
;
708 LttvAttributeValue value
;
710 LttvAttributeName name
;
714 LttEventPosition
*ep
;
716 tracefiles_tree
= lttv_attribute_find_subdir(container
,
717 LTTV_STATE_TRACEFILES
);
718 g_object_ref(G_OBJECT(tracefiles_tree
));
719 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
721 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
723 g_assert(type
== LTTV_POINTER
);
724 lttv_state_free_process_table(*(value
.v_pointer
));
725 *(value
.v_pointer
) = NULL
;
726 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
728 /* Free running processes array */
729 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
732 g_assert(type
== LTTV_POINTER
);
733 running_process
= *(value
.v_pointer
);
734 g_free(running_process
);
736 nb_tracefile
= self
->parent
.tracefiles
->len
;
738 for(i
= 0 ; i
< nb_tracefile
; i
++) {
740 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
741 LttvTracefileContext
*, i
));
742 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
743 g_assert(type
== LTTV_GOBJECT
);
744 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
746 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
748 g_assert(type
== LTTV_POINTER
);
749 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
751 g_object_unref(G_OBJECT(tracefiles_tree
));
755 static void free_saved_state(LttvTraceState
*self
)
759 LttvAttributeType type
;
761 LttvAttributeValue value
;
763 LttvAttributeName name
;
767 LttvAttribute
*saved_states
;
769 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
770 LTTV_STATE_SAVED_STATES
);
772 nb
= lttv_attribute_get_number(saved_states
);
773 for(i
= 0 ; i
< nb
; i
++) {
774 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
775 g_assert(type
== LTTV_GOBJECT
);
776 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
779 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
784 create_max_time(LttvTraceState
*tcs
)
786 LttvAttributeValue v
;
788 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
790 g_assert(*(v
.v_pointer
) == NULL
);
791 *(v
.v_pointer
) = g_new(LttTime
,1);
792 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
797 get_max_time(LttvTraceState
*tcs
)
799 LttvAttributeValue v
;
801 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
803 g_assert(*(v
.v_pointer
) != NULL
);
804 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
809 free_max_time(LttvTraceState
*tcs
)
811 LttvAttributeValue v
;
813 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
815 g_free(*(v
.v_pointer
));
816 *(v
.v_pointer
) = NULL
;
820 typedef struct _LttvNameTables
{
821 // FIXME GQuark *eventtype_names;
822 GQuark
*syscall_names
;
826 GQuark
*soft_irq_names
;
831 create_name_tables(LttvTraceState
*tcs
)
835 GQuark f_name
, e_name
;
839 LttvTraceHookByFacility
*thf
;
845 GString
*fe_name
= g_string_new("");
847 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
849 LttvAttributeValue v
;
851 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
853 g_assert(*(v
.v_pointer
) == NULL
);
854 *(v
.v_pointer
) = name_tables
;
855 #if 0 // Use iteration over the facilities_by_name and then list all event
856 // types of each facility
857 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
858 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
859 for(i
= 0 ; i
< nb
; i
++) {
860 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
861 e_name
= ltt_eventtype_name(et
);
862 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
863 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
864 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
867 if(lttv_trace_find_hook(tcs
->parent
.t
,
868 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
869 LTT_FIELD_SYSCALL_ID
, 0, 0,
873 thf
= lttv_trace_hook_get_first(&h
);
875 t
= ltt_field_type(thf
->f1
);
876 nb
= ltt_type_element_number(t
);
878 lttv_trace_hook_destroy(&h
);
880 name_tables
->syscall_names
= g_new(GQuark
, nb
);
881 name_tables
->nb_syscalls
= nb
;
883 for(i
= 0 ; i
< nb
; i
++) {
884 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
887 //name_tables->syscall_names = g_new(GQuark, 256);
888 //for(i = 0 ; i < 256 ; i++) {
889 // g_string_printf(fe_name, "syscall %d", i);
890 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
893 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
894 LTT_EVENT_TRAP_ENTRY
,
895 LTT_FIELD_TRAP_ID
, 0, 0,
899 thf
= lttv_trace_hook_get_first(&h
);
901 t
= ltt_field_type(thf
->f1
);
902 //nb = ltt_type_element_number(t);
904 lttv_trace_hook_destroy(&h
);
907 name_tables->trap_names = g_new(GQuark, nb);
908 for(i = 0 ; i < nb ; i++) {
909 name_tables->trap_names[i] = g_quark_from_string(
910 ltt_enum_string_get(t, i));
914 name_tables
->trap_names
= g_new(GQuark
, 256);
915 for(i
= 0 ; i
< 256 ; i
++) {
916 g_string_printf(fe_name
, "trap %d", i
);
917 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
920 if(lttv_trace_find_hook(tcs
->parent
.t
,
921 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
922 LTT_FIELD_IRQ_ID
, 0, 0,
926 thf
= lttv_trace_hook_get_first(&h
);
928 t
= ltt_field_type(thf
->f1
);
929 //nb = ltt_type_element_number(t);
931 lttv_trace_hook_destroy(&h
);
934 name_tables->irq_names = g_new(GQuark, nb);
935 for(i = 0 ; i < nb ; i++) {
936 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
940 name_tables
->irq_names
= g_new(GQuark
, 256);
941 for(i
= 0 ; i
< 256 ; i
++) {
942 g_string_printf(fe_name
, "irq %d", i
);
943 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
947 name_tables->soft_irq_names = g_new(GQuark, nb);
948 for(i = 0 ; i < nb ; i++) {
949 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
953 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
954 for(i
= 0 ; i
< 256 ; i
++) {
955 g_string_printf(fe_name
, "softirq %d", i
);
956 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
960 g_string_free(fe_name
, TRUE
);
965 get_name_tables(LttvTraceState
*tcs
)
967 LttvNameTables
*name_tables
;
969 LttvAttributeValue v
;
971 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
973 g_assert(*(v
.v_pointer
) != NULL
);
974 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
975 //tcs->eventtype_names = name_tables->eventtype_names;
976 tcs
->syscall_names
= name_tables
->syscall_names
;
977 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
978 tcs
->trap_names
= name_tables
->trap_names
;
979 tcs
->irq_names
= name_tables
->irq_names
;
980 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
985 free_name_tables(LttvTraceState
*tcs
)
987 LttvNameTables
*name_tables
;
989 LttvAttributeValue v
;
991 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
993 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
994 *(v
.v_pointer
) = NULL
;
996 // g_free(name_tables->eventtype_names);
997 g_free(name_tables
->syscall_names
);
998 g_free(name_tables
->trap_names
);
999 g_free(name_tables
->irq_names
);
1000 g_free(name_tables
->soft_irq_names
);
1001 g_free(name_tables
);
1004 #ifdef HASH_TABLE_DEBUG
1006 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1008 LttvProcessState
*process
= (LttvProcessState
*)value
;
1010 /* Test for process corruption */
1011 guint stack_len
= process
->execution_stack
->len
;
1014 static void hash_table_check(GHashTable
*table
)
1016 g_hash_table_foreach(table
, test_process
, NULL
);
1023 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1026 LttvExecutionState
*es
;
1028 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1029 guint cpu
= tfs
->cpu
;
1031 #ifdef HASH_TABLE_DEBUG
1032 hash_table_check(ts
->processes
);
1034 LttvProcessState
*process
= ts
->running_process
[cpu
];
1036 guint depth
= process
->execution_stack
->len
;
1038 process
->execution_stack
=
1039 g_array_set_size(process
->execution_stack
, depth
+ 1);
1042 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1044 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1047 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1048 es
->cum_cpu_time
= ltt_time_zero
;
1049 es
->s
= process
->state
->s
;
1050 process
->state
= es
;
1054 * return 1 when empty, else 0 */
1055 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1056 LttvTracefileState
*tfs
)
1058 guint cpu
= tfs
->cpu
;
1059 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1061 guint depth
= process
->execution_stack
->len
;
1067 process
->execution_stack
=
1068 g_array_set_size(process
->execution_stack
, depth
- 1);
1069 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1071 process
->state
->change
= tfs
->parent
.timestamp
;
1076 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1078 guint cpu
= tfs
->cpu
;
1079 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1080 LttvProcessState
*process
= ts
->running_process
[cpu
];
1082 guint depth
= process
->execution_stack
->len
;
1084 if(process
->state
->t
!= t
){
1085 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1086 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1087 g_info("process state has %s when pop_int is %s\n",
1088 g_quark_to_string(process
->state
->t
),
1089 g_quark_to_string(t
));
1090 g_info("{ %u, %u, %s, %s }\n",
1093 g_quark_to_string(process
->name
),
1094 g_quark_to_string(process
->state
->s
));
1099 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1100 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1104 process
->execution_stack
=
1105 g_array_set_size(process
->execution_stack
, depth
- 1);
1106 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1108 process
->state
->change
= tfs
->parent
.timestamp
;
1111 struct search_result
{
1112 const LttTime
*time
; /* Requested time */
1113 LttTime
*best
; /* Best result */
1116 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1118 const LttTime
*elem_time
= (const LttTime
*)a
;
1119 /* Explicit non const cast */
1120 struct search_result
*res
= (struct search_result
*)b
;
1122 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1123 /* The usertrace was created before the schedchange */
1124 /* Get larger keys */
1126 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1127 /* The usertrace was created after the schedchange time */
1128 /* Get smaller keys */
1130 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1131 res
->best
= elem_time
;
1134 res
->best
= elem_time
;
1141 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1142 guint pid
, const LttTime
*timestamp
)
1144 LttvTracefileState
*tfs
= NULL
;
1145 struct search_result res
;
1146 /* Find the usertrace associated with a pid and time interval.
1147 * Search in the usertraces by PID (within a hash) and then, for each
1148 * corresponding element of the array, find the first one with creation
1149 * timestamp the lowest, but higher or equal to "timestamp". */
1150 res
.time
= timestamp
;
1152 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1153 if(usertrace_tree
) {
1154 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1156 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1164 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1165 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1167 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1169 LttvExecutionState
*es
;
1171 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1177 process
->name
= name
;
1178 //process->last_cpu = tfs->cpu_name;
1179 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1180 process
->kernel_thread
= 0;
1181 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1182 process
->current_function
= 0; //function 0x0 by default.
1184 g_info("Process %u, core %p", process
->pid
, process
);
1185 g_hash_table_insert(tcs
->processes
, process
, process
);
1188 process
->ppid
= parent
->pid
;
1189 process
->creation_time
= *timestamp
;
1192 /* No parent. This process exists but we are missing all information about
1193 its creation. The birth time is set to zero but we remember the time of
1198 process
->creation_time
= ltt_time_zero
;
1201 process
->insertion_time
= *timestamp
;
1202 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1203 process
->creation_time
.tv_nsec
);
1204 process
->pid_time
= g_quark_from_string(buffer
);
1206 //process->last_cpu = tfs->cpu_name;
1207 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1208 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1209 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1210 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1211 es
= process
->state
= &g_array_index(process
->execution_stack
,
1212 LttvExecutionState
, 0);
1213 es
->t
= LTTV_STATE_USER_MODE
;
1214 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1215 es
->entry
= *timestamp
;
1216 //g_assert(timestamp->tv_sec != 0);
1217 es
->change
= *timestamp
;
1218 es
->cum_cpu_time
= ltt_time_zero
;
1219 es
->s
= LTTV_STATE_RUN
;
1221 es
= process
->state
= &g_array_index(process
->execution_stack
,
1222 LttvExecutionState
, 1);
1223 es
->t
= LTTV_STATE_SYSCALL
;
1224 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1225 es
->entry
= *timestamp
;
1226 //g_assert(timestamp->tv_sec != 0);
1227 es
->change
= *timestamp
;
1228 es
->cum_cpu_time
= ltt_time_zero
;
1229 es
->s
= LTTV_STATE_WAIT_FORK
;
1231 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1232 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1233 sizeof(guint64
), 0);
1238 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1241 LttvProcessState key
;
1242 LttvProcessState
*process
;
1246 process
= g_hash_table_lookup(ts
->processes
, &key
);
1251 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1254 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1255 LttvExecutionState
*es
;
1257 /* Put ltt_time_zero creation time for unexisting processes */
1258 if(unlikely(process
== NULL
)) {
1259 process
= lttv_state_create_process(ts
,
1260 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1261 /* We are not sure is it's a kernel thread or normal thread, put the
1262 * bottom stack state to unknown */
1263 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1264 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1269 /* FIXME : this function should be called when we receive an event telling that
1270 * release_task has been called in the kernel. In happens generally when
1271 * the parent waits for its child terminaison, but may also happen in special
1272 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1273 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1274 * of a killed thread ground, but isn't the leader.
1276 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1278 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1279 LttvProcessState key
;
1281 key
.pid
= process
->pid
;
1282 key
.cpu
= process
->cpu
;
1283 g_hash_table_remove(ts
->processes
, &key
);
1284 g_array_free(process
->execution_stack
, TRUE
);
1285 g_array_free(process
->user_stack
, TRUE
);
1290 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1292 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1293 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1298 static void lttv_state_free_process_table(GHashTable
*processes
)
1300 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1301 g_hash_table_destroy(processes
);
1305 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1307 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1308 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1309 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1310 LttField
*f
= thf
->f1
;
1312 LttvExecutionSubmode submode
;
1314 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1315 guint syscall
= ltt_event_get_unsigned(e
, f
);
1317 if(syscall
< nb_syscalls
) {
1318 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1321 /* Fixup an incomplete syscall table */
1322 GString
*string
= g_string_new("");
1323 g_string_printf(string
, "syscall %u", syscall
);
1324 submode
= g_quark_from_string(string
->str
);
1325 g_string_free(string
, TRUE
);
1327 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1332 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1334 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1336 pop_state(s
, LTTV_STATE_SYSCALL
);
1341 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1343 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1344 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1345 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1346 LttField
*f
= thf
->f1
;
1348 LttvExecutionSubmode submode
;
1350 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1351 ltt_event_get_unsigned(e
, f
)];
1352 push_state(s
, LTTV_STATE_TRAP
, submode
);
1357 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1359 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1361 pop_state(s
, LTTV_STATE_TRAP
);
1366 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1368 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1369 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1370 guint8 fac_id
= ltt_event_facility_id(e
);
1371 guint8 ev_id
= ltt_event_eventtype_id(e
);
1372 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1373 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1374 g_assert(thf
->f1
!= NULL
);
1375 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1376 LttField
*f
= thf
->f1
;
1378 LttvExecutionSubmode submode
;
1380 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1381 ltt_event_get_unsigned(e
, f
)];
1383 /* Do something with the info about being in user or system mode when int? */
1384 push_state(s
, LTTV_STATE_IRQ
, submode
);
1388 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1390 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1392 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1398 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1400 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1402 pop_state(s
, LTTV_STATE_IRQ
);
1406 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1408 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1409 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1410 guint8 fac_id
= ltt_event_facility_id(e
);
1411 guint8 ev_id
= ltt_event_eventtype_id(e
);
1412 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1413 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1414 g_assert(thf
->f1
!= NULL
);
1415 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1416 LttField
*f
= thf
->f1
;
1418 LttvExecutionSubmode submode
;
1420 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1421 ltt_event_get_unsigned(e
, f
)];
1423 /* Do something with the info about being in user or system mode when int? */
1424 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1428 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1432 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1433 guint cpu
= tfs
->cpu
;
1434 LttvProcessState
*process
= ts
->running_process
[cpu
];
1436 guint depth
= process
->user_stack
->len
;
1438 process
->user_stack
=
1439 g_array_set_size(process
->user_stack
, depth
+ 1);
1441 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1442 *new_func
= funcptr
;
1443 process
->current_function
= funcptr
;
1446 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1448 guint cpu
= tfs
->cpu
;
1449 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1450 LttvProcessState
*process
= ts
->running_process
[cpu
];
1452 if(process
->current_function
!= funcptr
){
1453 g_info("Different functions (%lu.%09lu): ignore it\n",
1454 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1455 g_info("process state has %llu when pop_function is %llu\n",
1456 process
->current_function
, funcptr
);
1457 g_info("{ %u, %u, %s, %s }\n",
1460 g_quark_to_string(process
->name
),
1461 g_quark_to_string(process
->state
->s
));
1464 guint depth
= process
->user_stack
->len
;
1467 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1468 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1472 process
->user_stack
=
1473 g_array_set_size(process
->user_stack
, depth
- 1);
1474 process
->current_function
=
1475 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1479 static gboolean
function_entry(void *hook_data
, void *call_data
)
1481 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1482 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1483 guint8 fac_id
= ltt_event_facility_id(e
);
1484 guint8 ev_id
= ltt_event_eventtype_id(e
);
1485 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1486 g_assert(thf
->f1
!= NULL
);
1487 LttField
*f
= thf
->f1
;
1488 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1490 push_function(s
, funcptr
);
1494 static gboolean
function_exit(void *hook_data
, void *call_data
)
1496 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1497 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1498 guint8 fac_id
= ltt_event_facility_id(e
);
1499 guint8 ev_id
= ltt_event_eventtype_id(e
);
1500 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1501 g_assert(thf
->f1
!= NULL
);
1502 LttField
*f
= thf
->f1
;
1503 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1505 LttvExecutionSubmode submode
;
1507 pop_function(s
, funcptr
);
1511 static gboolean
schedchange(void *hook_data
, void *call_data
)
1513 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1515 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1516 LttvProcessState
*process
= ts
->running_process
[cpu
];
1517 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1519 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1520 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1521 guint pid_in
, pid_out
;
1524 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1525 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1526 state_out
= ltt_event_get_int(e
, thf
->f3
);
1528 if(likely(process
!= NULL
)) {
1530 /* We could not know but it was not the idle process executing.
1531 This should only happen at the beginning, before the first schedule
1532 event, and when the initial information (current process for each CPU)
1533 is missing. It is not obvious how we could, after the fact, compensate
1534 the wrongly attributed statistics. */
1536 //This test only makes sense once the state is known and if there is no
1537 //missing events. We need to silently ignore schedchange coming after a
1538 //process_free, or it causes glitches. (FIXME)
1539 //if(unlikely(process->pid != pid_out)) {
1540 // g_assert(process->pid == 0);
1543 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1544 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1545 process
->state
->change
= s
->parent
.timestamp
;
1547 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1548 else process
->state
->s
= LTTV_STATE_WAIT
;
1549 process
->state
->change
= s
->parent
.timestamp
;
1553 exit_process(s
, process
); /* EXIT_DEAD */
1554 /* see sched.h for states */
1556 process
= ts
->running_process
[cpu
] =
1557 lttv_state_find_process_or_create(
1558 (LttvTraceState
*)s
->parent
.t_context
,
1560 &s
->parent
.timestamp
);
1561 process
->state
->s
= LTTV_STATE_RUN
;
1563 if(process
->usertrace
)
1564 process
->usertrace
->cpu
= cpu
;
1565 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1566 process
->state
->change
= s
->parent
.timestamp
;
1570 static gboolean
process_fork(void *hook_data
, void *call_data
)
1572 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1573 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1574 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1577 LttvProcessState
*zombie_process
;
1579 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1580 LttvProcessState
*process
= ts
->running_process
[cpu
];
1581 LttvProcessState
*child_process
;
1584 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1587 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1589 /* Mathieu : it seems like the process might have been scheduled in before the
1590 * fork, and, in a rare case, might be the current process. This might happen
1591 * in a SMP case where we don't have enough precision on the clocks.
1593 * Test reenabled after precision fixes on time. (Mathieu) */
1595 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1597 if(unlikely(zombie_process
!= NULL
)) {
1598 /* Reutilisation of PID. Only now we are sure that the old PID
1599 * has been released. FIXME : should know when release_task happens instead.
1601 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1603 for(i
=0; i
< num_cpus
; i
++) {
1604 g_assert(zombie_process
!= ts
->running_process
[i
]);
1607 exit_process(s
, zombie_process
);
1610 g_assert(process
->pid
!= child_pid
);
1611 // FIXME : Add this test in the "known state" section
1612 // g_assert(process->pid == parent_pid);
1613 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1614 if(child_process
== NULL
) {
1615 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1616 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1618 /* The process has already been created : due to time imprecision between
1619 * multiple CPUs : it has been scheduled in before creation. Note that we
1620 * shouldn't have this kind of imprecision.
1622 * Simply put a correct parent.
1624 g_assert(0); /* This is a problematic case : the process has been created
1625 before the fork event */
1626 child_process
->ppid
= process
->pid
;
1628 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1629 child_process
->name
= process
->name
;
1634 /* We stamp a newly created process as kernel_thread */
1635 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1637 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1638 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1639 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1642 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1643 LttvProcessState
*process
;
1644 LttvExecutionState
*es
;
1647 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1649 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1650 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1651 es
->t
= LTTV_STATE_SYSCALL
;
1652 process
->kernel_thread
= 1;
1657 static gboolean
process_exit(void *hook_data
, void *call_data
)
1659 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1660 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1661 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1665 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1666 LttvProcessState
*process
= ts
->running_process
[cpu
];
1668 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1670 // FIXME : Add this test in the "known state" section
1671 // g_assert(process->pid == pid);
1673 if(likely(process
!= NULL
)) {
1674 process
->state
->s
= LTTV_STATE_EXIT
;
1679 static gboolean
process_free(void *hook_data
, void *call_data
)
1681 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1682 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1683 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1684 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1686 LttvProcessState
*process
;
1688 /* PID of the process to release */
1689 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1691 g_assert(release_pid
!= 0);
1693 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1695 if(likely(process
!= NULL
)) {
1696 /* release_task is happening at kernel level : we can now safely release
1697 * the data structure of the process */
1698 //This test is fun, though, as it may happen that
1699 //at time t : CPU 0 : process_free
1700 //at time t+150ns : CPU 1 : schedule out
1701 //Clearly due to time imprecision, we disable it. (Mathieu)
1702 //If this weird case happen, we have no choice but to put the
1703 //Currently running process on the cpu to 0.
1704 //I re-enable it following time precision fixes. (Mathieu)
1705 //Well, in the case where an process is freed by a process on another CPU
1706 //and still scheduled, it happens that this is the schedchange that will
1707 //drop the last reference count. Do not free it here!
1708 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1710 for(i
=0; i
< num_cpus
; i
++) {
1711 //g_assert(process != ts->running_process[i]);
1712 if(process
== ts
->running_process
[i
]) {
1713 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1717 //if(i == num_cpus) /* process is not scheduled */
1718 //exit_process(s, process); // do nothing : wait for the schedchange to
1719 //delete the process.
1726 static gboolean
process_exec(void *hook_data
, void *call_data
)
1728 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1729 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1730 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1731 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1734 LttvProcessState
*process
= ts
->running_process
[cpu
];
1736 /* PID of the process to release */
1737 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1738 //name = ltt_event_get_string(e, thf->f1);
1739 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1741 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1742 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1743 memcpy(null_term_name
, name_begin
, name_len
);
1744 null_term_name
[name_len
] = '\0';
1746 process
->name
= g_quark_from_string(null_term_name
);
1747 g_free(null_term_name
);
1751 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1753 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1754 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1755 //It's slow : optimise later by doing this before reading trace.
1756 LttEventType
*et
= ltt_event_eventtype(e
);
1758 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1763 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1764 LttvProcessState
*process
= ts
->running_process
[cpu
];
1765 LttvProcessState
*parent_process
;
1766 LttField
*f4
, *f5
, *f6
;
1767 GQuark mode
, submode
, status
;
1770 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1773 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1776 command
= ltt_event_get_string(e
, thf
->f3
);
1779 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1780 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1781 ltt_event_get_unsigned(e
, f4
));
1784 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1785 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1786 ltt_event_get_unsigned(e
, f5
));
1789 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1790 status
= ltt_enum_string_get(ltt_field_type(f6
),
1791 ltt_event_get_unsigned(e
, f6
));
1793 /* The process might exist if a process was forked while performing the sate dump. */
1794 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1795 if(process
== NULL
) {
1796 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1797 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1798 pid
, g_quark_from_string(command
),
1799 &s
->parent
.timestamp
);
1801 /* Keep the stack bottom : a running user mode */
1803 /* Disabled because of inconsistencies in the current statedump states. */
1804 if(mode
== LTTV_STATE_USER_MODE
) {
1805 /* Only keep the bottom */
1806 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1808 /* On top of it : */
1809 LttvExecutionState
*es
;
1810 es
= process
->state
= &g_array_index(process
->execution_stack
,
1811 LttvExecutionState
, 1);
1820 LttvExecutionState
*es
;
1821 es
= process
->state
= &g_array_index(process
->execution_stack
,
1822 LttvExecutionState
, 1);
1823 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1824 es
->s
= LTTV_STATE_UNNAMED
;
1825 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1828 /* The process has already been created :
1829 * Probably was forked while dumping the process state or
1830 * was simply scheduled in prior to get the state dump event.
1832 process
->ppid
= parent_pid
;
1833 process
->name
= g_quark_from_string(command
);
1834 /* Don't mess around with the stack, it will eventually become
1835 * ok after the end of state dump. */
1841 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1843 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1845 lttv_state_add_event_hooks(tss
);
1850 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1852 LttvTraceset
*traceset
= self
->parent
.ts
;
1854 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1858 LttvTracefileState
*tfs
;
1862 LttvTraceHookByFacility
*thf
;
1864 LttvTraceHook
*hook
;
1866 LttvAttributeValue val
;
1871 nb_trace
= lttv_traceset_number(traceset
);
1872 for(i
= 0 ; i
< nb_trace
; i
++) {
1873 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1875 /* Find the eventtype id for the following events and register the
1876 associated by id hooks. */
1878 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1879 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1882 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1883 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1884 LTT_FIELD_SYSCALL_ID
, 0, 0,
1885 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1888 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1889 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1891 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1894 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1895 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1896 LTT_FIELD_TRAP_ID
, 0, 0,
1897 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1900 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1901 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1903 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1906 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1907 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1908 LTT_FIELD_IRQ_ID
, 0, 0,
1909 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1912 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1913 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1915 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1918 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1919 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1920 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1921 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1924 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1925 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1927 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1930 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1931 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1932 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1933 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1936 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1937 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1938 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1939 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1942 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1943 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1944 LTT_FIELD_PID
, 0, 0,
1945 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1949 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1950 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1951 LTT_FIELD_PID
, 0, 0,
1952 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1955 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1956 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1957 LTT_FIELD_PID
, 0, 0,
1958 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1961 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1962 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1963 LTT_FIELD_FILENAME
, 0, 0,
1964 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1967 /* statedump-related hooks */
1968 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1969 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1970 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1971 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1974 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1975 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1976 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1977 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1980 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1981 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1982 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1983 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1986 hooks
= g_array_set_size(hooks
, hn
);
1988 /* Add these hooks to each event_by_id hooks list */
1990 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1992 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1994 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1995 LttvTracefileContext
*, j
));
1997 for(k
= 0 ; k
< hooks
->len
; k
++) {
1998 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1999 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2000 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2002 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2009 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2010 *(val
.v_pointer
) = hooks
;
2014 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2016 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2018 lttv_state_remove_event_hooks(tss
);
2023 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2025 LttvTraceset
*traceset
= self
->parent
.ts
;
2027 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2031 LttvTracefileState
*tfs
;
2035 LttvTraceHook
*hook
;
2037 LttvTraceHookByFacility
*thf
;
2039 LttvAttributeValue val
;
2041 nb_trace
= lttv_traceset_number(traceset
);
2042 for(i
= 0 ; i
< nb_trace
; i
++) {
2043 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2044 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2045 hooks
= *(val
.v_pointer
);
2047 /* Remove these hooks from each event_by_id hooks list */
2049 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2051 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2053 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2054 LttvTracefileContext
*, j
));
2056 for(k
= 0 ; k
< hooks
->len
; k
++) {
2057 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2058 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2059 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2061 lttv_hooks_remove_data(
2062 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2068 for(k
= 0 ; k
< hooks
->len
; k
++)
2069 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2070 g_array_free(hooks
, TRUE
);
2074 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2076 guint
*event_count
= (guint
*)hook_data
;
2078 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2079 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2084 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2086 LttvTracefileState
*tfcs
;
2088 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2090 LttEventPosition
*ep
;
2096 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2098 LttvAttributeValue value
;
2100 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2101 LTTV_STATE_SAVED_STATES
);
2102 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2103 value
= lttv_attribute_add(saved_states_tree
,
2104 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2105 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2106 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2107 *(value
.v_time
) = self
->parent
.timestamp
;
2108 lttv_state_save(tcs
, saved_state_tree
);
2109 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2110 self
->parent
.timestamp
.tv_nsec
);
2112 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2117 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2119 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2121 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2126 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2134 static gboolean
block_start(void *hook_data
, void *call_data
)
2136 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2138 LttvTracefileState
*tfcs
;
2140 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2142 LttEventPosition
*ep
;
2144 guint i
, nb_block
, nb_event
, nb_tracefile
;
2148 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2150 LttvAttributeValue value
;
2152 ep
= ltt_event_position_new();
2154 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2156 /* Count the number of events added since the last block end in any
2159 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2161 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2162 LttvTracefileContext
, i
));
2163 ltt_event_position(tfcs
->parent
.e
, ep
);
2164 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2165 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2166 tfcs
->saved_position
= nb_event
;
2170 if(tcs
->nb_event
>= tcs
->save_interval
) {
2171 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2172 LTTV_STATE_SAVED_STATES
);
2173 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2174 value
= lttv_attribute_add(saved_states_tree
,
2175 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2176 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2177 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2178 *(value
.v_time
) = self
->parent
.timestamp
;
2179 lttv_state_save(tcs
, saved_state_tree
);
2181 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2182 self
->parent
.timestamp
.tv_nsec
);
2184 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2190 static gboolean
block_end(void *hook_data
, void *call_data
)
2192 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2194 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2198 LttEventPosition
*ep
;
2200 guint nb_block
, nb_event
;
2202 ep
= ltt_event_position_new();
2203 ltt_event_position(self
->parent
.e
, ep
);
2204 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2205 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2206 self
->saved_position
= 0;
2207 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2214 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2216 LttvTraceset
*traceset
= self
->parent
.ts
;
2218 guint i
, j
, nb_trace
, nb_tracefile
;
2222 LttvTracefileState
*tfs
;
2224 LttvTraceHook hook_start
, hook_end
;
2226 nb_trace
= lttv_traceset_number(traceset
);
2227 for(i
= 0 ; i
< nb_trace
; i
++) {
2228 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2230 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2231 NULL
, NULL
, block_start
, &hook_start
);
2232 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2233 NULL
, NULL
, block_end
, &hook_end
);
2235 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2237 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2239 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2240 LttvTracefileContext
, j
));
2241 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2242 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2243 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2244 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2250 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2252 LttvTraceset
*traceset
= self
->parent
.ts
;
2254 guint i
, j
, nb_trace
, nb_tracefile
;
2258 LttvTracefileState
*tfs
;
2261 nb_trace
= lttv_traceset_number(traceset
);
2262 for(i
= 0 ; i
< nb_trace
; i
++) {
2264 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2265 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2267 guint
*event_count
= g_new(guint
, 1);
2270 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2272 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2273 LttvTracefileContext
*, j
));
2274 lttv_hooks_add(tfs
->parent
.event
,
2275 state_save_event_hook
,
2282 lttv_process_traceset_begin(&self
->parent
,
2283 NULL
, NULL
, NULL
, NULL
, NULL
);
2287 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2289 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2291 lttv_state_save_add_event_hooks(tss
);
2298 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2300 LttvTraceset
*traceset
= self
->parent
.ts
;
2302 guint i
, j
, nb_trace
, nb_tracefile
;
2306 LttvTracefileState
*tfs
;
2308 LttvTraceHook hook_start
, hook_end
;
2310 nb_trace
= lttv_traceset_number(traceset
);
2311 for(i
= 0 ; i
< nb_trace
; i
++) {
2312 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2314 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2315 NULL
, NULL
, block_start
, &hook_start
);
2317 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2318 NULL
, NULL
, block_end
, &hook_end
);
2320 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2322 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2324 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2325 LttvTracefileContext
, j
));
2326 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2327 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2328 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2329 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2335 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2337 LttvTraceset
*traceset
= self
->parent
.ts
;
2339 guint i
, j
, nb_trace
, nb_tracefile
;
2343 LttvTracefileState
*tfs
;
2345 LttvHooks
*after_trace
= lttv_hooks_new();
2347 lttv_hooks_add(after_trace
,
2348 state_save_after_trace_hook
,
2353 lttv_process_traceset_end(&self
->parent
,
2354 NULL
, after_trace
, NULL
, NULL
, NULL
);
2356 lttv_hooks_destroy(after_trace
);
2358 nb_trace
= lttv_traceset_number(traceset
);
2359 for(i
= 0 ; i
< nb_trace
; i
++) {
2361 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2362 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2364 guint
*event_count
= NULL
;
2366 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2368 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2369 LttvTracefileContext
*, j
));
2370 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2371 state_save_event_hook
);
2373 if(event_count
) g_free(event_count
);
2377 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2379 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2381 lttv_state_save_remove_event_hooks(tss
);
2386 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2388 LttvTraceset
*traceset
= self
->parent
.ts
;
2392 int min_pos
, mid_pos
, max_pos
;
2394 guint call_rest
= 0;
2396 LttvTraceState
*tcs
;
2398 LttvAttributeValue value
;
2400 LttvAttributeType type
;
2402 LttvAttributeName name
;
2406 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2408 //g_tree_destroy(self->parent.pqueue);
2409 //self->parent.pqueue = g_tree_new(compare_tracefile);
2411 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2413 nb_trace
= lttv_traceset_number(traceset
);
2414 for(i
= 0 ; i
< nb_trace
; i
++) {
2415 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2417 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2418 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2419 LTTV_STATE_SAVED_STATES
);
2422 if(saved_states_tree
) {
2423 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2424 mid_pos
= max_pos
/ 2;
2425 while(min_pos
< max_pos
) {
2426 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2428 g_assert(type
== LTTV_GOBJECT
);
2429 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2430 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2432 g_assert(type
== LTTV_TIME
);
2433 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2435 closest_tree
= saved_state_tree
;
2437 else max_pos
= mid_pos
- 1;
2439 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2443 /* restore the closest earlier saved state */
2445 lttv_state_restore(tcs
, closest_tree
);
2449 /* There is no saved state, yet we want to have it. Restart at T0 */
2451 restore_init_state(tcs
);
2452 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2455 /* We want to seek quickly without restoring/updating the state */
2457 restore_init_state(tcs
);
2458 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2461 if(!call_rest
) g_info("NOT Calling restore");
2466 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2472 traceset_state_finalize (LttvTracesetState
*self
)
2474 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2475 finalize(G_OBJECT(self
));
2480 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2482 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2484 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2485 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2486 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2487 klass
->new_traceset_context
= new_traceset_context
;
2488 klass
->new_trace_context
= new_trace_context
;
2489 klass
->new_tracefile_context
= new_tracefile_context
;
2494 lttv_traceset_state_get_type(void)
2496 static GType type
= 0;
2498 static const GTypeInfo info
= {
2499 sizeof (LttvTracesetStateClass
),
2500 NULL
, /* base_init */
2501 NULL
, /* base_finalize */
2502 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2503 NULL
, /* class_finalize */
2504 NULL
, /* class_data */
2505 sizeof (LttvTracesetState
),
2506 0, /* n_preallocs */
2507 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2508 NULL
/* value handling */
2511 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2519 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2525 trace_state_finalize (LttvTraceState
*self
)
2527 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2528 finalize(G_OBJECT(self
));
2533 trace_state_class_init (LttvTraceStateClass
*klass
)
2535 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2537 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2538 klass
->state_save
= state_save
;
2539 klass
->state_restore
= state_restore
;
2540 klass
->state_saved_free
= state_saved_free
;
2545 lttv_trace_state_get_type(void)
2547 static GType type
= 0;
2549 static const GTypeInfo info
= {
2550 sizeof (LttvTraceStateClass
),
2551 NULL
, /* base_init */
2552 NULL
, /* base_finalize */
2553 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2554 NULL
, /* class_finalize */
2555 NULL
, /* class_data */
2556 sizeof (LttvTraceState
),
2557 0, /* n_preallocs */
2558 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2559 NULL
/* value handling */
2562 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2563 "LttvTraceStateType", &info
, 0);
2570 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2576 tracefile_state_finalize (LttvTracefileState
*self
)
2578 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2579 finalize(G_OBJECT(self
));
2584 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2586 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2588 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2593 lttv_tracefile_state_get_type(void)
2595 static GType type
= 0;
2597 static const GTypeInfo info
= {
2598 sizeof (LttvTracefileStateClass
),
2599 NULL
, /* base_init */
2600 NULL
, /* base_finalize */
2601 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2602 NULL
, /* class_finalize */
2603 NULL
, /* class_data */
2604 sizeof (LttvTracefileState
),
2605 0, /* n_preallocs */
2606 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2607 NULL
/* value handling */
2610 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2611 "LttvTracefileStateType", &info
, 0);
2617 static void module_init()
2619 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2620 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2621 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2622 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2623 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2624 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2625 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2626 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2627 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2628 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2629 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2630 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2631 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2632 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2633 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2634 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2635 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2636 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2637 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2638 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2639 LTTV_STATE_EVENT
= g_quark_from_string("event");
2640 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2641 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2642 LTTV_STATE_TIME
= g_quark_from_string("time");
2643 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2644 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2645 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2646 g_quark_from_string("trace_state_use_count");
2649 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2650 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2651 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2652 LTT_FACILITY_FS
= g_quark_from_string("fs");
2653 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2654 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2657 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2658 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2659 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2660 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2661 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2662 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2663 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2664 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2665 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2666 LTT_EVENT_FORK
= g_quark_from_string("fork");
2667 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2668 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2669 LTT_EVENT_FREE
= g_quark_from_string("free");
2670 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2671 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2672 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2673 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2676 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2677 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2678 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2679 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2680 LTT_FIELD_OUT
= g_quark_from_string("out");
2681 LTT_FIELD_IN
= g_quark_from_string("in");
2682 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2683 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2684 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2685 LTT_FIELD_PID
= g_quark_from_string("pid");
2686 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2687 LTT_FIELD_NAME
= g_quark_from_string("name");
2688 LTT_FIELD_MODE
= g_quark_from_string("mode");
2689 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2690 LTT_FIELD_STATUS
= g_quark_from_string("status");
2691 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2692 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2696 static void module_destroy()
2701 LTTV_MODULE("state", "State computation", \
2702 "Update the system state, possibly saving it at intervals", \
2703 module_init
, module_destroy
)