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,
20 #include <lttv/state.h>
21 #include <ltt/facility.h>
22 #include <ltt/trace.h>
23 #include <ltt/event.h>
27 LTTV_STATE_MODE_UNKNOWN
,
34 LTTV_STATE_SUBMODE_UNKNOWN
,
35 LTTV_STATE_SUBMODE_NONE
;
46 LTTV_STATE_TRACEFILES
,
50 LTTV_STATE_SAVED_STATES
,
55 static void fill_name_tables(LttvTraceState
*tcs
);
57 static void free_name_tables(LttvTraceState
*tcs
);
59 static void lttv_state_free_process_table(GHashTable
*processes
);
61 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
62 LttvProcessState
*parent
, guint pid
);
64 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
66 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
70 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
72 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
76 void lttv_state_saved_state_free(LttvTraceState
*self
,
77 LttvAttribute
*container
)
79 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
84 restore_init_state(LttvTraceState
*self
)
86 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
88 LttvTracefileState
*tfcs
;
90 LttTime null_time
= {0,0};
92 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
93 self
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
96 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
97 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
98 nb_tracefile
= nb_control
+ nb_per_cpu
;
99 for(i
= 0 ; i
< nb_tracefile
; i
++) {
101 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.control_tracefiles
[i
]);
104 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.per_cpu_tracefiles
[i
- nb_control
]);
107 tfcs
->parent
.timestamp
= null_time
;
108 tfcs
->saved_position
= 0;
109 tfcs
->process
= create_process(tfcs
, NULL
,0);
115 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
117 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
119 LttvTraceContext
*tc
;
123 LttvTracefileState
*tfcs
;
125 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
126 init((LttvTracesetContext
*)self
, ts
);
128 nb_trace
= lttv_traceset_number(ts
);
129 for(i
= 0 ; i
< nb_trace
; i
++) {
130 tc
= self
->parent
.traces
[i
];
131 tcs
= (LttvTraceState
*)tc
;
132 tcs
->save_interval
= 100000;
133 fill_name_tables(tcs
);
135 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
136 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
137 nb_tracefile
= nb_control
+ nb_per_cpu
;
138 for(j
= 0 ; j
< nb_tracefile
; j
++) {
140 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
143 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
145 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
147 tcs
->processes
= NULL
;
148 restore_init_state(tcs
);
154 fini(LttvTracesetState
*self
)
156 guint i
, j
, nb_trace
, nb_tracefile
;
160 LttvTracefileState
*tfcs
;
162 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
163 for(i
= 0 ; i
< nb_trace
; i
++) {
164 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
165 lttv_state_free_process_table(tcs
->processes
);
166 tcs
->processes
= NULL
;
167 free_name_tables(tcs
);
169 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
170 fini((LttvTracesetContext
*)self
);
174 static LttvTracesetContext
*
175 new_traceset_context(LttvTracesetContext
*self
)
177 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
181 static LttvTraceContext
*
182 new_trace_context(LttvTracesetContext
*self
)
184 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
188 static LttvTracefileContext
*
189 new_tracefile_context(LttvTracesetContext
*self
)
191 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
195 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
197 LttvProcessState
*process
, *new_process
;
199 GHashTable
*new_processes
= (GHashTable
*)user_data
;
203 process
= (LttvProcessState
*)value
;
204 new_process
= g_new(LttvProcessState
, 1);
205 *new_process
= *process
;
206 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
207 sizeof(LttvExecutionState
));
208 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
209 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
210 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
211 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
213 new_process
->state
= &g_array_index(new_process
->execution_stack
,
214 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
215 g_hash_table_insert(new_processes
, GUINT_TO_POINTER(new_process
->pid
),
220 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
222 GHashTable
*new_processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
224 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
225 return new_processes
;
229 /* The saved state for each trace contains a member "processes", which
230 stores a copy of the process table, and a member "tracefiles" with
231 one entry per tracefile. Each tracefile has a "process" member pointing
232 to the current process and a "position" member storing the tracefile
233 position (needed to seek to the current "next" event. */
235 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
237 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
239 LttvTracefileState
*tfcs
;
241 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
243 LttvAttributeType type
;
245 LttvAttributeValue value
;
247 LttvAttributeName name
;
249 LttEventPosition
*ep
;
251 tracefiles_tree
= lttv_attribute_find_subdir(container
,
252 LTTV_STATE_TRACEFILES
);
254 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
256 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
258 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
259 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
260 nb_tracefile
= nb_control
+ nb_per_cpu
;
262 for(i
= 0 ; i
< nb_tracefile
; i
++) {
264 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
265 else tfcs
= (LttvTracefileState
*)
266 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
268 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
269 value
= lttv_attribute_add(tracefiles_tree
, i
,
271 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
272 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
274 *(value
.v_uint
) = tfcs
->process
->pid
;
275 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
277 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
279 ep
= ltt_event_position_new();
280 ltt_event_position(tfcs
->parent
.e
, ep
);
281 *(value
.v_pointer
) = ep
;
287 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
289 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
291 LttvTracefileState
*tfcs
;
293 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
295 LttvAttributeType type
;
297 LttvAttributeValue value
;
299 LttvAttributeName name
;
301 LttEventPosition
*ep
;
303 tracefiles_tree
= lttv_attribute_find_subdir(container
,
304 LTTV_STATE_TRACEFILES
);
306 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
308 g_assert(type
== LTTV_POINTER
);
309 lttv_state_free_process_table(self
->processes
);
310 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
312 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
313 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
314 nb_tracefile
= nb_control
+ nb_per_cpu
;
316 for(i
= 0 ; i
< nb_tracefile
; i
++) {
317 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
318 self
->parent
.control_tracefiles
[i
];
319 else tfcs
= (LttvTracefileState
*)
320 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
322 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
323 g_assert(type
== LTTV_GOBJECT
);
324 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
326 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
328 g_assert(type
== LTTV_UINT
);
329 tfcs
->process
= lttv_state_find_process(tfcs
, *(value
.v_uint
));
330 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
332 g_assert(type
== LTTV_POINTER
);
333 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
335 ep
= *(value
.v_pointer
);
336 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
337 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
338 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
344 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
346 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
348 LttvTracefileState
*tfcs
;
350 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
352 LttvAttributeType type
;
354 LttvAttributeValue value
;
356 LttvAttributeName name
;
358 LttEventPosition
*ep
;
360 tracefiles_tree
= lttv_attribute_find_subdir(container
,
361 LTTV_STATE_TRACEFILES
);
362 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
364 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
366 g_assert(type
== LTTV_POINTER
);
367 lttv_state_free_process_table(*(value
.v_pointer
));
368 *(value
.v_pointer
) = NULL
;
369 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
371 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
372 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
373 nb_tracefile
= nb_control
+ nb_per_cpu
;
375 for(i
= 0 ; i
< nb_tracefile
; i
++) {
376 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
377 self
->parent
.control_tracefiles
[i
];
378 else tfcs
= (LttvTracefileState
*)
379 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
381 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
382 g_assert(type
== LTTV_GOBJECT
);
383 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
385 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
387 g_assert(type
== LTTV_POINTER
);
388 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
390 lttv_attribute_recursive_free(tracefiles_tree
);
395 fill_name_tables(LttvTraceState
*tcs
)
399 char *f_name
, *e_name
;
407 GString
*fe_name
= g_string_new("");
409 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
410 tcs
->eventtype_names
= g_new(GQuark
, nb
);
411 for(i
= 0 ; i
< nb
; i
++) {
412 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
413 e_name
= ltt_eventtype_name(et
);
414 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
415 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
416 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
419 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
420 "syscall_id", NULL
, NULL
, NULL
, &h
);
421 t
= ltt_field_type(h
.f1
);
422 nb
= ltt_type_element_number(t
);
424 /* CHECK syscalls should be an emun but currently are not!
425 tcs->syscall_names = g_new(GQuark, nb);
427 for(i = 0 ; i < nb ; i++) {
428 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
432 tcs
->syscall_names
= g_new(GQuark
, 256);
433 for(i
= 0 ; i
< 256 ; i
++) {
434 g_string_printf(fe_name
, "syscall %d", i
);
435 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
438 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
439 "trap_id", NULL
, NULL
, NULL
, &h
);
440 t
= ltt_field_type(h
.f1
);
441 nb
= ltt_type_element_number(t
);
444 tcs->trap_names = g_new(GQuark, nb);
445 for(i = 0 ; i < nb ; i++) {
446 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
450 tcs
->trap_names
= g_new(GQuark
, 256);
451 for(i
= 0 ; i
< 256 ; i
++) {
452 g_string_printf(fe_name
, "trap %d", i
);
453 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
456 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
457 "irq_id", NULL
, NULL
, NULL
, &h
);
458 t
= ltt_field_type(h
.f1
);
459 nb
= ltt_type_element_number(t
);
462 tcs->irq_names = g_new(GQuark, nb);
463 for(i = 0 ; i < nb ; i++) {
464 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
468 tcs
->irq_names
= g_new(GQuark
, 256);
469 for(i
= 0 ; i
< 256 ; i
++) {
470 g_string_printf(fe_name
, "irq %d", i
);
471 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
474 g_string_free(fe_name
, TRUE
);
479 free_name_tables(LttvTraceState
*tcs
)
481 g_free(tcs
->eventtype_names
);
482 g_free(tcs
->syscall_names
);
483 g_free(tcs
->trap_names
);
484 g_free(tcs
->irq_names
);
488 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
491 LttvExecutionState
*es
;
493 LttvProcessState
*process
= tfs
->process
;
495 guint depth
= process
->execution_stack
->len
;
497 g_array_set_size(process
->execution_stack
, depth
+ 1);
498 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
501 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
502 es
->s
= process
->state
->s
;
507 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
509 LttvProcessState
*process
= tfs
->process
;
511 guint depth
= process
->execution_stack
->len
- 1;
513 if(process
->state
->t
!= t
){
514 g_warning("Different execution mode type (%d.%09d): ignore it\n",
515 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
516 g_warning("process state has %s when pop_int is %s\n",
517 g_quark_to_string(process
->state
->t
),
518 g_quark_to_string(t
));
519 g_warning("{ %u, %u, %s, %s }\n",
522 g_quark_to_string(process
->name
),
523 g_quark_to_string(process
->state
->s
));
528 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
529 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
533 g_array_remove_index(process
->execution_stack
, depth
);
535 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
537 process
->state
->change
= tfs
->parent
.timestamp
;
541 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
542 LttvProcessState
*parent
, guint pid
)
544 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
546 LttvExecutionState
*es
;
548 LttvTraceContext
*tc
;
554 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
556 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
560 process
->ppid
= parent
->pid
;
561 process
->name
= parent
->name
;
565 process
->name
= LTTV_STATE_UNNAMED
;
568 process
->creation_time
= tfs
->parent
.timestamp
;
569 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
570 process
->creation_time
.tv_nsec
);
571 process
->pid_time
= g_quark_from_string(buffer
);
572 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
573 sizeof(LttvExecutionState
));
574 g_array_set_size(process
->execution_stack
, 1);
575 es
= process
->state
= &g_array_index(process
->execution_stack
,
576 LttvExecutionState
, 0);
577 es
->t
= LTTV_STATE_USER_MODE
;
578 es
->n
= LTTV_STATE_SUBMODE_NONE
;
579 es
->entry
= tfs
->parent
.timestamp
;
580 es
->change
= tfs
->parent
.timestamp
;
581 es
->s
= LTTV_STATE_WAIT_FORK
;
587 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
590 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
591 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
592 GUINT_TO_POINTER(pid
));
593 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
598 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
600 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
602 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
603 g_array_free(process
->execution_stack
, TRUE
);
608 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
610 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
615 static void lttv_state_free_process_table(GHashTable
*processes
)
617 g_hash_table_foreach(processes
, free_process_state
, NULL
);
618 g_hash_table_destroy(processes
);
622 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
624 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
626 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
628 LttvExecutionSubmode submode
;
630 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
631 ltt_event_get_unsigned(s
->parent
.e
, f
)];
632 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
637 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
639 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
641 pop_state(s
, LTTV_STATE_SYSCALL
);
646 static gboolean
trap_entry(void *hook_data
, void *call_data
)
648 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
650 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
652 LttvExecutionSubmode submode
;
654 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
655 ltt_event_get_unsigned(s
->parent
.e
, f
)];
656 push_state(s
, LTTV_STATE_TRAP
, submode
);
661 static gboolean
trap_exit(void *hook_data
, void *call_data
)
663 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
665 pop_state(s
, LTTV_STATE_TRAP
);
670 static gboolean
irq_entry(void *hook_data
, void *call_data
)
672 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
674 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
676 LttvExecutionSubmode submode
;
678 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
679 ltt_event_get_unsigned(s
->parent
.e
, f
)];
681 /* Do something with the info about being in user or system mode when int? */
682 push_state(s
, LTTV_STATE_IRQ
, submode
);
687 static gboolean
irq_exit(void *hook_data
, void *call_data
)
689 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
691 pop_state(s
, LTTV_STATE_IRQ
);
696 static gboolean
schedchange(void *hook_data
, void *call_data
)
698 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
700 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
702 guint pid_in
, pid_out
, state_out
;
704 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
705 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
706 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
708 if(s
->process
!= NULL
) {
710 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
711 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
712 exit_process(s
, s
->process
);
713 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
715 if(s
->process
->pid
== 0)
716 s
->process
->pid
= pid_out
;
718 s
->process
->state
->change
= s
->parent
.timestamp
;
720 s
->process
= lttv_state_find_process(s
, pid_in
);
721 s
->process
->state
->s
= LTTV_STATE_RUN
;
722 s
->process
->state
->change
= s
->parent
.timestamp
;
727 static gboolean
process_fork(void *hook_data
, void *call_data
)
729 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
731 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
735 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
736 create_process(s
, s
->process
, child_pid
);
741 static gboolean
process_exit(void *hook_data
, void *call_data
)
743 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
745 if(s
->process
!= NULL
) {
746 s
->process
->state
->s
= LTTV_STATE_EXIT
;
752 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
754 LttvTraceset
*traceset
= self
->parent
.ts
;
756 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
760 LttvTracefileState
*tfs
;
766 LttvAttributeValue val
;
768 nb_trace
= lttv_traceset_number(traceset
);
769 for(i
= 0 ; i
< nb_trace
; i
++) {
770 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
772 /* Find the eventtype id for the following events and register the
773 associated by id hooks. */
775 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
776 g_array_set_size(hooks
, 9);
778 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
779 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
781 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
782 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
784 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
785 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
787 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
788 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
790 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
791 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
793 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
794 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
796 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
797 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
799 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
800 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
802 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
803 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
805 /* Add these hooks to each before_event_by_id hooks list */
807 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
808 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
809 nb_tracefile
= nb_control
+ nb_per_cpu
;
810 for(j
= 0 ; j
< nb_tracefile
; j
++) {
812 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
815 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
818 for(k
= 0 ; k
< hooks
->len
; k
++) {
819 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
820 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
821 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
824 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
825 *(val
.v_pointer
) = hooks
;
830 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
832 LttvTraceset
*traceset
= self
->parent
.ts
;
834 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
838 LttvTracefileState
*tfs
;
844 LttvAttributeValue val
;
846 nb_trace
= lttv_traceset_number(traceset
);
847 for(i
= 0 ; i
< nb_trace
; i
++) {
848 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
849 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
850 hooks
= *(val
.v_pointer
);
852 /* Add these hooks to each before_event_by_id hooks list */
854 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
855 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
856 nb_tracefile
= nb_control
+ nb_per_cpu
;
857 for(j
= 0 ; j
< nb_tracefile
; j
++) {
859 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
862 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
865 for(k
= 0 ; k
< hooks
->len
; k
++) {
866 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
867 lttv_hooks_remove_data(
868 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
869 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
872 g_array_free(hooks
, TRUE
);
877 static gboolean
block_end(void *hook_data
, void *call_data
)
879 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
881 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
883 LttEventPosition
*ep
= ltt_event_position_new();
885 guint nb_block
, nb_event
;
889 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
891 LttvAttributeValue value
;
893 ltt_event_position(tfcs
->parent
.e
, ep
);
895 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
896 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
897 tfcs
->saved_position
= 0;
898 if(tcs
->nb_event
>= tcs
->save_interval
) {
899 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
900 LTTV_STATE_SAVED_STATES
);
901 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
902 value
= lttv_attribute_add(saved_states_tree
,
903 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
904 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
905 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
906 *(value
.v_time
) = tfcs
->parent
.timestamp
;
907 lttv_state_save(tcs
, saved_state_tree
);
914 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
916 LttvTraceset
*traceset
= self
->parent
.ts
;
918 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
922 LttvTracefileState
*tfs
;
926 nb_trace
= lttv_traceset_number(traceset
);
927 for(i
= 0 ; i
< nb_trace
; i
++) {
928 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
929 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
930 NULL
, NULL
, block_end
, &hook
);
932 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
933 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
934 nb_tracefile
= nb_control
+ nb_per_cpu
;
935 for(j
= 0 ; j
< nb_tracefile
; j
++) {
937 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
940 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
943 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
944 hook
.id
), hook
.h
, NULL
);
950 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
952 LttvTraceset
*traceset
= self
->parent
.ts
;
954 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
958 LttvTracefileState
*tfs
;
962 nb_trace
= lttv_traceset_number(traceset
);
963 for(i
= 0 ; i
< nb_trace
; i
++) {
964 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
965 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
966 NULL
, NULL
, block_end
, &hook
);
968 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
969 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
970 nb_tracefile
= nb_control
+ nb_per_cpu
;
971 for(j
= 0 ; j
< nb_tracefile
; j
++) {
973 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
976 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
979 lttv_hooks_remove_data(lttv_hooks_by_id_find(
980 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
986 void lttv_state_restore_closest_state(LttvTracesetState
*self
, LttTime t
)
988 LttvTraceset
*traceset
= self
->parent
.ts
;
990 guint i
, j
, nb_trace
, nb_saved_state
;
992 int min_pos
, mid_pos
, max_pos
;
996 LttvAttributeValue value
;
998 LttvAttributeType type
;
1000 LttvAttributeName name
;
1002 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1004 nb_trace
= lttv_traceset_number(traceset
);
1005 for(i
= 0 ; i
< nb_trace
; i
++) {
1006 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1008 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1009 LTTV_STATE_SAVED_STATES
);
1011 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1012 mid_pos
= max_pos
/ 2;
1013 while(min_pos
< max_pos
) {
1014 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1015 g_assert(type
== LTTV_GOBJECT
);
1016 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1017 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1019 g_assert(type
== LTTV_TIME
);
1020 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1022 closest_tree
= saved_state_tree
;
1024 else max_pos
= mid_pos
- 1;
1026 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1029 restore_init_state(tcs
);
1030 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1032 else lttv_state_restore(tcs
, closest_tree
);
1038 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1044 traceset_state_finalize (LttvTracesetState
*self
)
1046 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1047 finalize(G_OBJECT(self
));
1052 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1054 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1056 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1057 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1058 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1059 klass
->new_traceset_context
= new_traceset_context
;
1060 klass
->new_trace_context
= new_trace_context
;
1061 klass
->new_tracefile_context
= new_tracefile_context
;
1066 lttv_traceset_state_get_type(void)
1068 static GType type
= 0;
1070 static const GTypeInfo info
= {
1071 sizeof (LttvTracesetStateClass
),
1072 NULL
, /* base_init */
1073 NULL
, /* base_finalize */
1074 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1075 NULL
, /* class_finalize */
1076 NULL
, /* class_data */
1077 sizeof (LttvTracesetContext
),
1078 0, /* n_preallocs */
1079 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1082 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1090 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1096 trace_state_finalize (LttvTraceState
*self
)
1098 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1099 finalize(G_OBJECT(self
));
1104 trace_state_class_init (LttvTraceStateClass
*klass
)
1106 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1108 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1109 klass
->state_save
= state_save
;
1110 klass
->state_restore
= state_restore
;
1111 klass
->state_saved_free
= state_saved_free
;
1116 lttv_trace_state_get_type(void)
1118 static GType type
= 0;
1120 static const GTypeInfo info
= {
1121 sizeof (LttvTraceStateClass
),
1122 NULL
, /* base_init */
1123 NULL
, /* base_finalize */
1124 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1125 NULL
, /* class_finalize */
1126 NULL
, /* class_data */
1127 sizeof (LttvTraceState
),
1128 0, /* n_preallocs */
1129 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1132 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1133 "LttvTraceStateType", &info
, 0);
1140 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1146 tracefile_state_finalize (LttvTracefileState
*self
)
1148 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1149 finalize(G_OBJECT(self
));
1154 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1156 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1158 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1163 lttv_tracefile_state_get_type(void)
1165 static GType type
= 0;
1167 static const GTypeInfo info
= {
1168 sizeof (LttvTracefileStateClass
),
1169 NULL
, /* base_init */
1170 NULL
, /* base_finalize */
1171 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1172 NULL
, /* class_finalize */
1173 NULL
, /* class_data */
1174 sizeof (LttvTracefileState
),
1175 0, /* n_preallocs */
1176 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1179 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1180 "LttvTracefileStateType", &info
, 0);
1186 void lttv_state_init(int argc
, char **argv
)
1188 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1189 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1190 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1191 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1192 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1193 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1194 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1195 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1196 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1197 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1198 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1199 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1200 LTTV_STATE_RUN
= g_quark_from_string("running");
1201 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1202 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1203 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1204 LTTV_STATE_EVENT
= g_quark_from_string("event");
1205 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1206 LTTV_STATE_TIME
= g_quark_from_string("time");
1207 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1210 void lttv_state_destroy()