2 #include <lttv/state.h>
3 #include <ltt/facility.h>
24 void remove_all_processes(GHashTable
*processes
);
26 LttvProcessState
*create_process(LttvTracefileState
*tfs
,
27 LttvProcessState
*parent
, guint pid
);
30 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
32 guint i
, j
, nb_trace
, nb_tracefile
;
38 LttvTracefileContext
*tfc
;
40 LttvTracefileState
*tfcs
;
42 LttTime timestamp
= {0,0};
44 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->init((LttvTracesetContext
*)self
, ts
);
46 nb_trace
= lttv_traceset_number(ts
);
47 for(i
= 0 ; i
< nb_trace
; i
++) {
48 tcs
= (LttvTraceState
*)tc
= (LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
49 tcs
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
51 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
);
52 for(j
= 0 ; j
< nb_tracefile
; j
++) {
53 tfcs
= (LttvTracefileState
*)tfc
= tc
->control_tracefiles
[j
];
54 tfc
->timestamp
= timestamp
;
55 tfcs
->process
= create_process(tfcs
, NULL
,0);
58 nb_tracefile
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
59 for(j
= 0 ; j
< nb_tracefile
; j
++) {
60 tfcs
= (LttvTracefileState
*)tfc
= tc
->per_cpu_tracefiles
[j
];
61 tfc
->timestamp
= timestamp
;
62 tfcs
->process
= create_process(tfcs
, NULL
,0);
69 fini(LttvTracesetState
*self
)
71 guint i
, j
, nb_trace
, nb_tracefile
;
75 LttvTracefileState
*tfcs
;
77 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
78 for(i
= 0 ; i
< nb_trace
; i
++) {
79 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
80 remove_all_processes(tcs
->processes
);
81 g_hash_table_destroy(tcs
->processes
);
83 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
)))->fini((LttvTracesetContext
*)self
);
87 static LttvTracesetContext
*
88 new_traceset_context(LttvTracesetContext
*self
)
90 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
94 static LttvTraceContext
*
95 new_trace_context(LttvTracesetContext
*self
)
97 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
101 static LttvTracefileContext
*
102 new_tracefile_context(LttvTracesetContext
*self
)
104 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
109 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
115 traceset_state_finalize (LttvTracesetState
*self
)
117 G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACESET_STATE_GET_CLASS(self
))))->finalize(G_OBJECT(self
));
122 traceset_state_class_init (LttvTracesetContextClass
*klass
)
124 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
126 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
127 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
128 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
129 klass
->new_traceset_context
= new_traceset_context
;
130 klass
->new_trace_context
= new_trace_context
;
131 klass
->new_tracefile_context
= new_tracefile_context
;
136 lttv_traceset_state_get_type(void)
138 static GType type
= 0;
140 static const GTypeInfo info
= {
141 sizeof (LttvTracesetStateClass
),
142 NULL
, /* base_init */
143 NULL
, /* base_finalize */
144 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
145 NULL
, /* class_finalize */
146 NULL
, /* class_data */
147 sizeof (LttvTracesetContext
),
149 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
152 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
160 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
166 trace_state_finalize (LttvTraceState
*self
)
168 G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACE_STATE_GET_CLASS(self
))))->finalize(G_OBJECT(self
));
173 trace_state_class_init (LttvTraceContextClass
*klass
)
175 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
177 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
182 lttv_trace_state_get_type(void)
184 static GType type
= 0;
186 static const GTypeInfo info
= {
187 sizeof (LttvTraceStateClass
),
188 NULL
, /* base_init */
189 NULL
, /* base_finalize */
190 (GClassInitFunc
) trace_state_class_init
, /* class_init */
191 NULL
, /* class_finalize */
192 NULL
, /* class_data */
193 sizeof (LttvTraceState
),
195 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
198 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
199 "LttvTraceStateType", &info
, 0);
206 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
212 tracefile_state_finalize (LttvTracefileState
*self
)
214 G_OBJECT_CLASS(g_type_class_peek_parent(g_type_class_peek_parent(LTTV_TRACEFILE_STATE_GET_CLASS(self
))))->finalize(G_OBJECT(self
));
219 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
221 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
223 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
228 lttv_tracefile_state_get_type(void)
230 static GType type
= 0;
232 static const GTypeInfo info
= {
233 sizeof (LttvTracefileStateClass
),
234 NULL
, /* base_init */
235 NULL
, /* base_finalize */
236 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
237 NULL
, /* class_finalize */
238 NULL
, /* class_data */
239 sizeof (LttvTracefileState
),
241 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
244 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
245 "LttvTracefileStateType", &info
, 0);
262 gboolean free_hook_data
;
266 static void push_state(LttvTracefileState
*tfs
, LttvInterruptType t
,
269 LttvInterruptState
*intr
;
271 LttvProcessState
*process
= tfs
->process
;
273 guint depth
= process
->interrupt_stack
->len
;
275 g_array_set_size(process
->interrupt_stack
, depth
+ 1);
276 intr
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
, depth
);
279 intr
->entry
= intr
->last_change
= LTTV_TRACEFILE_CONTEXT(tfs
)->timestamp
;
280 intr
->s
= process
->state
->s
;
281 process
->state
= intr
;
285 static void pop_state(LttvTracefileState
*tfs
, LttvInterruptType t
)
287 LttvProcessState
*process
= tfs
->process
;
289 guint depth
= process
->interrupt_stack
->len
- 1;
291 // g_assert(process->state->t == t);
292 if(process
->state
->t
!= t
){
293 g_warning("Different interrupt type: ignore it\n");
294 g_warning("process state has %s when pop_int is %s\n",
295 g_quark_to_string(process
->state
->t
),
296 g_quark_to_string(t
));
297 g_warning("{ %u, %u, %s, %s }\n",
300 g_quark_to_string(process
->name
),
301 g_quark_to_string(process
->state
->s
));
304 g_array_remove_index(process
->interrupt_stack
, depth
);
306 process
->state
= &g_array_index(process
->interrupt_stack
, LttvInterruptState
,
311 LttvProcessState
*create_process(LttvTracefileState
*tfs
,
312 LttvProcessState
*parent
, guint pid
)
314 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
316 LttvInterruptState
*intr
;
318 LttvTraceContext
*tc
;
322 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfs
);
324 tcs
= (LttvTraceState
*)tc
= tfc
->t_context
;
326 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
328 if(parent
) process
->ppid
= parent
->pid
;
329 else process
->ppid
= 0;
330 process
->birth
= tfc
->timestamp
;
331 process
->name
= LTTV_STATE_UNNAMED
;
332 process
->interrupt_stack
= g_array_new(FALSE
, FALSE
,
333 sizeof(LttvInterruptState
));
334 g_array_set_size(process
->interrupt_stack
, 1);
335 intr
= process
->state
= &g_array_index(process
->interrupt_stack
,
336 LttvInterruptState
, 0);
337 intr
->t
= LTTV_STATE_USER_MODE
;
339 intr
->entry
= tfc
->timestamp
;
340 intr
->last_change
= tfc
->timestamp
;
341 intr
->s
= LTTV_STATE_WAIT_FORK
;
347 LttvProcessState
*find_process(LttvTracefileState
*tfs
, guint pid
)
349 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
350 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
351 GUINT_TO_POINTER(pid
));
352 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
357 void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
359 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
361 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
362 g_array_free(process
->interrupt_stack
, TRUE
);
367 void free_process_state(gpointer key
, gpointer value
, gpointer user_data
)
369 g_array_free(((LttvProcessState
*)value
)->interrupt_stack
, TRUE
);
374 void remove_all_processes(GHashTable
*processes
)
376 g_hash_table_foreach(processes
, free_process_state
, NULL
);
380 gboolean
syscall_entry(void *hook_data
, void *call_data
)
382 LttField
*f
= (LttField
*)hook_data
;
384 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
386 push_state(s
, LTTV_STATE_SYSCALL
, ltt_event_get_unsigned(
387 LTTV_TRACEFILE_CONTEXT(s
)->e
, f
));
392 gboolean
syscall_exit(void *hook_data
, void *call_data
)
394 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
396 pop_state(s
, LTTV_STATE_SYSCALL
);
401 gboolean
trap_entry(void *hook_data
, void *call_data
)
403 LttField
*f
= (LttField
*)hook_data
;
405 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
407 push_state(s
, LTTV_STATE_TRAP
, ltt_event_get_unsigned(s
->parent
.e
, f
));
412 gboolean
trap_exit(void *hook_data
, void *call_data
)
414 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
416 pop_state(s
, LTTV_STATE_TRAP
);
421 gboolean
irq_entry(void *hook_data
, void *call_data
)
423 LttField
*f
= (LttField
*)hook_data
;
425 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
427 /* Do something with the info about being in user or system mode when int? */
428 push_state(s
, LTTV_STATE_IRQ
, ltt_event_get_unsigned(s
->parent
.e
, f
));
433 gboolean
irq_exit(void *hook_data
, void *call_data
)
435 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
437 pop_state(s
, LTTV_STATE_IRQ
);
442 gboolean
schedchange(void *hook_data
, void *call_data
)
444 struct HookData
*h
= (struct HookData
*)hook_data
;
446 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
448 guint pid_in
, pid_out
, state_out
;
450 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
451 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
452 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
453 if(s
->process
!= NULL
) {
454 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
455 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
456 exit_process(s
, s
->process
);
457 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
459 if(s
->process
->pid
== 0)
460 s
->process
->pid
== pid_out
;
462 s
->process
= find_process(s
, pid_in
);
463 s
->process
->state
->s
= LTTV_STATE_RUN
;
468 gboolean
process_fork(void *hook_data
, void *call_data
)
470 LttField
*f
= (LttField
*)hook_data
;
472 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
476 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
477 create_process(s
, s
->process
, child_pid
);
482 gboolean
process_exit(void *hook_data
, void *call_data
)
484 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
486 if(s
->process
!= NULL
) {
487 s
->process
->state
->s
= LTTV_STATE_EXIT
;
494 find_field(LttEventType
*et
, const char *field
)
504 if(field
== NULL
) return NULL
;
506 f
= ltt_eventtype_field(et
);
507 t
= ltt_eventtype_type(et
);
508 g_assert(ltt_type_class(t
) == LTT_STRUCT
);
509 nb
= ltt_type_member_number(t
);
510 for(i
= 0 ; i
< nb
; i
++) {
511 ltt_type_member_type(t
, i
, &name
);
512 if(strcmp(name
, field
) == 0) break;
515 return ltt_field_member(f
, i
);
520 find_hook(LttTrace
*t
, char *facility
, char *event
,
521 char *field1
, char *field2
, char *field3
, LttvHook h
)
529 struct HookId hook_id
;
531 struct HookData hook_data
, *phook_data
;
535 nb
= ltt_trace_facility_find(t
, facility
, &pos
);
536 if(nb
< 1) g_error("No %s facility", facility
);
537 f
= ltt_trace_facility_get(t
, pos
);
538 et
= ltt_facility_eventtype_get_by_name(f
, event
);
539 if(et
== NULL
) g_error("Event %s does not exist", event
);
541 hook_id
.id
= ltt_eventtype_id(et
);
543 hook_id
.free_hook_data
= FALSE
;
544 hook_data
.f1
= find_field(et
, field1
);
545 hook_data
.f2
= find_field(et
, field2
);
546 hook_data
.f3
= find_field(et
, field3
);
547 if(hook_data
.f1
== NULL
) hook_id
.hook_data
= NULL
;
548 else if(hook_data
.f2
== NULL
) hook_id
.hook_data
= hook_data
.f1
;
550 phook_data
= g_new(struct HookData
, 1);
551 *phook_data
= hook_data
;
552 hook_id
.hook_data
= phook_data
;
553 hook_id
.free_hook_data
= TRUE
;
559 lttv_state_add_event_hooks(LttvTracesetState
*self
)
561 LttvTraceset
*traceset
= self
->parent
.ts
;
563 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
571 LttvTracefileState
*tfs
;
577 struct HookId hook_id
;
579 LttvAttributeValue val
;
581 nb_trace
= lttv_traceset_number(traceset
);
582 for(i
= 0 ; i
< nb_trace
; i
++) {
583 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
585 /* Find the eventtype id for the following events and register the
586 associated by id hooks. */
588 hooks
= g_array_new(FALSE
, FALSE
, sizeof(struct HookId
));
589 hook_id
= find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
590 NULL
, NULL
, syscall_entry
);
591 g_array_append_val(hooks
, hook_id
);
593 hook_id
= find_hook(ts
->parent
.t
, "core", "syscall_exit",
594 NULL
, NULL
, NULL
, syscall_exit
);
595 g_array_append_val(hooks
, hook_id
);
597 hook_id
= find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
598 NULL
, NULL
, trap_entry
);
599 g_array_append_val(hooks
, hook_id
);
601 hook_id
= find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
,
603 g_array_append_val(hooks
, hook_id
);
605 hook_id
= find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id",
606 NULL
, NULL
, irq_entry
);
607 g_array_append_val(hooks
, hook_id
);
609 hook_id
= find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
,
611 g_array_append_val(hooks
, hook_id
);
613 hook_id
= find_hook(ts
->parent
.t
, "core", "schedchange",
614 "in", "out", "out_state", schedchange
);
615 g_array_append_val(hooks
, hook_id
);
617 hook_id
= find_hook(ts
->parent
.t
, "core", "process_fork",
618 "child_pid", NULL
, NULL
, process_fork
);
619 g_array_append_val(hooks
, hook_id
);
621 hook_id
= find_hook(ts
->parent
.t
, "core", "process_exit",
622 NULL
, NULL
, NULL
, process_exit
);
623 g_array_append_val(hooks
, hook_id
);
625 /* Add these hooks to each before_event_by_id hooks list */
627 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
628 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
629 nb_tracefile
= nb_control
+ nb_per_cpu
;
630 for(j
= 0 ; j
< nb_tracefile
; j
++) {
632 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
635 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
638 for(k
= 0 ; k
< hooks
->len
; k
++) {
639 hook_id
= g_array_index(hooks
, struct HookId
, k
);
640 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.before_event_by_id
,
641 hook_id
.id
), hook_id
.h
, hook_id
.hook_data
);
644 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
645 *(val
.v_pointer
) = hooks
;
650 lttv_state_remove_event_hooks(LttvTracesetState
*self
)
652 LttvTraceset
*traceset
= self
->parent
.ts
;
654 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
658 LttvTracefileState
*tfs
;
664 struct HookId hook_id
;
666 LttvAttributeValue val
;
668 nb_trace
= lttv_traceset_number(traceset
);
669 for(i
= 0 ; i
< nb_trace
; i
++) {
670 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
671 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
672 hooks
= *(val
.v_pointer
);
674 /* Add these hooks to each before_event_by_id hooks list */
676 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
677 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
678 nb_tracefile
= nb_control
+ nb_per_cpu
;
679 for(j
= 0 ; j
< nb_tracefile
; j
++) {
681 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
684 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
687 for(k
= 0 ; k
< hooks
->len
; k
++) {
688 hook_id
= g_array_index(hooks
, struct HookId
, k
);
689 lttv_hooks_remove_data(
690 lttv_hooks_by_id_find(tfs
->parent
.before_event_by_id
,
691 hook_id
.id
), hook_id
.h
, hook_id
.hook_data
);
692 if(hook_id
.free_hook_data
) g_free(hook_id
.hook_data
);
694 // for(k = 0 ; k < hooks->len ; k++) {
695 // hook_id = g_array_index(hooks, struct HookId, k);
696 // if(hook_id.free_hook_data) g_free(hook_id.hook_data);
699 g_array_free(hooks
, TRUE
);
704 void lttv_state_init(int argc
, char **argv
)
706 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
707 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
708 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
709 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
710 LTTV_STATE_TRAP
= g_quark_from_string("trap");
711 LTTV_STATE_IRQ
= g_quark_from_string("irq");
712 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
713 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
714 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
715 LTTV_STATE_RUN
= g_quark_from_string("running");
716 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
719 void lttv_state_destroy()