2 #include <lttv/state.h>
3 #include <ltt/facility.h>
8 LTTV_STATE_MODE_UNKNOWN
,
15 LTTV_STATE_SUBMODE_UNKNOWN
,
16 LTTV_STATE_SUBMODE_NONE
;
27 LTTV_STATE_TRACEFILES
,
31 LTTV_STATE_SAVED_STATES
,
36 static void fill_name_tables(LttvTraceState
*tcs
);
38 static void free_name_tables(LttvTraceState
*tcs
);
40 static void lttv_state_free_process_table(GHashTable
*processes
);
42 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
43 LttvProcessState
*parent
, guint pid
);
45 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
47 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
51 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
53 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
57 void lttv_state_saved_state_free(LttvTraceState
*self
,
58 LttvAttribute
*container
)
60 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
65 restore_init_state(LttvTraceState
*self
)
67 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
69 LttvTracefileState
*tfcs
;
71 LttTime null_time
= {0,0};
73 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
74 self
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
77 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
78 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
79 nb_tracefile
= nb_control
+ nb_per_cpu
;
80 for(i
= 0 ; i
< nb_tracefile
; i
++) {
82 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.control_tracefiles
[i
]);
85 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.per_cpu_tracefiles
[i
- nb_control
]);
88 tfcs
->parent
.timestamp
= null_time
;
89 tfcs
->saved_position
= 0;
90 tfcs
->process
= create_process(tfcs
, NULL
,0);
96 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
98 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
100 LttvTraceContext
*tc
;
104 LttvTracefileState
*tfcs
;
106 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
107 init((LttvTracesetContext
*)self
, ts
);
109 nb_trace
= lttv_traceset_number(ts
);
110 for(i
= 0 ; i
< nb_trace
; i
++) {
111 tc
= self
->parent
.traces
[i
];
112 tcs
= (LttvTraceState
*)tc
;
113 tcs
->save_interval
= 100000;
114 fill_name_tables(tcs
);
116 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
117 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
118 nb_tracefile
= nb_control
+ nb_per_cpu
;
119 for(j
= 0 ; j
< nb_tracefile
; j
++) {
121 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
124 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
126 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
128 tcs
->processes
= NULL
;
129 restore_init_state(tcs
);
135 fini(LttvTracesetState
*self
)
137 guint i
, j
, nb_trace
, nb_tracefile
;
141 LttvTracefileState
*tfcs
;
143 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
144 for(i
= 0 ; i
< nb_trace
; i
++) {
145 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
146 lttv_state_free_process_table(tcs
->processes
);
147 tcs
->processes
= NULL
;
148 free_name_tables(tcs
);
150 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
151 fini((LttvTracesetContext
*)self
);
155 static LttvTracesetContext
*
156 new_traceset_context(LttvTracesetContext
*self
)
158 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
162 static LttvTraceContext
*
163 new_trace_context(LttvTracesetContext
*self
)
165 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
169 static LttvTracefileContext
*
170 new_tracefile_context(LttvTracesetContext
*self
)
172 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
176 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
178 LttvProcessState
*process
, *new_process
;
180 GHashTable
*new_processes
= (GHashTable
*)user_data
;
184 process
= (LttvProcessState
*)value
;
185 new_process
= g_new(LttvProcessState
, 1);
186 *new_process
= *process
;
187 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
188 sizeof(LttvExecutionState
));
189 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
190 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
191 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
192 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
194 new_process
->state
= &g_array_index(new_process
->execution_stack
,
195 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
196 g_hash_table_insert(new_processes
, GUINT_TO_POINTER(new_process
->pid
),
201 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
203 GHashTable
*new_processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
205 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
206 return new_processes
;
210 /* The saved state for each trace contains a member "processes", which
211 stores a copy of the process table, and a member "tracefiles" with
212 one entry per tracefile. Each tracefile has a "process" member pointing
213 to the current process and a "position" member storing the tracefile
214 position (needed to seek to the current "next" event. */
216 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
218 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
220 LttvTracefileState
*tfcs
;
222 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
224 LttvAttributeType type
;
226 LttvAttributeValue value
;
228 LttvAttributeName name
;
230 LttEventPosition
*ep
;
232 tracefiles_tree
= lttv_attribute_find_subdir(container
,
233 LTTV_STATE_TRACEFILES
);
235 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
237 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
239 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
240 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
241 nb_tracefile
= nb_control
+ nb_per_cpu
;
243 for(i
= 0 ; i
< nb_tracefile
; i
++) {
245 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
246 else tfcs
= (LttvTracefileState
*)
247 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
249 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
250 value
= lttv_attribute_add(tracefiles_tree
, i
,
252 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
253 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
255 *(value
.v_uint
) = tfcs
->process
->pid
;
256 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
258 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
260 ep
= g_new(LttEventPosition
, 1);
261 ltt_event_position(tfcs
->parent
.e
, ep
);
262 *(value
.v_pointer
) = ep
;
268 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
270 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
272 LttvTracefileState
*tfcs
;
274 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
276 LttvAttributeType type
;
278 LttvAttributeValue value
;
280 LttvAttributeName name
;
282 LttEventPosition
*ep
;
284 tracefiles_tree
= lttv_attribute_find_subdir(container
,
285 LTTV_STATE_TRACEFILES
);
287 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
289 g_assert(type
== LTTV_POINTER
);
290 lttv_state_free_process_table(self
->processes
);
291 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
293 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
294 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
295 nb_tracefile
= nb_control
+ nb_per_cpu
;
297 for(i
= 0 ; i
< nb_tracefile
; i
++) {
298 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
299 self
->parent
.control_tracefiles
[i
];
300 else tfcs
= (LttvTracefileState
*)
301 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
303 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
304 g_assert(type
== LTTV_GOBJECT
);
305 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
307 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
309 g_assert(type
== LTTV_UINT
);
310 tfcs
->process
= lttv_state_find_process(tfcs
, *(value
.v_uint
));
311 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
313 g_assert(type
== LTTV_POINTER
);
314 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
316 ep
= *(value
.v_pointer
);
317 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
318 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
319 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
325 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
327 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
329 LttvTracefileState
*tfcs
;
331 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
333 LttvAttributeType type
;
335 LttvAttributeValue value
;
337 LttvAttributeName name
;
339 LttEventPosition
*ep
;
341 tracefiles_tree
= lttv_attribute_find_subdir(container
,
342 LTTV_STATE_TRACEFILES
);
343 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
345 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
347 g_assert(type
== LTTV_POINTER
);
348 lttv_state_free_process_table(*(value
.v_pointer
));
349 *(value
.v_pointer
) = NULL
;
350 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
352 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
353 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
354 nb_tracefile
= nb_control
+ nb_per_cpu
;
356 for(i
= 0 ; i
< nb_tracefile
; i
++) {
357 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
358 self
->parent
.control_tracefiles
[i
];
359 else tfcs
= (LttvTracefileState
*)
360 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
362 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
363 g_assert(type
== LTTV_GOBJECT
);
364 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
366 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
368 g_assert(type
== LTTV_POINTER
);
369 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
371 lttv_attribute_recursive_free(tracefiles_tree
);
376 fill_name_tables(LttvTraceState
*tcs
)
380 char *f_name
, *e_name
;
388 GString
*fe_name
= g_string_new("");
390 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
391 tcs
->eventtype_names
= g_new(GQuark
, nb
);
392 for(i
= 0 ; i
< nb
; i
++) {
393 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
394 e_name
= ltt_eventtype_name(et
);
395 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
396 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
397 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
400 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
401 "syscall_id", NULL
, NULL
, NULL
, &h
);
402 t
= ltt_field_type(h
.f1
);
403 nb
= ltt_type_element_number(t
);
405 /* CHECK syscalls should be an emun but currently are not!
406 tcs->syscall_names = g_new(GQuark, nb);
408 for(i = 0 ; i < nb ; i++) {
409 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
413 tcs
->syscall_names
= g_new(GQuark
, 256);
414 for(i
= 0 ; i
< 256 ; i
++) {
415 g_string_printf(fe_name
, "syscall %d", i
);
416 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
419 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
420 "trap_id", NULL
, NULL
, NULL
, &h
);
421 t
= ltt_field_type(h
.f1
);
422 nb
= ltt_type_element_number(t
);
425 tcs->trap_names = g_new(GQuark, nb);
426 for(i = 0 ; i < nb ; i++) {
427 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
431 tcs
->trap_names
= g_new(GQuark
, 256);
432 for(i
= 0 ; i
< 256 ; i
++) {
433 g_string_printf(fe_name
, "trap %d", i
);
434 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
437 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
438 "irq_id", NULL
, NULL
, NULL
, &h
);
439 t
= ltt_field_type(h
.f1
);
440 nb
= ltt_type_element_number(t
);
443 tcs->irq_names = g_new(GQuark, nb);
444 for(i = 0 ; i < nb ; i++) {
445 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
449 tcs
->irq_names
= g_new(GQuark
, 256);
450 for(i
= 0 ; i
< 256 ; i
++) {
451 g_string_printf(fe_name
, "irq %d", i
);
452 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
455 g_string_free(fe_name
, TRUE
);
460 free_name_tables(LttvTraceState
*tcs
)
462 g_free(tcs
->eventtype_names
);
463 g_free(tcs
->syscall_names
);
464 g_free(tcs
->trap_names
);
465 g_free(tcs
->irq_names
);
469 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
472 LttvExecutionState
*es
;
474 LttvProcessState
*process
= tfs
->process
;
476 guint depth
= process
->execution_stack
->len
;
478 g_array_set_size(process
->execution_stack
, depth
+ 1);
479 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
482 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
483 es
->s
= process
->state
->s
;
488 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
490 LttvProcessState
*process
= tfs
->process
;
492 guint depth
= process
->execution_stack
->len
- 1;
494 if(process
->state
->t
!= t
){
495 g_warning("Different execution mode type (%d.%09d): ignore it\n",
496 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
497 g_warning("process state has %s when pop_int is %s\n",
498 g_quark_to_string(process
->state
->t
),
499 g_quark_to_string(t
));
500 g_warning("{ %u, %u, %s, %s }\n",
503 g_quark_to_string(process
->name
),
504 g_quark_to_string(process
->state
->s
));
509 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
510 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
514 g_array_remove_index(process
->execution_stack
, depth
);
516 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
518 process
->state
->change
= tfs
->parent
.timestamp
;
522 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
523 LttvProcessState
*parent
, guint pid
)
525 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
527 LttvExecutionState
*es
;
529 LttvTraceContext
*tc
;
535 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
537 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
541 process
->ppid
= parent
->pid
;
542 process
->name
= parent
->name
;
546 process
->name
= LTTV_STATE_UNNAMED
;
549 process
->creation_time
= tfs
->parent
.timestamp
;
550 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
551 process
->creation_time
.tv_nsec
);
552 process
->pid_time
= g_quark_from_string(buffer
);
553 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
554 sizeof(LttvExecutionState
));
555 g_array_set_size(process
->execution_stack
, 1);
556 es
= process
->state
= &g_array_index(process
->execution_stack
,
557 LttvExecutionState
, 0);
558 es
->t
= LTTV_STATE_USER_MODE
;
559 es
->n
= LTTV_STATE_SUBMODE_NONE
;
560 es
->entry
= tfs
->parent
.timestamp
;
561 es
->change
= tfs
->parent
.timestamp
;
562 es
->s
= LTTV_STATE_WAIT_FORK
;
568 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
571 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
572 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
573 GUINT_TO_POINTER(pid
));
574 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
579 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
581 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
583 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
584 g_array_free(process
->execution_stack
, TRUE
);
589 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
591 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
596 static void lttv_state_free_process_table(GHashTable
*processes
)
598 g_hash_table_foreach(processes
, free_process_state
, NULL
);
599 g_hash_table_destroy(processes
);
603 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
605 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
607 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
609 LttvExecutionSubmode submode
;
611 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
612 ltt_event_get_unsigned(s
->parent
.e
, f
)];
613 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
618 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
620 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
622 pop_state(s
, LTTV_STATE_SYSCALL
);
627 static gboolean
trap_entry(void *hook_data
, void *call_data
)
629 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
631 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
633 LttvExecutionSubmode submode
;
635 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
636 ltt_event_get_unsigned(s
->parent
.e
, f
)];
637 push_state(s
, LTTV_STATE_TRAP
, submode
);
642 static gboolean
trap_exit(void *hook_data
, void *call_data
)
644 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
646 pop_state(s
, LTTV_STATE_TRAP
);
651 static gboolean
irq_entry(void *hook_data
, void *call_data
)
653 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
655 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
657 LttvExecutionSubmode submode
;
659 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
660 ltt_event_get_unsigned(s
->parent
.e
, f
)];
662 /* Do something with the info about being in user or system mode when int? */
663 push_state(s
, LTTV_STATE_IRQ
, submode
);
668 static gboolean
irq_exit(void *hook_data
, void *call_data
)
670 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
672 pop_state(s
, LTTV_STATE_IRQ
);
677 static gboolean
schedchange(void *hook_data
, void *call_data
)
679 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
681 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
683 guint pid_in
, pid_out
, state_out
;
685 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
686 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
687 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
689 if(s
->process
!= NULL
) {
691 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
692 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
693 exit_process(s
, s
->process
);
694 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
696 if(s
->process
->pid
== 0)
697 s
->process
->pid
== pid_out
;
699 s
->process
->state
->change
= s
->parent
.timestamp
;
701 s
->process
= lttv_state_find_process(s
, pid_in
);
702 s
->process
->state
->s
= LTTV_STATE_RUN
;
703 s
->process
->state
->change
= s
->parent
.timestamp
;
708 static gboolean
process_fork(void *hook_data
, void *call_data
)
710 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
712 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
716 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
717 create_process(s
, s
->process
, child_pid
);
722 static gboolean
process_exit(void *hook_data
, void *call_data
)
724 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
726 if(s
->process
!= NULL
) {
727 s
->process
->state
->s
= LTTV_STATE_EXIT
;
733 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
735 LttvTraceset
*traceset
= self
->parent
.ts
;
737 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
741 LttvTracefileState
*tfs
;
747 LttvAttributeValue val
;
749 nb_trace
= lttv_traceset_number(traceset
);
750 for(i
= 0 ; i
< nb_trace
; i
++) {
751 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
753 /* Find the eventtype id for the following events and register the
754 associated by id hooks. */
756 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
757 g_array_set_size(hooks
, 9);
759 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
760 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
762 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
763 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
765 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
766 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
768 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
769 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
771 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
772 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
774 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
775 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
777 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
778 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
780 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
781 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
783 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
784 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
786 /* Add these hooks to each before_event_by_id hooks list */
788 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
789 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
790 nb_tracefile
= nb_control
+ nb_per_cpu
;
791 for(j
= 0 ; j
< nb_tracefile
; j
++) {
793 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
796 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
799 for(k
= 0 ; k
< hooks
->len
; k
++) {
800 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
801 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
802 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
805 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
806 *(val
.v_pointer
) = hooks
;
811 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
813 LttvTraceset
*traceset
= self
->parent
.ts
;
815 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
819 LttvTracefileState
*tfs
;
825 LttvAttributeValue val
;
827 nb_trace
= lttv_traceset_number(traceset
);
828 for(i
= 0 ; i
< nb_trace
; i
++) {
829 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
830 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
831 hooks
= *(val
.v_pointer
);
833 /* Add these hooks to each before_event_by_id hooks list */
835 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
836 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
837 nb_tracefile
= nb_control
+ nb_per_cpu
;
838 for(j
= 0 ; j
< nb_tracefile
; j
++) {
840 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
843 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
846 for(k
= 0 ; k
< hooks
->len
; k
++) {
847 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
848 lttv_hooks_remove_data(
849 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
850 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
853 g_array_free(hooks
, TRUE
);
858 static gboolean
block_end(void *hook_data
, void *call_data
)
860 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
862 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
866 guint nb_block
, nb_event
;
870 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
872 LttvAttributeValue value
;
874 ltt_event_position(tfcs
->parent
.e
, &ep
);
876 ltt_event_position_get(&ep
, &nb_block
, &nb_event
, &tf
);
877 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
878 tfcs
->saved_position
= 0;
879 if(tcs
->nb_event
>= tcs
->save_interval
) {
880 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
881 LTTV_STATE_SAVED_STATES
);
882 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
883 value
= lttv_attribute_add(saved_states_tree
,
884 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
885 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
886 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
887 *(value
.v_time
) = tfcs
->parent
.timestamp
;
888 lttv_state_save(tcs
, saved_state_tree
);
895 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
897 LttvTraceset
*traceset
= self
->parent
.ts
;
899 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
903 LttvTracefileState
*tfs
;
907 nb_trace
= lttv_traceset_number(traceset
);
908 for(i
= 0 ; i
< nb_trace
; i
++) {
909 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
910 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
911 NULL
, NULL
, block_end
, &hook
);
913 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
914 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
915 nb_tracefile
= nb_control
+ nb_per_cpu
;
916 for(j
= 0 ; j
< nb_tracefile
; j
++) {
918 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
921 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
924 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
925 hook
.id
), hook
.h
, NULL
);
931 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
933 LttvTraceset
*traceset
= self
->parent
.ts
;
935 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
939 LttvTracefileState
*tfs
;
943 nb_trace
= lttv_traceset_number(traceset
);
944 for(i
= 0 ; i
< nb_trace
; i
++) {
945 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
946 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
947 NULL
, NULL
, block_end
, &hook
);
949 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
950 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
951 nb_tracefile
= nb_control
+ nb_per_cpu
;
952 for(j
= 0 ; j
< nb_tracefile
; j
++) {
954 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
957 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
960 lttv_hooks_remove_data(lttv_hooks_by_id_find(
961 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
967 void lttv_state_restore_closest_state(LttvTracesetState
*self
, LttTime t
)
969 LttvTraceset
*traceset
= self
->parent
.ts
;
971 guint i
, j
, nb_trace
, nb_saved_state
;
973 int min_pos
, mid_pos
, max_pos
;
977 LttvAttributeValue value
;
979 LttvAttributeType type
;
981 LttvAttributeName name
;
983 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
985 nb_trace
= lttv_traceset_number(traceset
);
986 for(i
= 0 ; i
< nb_trace
; i
++) {
987 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
989 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
990 LTTV_STATE_SAVED_STATES
);
992 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
993 mid_pos
= max_pos
/ 2;
994 while(min_pos
< max_pos
) {
995 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
996 g_assert(type
== LTTV_GOBJECT
);
997 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
998 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1000 g_assert(type
== LTTV_TIME
);
1001 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1003 closest_tree
= saved_state_tree
;
1005 else max_pos
= mid_pos
- 1;
1007 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1010 restore_init_state(tcs
);
1011 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1013 else lttv_state_restore(tcs
, closest_tree
);
1019 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1025 traceset_state_finalize (LttvTracesetState
*self
)
1027 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1028 finalize(G_OBJECT(self
));
1033 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1035 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1037 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1038 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1039 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1040 klass
->new_traceset_context
= new_traceset_context
;
1041 klass
->new_trace_context
= new_trace_context
;
1042 klass
->new_tracefile_context
= new_tracefile_context
;
1047 lttv_traceset_state_get_type(void)
1049 static GType type
= 0;
1051 static const GTypeInfo info
= {
1052 sizeof (LttvTracesetStateClass
),
1053 NULL
, /* base_init */
1054 NULL
, /* base_finalize */
1055 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1056 NULL
, /* class_finalize */
1057 NULL
, /* class_data */
1058 sizeof (LttvTracesetContext
),
1059 0, /* n_preallocs */
1060 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1063 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1071 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1077 trace_state_finalize (LttvTraceState
*self
)
1079 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1080 finalize(G_OBJECT(self
));
1085 trace_state_class_init (LttvTraceStateClass
*klass
)
1087 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1089 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1090 klass
->state_save
= state_save
;
1091 klass
->state_restore
= state_restore
;
1092 klass
->state_saved_free
= state_saved_free
;
1097 lttv_trace_state_get_type(void)
1099 static GType type
= 0;
1101 static const GTypeInfo info
= {
1102 sizeof (LttvTraceStateClass
),
1103 NULL
, /* base_init */
1104 NULL
, /* base_finalize */
1105 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1106 NULL
, /* class_finalize */
1107 NULL
, /* class_data */
1108 sizeof (LttvTraceState
),
1109 0, /* n_preallocs */
1110 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1113 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1114 "LttvTraceStateType", &info
, 0);
1121 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1127 tracefile_state_finalize (LttvTracefileState
*self
)
1129 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1130 finalize(G_OBJECT(self
));
1135 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1137 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1139 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1144 lttv_tracefile_state_get_type(void)
1146 static GType type
= 0;
1148 static const GTypeInfo info
= {
1149 sizeof (LttvTracefileStateClass
),
1150 NULL
, /* base_init */
1151 NULL
, /* base_finalize */
1152 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1153 NULL
, /* class_finalize */
1154 NULL
, /* class_data */
1155 sizeof (LttvTracefileState
),
1156 0, /* n_preallocs */
1157 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1160 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1161 "LttvTracefileStateType", &info
, 0);
1167 void lttv_state_init(int argc
, char **argv
)
1169 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1170 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1171 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1172 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1173 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1174 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1175 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1176 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1177 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1178 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1179 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1180 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1181 LTTV_STATE_RUN
= g_quark_from_string("running");
1182 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1183 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1184 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1185 LTTV_STATE_EVENT
= g_quark_from_string("event");
1186 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1187 LTTV_STATE_TIME
= g_quark_from_string("time");
1188 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1191 void lttv_state_destroy()