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
= ((LttvTracefileContext
*)tfcs
)->index
;
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
= (LttvTraceState
*)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 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
376 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
377 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
378 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
380 new_process
->state
= &g_array_index(new_process
->execution_stack
,
381 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
382 g_hash_table_insert(new_processes
, new_process
, new_process
);
386 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
388 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
390 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
391 return new_processes
;
395 /* The saved state for each trace contains a member "processes", which
396 stores a copy of the process table, and a member "tracefiles" with
397 one entry per tracefile. Each tracefile has a "process" member pointing
398 to the current process and a "position" member storing the tracefile
399 position (needed to seek to the current "next" event. */
401 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
403 guint i
, nb_tracefile
;
405 LttvTracefileState
*tfcs
;
407 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
409 LttvAttributeType type
;
411 LttvAttributeValue value
;
413 LttvAttributeName name
;
415 LttEventPosition
*ep
;
417 tracefiles_tree
= lttv_attribute_find_subdir(container
,
418 LTTV_STATE_TRACEFILES
);
420 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
422 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
424 nb_tracefile
= self
->parent
.tracefiles
->len
;
426 for(i
= 0 ; i
< nb_tracefile
; i
++) {
428 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
429 LttvTracefileContext
*, i
));
430 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
431 value
= lttv_attribute_add(tracefiles_tree
, i
,
433 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
434 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
436 *(value
.v_uint
) = tfcs
->process
->pid
;
437 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
439 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
440 if(e
== NULL
) *(value
.v_pointer
) = NULL
;
442 ep
= ltt_event_position_new();
443 ltt_event_position(e
, ep
);
444 *(value
.v_pointer
) = ep
;
446 guint nb_block
, offset
;
449 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
450 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
452 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
458 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
460 guint i
, nb_tracefile
, pid
;
462 LttvTracefileState
*tfcs
;
464 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
466 LttvAttributeType type
;
468 LttvAttributeValue value
;
470 LttvAttributeName name
;
472 LttEventPosition
*ep
;
474 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
476 tracefiles_tree
= lttv_attribute_find_subdir(container
,
477 LTTV_STATE_TRACEFILES
);
479 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
481 g_assert(type
== LTTV_POINTER
);
482 lttv_state_free_process_table(self
->processes
);
483 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
485 nb_tracefile
= self
->parent
.tracefiles
->len
;
487 for(i
= 0 ; i
< nb_tracefile
; i
++) {
489 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
490 LttvTracefileContext
*, i
));
491 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
492 g_assert(type
== LTTV_GOBJECT
);
493 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
495 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
497 g_assert(type
== LTTV_UINT
);
498 pid
= *(value
.v_uint
);
499 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
501 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
503 g_assert(type
== LTTV_POINTER
);
504 g_assert(*(value
.v_pointer
) != NULL
);
505 ep
= *(value
.v_pointer
);
506 g_assert(tfcs
->parent
.t_context
!= NULL
);
508 g_tree_destroy(tsc
->pqueue
);
509 tsc
->pqueue
= g_tree_new(compare_tracefile
);
511 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
513 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
514 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
515 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
520 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
522 guint i
, nb_tracefile
;
524 LttvTracefileState
*tfcs
;
526 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
528 LttvAttributeType type
;
530 LttvAttributeValue value
;
532 LttvAttributeName name
;
534 LttEventPosition
*ep
;
536 tracefiles_tree
= lttv_attribute_find_subdir(container
,
537 LTTV_STATE_TRACEFILES
);
538 g_object_ref(G_OBJECT(tracefiles_tree
));
539 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
541 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
543 g_assert(type
== LTTV_POINTER
);
544 lttv_state_free_process_table(*(value
.v_pointer
));
545 *(value
.v_pointer
) = NULL
;
546 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
548 nb_tracefile
= self
->parent
.tracefiles
->len
;
550 for(i
= 0 ; i
< nb_tracefile
; i
++) {
552 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
553 LttvTracefileContext
*, i
));
554 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
555 g_assert(type
== LTTV_GOBJECT
);
556 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
558 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
560 g_assert(type
== LTTV_POINTER
);
561 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
563 g_object_unref(G_OBJECT(tracefiles_tree
));
567 static void free_saved_state(LttvTraceState
*self
)
571 LttvAttributeType type
;
573 LttvAttributeValue value
;
575 LttvAttributeName name
;
577 LttvAttribute
*saved_states
;
579 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
580 LTTV_STATE_SAVED_STATES
);
582 nb
= lttv_attribute_get_number(saved_states
);
583 for(i
= 0 ; i
< nb
; i
++) {
584 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
585 g_assert(type
== LTTV_GOBJECT
);
586 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
589 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
594 create_max_time(LttvTraceState
*tcs
)
596 LttvAttributeValue v
;
598 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
600 g_assert(*(v
.v_pointer
) == NULL
);
601 *(v
.v_pointer
) = g_new(LttTime
,1);
602 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
607 get_max_time(LttvTraceState
*tcs
)
609 LttvAttributeValue v
;
611 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
613 g_assert(*(v
.v_pointer
) != NULL
);
614 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
619 free_max_time(LttvTraceState
*tcs
)
621 LttvAttributeValue v
;
623 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
625 g_free(*(v
.v_pointer
));
626 *(v
.v_pointer
) = NULL
;
630 typedef struct _LttvNameTables
{
631 // FIXME GQuark *eventtype_names;
632 GQuark
*syscall_names
;
639 create_name_tables(LttvTraceState
*tcs
)
643 GQuark f_name
, e_name
;
647 LttvTraceHookByFacility
*thf
;
653 GString
*fe_name
= g_string_new("");
655 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
657 LttvAttributeValue v
;
659 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
661 g_assert(*(v
.v_pointer
) == NULL
);
662 *(v
.v_pointer
) = name_tables
;
663 #if 0 // Use iteration over the facilities_by_name and then list all event
664 // types of each facility
665 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
666 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
667 for(i
= 0 ; i
< nb
; i
++) {
668 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
669 e_name
= ltt_eventtype_name(et
);
670 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
671 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
672 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
675 if(lttv_trace_find_hook(tcs
->parent
.t
,
676 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
677 LTT_FIELD_SYSCALL_ID
, 0, 0,
681 thf
= lttv_trace_hook_get_first(h
);
683 t
= ltt_field_type(thf
->f1
);
684 nb
= ltt_type_element_number(t
);
686 lttv_trace_hook_destroy(h
);
688 /* CHECK syscalls should be an enum but currently are not!
689 name_tables->syscall_names = g_new(GQuark, nb);
691 for(i = 0 ; i < nb ; i++) {
692 name_tables->syscall_names[i] = g_quark_from_string(
693 ltt_enum_string_get(t, i));
697 name_tables
->syscall_names
= g_new(GQuark
, 256);
698 for(i
= 0 ; i
< 256 ; i
++) {
699 g_string_printf(fe_name
, "syscall %d", i
);
700 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
703 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
704 LTT_EVENT_TRAP_ENTRY
,
705 LTT_FIELD_TRAP_ID
, 0, 0,
709 thf
= lttv_trace_hook_get_first(h
);
711 t
= ltt_field_type(thf
->f1
);
712 nb
= ltt_type_element_number(t
);
714 lttv_trace_hook_destroy(h
);
717 name_tables->trap_names = g_new(GQuark, nb);
718 for(i = 0 ; i < nb ; i++) {
719 name_tables->trap_names[i] = g_quark_from_string(
720 ltt_enum_string_get(t, i));
724 name_tables
->trap_names
= g_new(GQuark
, 256);
725 for(i
= 0 ; i
< 256 ; i
++) {
726 g_string_printf(fe_name
, "trap %d", i
);
727 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
730 if(lttv_trace_find_hook(tcs
->parent
.t
,
731 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
732 LTT_FIELD_IRQ_ID
, 0, 0,
736 thf
= lttv_trace_hook_get_first(h
);
738 t
= ltt_field_type(thf
->f1
);
739 nb
= ltt_type_element_number(t
);
741 lttv_trace_hook_destroy(h
);
744 name_tables->irq_names = g_new(GQuark, nb);
745 for(i = 0 ; i < nb ; i++) {
746 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
750 name_tables
->irq_names
= g_new(GQuark
, 256);
751 for(i
= 0 ; i
< 256 ; i
++) {
752 g_string_printf(fe_name
, "irq %d", i
);
753 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
756 g_string_free(fe_name
, TRUE
);
761 get_name_tables(LttvTraceState
*tcs
)
763 LttvNameTables
*name_tables
;
765 LttvAttributeValue v
;
767 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
769 g_assert(*(v
.v_pointer
) != NULL
);
770 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
771 //tcs->eventtype_names = name_tables->eventtype_names;
772 tcs
->syscall_names
= name_tables
->syscall_names
;
773 tcs
->trap_names
= name_tables
->trap_names
;
774 tcs
->irq_names
= name_tables
->irq_names
;
779 free_name_tables(LttvTraceState
*tcs
)
781 LttvNameTables
*name_tables
;
783 LttvAttributeValue v
;
785 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
787 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
788 *(v
.v_pointer
) = NULL
;
790 // g_free(name_tables->eventtype_names);
791 g_free(name_tables
->syscall_names
);
792 g_free(name_tables
->trap_names
);
793 g_free(name_tables
->irq_names
);
798 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
801 LttvExecutionState
*es
;
803 LttvProcessState
*process
= tfs
->process
;
805 guint depth
= process
->execution_stack
->len
;
807 g_array_set_size(process
->execution_stack
, depth
+ 1);
808 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
811 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
812 es
->s
= process
->state
->s
;
817 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
819 LttvProcessState
*process
= tfs
->process
;
821 guint depth
= process
->execution_stack
->len
;
823 if(process
->state
->t
!= t
){
824 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
825 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
826 g_info("process state has %s when pop_int is %s\n",
827 g_quark_to_string(process
->state
->t
),
828 g_quark_to_string(t
));
829 g_info("{ %u, %u, %s, %s }\n",
832 g_quark_to_string(process
->name
),
833 g_quark_to_string(process
->state
->s
));
838 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
839 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
843 g_array_set_size(process
->execution_stack
, depth
- 1);
844 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
846 process
->state
->change
= tfs
->parent
.timestamp
;
851 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
854 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
856 LttvExecutionState
*es
;
858 LttvTraceContext
*tc
;
864 tc
= tfs
->parent
.t_context
;
865 tcs
= (LttvTraceState
*)tc
;
868 process
->last_cpu
= tfs
->cpu_name
;
869 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
870 g_info("Process %u, core %p", process
->pid
, process
);
871 g_hash_table_insert(tcs
->processes
, process
, process
);
874 process
->ppid
= parent
->pid
;
875 process
->name
= parent
->name
;
876 process
->creation_time
= tfs
->parent
.timestamp
;
879 /* No parent. This process exists but we are missing all information about
880 its creation. The birth time is set to zero but we remember the time of
885 process
->name
= LTTV_STATE_UNNAMED
;
886 process
->creation_time
= ltt_time_zero
;
889 process
->insertion_time
= tfs
->parent
.timestamp
;
890 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
891 process
->creation_time
.tv_nsec
);
892 process
->pid_time
= g_quark_from_string(buffer
);
893 process
->last_cpu
= tfs
->cpu_name
;
894 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
895 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
896 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
897 g_array_set_size(process
->execution_stack
, 1);
898 es
= process
->state
= &g_array_index(process
->execution_stack
,
899 LttvExecutionState
, 0);
900 es
->t
= LTTV_STATE_USER_MODE
;
901 es
->n
= LTTV_STATE_SUBMODE_NONE
;
902 es
->entry
= tfs
->parent
.timestamp
;
903 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
904 es
->change
= tfs
->parent
.timestamp
;
905 es
->s
= LTTV_STATE_WAIT_FORK
;
910 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
913 LttvProcessState key
;
914 LttvProcessState
*process
;
916 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
919 key
.last_cpu
= tfs
->cpu_name
;
920 process
= g_hash_table_lookup(ts
->processes
, &key
);
925 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
927 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
929 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
933 /* FIXME : this function should be called when we receive an event telling that
934 * release_task has been called in the kernel. In happens generally when
935 * the parent waits for its child terminaison, but may also happen in special
936 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
937 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
938 * of a killed thread ground, but isn't the leader.
940 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
942 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
943 LttvProcessState key
;
945 key
.pid
= process
->pid
;
946 key
.last_cpu
= process
->last_cpu
;
947 g_hash_table_remove(ts
->processes
, &key
);
948 g_array_free(process
->execution_stack
, TRUE
);
953 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
955 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
960 static void lttv_state_free_process_table(GHashTable
*processes
)
962 g_hash_table_foreach(processes
, free_process_state
, NULL
);
963 g_hash_table_destroy(processes
);
967 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
969 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
970 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
971 LttvTraceHookByFacility
*thf
=
972 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
973 ltt_event_facility_id(e
));
974 LttField
*f
= thf
->f1
;
976 LttvExecutionSubmode submode
;
978 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
979 ltt_event_get_unsigned(e
, f
)];
980 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
985 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
987 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
989 pop_state(s
, LTTV_STATE_SYSCALL
);
994 static gboolean
trap_entry(void *hook_data
, void *call_data
)
996 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
997 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
998 LttvTraceHookByFacility
*thf
=
999 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1000 ltt_event_facility_id(e
));
1001 LttField
*f
= thf
->f1
;
1003 LttvExecutionSubmode submode
;
1005 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1006 ltt_event_get_unsigned(e
, f
)];
1007 push_state(s
, LTTV_STATE_TRAP
, submode
);
1012 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1014 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1016 pop_state(s
, LTTV_STATE_TRAP
);
1021 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1023 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1024 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1025 LttvTraceHookByFacility
*thf
=
1026 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1027 ltt_event_facility_id(e
));
1028 LttField
*f
= thf
->f1
;
1030 LttvExecutionSubmode submode
;
1032 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1033 ltt_event_get_unsigned(e
, f
)];
1035 /* Do something with the info about being in user or system mode when int? */
1036 push_state(s
, LTTV_STATE_IRQ
, submode
);
1041 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1043 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1045 pop_state(s
, LTTV_STATE_IRQ
);
1050 static gboolean
schedchange(void *hook_data
, void *call_data
)
1052 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1053 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1054 LttvTraceHookByFacility
*thf
=
1055 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1056 ltt_event_facility_id(e
));
1057 guint pid_in
, pid_out
, state_out
;
1059 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1060 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1061 state_out
= ltt_event_get_unsigned(e
, thf
->f3
);
1063 if(likely(s
->process
!= NULL
)) {
1065 /* We could not know but it was not the idle process executing.
1066 This should only happen at the beginning, before the first schedule
1067 event, and when the initial information (current process for each CPU)
1068 is missing. It is not obvious how we could, after the fact, compensate
1069 the wrongly attributed statistics. */
1071 if(unlikely(s
->process
->pid
!= pid_out
)) {
1072 g_assert(s
->process
->pid
== 0);
1075 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1076 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1078 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1079 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1080 } /* FIXME : we do not remove process here, because the kernel
1081 * still has them : they may be zombies. We need to know
1082 * exactly when release_task is executed on the PID to
1083 * know when the zombie is destroyed.
1086 // exit_process(s, s->process);
1088 s
->process
->state
->change
= s
->parent
.timestamp
;
1090 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1091 s
->process
->state
->s
= LTTV_STATE_RUN
;
1092 s
->process
->last_cpu
= s
->cpu_name
;
1093 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1094 s
->process
->state
->change
= s
->parent
.timestamp
;
1098 static gboolean
process_fork(void *hook_data
, void *call_data
)
1100 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1101 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1102 LttvTraceHookByFacility
*thf
=
1103 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1104 ltt_event_facility_id(e
));
1108 LttvProcessState
*zombie_process
;
1112 parent_pid
= ltt_event_get_unsigned(e
, f
);
1116 child_pid
= ltt_event_get_unsigned(e
, f
);
1118 zombie_process
= lttv_state_find_process(s
, child_pid
);
1120 if(unlikely(zombie_process
!= NULL
)) {
1121 /* Reutilisation of PID. Only now we are sure that the old PID
1122 * has been released. FIXME : should know when release_task happens instead.
1124 exit_process(s
, zombie_process
);
1126 g_assert(s
->process
->pid
!= child_pid
);
1127 // FIXME : Add this test in the "known state" section
1128 // g_assert(s->process->pid == parent_pid);
1129 lttv_state_create_process(s
, s
->process
, child_pid
);
1135 static gboolean
process_exit(void *hook_data
, void *call_data
)
1137 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1138 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1139 LttvTraceHookByFacility
*thf
=
1140 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1141 ltt_event_facility_id(e
));
1145 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1147 // FIXME : Add this test in the "known state" section
1148 // g_assert(s->process->pid == pid);
1150 if(likely(s
->process
!= NULL
)) {
1151 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1156 static gboolean
process_free(void *hook_data
, void *call_data
)
1158 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1159 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1160 LttvTraceHookByFacility
*thf
=
1161 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1162 ltt_event_facility_id(e
));
1164 LttvProcessState
*process
;
1166 /* PID of the process to release */
1167 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1169 process
= lttv_state_find_process(s
, release_pid
);
1171 if(likely(process
!= NULL
)) {
1172 /* release_task is happening at kernel level : we can now safely release
1173 * the data structure of the process */
1174 exit_process(s
, process
);
1180 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1182 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1184 lttv_state_add_event_hooks(tss
);
1189 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1191 LttvTraceset
*traceset
= self
->parent
.ts
;
1193 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1197 LttvTracefileState
*tfs
;
1201 LttvTraceHookByFacility
*thf
;
1203 LttvTraceHook
*hook
;
1205 LttvAttributeValue val
;
1207 nb_trace
= lttv_traceset_number(traceset
);
1208 for(i
= 0 ; i
< nb_trace
; i
++) {
1209 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1211 /* Find the eventtype id for the following events and register the
1212 associated by id hooks. */
1214 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1215 g_array_set_size(hooks
, 10);
1217 lttv_trace_find_hook(ts
->parent
.t
,
1218 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1219 LTT_FIELD_SYSCALL_ID
, 0, 0,
1220 syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1222 lttv_trace_find_hook(ts
->parent
.t
,
1223 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1225 syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1227 lttv_trace_find_hook(ts
->parent
.t
,
1228 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1229 LTT_FIELD_TRAP_ID
, 0, 0,
1230 trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1232 lttv_trace_find_hook(ts
->parent
.t
,
1233 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1235 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1237 lttv_trace_find_hook(ts
->parent
.t
,
1238 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1239 LTT_FIELD_IRQ_ID
, 0, 0,
1240 irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1242 lttv_trace_find_hook(ts
->parent
.t
,
1243 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1245 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1247 lttv_trace_find_hook(ts
->parent
.t
,
1248 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1249 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1250 schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1252 lttv_trace_find_hook(ts
->parent
.t
,
1253 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1254 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1255 process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1257 lttv_trace_find_hook(ts
->parent
.t
,
1258 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1259 LTT_FIELD_PID
, 0, 0,
1260 process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1262 lttv_trace_find_hook(ts
->parent
.t
,
1263 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1264 LTT_FIELD_PID
, 0, 0,
1265 process_free
, &g_array_index(hooks
, LttvTraceHook
, 9));
1268 /* Add these hooks to each event_by_id hooks list */
1270 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1272 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1274 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1275 LttvTracefileContext
, j
));
1277 for(k
= 0 ; k
< hooks
->len
; k
++) {
1278 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1279 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1280 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1282 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1284 &g_array_index(hooks
, LttvTraceHook
, k
),
1289 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1290 *(val
.v_pointer
) = hooks
;
1294 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1296 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1298 lttv_state_remove_event_hooks(tss
);
1303 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1305 LttvTraceset
*traceset
= self
->parent
.ts
;
1307 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1311 LttvTracefileState
*tfs
;
1315 LttvTraceHook
*hook
;
1317 LttvTraceHookByFacility
*thf
;
1319 LttvAttributeValue val
;
1321 nb_trace
= lttv_traceset_number(traceset
);
1322 for(i
= 0 ; i
< nb_trace
; i
++) {
1323 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1324 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1325 hooks
= *(val
.v_pointer
);
1327 /* Remove these hooks from each event_by_id hooks list */
1329 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1331 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1333 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1334 LttvTracefileContext
*, j
));
1336 for(k
= 0 ; k
< hooks
->len
; k
++) {
1337 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1338 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1339 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1341 lttv_hooks_remove_data(
1342 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1344 &g_array_index(hooks
, LttvTraceHook
, k
));
1346 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1349 g_array_free(hooks
, TRUE
);
1354 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1356 guint
*event_count
= (guint
*)hook_data
;
1358 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1359 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1364 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1366 LttvTracefileState
*tfcs
;
1368 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1370 LttEventPosition
*ep
;
1376 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1378 LttvAttributeValue value
;
1380 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1381 LTTV_STATE_SAVED_STATES
);
1382 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1383 value
= lttv_attribute_add(saved_states_tree
,
1384 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1385 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1386 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1387 *(value
.v_time
) = self
->parent
.timestamp
;
1388 lttv_state_save(tcs
, saved_state_tree
);
1389 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1390 self
->parent
.timestamp
.tv_nsec
);
1392 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1398 static gboolean
block_start(void *hook_data
, void *call_data
)
1400 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1402 LttvTracefileState
*tfcs
;
1404 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1406 LttEventPosition
*ep
;
1408 guint i
, nb_block
, nb_event
, nb_tracefile
;
1412 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1414 LttvAttributeValue value
;
1416 ep
= ltt_event_position_new();
1418 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1420 /* Count the number of events added since the last block end in any
1423 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1425 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1426 LttvTracefileContext
, i
));
1427 ltt_event_position(tfcs
->parent
.e
, ep
);
1428 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1429 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1430 tfcs
->saved_position
= nb_event
;
1434 if(tcs
->nb_event
>= tcs
->save_interval
) {
1435 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1436 LTTV_STATE_SAVED_STATES
);
1437 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1438 value
= lttv_attribute_add(saved_states_tree
,
1439 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1440 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1441 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1442 *(value
.v_time
) = self
->parent
.timestamp
;
1443 lttv_state_save(tcs
, saved_state_tree
);
1445 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1446 self
->parent
.timestamp
.tv_nsec
);
1448 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1454 static gboolean
block_end(void *hook_data
, void *call_data
)
1456 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1458 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1462 LttEventPosition
*ep
;
1464 guint nb_block
, nb_event
;
1466 ep
= ltt_event_position_new();
1467 ltt_event_position(self
->parent
.e
, ep
);
1468 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1469 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1470 self
->saved_position
= 0;
1471 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1478 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1480 LttvTraceset
*traceset
= self
->parent
.ts
;
1482 guint i
, j
, nb_trace
, nb_tracefile
;
1486 LttvTracefileState
*tfs
;
1488 LttvTraceHook hook_start
, hook_end
;
1490 nb_trace
= lttv_traceset_number(traceset
);
1491 for(i
= 0 ; i
< nb_trace
; i
++) {
1492 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1494 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1495 NULL
, NULL
, block_start
, &hook_start
);
1496 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1497 NULL
, NULL
, block_end
, &hook_end
);
1499 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1501 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1503 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1504 LttvTracefileContext
, j
));
1505 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1506 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1507 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1508 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1514 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1516 LttvTraceset
*traceset
= self
->parent
.ts
;
1518 guint i
, j
, nb_trace
, nb_tracefile
;
1522 LttvTracefileState
*tfs
;
1525 nb_trace
= lttv_traceset_number(traceset
);
1526 for(i
= 0 ; i
< nb_trace
; i
++) {
1528 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1529 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1531 guint
*event_count
= g_new(guint
, 1);
1534 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1536 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1537 LttvTracefileContext
*, j
));
1538 lttv_hooks_add(tfs
->parent
.event
,
1539 state_save_event_hook
,
1547 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1549 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1551 lttv_state_save_add_event_hooks(tss
);
1558 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1560 LttvTraceset
*traceset
= self
->parent
.ts
;
1562 guint i
, j
, nb_trace
, nb_tracefile
;
1566 LttvTracefileState
*tfs
;
1568 LttvTraceHook hook_start
, hook_end
;
1570 nb_trace
= lttv_traceset_number(traceset
);
1571 for(i
= 0 ; i
< nb_trace
; i
++) {
1572 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1574 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1575 NULL
, NULL
, block_start
, &hook_start
);
1577 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1578 NULL
, NULL
, block_end
, &hook_end
);
1580 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1582 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1584 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1585 LttvTracefileContext
, j
));
1586 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1587 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1588 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1589 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1595 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1597 LttvTraceset
*traceset
= self
->parent
.ts
;
1599 guint i
, j
, nb_trace
, nb_tracefile
;
1603 LttvTracefileState
*tfs
;
1606 nb_trace
= lttv_traceset_number(traceset
);
1607 for(i
= 0 ; i
< nb_trace
; i
++) {
1609 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1610 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1614 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1616 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1617 LttvTracefileContext
*, j
));
1618 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1619 state_save_event_hook
);
1620 g_free(event_count
);
1626 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1628 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1630 lttv_state_save_remove_event_hooks(tss
);
1635 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1637 LttvTraceset
*traceset
= self
->parent
.ts
;
1641 int min_pos
, mid_pos
, max_pos
;
1643 LttvTraceState
*tcs
;
1645 LttvAttributeValue value
;
1647 LttvAttributeType type
;
1649 LttvAttributeName name
;
1651 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1653 nb_trace
= lttv_traceset_number(traceset
);
1654 for(i
= 0 ; i
< nb_trace
; i
++) {
1655 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1657 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1658 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1659 LTTV_STATE_SAVED_STATES
);
1662 if(saved_states_tree
) {
1663 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1664 mid_pos
= max_pos
/ 2;
1665 while(min_pos
< max_pos
) {
1666 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1667 g_assert(type
== LTTV_GOBJECT
);
1668 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1669 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1671 g_assert(type
== LTTV_TIME
);
1672 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1674 closest_tree
= saved_state_tree
;
1676 else max_pos
= mid_pos
- 1;
1678 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1682 /* restore the closest earlier saved state */
1684 lttv_state_restore(tcs
, closest_tree
);
1687 /* There is no saved state, yet we want to have it. Restart at T0 */
1689 restore_init_state(tcs
);
1690 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1693 /* We want to seek quickly without restoring/updating the state */
1695 restore_init_state(tcs
);
1696 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1703 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1709 traceset_state_finalize (LttvTracesetState
*self
)
1711 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1712 finalize(G_OBJECT(self
));
1717 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1719 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1721 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1722 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1723 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1724 klass
->new_traceset_context
= new_traceset_context
;
1725 klass
->new_trace_context
= new_trace_context
;
1726 klass
->new_tracefile_context
= new_tracefile_context
;
1731 lttv_traceset_state_get_type(void)
1733 static GType type
= 0;
1735 static const GTypeInfo info
= {
1736 sizeof (LttvTracesetStateClass
),
1737 NULL
, /* base_init */
1738 NULL
, /* base_finalize */
1739 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1740 NULL
, /* class_finalize */
1741 NULL
, /* class_data */
1742 sizeof (LttvTracesetState
),
1743 0, /* n_preallocs */
1744 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1745 NULL
/* value handling */
1748 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1756 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1762 trace_state_finalize (LttvTraceState
*self
)
1764 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1765 finalize(G_OBJECT(self
));
1770 trace_state_class_init (LttvTraceStateClass
*klass
)
1772 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1774 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1775 klass
->state_save
= state_save
;
1776 klass
->state_restore
= state_restore
;
1777 klass
->state_saved_free
= state_saved_free
;
1782 lttv_trace_state_get_type(void)
1784 static GType type
= 0;
1786 static const GTypeInfo info
= {
1787 sizeof (LttvTraceStateClass
),
1788 NULL
, /* base_init */
1789 NULL
, /* base_finalize */
1790 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1791 NULL
, /* class_finalize */
1792 NULL
, /* class_data */
1793 sizeof (LttvTraceState
),
1794 0, /* n_preallocs */
1795 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1796 NULL
/* value handling */
1799 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1800 "LttvTraceStateType", &info
, 0);
1807 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1813 tracefile_state_finalize (LttvTracefileState
*self
)
1815 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1816 finalize(G_OBJECT(self
));
1821 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1823 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1825 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1830 lttv_tracefile_state_get_type(void)
1832 static GType type
= 0;
1834 static const GTypeInfo info
= {
1835 sizeof (LttvTracefileStateClass
),
1836 NULL
, /* base_init */
1837 NULL
, /* base_finalize */
1838 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1839 NULL
, /* class_finalize */
1840 NULL
, /* class_data */
1841 sizeof (LttvTracefileState
),
1842 0, /* n_preallocs */
1843 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1844 NULL
/* value handling */
1847 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1848 "LttvTracefileStateType", &info
, 0);
1854 static void module_init()
1856 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1857 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1858 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1859 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1860 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1861 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1862 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1863 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1864 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1865 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1866 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1867 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1868 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1869 LTTV_STATE_RUN
= g_quark_from_string("running");
1870 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1871 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1872 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1873 LTTV_STATE_EVENT
= g_quark_from_string("event");
1874 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1875 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1876 LTTV_STATE_TIME
= g_quark_from_string("time");
1877 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1878 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1879 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1880 g_quark_from_string("trace_state_use_count");
1883 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1884 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1887 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1888 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1889 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1890 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1891 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1892 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1893 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1894 LTT_EVENT_FORK
= g_quark_from_string("fork");
1895 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1896 LTT_EVENT_FREE
= g_quark_from_string("free");
1899 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1900 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1901 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1902 LTT_FIELD_OUT
= g_quark_from_string("out");
1903 LTT_FIELD_IN
= g_quark_from_string("in");
1904 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1905 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1906 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1907 LTT_FIELD_PID
= g_quark_from_string("pid");
1911 static void module_destroy()
1916 LTTV_MODULE("state", "State computation", \
1917 "Update the system state, possibly saving it at intervals", \
1918 module_init
, module_destroy
)