1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
32 #define PREALLOCATED_EXECUTION_STACK 10
34 /* Facilities Quarks */
43 LTT_EVENT_SYSCALL_ENTRY
,
44 LTT_EVENT_SYSCALL_EXIT
,
49 LTT_EVENT_SCHEDCHANGE
,
68 LTTV_STATE_MODE_UNKNOWN
,
75 LTTV_STATE_SUBMODE_UNKNOWN
,
76 LTTV_STATE_SUBMODE_NONE
;
88 LTTV_STATE_TRACEFILES
,
92 LTTV_STATE_SAVED_STATES
,
93 LTTV_STATE_SAVED_STATES_TIME
,
96 LTTV_STATE_NAME_TABLES
,
97 LTTV_STATE_TRACE_STATE_USE_COUNT
;
99 static void create_max_time(LttvTraceState
*tcs
);
101 static void get_max_time(LttvTraceState
*tcs
);
103 static void free_max_time(LttvTraceState
*tcs
);
105 static void create_name_tables(LttvTraceState
*tcs
);
107 static void get_name_tables(LttvTraceState
*tcs
);
109 static void free_name_tables(LttvTraceState
*tcs
);
111 static void free_saved_state(LttvTraceState
*tcs
);
113 static void lttv_state_free_process_table(GHashTable
*processes
);
116 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
118 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
122 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
124 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
128 void lttv_state_state_saved_free(LttvTraceState
*self
,
129 LttvAttribute
*container
)
131 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
135 guint
process_hash(gconstpointer key
)
137 guint pid
= ((const LttvProcessState
*)key
)->pid
;
138 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
142 /* If the hash table hash function is well distributed,
143 * the process_equal should compare different pid */
144 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
146 const LttvProcessState
*process_a
, *process_b
;
149 process_a
= (const LttvProcessState
*)a
;
150 process_b
= (const LttvProcessState
*)b
;
152 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
153 else if(likely(process_a
->pid
== 0 &&
154 process_a
->last_cpu
!= process_b
->last_cpu
)) ret
= FALSE
;
161 restore_init_state(LttvTraceState
*self
)
163 guint i
, nb_tracefile
;
165 LttvTracefileState
*tfcs
;
167 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
168 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
171 nb_tracefile
= self
->parent
.tracefiles
->len
;
173 for(i
= 0 ; i
< nb_tracefile
; i
++) {
175 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
176 LttvTracefileContext
*, i
));
177 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
178 // tfcs->saved_position = 0;
179 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
180 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
181 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
182 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
186 static LttTime time_zero
= {0,0};
189 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
191 guint i
, j
, nb_trace
, nb_tracefile
;
193 LttvTraceContext
*tc
;
197 LttvTracefileState
*tfcs
;
199 LttvAttributeValue v
;
201 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
202 init((LttvTracesetContext
*)self
, ts
);
204 nb_trace
= lttv_traceset_number(ts
);
205 for(i
= 0 ; i
< nb_trace
; i
++) {
206 tc
= self
->parent
.traces
[i
];
207 tcs
= LTTV_TRACE_STATE(tc
);
208 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
209 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
213 if(*(v
.v_uint
) == 1) {
214 create_name_tables(tcs
);
215 create_max_time(tcs
);
217 get_name_tables(tcs
);
220 nb_tracefile
= tc
->tracefiles
->len
;
222 for(j
= 0 ; j
< nb_tracefile
; j
++) {
224 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
225 LttvTracefileContext
*, j
));
226 tfcs
->cpu_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
228 tcs
->processes
= NULL
;
229 restore_init_state(tcs
);
235 fini(LttvTracesetState
*self
)
241 LttvTracefileState
*tfcs
;
243 LttvAttributeValue v
;
245 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
246 for(i
= 0 ; i
< nb_trace
; i
++) {
247 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
248 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
251 g_assert(*(v
.v_uint
) != 0);
254 if(*(v
.v_uint
) == 0) {
255 free_name_tables(tcs
);
257 free_saved_state(tcs
);
259 lttv_state_free_process_table(tcs
->processes
);
260 tcs
->processes
= NULL
;
262 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
263 fini((LttvTracesetContext
*)self
);
267 static LttvTracesetContext
*
268 new_traceset_context(LttvTracesetContext
*self
)
270 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
274 static LttvTraceContext
*
275 new_trace_context(LttvTracesetContext
*self
)
277 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
281 static LttvTracefileContext
*
282 new_tracefile_context(LttvTracesetContext
*self
)
284 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
288 /* Write the process state of the trace */
290 static void write_process_state(gpointer key
, gpointer value
,
293 LttvProcessState
*process
;
295 LttvExecutionState
*es
;
297 FILE *fp
= (FILE *)user_data
;
301 process
= (LttvProcessState
*)value
;
303 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
304 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
305 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
306 g_quark_to_string(process
->last_cpu
));
308 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
309 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
310 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
311 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
312 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
313 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
314 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
316 fprintf(fp
, " </PROCESS>\n");
320 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
322 guint i
, nb_tracefile
, nb_block
, offset
;
325 LttvTracefileState
*tfcs
;
329 LttEventPosition
*ep
;
331 ep
= ltt_event_position_new();
333 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
335 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
337 nb_tracefile
= self
->parent
.tracefiles
->len
;
339 for(i
= 0 ; i
< nb_tracefile
; i
++) {
341 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
342 LttvTracefileContext
*, i
));
343 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
344 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
345 tfcs
->parent
.timestamp
.tv_nsec
);
346 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
347 if(e
== NULL
) fprintf(fp
,"/>\n");
349 ltt_event_position(e
, ep
);
350 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
351 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
356 fprintf(fp
,"</PROCESS_STATE>");
360 /* Copy each process from an existing hash table to a new one */
362 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
364 LttvProcessState
*process
, *new_process
;
366 GHashTable
*new_processes
= (GHashTable
*)user_data
;
370 process
= (LttvProcessState
*)value
;
371 new_process
= g_new(LttvProcessState
, 1);
372 *new_process
= *process
;
373 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
374 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
375 new_process
->execution_stack
=
376 g_array_set_size(new_process
->execution_stack
,
377 process
->execution_stack
->len
);
378 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
379 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
380 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
382 new_process
->state
= &g_array_index(new_process
->execution_stack
,
383 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
384 g_hash_table_insert(new_processes
, new_process
, new_process
);
388 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
390 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
392 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
393 return new_processes
;
397 /* The saved state for each trace contains a member "processes", which
398 stores a copy of the process table, and a member "tracefiles" with
399 one entry per tracefile. Each tracefile has a "process" member pointing
400 to the current process and a "position" member storing the tracefile
401 position (needed to seek to the current "next" event. */
403 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
405 guint i
, nb_tracefile
;
407 LttvTracefileState
*tfcs
;
409 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
411 LttvAttributeType type
;
413 LttvAttributeValue value
;
415 LttvAttributeName name
;
417 LttEventPosition
*ep
;
419 tracefiles_tree
= lttv_attribute_find_subdir(container
,
420 LTTV_STATE_TRACEFILES
);
422 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
424 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
426 nb_tracefile
= self
->parent
.tracefiles
->len
;
428 for(i
= 0 ; i
< nb_tracefile
; i
++) {
430 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
431 LttvTracefileContext
*, i
));
432 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
433 value
= lttv_attribute_add(tracefiles_tree
, i
,
435 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
436 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
438 *(value
.v_uint
) = tfcs
->process
->pid
;
439 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
441 /* Only save the position if the tfs has not infinite time. */
442 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
443 // && current_tfcs != tfcs) {
444 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
445 *(value
.v_pointer
) = NULL
;
447 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
448 ep
= ltt_event_position_new();
449 ltt_event_position(e
, ep
);
450 *(value
.v_pointer
) = ep
;
452 guint nb_block
, offset
;
455 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
456 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
458 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
464 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
466 guint i
, nb_tracefile
, pid
;
468 LttvTracefileState
*tfcs
;
470 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
472 LttvAttributeType type
;
474 LttvAttributeValue value
;
476 LttvAttributeName name
;
478 LttEventPosition
*ep
;
480 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
482 tracefiles_tree
= lttv_attribute_find_subdir(container
,
483 LTTV_STATE_TRACEFILES
);
485 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
487 g_assert(type
== LTTV_POINTER
);
488 lttv_state_free_process_table(self
->processes
);
489 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
491 nb_tracefile
= self
->parent
.tracefiles
->len
;
493 g_tree_destroy(tsc
->pqueue
);
494 tsc
->pqueue
= g_tree_new(compare_tracefile
);
496 for(i
= 0 ; i
< nb_tracefile
; i
++) {
498 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
499 LttvTracefileContext
*, i
));
500 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
501 g_assert(type
== LTTV_GOBJECT
);
502 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
504 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
506 g_assert(type
== LTTV_UINT
);
507 pid
= *(value
.v_uint
);
508 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
510 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
512 g_assert(type
== LTTV_POINTER
);
513 //g_assert(*(value.v_pointer) != NULL);
514 ep
= *(value
.v_pointer
);
515 g_assert(tfcs
->parent
.t_context
!= NULL
);
517 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
520 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
521 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
522 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
523 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
525 tfc
->timestamp
= ltt_time_infinite
;
531 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
533 guint i
, nb_tracefile
;
535 LttvTracefileState
*tfcs
;
537 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
539 LttvAttributeType type
;
541 LttvAttributeValue value
;
543 LttvAttributeName name
;
545 LttEventPosition
*ep
;
547 tracefiles_tree
= lttv_attribute_find_subdir(container
,
548 LTTV_STATE_TRACEFILES
);
549 g_object_ref(G_OBJECT(tracefiles_tree
));
550 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
552 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
554 g_assert(type
== LTTV_POINTER
);
555 lttv_state_free_process_table(*(value
.v_pointer
));
556 *(value
.v_pointer
) = NULL
;
557 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
559 nb_tracefile
= self
->parent
.tracefiles
->len
;
561 for(i
= 0 ; i
< nb_tracefile
; i
++) {
563 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
564 LttvTracefileContext
*, i
));
565 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
566 g_assert(type
== LTTV_GOBJECT
);
567 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
569 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
571 g_assert(type
== LTTV_POINTER
);
572 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
574 g_object_unref(G_OBJECT(tracefiles_tree
));
578 static void free_saved_state(LttvTraceState
*self
)
582 LttvAttributeType type
;
584 LttvAttributeValue value
;
586 LttvAttributeName name
;
588 LttvAttribute
*saved_states
;
590 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
591 LTTV_STATE_SAVED_STATES
);
593 nb
= lttv_attribute_get_number(saved_states
);
594 for(i
= 0 ; i
< nb
; i
++) {
595 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
596 g_assert(type
== LTTV_GOBJECT
);
597 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
600 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
605 create_max_time(LttvTraceState
*tcs
)
607 LttvAttributeValue v
;
609 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
611 g_assert(*(v
.v_pointer
) == NULL
);
612 *(v
.v_pointer
) = g_new(LttTime
,1);
613 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
618 get_max_time(LttvTraceState
*tcs
)
620 LttvAttributeValue v
;
622 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
624 g_assert(*(v
.v_pointer
) != NULL
);
625 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
630 free_max_time(LttvTraceState
*tcs
)
632 LttvAttributeValue v
;
634 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
636 g_free(*(v
.v_pointer
));
637 *(v
.v_pointer
) = NULL
;
641 typedef struct _LttvNameTables
{
642 // FIXME GQuark *eventtype_names;
643 GQuark
*syscall_names
;
650 create_name_tables(LttvTraceState
*tcs
)
654 GQuark f_name
, e_name
;
658 LttvTraceHookByFacility
*thf
;
664 GString
*fe_name
= g_string_new("");
666 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
668 LttvAttributeValue v
;
670 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
672 g_assert(*(v
.v_pointer
) == NULL
);
673 *(v
.v_pointer
) = name_tables
;
674 #if 0 // Use iteration over the facilities_by_name and then list all event
675 // types of each facility
676 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
677 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
678 for(i
= 0 ; i
< nb
; i
++) {
679 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
680 e_name
= ltt_eventtype_name(et
);
681 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
682 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
683 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
686 if(lttv_trace_find_hook(tcs
->parent
.t
,
687 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
688 LTT_FIELD_SYSCALL_ID
, 0, 0,
692 thf
= lttv_trace_hook_get_first(&h
);
694 t
= ltt_field_type(thf
->f1
);
695 nb
= ltt_type_element_number(t
);
697 lttv_trace_hook_destroy(&h
);
699 /* CHECK syscalls should be an enum but currently are not!
700 name_tables->syscall_names = g_new(GQuark, nb);
702 for(i = 0 ; i < nb ; i++) {
703 name_tables->syscall_names[i] = g_quark_from_string(
704 ltt_enum_string_get(t, i));
708 name_tables
->syscall_names
= g_new(GQuark
, 256);
709 for(i
= 0 ; i
< 256 ; i
++) {
710 g_string_printf(fe_name
, "syscall %d", i
);
711 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
714 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
715 LTT_EVENT_TRAP_ENTRY
,
716 LTT_FIELD_TRAP_ID
, 0, 0,
720 thf
= lttv_trace_hook_get_first(&h
);
722 t
= ltt_field_type(thf
->f1
);
723 nb
= ltt_type_element_number(t
);
725 lttv_trace_hook_destroy(&h
);
728 name_tables->trap_names = g_new(GQuark, nb);
729 for(i = 0 ; i < nb ; i++) {
730 name_tables->trap_names[i] = g_quark_from_string(
731 ltt_enum_string_get(t, i));
735 name_tables
->trap_names
= g_new(GQuark
, 256);
736 for(i
= 0 ; i
< 256 ; i
++) {
737 g_string_printf(fe_name
, "trap %d", i
);
738 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
741 if(lttv_trace_find_hook(tcs
->parent
.t
,
742 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
743 LTT_FIELD_IRQ_ID
, 0, 0,
747 thf
= lttv_trace_hook_get_first(&h
);
749 t
= ltt_field_type(thf
->f1
);
750 nb
= ltt_type_element_number(t
);
752 lttv_trace_hook_destroy(&h
);
755 name_tables->irq_names = g_new(GQuark, nb);
756 for(i = 0 ; i < nb ; i++) {
757 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
761 name_tables
->irq_names
= g_new(GQuark
, 256);
762 for(i
= 0 ; i
< 256 ; i
++) {
763 g_string_printf(fe_name
, "irq %d", i
);
764 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
767 g_string_free(fe_name
, TRUE
);
772 get_name_tables(LttvTraceState
*tcs
)
774 LttvNameTables
*name_tables
;
776 LttvAttributeValue v
;
778 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
780 g_assert(*(v
.v_pointer
) != NULL
);
781 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
782 //tcs->eventtype_names = name_tables->eventtype_names;
783 tcs
->syscall_names
= name_tables
->syscall_names
;
784 tcs
->trap_names
= name_tables
->trap_names
;
785 tcs
->irq_names
= name_tables
->irq_names
;
790 free_name_tables(LttvTraceState
*tcs
)
792 LttvNameTables
*name_tables
;
794 LttvAttributeValue v
;
796 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
798 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
799 *(v
.v_pointer
) = NULL
;
801 // g_free(name_tables->eventtype_names);
802 g_free(name_tables
->syscall_names
);
803 g_free(name_tables
->trap_names
);
804 g_free(name_tables
->irq_names
);
808 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
811 LttvExecutionState
*es
;
813 LttvProcessState
*process
= tfs
->process
;
815 guint depth
= process
->execution_stack
->len
;
817 process
->execution_stack
=
818 g_array_set_size(process
->execution_stack
, depth
+ 1);
821 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
823 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
826 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
827 es
->s
= process
->state
->s
;
832 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
834 LttvProcessState
*process
= tfs
->process
;
836 guint depth
= process
->execution_stack
->len
;
838 if(process
->state
->t
!= t
){
839 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
840 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
841 g_info("process state has %s when pop_int is %s\n",
842 g_quark_to_string(process
->state
->t
),
843 g_quark_to_string(t
));
844 g_info("{ %u, %u, %s, %s }\n",
847 g_quark_to_string(process
->name
),
848 g_quark_to_string(process
->state
->s
));
853 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
854 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
858 process
->execution_stack
=
859 g_array_set_size(process
->execution_stack
, depth
- 1);
860 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
862 process
->state
->change
= tfs
->parent
.timestamp
;
867 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
870 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
872 LttvExecutionState
*es
;
874 LttvTraceContext
*tc
;
880 tc
= tfs
->parent
.t_context
;
881 tcs
= (LttvTraceState
*)tc
;
884 process
->last_cpu
= tfs
->cpu_name
;
885 process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfs
)->tf
);
886 g_info("Process %u, core %p", process
->pid
, process
);
887 g_hash_table_insert(tcs
->processes
, process
, process
);
890 process
->ppid
= parent
->pid
;
891 process
->name
= parent
->name
;
892 process
->creation_time
= tfs
->parent
.timestamp
;
895 /* No parent. This process exists but we are missing all information about
896 its creation. The birth time is set to zero but we remember the time of
901 process
->name
= LTTV_STATE_UNNAMED
;
902 process
->creation_time
= ltt_time_zero
;
905 process
->insertion_time
= tfs
->parent
.timestamp
;
906 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
907 process
->creation_time
.tv_nsec
);
908 process
->pid_time
= g_quark_from_string(buffer
);
909 process
->last_cpu
= tfs
->cpu_name
;
910 process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfs
)->tf
);
911 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
912 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
913 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
914 es
= process
->state
= &g_array_index(process
->execution_stack
,
915 LttvExecutionState
, 0);
916 es
->t
= LTTV_STATE_USER_MODE
;
917 es
->n
= LTTV_STATE_SUBMODE_NONE
;
918 es
->entry
= tfs
->parent
.timestamp
;
919 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
920 es
->change
= tfs
->parent
.timestamp
;
921 es
->s
= LTTV_STATE_WAIT_FORK
;
926 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
929 LttvProcessState key
;
930 LttvProcessState
*process
;
932 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
935 key
.last_cpu
= tfs
->cpu_name
;
936 process
= g_hash_table_lookup(ts
->processes
, &key
);
941 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
943 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
945 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
949 /* FIXME : this function should be called when we receive an event telling that
950 * release_task has been called in the kernel. In happens generally when
951 * the parent waits for its child terminaison, but may also happen in special
952 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
953 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
954 * of a killed thread ground, but isn't the leader.
956 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
958 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
959 LttvProcessState key
;
961 key
.pid
= process
->pid
;
962 key
.last_cpu
= process
->last_cpu
;
963 g_hash_table_remove(ts
->processes
, &key
);
964 g_array_free(process
->execution_stack
, TRUE
);
969 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
971 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
976 static void lttv_state_free_process_table(GHashTable
*processes
)
978 g_hash_table_foreach(processes
, free_process_state
, NULL
);
979 g_hash_table_destroy(processes
);
983 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
985 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
986 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
987 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
988 LttField
*f
= thf
->f1
;
990 LttvExecutionSubmode submode
;
992 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
993 ltt_event_get_unsigned(e
, f
)];
994 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
999 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1001 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1003 pop_state(s
, LTTV_STATE_SYSCALL
);
1008 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1010 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1011 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1012 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1013 LttField
*f
= thf
->f1
;
1015 LttvExecutionSubmode submode
;
1017 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1018 ltt_event_get_unsigned(e
, f
)];
1019 push_state(s
, LTTV_STATE_TRAP
, submode
);
1024 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1026 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1028 pop_state(s
, LTTV_STATE_TRAP
);
1033 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1035 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1036 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1037 guint8 fac_id
= ltt_event_facility_id(e
);
1038 guint8 ev_id
= ltt_event_eventtype_id(e
);
1039 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1040 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1041 g_assert(thf
->f1
!= NULL
);
1042 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1043 LttField
*f
= thf
->f1
;
1045 LttvExecutionSubmode submode
;
1047 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1048 ltt_event_get_unsigned(e
, f
)];
1050 /* Do something with the info about being in user or system mode when int? */
1051 push_state(s
, LTTV_STATE_IRQ
, submode
);
1056 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1058 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1060 pop_state(s
, LTTV_STATE_IRQ
);
1065 static gboolean
schedchange(void *hook_data
, void *call_data
)
1067 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1068 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1069 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1070 guint pid_in
, pid_out
;
1073 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1074 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1075 state_out
= ltt_event_get_int(e
, thf
->f3
);
1077 if(likely(s
->process
!= NULL
)) {
1079 /* We could not know but it was not the idle process executing.
1080 This should only happen at the beginning, before the first schedule
1081 event, and when the initial information (current process for each CPU)
1082 is missing. It is not obvious how we could, after the fact, compensate
1083 the wrongly attributed statistics. */
1085 //This test only makes sense once the state is known and if there is no
1087 //if(unlikely(s->process->pid != pid_out)) {
1088 // g_assert(s->process->pid == 0);
1091 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1092 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1094 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1095 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1096 } /* FIXME : we do not remove process here, because the kernel
1097 * still has them : they may be zombies. We need to know
1098 * exactly when release_task is executed on the PID to
1099 * know when the zombie is destroyed.
1102 // exit_process(s, s->process);
1104 s
->process
->state
->change
= s
->parent
.timestamp
;
1106 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1107 s
->process
->state
->s
= LTTV_STATE_RUN
;
1108 s
->process
->last_cpu
= s
->cpu_name
;
1109 s
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)s
)->tf
);
1110 s
->process
->state
->change
= s
->parent
.timestamp
;
1114 static gboolean
process_fork(void *hook_data
, void *call_data
)
1116 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1117 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1118 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1122 LttvProcessState
*zombie_process
;
1126 parent_pid
= ltt_event_get_unsigned(e
, f
);
1130 child_pid
= ltt_event_get_unsigned(e
, f
);
1132 zombie_process
= lttv_state_find_process(s
, child_pid
);
1134 if(unlikely(zombie_process
!= NULL
)) {
1135 /* Reutilisation of PID. Only now we are sure that the old PID
1136 * has been released. FIXME : should know when release_task happens instead.
1138 exit_process(s
, zombie_process
);
1140 g_assert(s
->process
->pid
!= child_pid
);
1141 // FIXME : Add this test in the "known state" section
1142 // g_assert(s->process->pid == parent_pid);
1143 lttv_state_create_process(s
, s
->process
, child_pid
);
1149 static gboolean
process_exit(void *hook_data
, void *call_data
)
1151 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1152 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1153 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1157 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1159 // FIXME : Add this test in the "known state" section
1160 // g_assert(s->process->pid == pid);
1162 if(likely(s
->process
!= NULL
)) {
1163 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1168 static gboolean
process_free(void *hook_data
, void *call_data
)
1170 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1171 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1172 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1174 LttvProcessState
*process
;
1176 /* PID of the process to release */
1177 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1179 process
= lttv_state_find_process(s
, release_pid
);
1181 if(likely(process
!= NULL
)) {
1182 /* release_task is happening at kernel level : we can now safely release
1183 * the data structure of the process */
1184 exit_process(s
, process
);
1190 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1192 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1194 lttv_state_add_event_hooks(tss
);
1199 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1201 LttvTraceset
*traceset
= self
->parent
.ts
;
1203 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1207 LttvTracefileState
*tfs
;
1211 LttvTraceHookByFacility
*thf
;
1213 LttvTraceHook
*hook
;
1215 LttvAttributeValue val
;
1219 nb_trace
= lttv_traceset_number(traceset
);
1220 for(i
= 0 ; i
< nb_trace
; i
++) {
1221 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1223 /* Find the eventtype id for the following events and register the
1224 associated by id hooks. */
1226 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1227 hooks
= g_array_set_size(hooks
, 10);
1229 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1230 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1231 LTT_FIELD_SYSCALL_ID
, 0, 0,
1232 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1235 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1236 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1238 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1241 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1242 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1243 LTT_FIELD_TRAP_ID
, 0, 0,
1244 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1247 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1248 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1250 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1253 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1254 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1255 LTT_FIELD_IRQ_ID
, 0, 0,
1256 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1259 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1260 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1262 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1265 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1266 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1267 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1268 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1271 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1272 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1273 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1274 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1277 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1278 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1279 LTT_FIELD_PID
, 0, 0,
1280 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1283 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1284 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1285 LTT_FIELD_PID
, 0, 0,
1286 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1290 /* Add these hooks to each event_by_id hooks list */
1292 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1294 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1296 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1297 LttvTracefileContext
*, j
));
1299 for(k
= 0 ; k
< hooks
->len
; k
++) {
1300 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1301 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1302 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1304 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1311 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1312 *(val
.v_pointer
) = hooks
;
1316 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1318 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1320 lttv_state_remove_event_hooks(tss
);
1325 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1327 LttvTraceset
*traceset
= self
->parent
.ts
;
1329 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1333 LttvTracefileState
*tfs
;
1337 LttvTraceHook
*hook
;
1339 LttvTraceHookByFacility
*thf
;
1341 LttvAttributeValue val
;
1343 nb_trace
= lttv_traceset_number(traceset
);
1344 for(i
= 0 ; i
< nb_trace
; i
++) {
1345 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1346 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1347 hooks
= *(val
.v_pointer
);
1349 /* Remove these hooks from each event_by_id hooks list */
1351 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1353 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1355 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1356 LttvTracefileContext
*, j
));
1358 for(k
= 0 ; k
< hooks
->len
; k
++) {
1359 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1360 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1361 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1363 lttv_hooks_remove_data(
1364 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1370 for(k
= 0 ; k
< hooks
->len
; k
++)
1371 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1372 g_array_free(hooks
, TRUE
);
1377 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1379 guint
*event_count
= (guint
*)hook_data
;
1381 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1382 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1387 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1389 LttvTracefileState
*tfcs
;
1391 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1393 LttEventPosition
*ep
;
1399 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1401 LttvAttributeValue value
;
1403 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1404 LTTV_STATE_SAVED_STATES
);
1405 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1406 value
= lttv_attribute_add(saved_states_tree
,
1407 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1408 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1409 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1410 *(value
.v_time
) = self
->parent
.timestamp
;
1411 lttv_state_save(tcs
, saved_state_tree
);
1412 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1413 self
->parent
.timestamp
.tv_nsec
);
1415 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1421 static gboolean
block_start(void *hook_data
, void *call_data
)
1423 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1425 LttvTracefileState
*tfcs
;
1427 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1429 LttEventPosition
*ep
;
1431 guint i
, nb_block
, nb_event
, nb_tracefile
;
1435 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1437 LttvAttributeValue value
;
1439 ep
= ltt_event_position_new();
1441 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1443 /* Count the number of events added since the last block end in any
1446 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1448 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1449 LttvTracefileContext
, i
));
1450 ltt_event_position(tfcs
->parent
.e
, ep
);
1451 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1452 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1453 tfcs
->saved_position
= nb_event
;
1457 if(tcs
->nb_event
>= tcs
->save_interval
) {
1458 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1459 LTTV_STATE_SAVED_STATES
);
1460 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1461 value
= lttv_attribute_add(saved_states_tree
,
1462 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1463 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1464 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1465 *(value
.v_time
) = self
->parent
.timestamp
;
1466 lttv_state_save(tcs
, saved_state_tree
);
1468 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1469 self
->parent
.timestamp
.tv_nsec
);
1471 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1477 static gboolean
block_end(void *hook_data
, void *call_data
)
1479 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1481 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1485 LttEventPosition
*ep
;
1487 guint nb_block
, nb_event
;
1489 ep
= ltt_event_position_new();
1490 ltt_event_position(self
->parent
.e
, ep
);
1491 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1492 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1493 self
->saved_position
= 0;
1494 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1501 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1503 LttvTraceset
*traceset
= self
->parent
.ts
;
1505 guint i
, j
, nb_trace
, nb_tracefile
;
1509 LttvTracefileState
*tfs
;
1511 LttvTraceHook hook_start
, hook_end
;
1513 nb_trace
= lttv_traceset_number(traceset
);
1514 for(i
= 0 ; i
< nb_trace
; i
++) {
1515 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1517 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1518 NULL
, NULL
, block_start
, &hook_start
);
1519 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1520 NULL
, NULL
, block_end
, &hook_end
);
1522 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1524 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1526 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1527 LttvTracefileContext
, j
));
1528 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1529 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1530 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1531 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1537 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1539 LttvTraceset
*traceset
= self
->parent
.ts
;
1541 guint i
, j
, nb_trace
, nb_tracefile
;
1545 LttvTracefileState
*tfs
;
1548 nb_trace
= lttv_traceset_number(traceset
);
1549 for(i
= 0 ; i
< nb_trace
; i
++) {
1551 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1552 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1554 guint
*event_count
= g_new(guint
, 1);
1557 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1559 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1560 LttvTracefileContext
*, j
));
1561 lttv_hooks_add(tfs
->parent
.event
,
1562 state_save_event_hook
,
1570 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1572 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1574 lttv_state_save_add_event_hooks(tss
);
1581 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1583 LttvTraceset
*traceset
= self
->parent
.ts
;
1585 guint i
, j
, nb_trace
, nb_tracefile
;
1589 LttvTracefileState
*tfs
;
1591 LttvTraceHook hook_start
, hook_end
;
1593 nb_trace
= lttv_traceset_number(traceset
);
1594 for(i
= 0 ; i
< nb_trace
; i
++) {
1595 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1597 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1598 NULL
, NULL
, block_start
, &hook_start
);
1600 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1601 NULL
, NULL
, block_end
, &hook_end
);
1603 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1605 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1607 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1608 LttvTracefileContext
, j
));
1609 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1610 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1611 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1612 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1618 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1620 LttvTraceset
*traceset
= self
->parent
.ts
;
1622 guint i
, j
, nb_trace
, nb_tracefile
;
1626 LttvTracefileState
*tfs
;
1629 nb_trace
= lttv_traceset_number(traceset
);
1630 for(i
= 0 ; i
< nb_trace
; i
++) {
1632 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1633 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1637 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1639 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1640 LttvTracefileContext
*, j
));
1641 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1642 state_save_event_hook
);
1645 g_free(event_count
);
1649 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1651 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1653 lttv_state_save_remove_event_hooks(tss
);
1658 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1660 LttvTraceset
*traceset
= self
->parent
.ts
;
1664 int min_pos
, mid_pos
, max_pos
;
1666 LttvTraceState
*tcs
;
1668 LttvAttributeValue value
;
1670 LttvAttributeType type
;
1672 LttvAttributeName name
;
1674 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1676 nb_trace
= lttv_traceset_number(traceset
);
1677 for(i
= 0 ; i
< nb_trace
; i
++) {
1678 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1680 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1681 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1682 LTTV_STATE_SAVED_STATES
);
1685 if(saved_states_tree
) {
1686 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1687 mid_pos
= max_pos
/ 2;
1688 while(min_pos
< max_pos
) {
1689 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1690 g_assert(type
== LTTV_GOBJECT
);
1691 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1692 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1694 g_assert(type
== LTTV_TIME
);
1695 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1697 closest_tree
= saved_state_tree
;
1699 else max_pos
= mid_pos
- 1;
1701 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1705 /* restore the closest earlier saved state */
1707 lttv_state_restore(tcs
, closest_tree
);
1710 /* There is no saved state, yet we want to have it. Restart at T0 */
1712 restore_init_state(tcs
);
1713 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1716 /* We want to seek quickly without restoring/updating the state */
1718 restore_init_state(tcs
);
1719 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1726 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1732 traceset_state_finalize (LttvTracesetState
*self
)
1734 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1735 finalize(G_OBJECT(self
));
1740 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1742 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1744 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1745 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1746 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1747 klass
->new_traceset_context
= new_traceset_context
;
1748 klass
->new_trace_context
= new_trace_context
;
1749 klass
->new_tracefile_context
= new_tracefile_context
;
1754 lttv_traceset_state_get_type(void)
1756 static GType type
= 0;
1758 static const GTypeInfo info
= {
1759 sizeof (LttvTracesetStateClass
),
1760 NULL
, /* base_init */
1761 NULL
, /* base_finalize */
1762 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1763 NULL
, /* class_finalize */
1764 NULL
, /* class_data */
1765 sizeof (LttvTracesetState
),
1766 0, /* n_preallocs */
1767 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1768 NULL
/* value handling */
1771 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1779 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1785 trace_state_finalize (LttvTraceState
*self
)
1787 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1788 finalize(G_OBJECT(self
));
1793 trace_state_class_init (LttvTraceStateClass
*klass
)
1795 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1797 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1798 klass
->state_save
= state_save
;
1799 klass
->state_restore
= state_restore
;
1800 klass
->state_saved_free
= state_saved_free
;
1805 lttv_trace_state_get_type(void)
1807 static GType type
= 0;
1809 static const GTypeInfo info
= {
1810 sizeof (LttvTraceStateClass
),
1811 NULL
, /* base_init */
1812 NULL
, /* base_finalize */
1813 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1814 NULL
, /* class_finalize */
1815 NULL
, /* class_data */
1816 sizeof (LttvTraceState
),
1817 0, /* n_preallocs */
1818 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1819 NULL
/* value handling */
1822 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1823 "LttvTraceStateType", &info
, 0);
1830 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1836 tracefile_state_finalize (LttvTracefileState
*self
)
1838 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1839 finalize(G_OBJECT(self
));
1844 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1846 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1848 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1853 lttv_tracefile_state_get_type(void)
1855 static GType type
= 0;
1857 static const GTypeInfo info
= {
1858 sizeof (LttvTracefileStateClass
),
1859 NULL
, /* base_init */
1860 NULL
, /* base_finalize */
1861 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1862 NULL
, /* class_finalize */
1863 NULL
, /* class_data */
1864 sizeof (LttvTracefileState
),
1865 0, /* n_preallocs */
1866 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1867 NULL
/* value handling */
1870 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1871 "LttvTracefileStateType", &info
, 0);
1877 static void module_init()
1879 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1880 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1881 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1882 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1883 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1884 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1885 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1886 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1887 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1888 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1889 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1890 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1891 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1892 LTTV_STATE_RUN
= g_quark_from_string("running");
1893 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1894 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1895 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1896 LTTV_STATE_EVENT
= g_quark_from_string("event");
1897 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1898 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1899 LTTV_STATE_TIME
= g_quark_from_string("time");
1900 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1901 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1902 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1903 g_quark_from_string("trace_state_use_count");
1906 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1907 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1910 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1911 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1912 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1913 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1914 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1915 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1916 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1917 LTT_EVENT_FORK
= g_quark_from_string("fork");
1918 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1919 LTT_EVENT_FREE
= g_quark_from_string("free");
1922 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1923 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1924 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1925 LTT_FIELD_OUT
= g_quark_from_string("out");
1926 LTT_FIELD_IN
= g_quark_from_string("in");
1927 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1928 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1929 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1930 LTT_FIELD_PID
= g_quark_from_string("pid");
1934 static void module_destroy()
1939 LTTV_MODULE("state", "State computation", \
1940 "Update the system state, possibly saving it at intervals", \
1941 module_init
, module_destroy
)