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=%lu OFFSET=%lu 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 %lu offset %lu 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 tracefiles_tree
= lttv_attribute_find_subdir(container
,
475 LTTV_STATE_TRACEFILES
);
477 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
479 g_assert(type
== LTTV_POINTER
);
480 lttv_state_free_process_table(self
->processes
);
481 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
483 nb_tracefile
= self
->parent
.tracefiles
->len
;
485 for(i
= 0 ; i
< nb_tracefile
; i
++) {
487 LTTV_TRACEFILE_STATE(&g_array_index(self
->parent
.tracefiles
,
488 LttvTracefileContext
, i
));
489 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
490 g_assert(type
== LTTV_GOBJECT
);
491 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
493 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
495 g_assert(type
== LTTV_UINT
);
496 pid
= *(value
.v_uint
);
497 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
499 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
501 g_assert(type
== LTTV_POINTER
);
502 g_assert(*(value
.v_pointer
) != NULL
);
503 ep
= *(value
.v_pointer
);
504 g_assert(tfcs
->parent
.t_context
!= NULL
);
505 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
510 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
512 guint i
, nb_tracefile
;
514 LttvTracefileState
*tfcs
;
516 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
518 LttvAttributeType type
;
520 LttvAttributeValue value
;
522 LttvAttributeName name
;
524 LttEventPosition
*ep
;
526 tracefiles_tree
= lttv_attribute_find_subdir(container
,
527 LTTV_STATE_TRACEFILES
);
528 g_object_ref(G_OBJECT(tracefiles_tree
));
529 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
531 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
533 g_assert(type
== LTTV_POINTER
);
534 lttv_state_free_process_table(*(value
.v_pointer
));
535 *(value
.v_pointer
) = NULL
;
536 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
538 nb_tracefile
= self
->parent
.tracefiles
->len
;
540 for(i
= 0 ; i
< nb_tracefile
; i
++) {
542 LTTV_TRACEFILE_STATE(&g_array_index(self
->parent
.tracefiles
,
543 LttvTracefileContext
, i
));
544 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
545 g_assert(type
== LTTV_GOBJECT
);
546 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
548 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
550 g_assert(type
== LTTV_POINTER
);
551 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
553 g_object_unref(G_OBJECT(tracefiles_tree
));
557 static void free_saved_state(LttvTraceState
*self
)
561 LttvAttributeType type
;
563 LttvAttributeValue value
;
565 LttvAttributeName name
;
567 LttvAttribute
*saved_states
;
569 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
570 LTTV_STATE_SAVED_STATES
);
572 nb
= lttv_attribute_get_number(saved_states
);
573 for(i
= 0 ; i
< nb
; i
++) {
574 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
575 g_assert(type
== LTTV_GOBJECT
);
576 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
579 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
584 create_max_time(LttvTraceState
*tcs
)
586 LttvAttributeValue v
;
588 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
590 g_assert(*(v
.v_pointer
) == NULL
);
591 *(v
.v_pointer
) = g_new(LttTime
,1);
592 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
597 get_max_time(LttvTraceState
*tcs
)
599 LttvAttributeValue v
;
601 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
603 g_assert(*(v
.v_pointer
) != NULL
);
604 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
609 free_max_time(LttvTraceState
*tcs
)
611 LttvAttributeValue v
;
613 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
615 g_free(*(v
.v_pointer
));
616 *(v
.v_pointer
) = NULL
;
620 typedef struct _LttvNameTables
{
621 // FIXME GQuark *eventtype_names;
622 GQuark
*syscall_names
;
629 create_name_tables(LttvTraceState
*tcs
)
633 GQuark f_name
, e_name
;
637 LttvTraceHookByFacility
*thf
;
643 GString
*fe_name
= g_string_new("");
645 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
647 LttvAttributeValue v
;
649 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
651 g_assert(*(v
.v_pointer
) == NULL
);
652 *(v
.v_pointer
) = name_tables
;
653 #if 0 // Use iteration over the facilities_by_name and then list all event
654 // types of each facility
655 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
656 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
657 for(i
= 0 ; i
< nb
; i
++) {
658 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
659 e_name
= ltt_eventtype_name(et
);
660 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
661 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
662 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
665 if(lttv_trace_find_hook(tcs
->parent
.t
,
666 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
667 LTT_FIELD_SYSCALL_ID
, 0, 0,
671 thf
= lttv_trace_hook_get_first(h
);
673 t
= ltt_field_type(thf
->f1
);
674 nb
= ltt_type_element_number(t
);
676 lttv_trace_hook_destroy(h
);
678 /* CHECK syscalls should be an enum but currently are not!
679 name_tables->syscall_names = g_new(GQuark, nb);
681 for(i = 0 ; i < nb ; i++) {
682 name_tables->syscall_names[i] = g_quark_from_string(
683 ltt_enum_string_get(t, i));
687 name_tables
->syscall_names
= g_new(GQuark
, 256);
688 for(i
= 0 ; i
< 256 ; i
++) {
689 g_string_printf(fe_name
, "syscall %d", i
);
690 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
693 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
694 LTT_EVENT_TRAP_ENTRY
,
695 LTT_FIELD_TRAP_ID
, 0, 0,
699 thf
= lttv_trace_hook_get_first(h
);
701 t
= ltt_field_type(thf
->f1
);
702 nb
= ltt_type_element_number(t
);
704 lttv_trace_hook_destroy(h
);
707 name_tables->trap_names = g_new(GQuark, nb);
708 for(i = 0 ; i < nb ; i++) {
709 name_tables->trap_names[i] = g_quark_from_string(
710 ltt_enum_string_get(t, i));
714 name_tables
->trap_names
= g_new(GQuark
, 256);
715 for(i
= 0 ; i
< 256 ; i
++) {
716 g_string_printf(fe_name
, "trap %d", i
);
717 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
720 if(lttv_trace_find_hook(tcs
->parent
.t
,
721 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
722 LTT_FIELD_IRQ_ID
, 0, 0,
726 thf
= lttv_trace_hook_get_first(h
);
728 t
= ltt_field_type(thf
->f1
);
729 nb
= ltt_type_element_number(t
);
731 lttv_trace_hook_destroy(h
);
734 name_tables->irq_names = g_new(GQuark, nb);
735 for(i = 0 ; i < nb ; i++) {
736 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
740 name_tables
->irq_names
= g_new(GQuark
, 256);
741 for(i
= 0 ; i
< 256 ; i
++) {
742 g_string_printf(fe_name
, "irq %d", i
);
743 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
746 g_string_free(fe_name
, TRUE
);
751 get_name_tables(LttvTraceState
*tcs
)
753 LttvNameTables
*name_tables
;
755 LttvAttributeValue v
;
757 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
759 g_assert(*(v
.v_pointer
) != NULL
);
760 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
761 //tcs->eventtype_names = name_tables->eventtype_names;
762 tcs
->syscall_names
= name_tables
->syscall_names
;
763 tcs
->trap_names
= name_tables
->trap_names
;
764 tcs
->irq_names
= name_tables
->irq_names
;
769 free_name_tables(LttvTraceState
*tcs
)
771 LttvNameTables
*name_tables
;
773 LttvAttributeValue v
;
775 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
777 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
778 *(v
.v_pointer
) = NULL
;
780 // g_free(name_tables->eventtype_names);
781 g_free(name_tables
->syscall_names
);
782 g_free(name_tables
->trap_names
);
783 g_free(name_tables
->irq_names
);
788 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
791 LttvExecutionState
*es
;
793 LttvProcessState
*process
= tfs
->process
;
795 guint depth
= process
->execution_stack
->len
;
797 g_array_set_size(process
->execution_stack
, depth
+ 1);
798 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
801 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
802 es
->s
= process
->state
->s
;
807 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
809 LttvProcessState
*process
= tfs
->process
;
811 guint depth
= process
->execution_stack
->len
;
813 if(process
->state
->t
!= t
){
814 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
815 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
816 g_info("process state has %s when pop_int is %s\n",
817 g_quark_to_string(process
->state
->t
),
818 g_quark_to_string(t
));
819 g_info("{ %u, %u, %s, %s }\n",
822 g_quark_to_string(process
->name
),
823 g_quark_to_string(process
->state
->s
));
828 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
829 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
833 g_array_set_size(process
->execution_stack
, depth
- 1);
834 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
836 process
->state
->change
= tfs
->parent
.timestamp
;
841 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
844 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
846 LttvExecutionState
*es
;
848 LttvTraceContext
*tc
;
854 tc
= tfs
->parent
.t_context
;
855 tcs
= (LttvTraceState
*)tc
;
858 process
->last_cpu
= tfs
->cpu_name
;
859 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
860 g_warning("Process %u, core %p", process
->pid
, process
);
861 g_hash_table_insert(tcs
->processes
, process
, process
);
864 process
->ppid
= parent
->pid
;
865 process
->name
= parent
->name
;
866 process
->creation_time
= tfs
->parent
.timestamp
;
869 /* No parent. This process exists but we are missing all information about
870 its creation. The birth time is set to zero but we remember the time of
875 process
->name
= LTTV_STATE_UNNAMED
;
876 process
->creation_time
= ltt_time_zero
;
879 process
->insertion_time
= tfs
->parent
.timestamp
;
880 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
881 process
->creation_time
.tv_nsec
);
882 process
->pid_time
= g_quark_from_string(buffer
);
883 process
->last_cpu
= tfs
->cpu_name
;
884 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
885 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
886 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
887 g_array_set_size(process
->execution_stack
, 1);
888 es
= process
->state
= &g_array_index(process
->execution_stack
,
889 LttvExecutionState
, 0);
890 es
->t
= LTTV_STATE_USER_MODE
;
891 es
->n
= LTTV_STATE_SUBMODE_NONE
;
892 es
->entry
= tfs
->parent
.timestamp
;
893 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
894 es
->change
= tfs
->parent
.timestamp
;
895 es
->s
= LTTV_STATE_WAIT_FORK
;
900 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
903 LttvProcessState key
;
904 LttvProcessState
*process
;
906 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
909 key
.last_cpu
= tfs
->cpu_name
;
910 process
= g_hash_table_lookup(ts
->processes
, &key
);
915 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
917 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
919 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
923 /* FIXME : this function should be called when we receive an event telling that
924 * release_task has been called in the kernel. In happens generally when
925 * the parent waits for its child terminaison, but may also happen in special
926 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
927 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
928 * of a killed thread ground, but isn't the leader.
930 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
932 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
933 LttvProcessState key
;
935 key
.pid
= process
->pid
;
936 key
.last_cpu
= process
->last_cpu
;
937 g_hash_table_remove(ts
->processes
, &key
);
938 g_array_free(process
->execution_stack
, TRUE
);
943 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
945 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
950 static void lttv_state_free_process_table(GHashTable
*processes
)
952 g_hash_table_foreach(processes
, free_process_state
, NULL
);
953 g_hash_table_destroy(processes
);
957 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
959 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
960 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
961 LttvTraceHookByFacility
*thf
=
962 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
963 ltt_event_facility_id(e
));
964 LttField
*f
= thf
->f1
;
966 LttvExecutionSubmode submode
;
968 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
969 ltt_event_get_unsigned(e
, f
)];
970 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
975 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
977 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
979 pop_state(s
, LTTV_STATE_SYSCALL
);
984 static gboolean
trap_entry(void *hook_data
, void *call_data
)
986 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
987 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
988 LttvTraceHookByFacility
*thf
=
989 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
990 ltt_event_facility_id(e
));
991 LttField
*f
= thf
->f1
;
993 LttvExecutionSubmode submode
;
995 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
996 ltt_event_get_unsigned(e
, f
)];
997 push_state(s
, LTTV_STATE_TRAP
, submode
);
1002 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1004 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1006 pop_state(s
, LTTV_STATE_TRAP
);
1011 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1013 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1014 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1015 LttvTraceHookByFacility
*thf
=
1016 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1017 ltt_event_facility_id(e
));
1018 LttField
*f
= thf
->f1
;
1020 LttvExecutionSubmode submode
;
1022 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1023 ltt_event_get_unsigned(e
, f
)];
1025 /* Do something with the info about being in user or system mode when int? */
1026 push_state(s
, LTTV_STATE_IRQ
, submode
);
1031 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1033 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1035 pop_state(s
, LTTV_STATE_IRQ
);
1040 static gboolean
schedchange(void *hook_data
, void *call_data
)
1042 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1043 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1044 LttvTraceHookByFacility
*thf
=
1045 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1046 ltt_event_facility_id(e
));
1047 guint pid_in
, pid_out
, state_out
;
1049 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1050 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1051 state_out
= ltt_event_get_unsigned(e
, thf
->f3
);
1053 if(likely(s
->process
!= NULL
)) {
1055 /* We could not know but it was not the idle process executing.
1056 This should only happen at the beginning, before the first schedule
1057 event, and when the initial information (current process for each CPU)
1058 is missing. It is not obvious how we could, after the fact, compensate
1059 the wrongly attributed statistics. */
1061 if(unlikely(s
->process
->pid
!= pid_out
)) {
1062 g_assert(s
->process
->pid
== 0);
1065 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1066 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1068 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1069 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1070 } /* FIXME : we do not remove process here, because the kernel
1071 * still has them : they may be zombies. We need to know
1072 * exactly when release_task is executed on the PID to
1073 * know when the zombie is destroyed.
1076 // exit_process(s, s->process);
1078 s
->process
->state
->change
= s
->parent
.timestamp
;
1080 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1081 s
->process
->state
->s
= LTTV_STATE_RUN
;
1082 s
->process
->last_cpu
= s
->cpu_name
;
1083 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1084 s
->process
->state
->change
= s
->parent
.timestamp
;
1088 static gboolean
process_fork(void *hook_data
, void *call_data
)
1090 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1091 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1092 LttvTraceHookByFacility
*thf
=
1093 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1094 ltt_event_facility_id(e
));
1098 LttvProcessState
*zombie_process
;
1102 parent_pid
= ltt_event_get_unsigned(e
, f
);
1106 child_pid
= ltt_event_get_unsigned(e
, f
);
1108 zombie_process
= lttv_state_find_process(s
, child_pid
);
1110 if(unlikely(zombie_process
!= NULL
)) {
1111 /* Reutilisation of PID. Only now we are sure that the old PID
1112 * has been released. FIXME : should know when release_task happens instead.
1114 exit_process(s
, zombie_process
);
1116 g_assert(s
->process
->pid
!= child_pid
);
1117 // FIXME : Add this test in the "known state" section
1118 // g_assert(s->process->pid == parent_pid);
1119 lttv_state_create_process(s
, s
->process
, child_pid
);
1125 static gboolean
process_exit(void *hook_data
, void *call_data
)
1127 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1128 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1129 LttvTraceHookByFacility
*thf
=
1130 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1131 ltt_event_facility_id(e
));
1135 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1137 // FIXME : Add this test in the "known state" section
1138 // g_assert(s->process->pid == pid);
1140 if(likely(s
->process
!= NULL
)) {
1141 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1146 static gboolean
process_free(void *hook_data
, void *call_data
)
1148 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1149 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1150 LttvTraceHookByFacility
*thf
=
1151 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1152 ltt_event_facility_id(e
));
1154 LttvProcessState
*process
;
1156 /* PID of the process to release */
1157 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1159 process
= lttv_state_find_process(s
, release_pid
);
1161 if(likely(process
!= NULL
)) {
1162 /* release_task is happening at kernel level : we can now safely release
1163 * the data structure of the process */
1164 exit_process(s
, process
);
1170 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1172 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1174 lttv_state_add_event_hooks(tss
);
1179 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1181 LttvTraceset
*traceset
= self
->parent
.ts
;
1183 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1187 LttvTracefileState
*tfs
;
1191 LttvTraceHookByFacility
*thf
;
1193 LttvTraceHook
*hook
;
1195 LttvAttributeValue val
;
1197 nb_trace
= lttv_traceset_number(traceset
);
1198 for(i
= 0 ; i
< nb_trace
; i
++) {
1199 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1201 /* Find the eventtype id for the following events and register the
1202 associated by id hooks. */
1204 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1205 g_array_set_size(hooks
, 10);
1207 lttv_trace_find_hook(ts
->parent
.t
,
1208 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1209 LTT_FIELD_SYSCALL_ID
, 0, 0,
1210 syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1212 lttv_trace_find_hook(ts
->parent
.t
,
1213 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1215 syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1217 lttv_trace_find_hook(ts
->parent
.t
,
1218 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1219 LTT_FIELD_TRAP_ID
, 0, 0,
1220 trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1222 lttv_trace_find_hook(ts
->parent
.t
,
1223 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1225 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1227 lttv_trace_find_hook(ts
->parent
.t
,
1228 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1229 LTT_FIELD_IRQ_ID
, 0, 0,
1230 irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1232 lttv_trace_find_hook(ts
->parent
.t
,
1233 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1235 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1237 lttv_trace_find_hook(ts
->parent
.t
,
1238 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1239 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1240 schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1242 lttv_trace_find_hook(ts
->parent
.t
,
1243 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1244 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1245 process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1247 lttv_trace_find_hook(ts
->parent
.t
,
1248 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1249 LTT_FIELD_PID
, 0, 0,
1250 process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1252 lttv_trace_find_hook(ts
->parent
.t
,
1253 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1254 LTT_FIELD_PID
, 0, 0,
1255 process_free
, &g_array_index(hooks
, LttvTraceHook
, 9));
1258 /* Add these hooks to each event_by_id hooks list */
1260 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1262 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1264 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1265 LttvTracefileContext
, j
));
1267 for(k
= 0 ; k
< hooks
->len
; k
++) {
1268 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1269 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1270 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1272 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1274 &g_array_index(hooks
, LttvTraceHook
, k
),
1279 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1280 *(val
.v_pointer
) = hooks
;
1284 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1286 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1288 lttv_state_remove_event_hooks(tss
);
1293 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1295 LttvTraceset
*traceset
= self
->parent
.ts
;
1297 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1301 LttvTracefileState
*tfs
;
1305 LttvTraceHook
*hook
;
1307 LttvTraceHookByFacility
*thf
;
1309 LttvAttributeValue val
;
1311 nb_trace
= lttv_traceset_number(traceset
);
1312 for(i
= 0 ; i
< nb_trace
; i
++) {
1313 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1314 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1315 hooks
= *(val
.v_pointer
);
1317 /* Remove these hooks from each event_by_id hooks list */
1319 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1321 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1323 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1324 LttvTracefileContext
, j
));
1326 for(k
= 0 ; k
< hooks
->len
; k
++) {
1327 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1328 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1329 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1331 lttv_hooks_remove_data(
1332 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1334 &g_array_index(hooks
, LttvTraceHook
, k
));
1336 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1339 g_array_free(hooks
, TRUE
);
1344 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1346 guint
*event_count
= (guint
*)hook_data
;
1348 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1349 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1354 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1356 LttvTracefileState
*tfcs
;
1358 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1360 LttEventPosition
*ep
;
1366 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1368 LttvAttributeValue value
;
1370 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1371 LTTV_STATE_SAVED_STATES
);
1372 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1373 value
= lttv_attribute_add(saved_states_tree
,
1374 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1375 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1376 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1377 *(value
.v_time
) = self
->parent
.timestamp
;
1378 lttv_state_save(tcs
, saved_state_tree
);
1379 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1380 self
->parent
.timestamp
.tv_nsec
);
1382 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1388 static gboolean
block_start(void *hook_data
, void *call_data
)
1390 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1392 LttvTracefileState
*tfcs
;
1394 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1396 LttEventPosition
*ep
;
1398 guint i
, nb_block
, nb_event
, nb_tracefile
;
1402 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1404 LttvAttributeValue value
;
1406 ep
= ltt_event_position_new();
1408 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1410 /* Count the number of events added since the last block end in any
1413 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1415 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1416 LttvTracefileContext
, i
));
1417 ltt_event_position(tfcs
->parent
.e
, ep
);
1418 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1419 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1420 tfcs
->saved_position
= nb_event
;
1424 if(tcs
->nb_event
>= tcs
->save_interval
) {
1425 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1426 LTTV_STATE_SAVED_STATES
);
1427 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1428 value
= lttv_attribute_add(saved_states_tree
,
1429 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1430 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1431 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1432 *(value
.v_time
) = self
->parent
.timestamp
;
1433 lttv_state_save(tcs
, saved_state_tree
);
1435 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1436 self
->parent
.timestamp
.tv_nsec
);
1438 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1444 static gboolean
block_end(void *hook_data
, void *call_data
)
1446 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1448 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1452 LttEventPosition
*ep
;
1454 guint nb_block
, nb_event
;
1456 ep
= ltt_event_position_new();
1457 ltt_event_position(self
->parent
.e
, ep
);
1458 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1459 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1460 self
->saved_position
= 0;
1461 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1468 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1470 LttvTraceset
*traceset
= self
->parent
.ts
;
1472 guint i
, j
, nb_trace
, nb_tracefile
;
1476 LttvTracefileState
*tfs
;
1478 LttvTraceHook hook_start
, hook_end
;
1480 nb_trace
= lttv_traceset_number(traceset
);
1481 for(i
= 0 ; i
< nb_trace
; i
++) {
1482 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1484 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1485 NULL
, NULL
, block_start
, &hook_start
);
1486 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1487 NULL
, NULL
, block_end
, &hook_end
);
1489 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1491 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1493 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1494 LttvTracefileContext
, j
));
1495 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1496 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1497 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1498 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1504 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1506 LttvTraceset
*traceset
= self
->parent
.ts
;
1508 guint i
, j
, nb_trace
, nb_tracefile
;
1512 LttvTracefileState
*tfs
;
1515 nb_trace
= lttv_traceset_number(traceset
);
1516 for(i
= 0 ; i
< nb_trace
; i
++) {
1518 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1519 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1521 guint
*event_count
= g_new(guint
, 1);
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(tfs
->parent
.event
,
1529 state_save_event_hook
,
1537 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1539 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1541 lttv_state_save_add_event_hooks(tss
);
1548 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1550 LttvTraceset
*traceset
= self
->parent
.ts
;
1552 guint i
, j
, nb_trace
, nb_tracefile
;
1556 LttvTracefileState
*tfs
;
1558 LttvTraceHook hook_start
, hook_end
;
1560 nb_trace
= lttv_traceset_number(traceset
);
1561 for(i
= 0 ; i
< nb_trace
; i
++) {
1562 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1564 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1565 NULL
, NULL
, block_start
, &hook_start
);
1567 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1568 NULL
, NULL
, block_end
, &hook_end
);
1570 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1572 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1574 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1575 LttvTracefileContext
, j
));
1576 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1577 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1578 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1579 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1585 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1587 LttvTraceset
*traceset
= self
->parent
.ts
;
1589 guint i
, j
, nb_trace
, nb_tracefile
;
1593 LttvTracefileState
*tfs
;
1596 nb_trace
= lttv_traceset_number(traceset
);
1597 for(i
= 0 ; i
< nb_trace
; i
++) {
1599 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1600 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1604 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1606 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1607 LttvTracefileContext
, j
));
1608 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1609 state_save_event_hook
);
1610 g_free(event_count
);
1616 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1618 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1620 lttv_state_save_remove_event_hooks(tss
);
1625 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1627 LttvTraceset
*traceset
= self
->parent
.ts
;
1631 int min_pos
, mid_pos
, max_pos
;
1633 LttvTraceState
*tcs
;
1635 LttvAttributeValue value
;
1637 LttvAttributeType type
;
1639 LttvAttributeName name
;
1641 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1643 nb_trace
= lttv_traceset_number(traceset
);
1644 for(i
= 0 ; i
< nb_trace
; i
++) {
1645 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1647 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1648 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1649 LTTV_STATE_SAVED_STATES
);
1652 if(saved_states_tree
) {
1653 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1654 mid_pos
= max_pos
/ 2;
1655 while(min_pos
< max_pos
) {
1656 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1657 g_assert(type
== LTTV_GOBJECT
);
1658 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1659 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1661 g_assert(type
== LTTV_TIME
);
1662 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1664 closest_tree
= saved_state_tree
;
1666 else max_pos
= mid_pos
- 1;
1668 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1672 /* restore the closest earlier saved state */
1674 lttv_state_restore(tcs
, closest_tree
);
1677 /* There is no saved state, yet we want to have it. Restart at T0 */
1679 restore_init_state(tcs
);
1680 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1683 /* We want to seek quickly without restoring/updating the state */
1685 restore_init_state(tcs
);
1686 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1693 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1699 traceset_state_finalize (LttvTracesetState
*self
)
1701 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1702 finalize(G_OBJECT(self
));
1707 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1709 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1711 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1712 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1713 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1714 klass
->new_traceset_context
= new_traceset_context
;
1715 klass
->new_trace_context
= new_trace_context
;
1716 klass
->new_tracefile_context
= new_tracefile_context
;
1721 lttv_traceset_state_get_type(void)
1723 static GType type
= 0;
1725 static const GTypeInfo info
= {
1726 sizeof (LttvTracesetStateClass
),
1727 NULL
, /* base_init */
1728 NULL
, /* base_finalize */
1729 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1730 NULL
, /* class_finalize */
1731 NULL
, /* class_data */
1732 sizeof (LttvTracesetState
),
1733 0, /* n_preallocs */
1734 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1735 NULL
/* value handling */
1738 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1746 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1752 trace_state_finalize (LttvTraceState
*self
)
1754 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1755 finalize(G_OBJECT(self
));
1760 trace_state_class_init (LttvTraceStateClass
*klass
)
1762 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1764 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1765 klass
->state_save
= state_save
;
1766 klass
->state_restore
= state_restore
;
1767 klass
->state_saved_free
= state_saved_free
;
1772 lttv_trace_state_get_type(void)
1774 static GType type
= 0;
1776 static const GTypeInfo info
= {
1777 sizeof (LttvTraceStateClass
),
1778 NULL
, /* base_init */
1779 NULL
, /* base_finalize */
1780 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1781 NULL
, /* class_finalize */
1782 NULL
, /* class_data */
1783 sizeof (LttvTraceState
),
1784 0, /* n_preallocs */
1785 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1786 NULL
/* value handling */
1789 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1790 "LttvTraceStateType", &info
, 0);
1797 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1803 tracefile_state_finalize (LttvTracefileState
*self
)
1805 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1806 finalize(G_OBJECT(self
));
1811 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1813 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1815 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1820 lttv_tracefile_state_get_type(void)
1822 static GType type
= 0;
1824 static const GTypeInfo info
= {
1825 sizeof (LttvTracefileStateClass
),
1826 NULL
, /* base_init */
1827 NULL
, /* base_finalize */
1828 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1829 NULL
, /* class_finalize */
1830 NULL
, /* class_data */
1831 sizeof (LttvTracefileState
),
1832 0, /* n_preallocs */
1833 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1834 NULL
/* value handling */
1837 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1838 "LttvTracefileStateType", &info
, 0);
1844 static void module_init()
1846 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1847 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1848 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1849 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1850 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1851 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1852 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1853 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1854 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1855 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1856 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1857 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1858 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1859 LTTV_STATE_RUN
= g_quark_from_string("running");
1860 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1861 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1862 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1863 LTTV_STATE_EVENT
= g_quark_from_string("event");
1864 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1865 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1866 LTTV_STATE_TIME
= g_quark_from_string("time");
1867 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1868 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1869 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1870 g_quark_from_string("trace_state_use_count");
1873 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1874 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1877 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1878 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1879 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1880 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1881 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1882 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1883 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1884 LTT_EVENT_FORK
= g_quark_from_string("fork");
1885 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1886 LTT_EVENT_FREE
= g_quark_from_string("free");
1889 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1890 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1891 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1892 LTT_FIELD_OUT
= g_quark_from_string("out");
1893 LTT_FIELD_IN
= g_quark_from_string("in");
1894 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1895 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1896 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1897 LTT_FIELD_PID
= g_quark_from_string("pid");
1901 static void module_destroy()
1906 LTTV_MODULE("state", "State computation", \
1907 "Update the system state, possibly saving it at intervals", \
1908 module_init
, module_destroy
)