2 #include <lttv/state.h>
3 #include <ltt/facility.h>
9 LTTV_STATE_MODE_UNKNOWN
,
16 LTTV_STATE_SUBMODE_UNKNOWN
,
17 LTTV_STATE_SUBMODE_NONE
;
28 LTTV_STATE_TRACEFILES
,
32 LTTV_STATE_SAVED_STATES
,
37 static void fill_name_tables(LttvTraceState
*tcs
);
39 static void free_name_tables(LttvTraceState
*tcs
);
41 static void lttv_state_free_process_table(GHashTable
*processes
);
43 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
44 LttvProcessState
*parent
, guint pid
);
46 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
48 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
52 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
54 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
58 void lttv_state_saved_state_free(LttvTraceState
*self
,
59 LttvAttribute
*container
)
61 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
66 restore_init_state(LttvTraceState
*self
)
68 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
70 LttvTracefileState
*tfcs
;
72 LttTime null_time
= {0,0};
74 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
75 self
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
78 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
79 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
80 nb_tracefile
= nb_control
+ nb_per_cpu
;
81 for(i
= 0 ; i
< nb_tracefile
; i
++) {
83 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.control_tracefiles
[i
]);
86 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.per_cpu_tracefiles
[i
- nb_control
]);
89 tfcs
->parent
.timestamp
= null_time
;
90 tfcs
->saved_position
= 0;
91 tfcs
->process
= create_process(tfcs
, NULL
,0);
97 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
99 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
101 LttvTraceContext
*tc
;
105 LttvTracefileState
*tfcs
;
107 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
108 init((LttvTracesetContext
*)self
, ts
);
110 nb_trace
= lttv_traceset_number(ts
);
111 for(i
= 0 ; i
< nb_trace
; i
++) {
112 tc
= self
->parent
.traces
[i
];
113 tcs
= (LttvTraceState
*)tc
;
114 tcs
->save_interval
= 100000;
115 fill_name_tables(tcs
);
117 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
118 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
119 nb_tracefile
= nb_control
+ nb_per_cpu
;
120 for(j
= 0 ; j
< nb_tracefile
; j
++) {
122 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
125 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
127 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
129 tcs
->processes
= NULL
;
130 restore_init_state(tcs
);
136 fini(LttvTracesetState
*self
)
138 guint i
, j
, nb_trace
, nb_tracefile
;
142 LttvTracefileState
*tfcs
;
144 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
145 for(i
= 0 ; i
< nb_trace
; i
++) {
146 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
147 lttv_state_free_process_table(tcs
->processes
);
148 tcs
->processes
= NULL
;
149 free_name_tables(tcs
);
151 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
152 fini((LttvTracesetContext
*)self
);
156 static LttvTracesetContext
*
157 new_traceset_context(LttvTracesetContext
*self
)
159 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
163 static LttvTraceContext
*
164 new_trace_context(LttvTracesetContext
*self
)
166 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
170 static LttvTracefileContext
*
171 new_tracefile_context(LttvTracesetContext
*self
)
173 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
177 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
179 LttvProcessState
*process
, *new_process
;
181 GHashTable
*new_processes
= (GHashTable
*)user_data
;
185 process
= (LttvProcessState
*)value
;
186 new_process
= g_new(LttvProcessState
, 1);
187 *new_process
= *process
;
188 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
189 sizeof(LttvExecutionState
));
190 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
191 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
192 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
193 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
195 new_process
->state
= &g_array_index(new_process
->execution_stack
,
196 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
197 g_hash_table_insert(new_processes
, GUINT_TO_POINTER(new_process
->pid
),
202 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
204 GHashTable
*new_processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
206 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
207 return new_processes
;
211 /* The saved state for each trace contains a member "processes", which
212 stores a copy of the process table, and a member "tracefiles" with
213 one entry per tracefile. Each tracefile has a "process" member pointing
214 to the current process and a "position" member storing the tracefile
215 position (needed to seek to the current "next" event. */
217 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
219 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
221 LttvTracefileState
*tfcs
;
223 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
225 LttvAttributeType type
;
227 LttvAttributeValue value
;
229 LttvAttributeName name
;
231 LttEventPosition
*ep
;
233 tracefiles_tree
= lttv_attribute_find_subdir(container
,
234 LTTV_STATE_TRACEFILES
);
236 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
238 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
240 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
241 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
242 nb_tracefile
= nb_control
+ nb_per_cpu
;
244 for(i
= 0 ; i
< nb_tracefile
; i
++) {
246 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
247 else tfcs
= (LttvTracefileState
*)
248 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
250 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
251 value
= lttv_attribute_add(tracefiles_tree
, i
,
253 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
254 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
256 *(value
.v_uint
) = tfcs
->process
->pid
;
257 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
259 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
261 ep
= ltt_event_position_new();
262 ltt_event_position(tfcs
->parent
.e
, ep
);
263 *(value
.v_pointer
) = ep
;
269 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
271 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
273 LttvTracefileState
*tfcs
;
275 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
277 LttvAttributeType type
;
279 LttvAttributeValue value
;
281 LttvAttributeName name
;
283 LttEventPosition
*ep
;
285 tracefiles_tree
= lttv_attribute_find_subdir(container
,
286 LTTV_STATE_TRACEFILES
);
288 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
290 g_assert(type
== LTTV_POINTER
);
291 lttv_state_free_process_table(self
->processes
);
292 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
294 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
295 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
296 nb_tracefile
= nb_control
+ nb_per_cpu
;
298 for(i
= 0 ; i
< nb_tracefile
; i
++) {
299 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
300 self
->parent
.control_tracefiles
[i
];
301 else tfcs
= (LttvTracefileState
*)
302 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
304 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
305 g_assert(type
== LTTV_GOBJECT
);
306 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
308 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
310 g_assert(type
== LTTV_UINT
);
311 tfcs
->process
= lttv_state_find_process(tfcs
, *(value
.v_uint
));
312 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
314 g_assert(type
== LTTV_POINTER
);
315 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
317 ep
= *(value
.v_pointer
);
318 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
319 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
320 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
326 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
328 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
330 LttvTracefileState
*tfcs
;
332 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
334 LttvAttributeType type
;
336 LttvAttributeValue value
;
338 LttvAttributeName name
;
340 LttEventPosition
*ep
;
342 tracefiles_tree
= lttv_attribute_find_subdir(container
,
343 LTTV_STATE_TRACEFILES
);
344 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
346 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
348 g_assert(type
== LTTV_POINTER
);
349 lttv_state_free_process_table(*(value
.v_pointer
));
350 *(value
.v_pointer
) = NULL
;
351 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
353 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
354 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
355 nb_tracefile
= nb_control
+ nb_per_cpu
;
357 for(i
= 0 ; i
< nb_tracefile
; i
++) {
358 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
359 self
->parent
.control_tracefiles
[i
];
360 else tfcs
= (LttvTracefileState
*)
361 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
363 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
364 g_assert(type
== LTTV_GOBJECT
);
365 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
367 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
369 g_assert(type
== LTTV_POINTER
);
370 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
372 lttv_attribute_recursive_free(tracefiles_tree
);
377 fill_name_tables(LttvTraceState
*tcs
)
381 char *f_name
, *e_name
;
389 GString
*fe_name
= g_string_new("");
391 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
392 tcs
->eventtype_names
= g_new(GQuark
, nb
);
393 for(i
= 0 ; i
< nb
; i
++) {
394 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
395 e_name
= ltt_eventtype_name(et
);
396 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
397 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
398 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
401 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
402 "syscall_id", NULL
, NULL
, NULL
, &h
);
403 t
= ltt_field_type(h
.f1
);
404 nb
= ltt_type_element_number(t
);
406 /* CHECK syscalls should be an emun but currently are not!
407 tcs->syscall_names = g_new(GQuark, nb);
409 for(i = 0 ; i < nb ; i++) {
410 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
414 tcs
->syscall_names
= g_new(GQuark
, 256);
415 for(i
= 0 ; i
< 256 ; i
++) {
416 g_string_printf(fe_name
, "syscall %d", i
);
417 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
420 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
421 "trap_id", NULL
, NULL
, NULL
, &h
);
422 t
= ltt_field_type(h
.f1
);
423 nb
= ltt_type_element_number(t
);
426 tcs->trap_names = g_new(GQuark, nb);
427 for(i = 0 ; i < nb ; i++) {
428 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
432 tcs
->trap_names
= g_new(GQuark
, 256);
433 for(i
= 0 ; i
< 256 ; i
++) {
434 g_string_printf(fe_name
, "trap %d", i
);
435 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
438 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
439 "irq_id", NULL
, NULL
, NULL
, &h
);
440 t
= ltt_field_type(h
.f1
);
441 nb
= ltt_type_element_number(t
);
444 tcs->irq_names = g_new(GQuark, nb);
445 for(i = 0 ; i < nb ; i++) {
446 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
450 tcs
->irq_names
= g_new(GQuark
, 256);
451 for(i
= 0 ; i
< 256 ; i
++) {
452 g_string_printf(fe_name
, "irq %d", i
);
453 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
456 g_string_free(fe_name
, TRUE
);
461 free_name_tables(LttvTraceState
*tcs
)
463 g_free(tcs
->eventtype_names
);
464 g_free(tcs
->syscall_names
);
465 g_free(tcs
->trap_names
);
466 g_free(tcs
->irq_names
);
470 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
473 LttvExecutionState
*es
;
475 LttvProcessState
*process
= tfs
->process
;
477 guint depth
= process
->execution_stack
->len
;
479 g_array_set_size(process
->execution_stack
, depth
+ 1);
480 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
483 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
484 es
->s
= process
->state
->s
;
489 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
491 LttvProcessState
*process
= tfs
->process
;
493 guint depth
= process
->execution_stack
->len
- 1;
495 if(process
->state
->t
!= t
){
496 g_warning("Different execution mode type (%d.%09d): ignore it\n",
497 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
498 g_warning("process state has %s when pop_int is %s\n",
499 g_quark_to_string(process
->state
->t
),
500 g_quark_to_string(t
));
501 g_warning("{ %u, %u, %s, %s }\n",
504 g_quark_to_string(process
->name
),
505 g_quark_to_string(process
->state
->s
));
510 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
511 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
515 g_array_remove_index(process
->execution_stack
, depth
);
517 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
519 process
->state
->change
= tfs
->parent
.timestamp
;
523 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
524 LttvProcessState
*parent
, guint pid
)
526 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
528 LttvExecutionState
*es
;
530 LttvTraceContext
*tc
;
536 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
538 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
542 process
->ppid
= parent
->pid
;
543 process
->name
= parent
->name
;
547 process
->name
= LTTV_STATE_UNNAMED
;
550 process
->creation_time
= tfs
->parent
.timestamp
;
551 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
552 process
->creation_time
.tv_nsec
);
553 process
->pid_time
= g_quark_from_string(buffer
);
554 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
555 sizeof(LttvExecutionState
));
556 g_array_set_size(process
->execution_stack
, 1);
557 es
= process
->state
= &g_array_index(process
->execution_stack
,
558 LttvExecutionState
, 0);
559 es
->t
= LTTV_STATE_USER_MODE
;
560 es
->n
= LTTV_STATE_SUBMODE_NONE
;
561 es
->entry
= tfs
->parent
.timestamp
;
562 es
->change
= tfs
->parent
.timestamp
;
563 es
->s
= LTTV_STATE_WAIT_FORK
;
569 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
572 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
573 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
574 GUINT_TO_POINTER(pid
));
575 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
580 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
582 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
584 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
585 g_array_free(process
->execution_stack
, TRUE
);
590 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
592 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
597 static void lttv_state_free_process_table(GHashTable
*processes
)
599 g_hash_table_foreach(processes
, free_process_state
, NULL
);
600 g_hash_table_destroy(processes
);
604 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
606 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
608 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
610 LttvExecutionSubmode submode
;
612 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
613 ltt_event_get_unsigned(s
->parent
.e
, f
)];
614 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
619 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
621 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
623 pop_state(s
, LTTV_STATE_SYSCALL
);
628 static gboolean
trap_entry(void *hook_data
, void *call_data
)
630 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
632 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
634 LttvExecutionSubmode submode
;
636 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
637 ltt_event_get_unsigned(s
->parent
.e
, f
)];
638 push_state(s
, LTTV_STATE_TRAP
, submode
);
643 static gboolean
trap_exit(void *hook_data
, void *call_data
)
645 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
647 pop_state(s
, LTTV_STATE_TRAP
);
652 static gboolean
irq_entry(void *hook_data
, void *call_data
)
654 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
656 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
658 LttvExecutionSubmode submode
;
660 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
661 ltt_event_get_unsigned(s
->parent
.e
, f
)];
663 /* Do something with the info about being in user or system mode when int? */
664 push_state(s
, LTTV_STATE_IRQ
, submode
);
669 static gboolean
irq_exit(void *hook_data
, void *call_data
)
671 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
673 pop_state(s
, LTTV_STATE_IRQ
);
678 static gboolean
schedchange(void *hook_data
, void *call_data
)
680 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
682 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
684 guint pid_in
, pid_out
, state_out
;
686 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
687 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
688 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
690 if(s
->process
!= NULL
) {
692 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
693 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
694 exit_process(s
, s
->process
);
695 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
697 if(s
->process
->pid
== 0)
698 s
->process
->pid
= pid_out
;
700 s
->process
->state
->change
= s
->parent
.timestamp
;
702 s
->process
= lttv_state_find_process(s
, pid_in
);
703 s
->process
->state
->s
= LTTV_STATE_RUN
;
704 s
->process
->state
->change
= s
->parent
.timestamp
;
709 static gboolean
process_fork(void *hook_data
, void *call_data
)
711 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
713 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
717 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
718 create_process(s
, s
->process
, child_pid
);
723 static gboolean
process_exit(void *hook_data
, void *call_data
)
725 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
727 if(s
->process
!= NULL
) {
728 s
->process
->state
->s
= LTTV_STATE_EXIT
;
734 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
736 LttvTraceset
*traceset
= self
->parent
.ts
;
738 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
742 LttvTracefileState
*tfs
;
748 LttvAttributeValue val
;
750 nb_trace
= lttv_traceset_number(traceset
);
751 for(i
= 0 ; i
< nb_trace
; i
++) {
752 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
754 /* Find the eventtype id for the following events and register the
755 associated by id hooks. */
757 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
758 g_array_set_size(hooks
, 9);
760 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
761 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
763 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
764 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
766 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
767 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
769 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
770 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
772 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
773 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
775 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
776 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
778 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
779 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
781 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
782 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
784 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
785 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
787 /* Add these hooks to each before_event_by_id hooks list */
789 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
790 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
791 nb_tracefile
= nb_control
+ nb_per_cpu
;
792 for(j
= 0 ; j
< nb_tracefile
; j
++) {
794 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
797 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
800 for(k
= 0 ; k
< hooks
->len
; k
++) {
801 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
802 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
803 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
806 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
807 *(val
.v_pointer
) = hooks
;
812 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
814 LttvTraceset
*traceset
= self
->parent
.ts
;
816 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
820 LttvTracefileState
*tfs
;
826 LttvAttributeValue val
;
828 nb_trace
= lttv_traceset_number(traceset
);
829 for(i
= 0 ; i
< nb_trace
; i
++) {
830 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
831 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
832 hooks
= *(val
.v_pointer
);
834 /* Add these hooks to each before_event_by_id hooks list */
836 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
837 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
838 nb_tracefile
= nb_control
+ nb_per_cpu
;
839 for(j
= 0 ; j
< nb_tracefile
; j
++) {
841 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
844 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
847 for(k
= 0 ; k
< hooks
->len
; k
++) {
848 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
849 lttv_hooks_remove_data(
850 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
851 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
854 g_array_free(hooks
, TRUE
);
859 static gboolean
block_end(void *hook_data
, void *call_data
)
861 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
863 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
865 LttEventPosition
*ep
= ltt_event_position_new();
867 guint nb_block
, nb_event
;
871 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
873 LttvAttributeValue value
;
875 ltt_event_position(tfcs
->parent
.e
, ep
);
877 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
878 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
879 tfcs
->saved_position
= 0;
880 if(tcs
->nb_event
>= tcs
->save_interval
) {
881 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
882 LTTV_STATE_SAVED_STATES
);
883 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
884 value
= lttv_attribute_add(saved_states_tree
,
885 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
886 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
887 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
888 *(value
.v_time
) = tfcs
->parent
.timestamp
;
889 lttv_state_save(tcs
, saved_state_tree
);
896 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
898 LttvTraceset
*traceset
= self
->parent
.ts
;
900 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
904 LttvTracefileState
*tfs
;
908 nb_trace
= lttv_traceset_number(traceset
);
909 for(i
= 0 ; i
< nb_trace
; i
++) {
910 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
911 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
912 NULL
, NULL
, block_end
, &hook
);
914 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
915 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
916 nb_tracefile
= nb_control
+ nb_per_cpu
;
917 for(j
= 0 ; j
< nb_tracefile
; j
++) {
919 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
922 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
925 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
926 hook
.id
), hook
.h
, NULL
);
932 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
934 LttvTraceset
*traceset
= self
->parent
.ts
;
936 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
940 LttvTracefileState
*tfs
;
944 nb_trace
= lttv_traceset_number(traceset
);
945 for(i
= 0 ; i
< nb_trace
; i
++) {
946 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
947 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
948 NULL
, NULL
, block_end
, &hook
);
950 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
951 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
952 nb_tracefile
= nb_control
+ nb_per_cpu
;
953 for(j
= 0 ; j
< nb_tracefile
; j
++) {
955 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
958 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
961 lttv_hooks_remove_data(lttv_hooks_by_id_find(
962 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
968 void lttv_state_restore_closest_state(LttvTracesetState
*self
, LttTime t
)
970 LttvTraceset
*traceset
= self
->parent
.ts
;
972 guint i
, j
, nb_trace
, nb_saved_state
;
974 int min_pos
, mid_pos
, max_pos
;
978 LttvAttributeValue value
;
980 LttvAttributeType type
;
982 LttvAttributeName name
;
984 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
986 nb_trace
= lttv_traceset_number(traceset
);
987 for(i
= 0 ; i
< nb_trace
; i
++) {
988 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
990 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
991 LTTV_STATE_SAVED_STATES
);
993 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
994 mid_pos
= max_pos
/ 2;
995 while(min_pos
< max_pos
) {
996 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
997 g_assert(type
== LTTV_GOBJECT
);
998 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
999 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1001 g_assert(type
== LTTV_TIME
);
1002 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1004 closest_tree
= saved_state_tree
;
1006 else max_pos
= mid_pos
- 1;
1008 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1011 restore_init_state(tcs
);
1012 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1014 else lttv_state_restore(tcs
, closest_tree
);
1020 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1026 traceset_state_finalize (LttvTracesetState
*self
)
1028 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1029 finalize(G_OBJECT(self
));
1034 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1036 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1038 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1039 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1040 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1041 klass
->new_traceset_context
= new_traceset_context
;
1042 klass
->new_trace_context
= new_trace_context
;
1043 klass
->new_tracefile_context
= new_tracefile_context
;
1048 lttv_traceset_state_get_type(void)
1050 static GType type
= 0;
1052 static const GTypeInfo info
= {
1053 sizeof (LttvTracesetStateClass
),
1054 NULL
, /* base_init */
1055 NULL
, /* base_finalize */
1056 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1057 NULL
, /* class_finalize */
1058 NULL
, /* class_data */
1059 sizeof (LttvTracesetContext
),
1060 0, /* n_preallocs */
1061 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1064 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1072 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1078 trace_state_finalize (LttvTraceState
*self
)
1080 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1081 finalize(G_OBJECT(self
));
1086 trace_state_class_init (LttvTraceStateClass
*klass
)
1088 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1090 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1091 klass
->state_save
= state_save
;
1092 klass
->state_restore
= state_restore
;
1093 klass
->state_saved_free
= state_saved_free
;
1098 lttv_trace_state_get_type(void)
1100 static GType type
= 0;
1102 static const GTypeInfo info
= {
1103 sizeof (LttvTraceStateClass
),
1104 NULL
, /* base_init */
1105 NULL
, /* base_finalize */
1106 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1107 NULL
, /* class_finalize */
1108 NULL
, /* class_data */
1109 sizeof (LttvTraceState
),
1110 0, /* n_preallocs */
1111 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1114 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1115 "LttvTraceStateType", &info
, 0);
1122 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1128 tracefile_state_finalize (LttvTracefileState
*self
)
1130 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1131 finalize(G_OBJECT(self
));
1136 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1138 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1140 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1145 lttv_tracefile_state_get_type(void)
1147 static GType type
= 0;
1149 static const GTypeInfo info
= {
1150 sizeof (LttvTracefileStateClass
),
1151 NULL
, /* base_init */
1152 NULL
, /* base_finalize */
1153 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1154 NULL
, /* class_finalize */
1155 NULL
, /* class_data */
1156 sizeof (LttvTracefileState
),
1157 0, /* n_preallocs */
1158 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1161 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1162 "LttvTracefileStateType", &info
, 0);
1168 void lttv_state_init(int argc
, char **argv
)
1170 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1171 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1172 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1173 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1174 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1175 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1176 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1177 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1178 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1179 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1180 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1181 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1182 LTTV_STATE_RUN
= g_quark_from_string("running");
1183 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1184 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1185 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1186 LTTV_STATE_EVENT
= g_quark_from_string("event");
1187 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1188 LTTV_STATE_TIME
= g_quark_from_string("time");
1189 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1192 void lttv_state_destroy()