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 tcs
->recompute_state_in_seek
= TRUE
;
134 tcs
->saved_state_ready
= FALSE
;
135 fill_name_tables(tcs
);
137 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
138 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
139 nb_tracefile
= nb_control
+ nb_per_cpu
;
140 for(j
= 0 ; j
< nb_tracefile
; j
++) {
142 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
145 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
147 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
149 tcs
->processes
= NULL
;
150 restore_init_state(tcs
);
156 fini(LttvTracesetState
*self
)
158 guint i
, j
, nb_trace
, nb_tracefile
;
162 LttvTracefileState
*tfcs
;
164 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
165 for(i
= 0 ; i
< nb_trace
; i
++) {
166 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
167 lttv_state_free_process_table(tcs
->processes
);
168 tcs
->processes
= NULL
;
169 free_name_tables(tcs
);
171 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
172 fini((LttvTracesetContext
*)self
);
176 static LttvTracesetContext
*
177 new_traceset_context(LttvTracesetContext
*self
)
179 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
183 static LttvTraceContext
*
184 new_trace_context(LttvTracesetContext
*self
)
186 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
190 static LttvTracefileContext
*
191 new_tracefile_context(LttvTracesetContext
*self
)
193 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
197 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
199 LttvProcessState
*process
, *new_process
;
201 GHashTable
*new_processes
= (GHashTable
*)user_data
;
205 process
= (LttvProcessState
*)value
;
206 new_process
= g_new(LttvProcessState
, 1);
207 *new_process
= *process
;
208 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
209 sizeof(LttvExecutionState
));
210 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
211 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
212 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
213 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
215 new_process
->state
= &g_array_index(new_process
->execution_stack
,
216 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
217 g_hash_table_insert(new_processes
, GUINT_TO_POINTER(new_process
->pid
),
222 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
224 GHashTable
*new_processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
226 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
227 return new_processes
;
231 /* The saved state for each trace contains a member "processes", which
232 stores a copy of the process table, and a member "tracefiles" with
233 one entry per tracefile. Each tracefile has a "process" member pointing
234 to the current process and a "position" member storing the tracefile
235 position (needed to seek to the current "next" event. */
237 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
239 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
241 LttvTracefileState
*tfcs
;
243 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
245 LttvAttributeType type
;
247 LttvAttributeValue value
;
249 LttvAttributeName name
;
251 LttEventPosition
*ep
;
253 tracefiles_tree
= lttv_attribute_find_subdir(container
,
254 LTTV_STATE_TRACEFILES
);
256 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
258 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
260 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
261 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
262 nb_tracefile
= nb_control
+ nb_per_cpu
;
264 for(i
= 0 ; i
< nb_tracefile
; i
++) {
266 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
267 else tfcs
= (LttvTracefileState
*)
268 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
270 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
271 value
= lttv_attribute_add(tracefiles_tree
, i
,
273 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
274 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
276 *(value
.v_uint
) = tfcs
->process
->pid
;
277 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
279 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
281 ep
= ltt_event_position_new();
282 ltt_event_position(tfcs
->parent
.e
, ep
);
283 *(value
.v_pointer
) = ep
;
289 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
291 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
293 LttvTracefileState
*tfcs
;
295 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
297 LttvAttributeType type
;
299 LttvAttributeValue value
;
301 LttvAttributeName name
;
303 LttEventPosition
*ep
;
305 tracefiles_tree
= lttv_attribute_find_subdir(container
,
306 LTTV_STATE_TRACEFILES
);
308 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
310 g_assert(type
== LTTV_POINTER
);
311 lttv_state_free_process_table(self
->processes
);
312 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
314 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
315 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
316 nb_tracefile
= nb_control
+ nb_per_cpu
;
318 for(i
= 0 ; i
< nb_tracefile
; i
++) {
319 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
320 self
->parent
.control_tracefiles
[i
];
321 else tfcs
= (LttvTracefileState
*)
322 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
324 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
325 g_assert(type
== LTTV_GOBJECT
);
326 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
328 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
330 g_assert(type
== LTTV_UINT
);
331 tfcs
->process
= lttv_state_find_process(tfcs
, *(value
.v_uint
));
332 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
334 g_assert(type
== LTTV_POINTER
);
335 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
337 ep
= *(value
.v_pointer
);
338 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
339 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
340 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
346 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
348 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
350 LttvTracefileState
*tfcs
;
352 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
354 LttvAttributeType type
;
356 LttvAttributeValue value
;
358 LttvAttributeName name
;
360 LttEventPosition
*ep
;
362 tracefiles_tree
= lttv_attribute_find_subdir(container
,
363 LTTV_STATE_TRACEFILES
);
364 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
366 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
368 g_assert(type
== LTTV_POINTER
);
369 lttv_state_free_process_table(*(value
.v_pointer
));
370 *(value
.v_pointer
) = NULL
;
371 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
373 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
374 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
375 nb_tracefile
= nb_control
+ nb_per_cpu
;
377 for(i
= 0 ; i
< nb_tracefile
; i
++) {
378 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
379 self
->parent
.control_tracefiles
[i
];
380 else tfcs
= (LttvTracefileState
*)
381 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
383 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
384 g_assert(type
== LTTV_GOBJECT
);
385 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
387 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
389 g_assert(type
== LTTV_POINTER
);
390 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
392 lttv_attribute_recursive_free(tracefiles_tree
);
397 fill_name_tables(LttvTraceState
*tcs
)
401 char *f_name
, *e_name
;
409 GString
*fe_name
= g_string_new("");
411 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
412 tcs
->eventtype_names
= g_new(GQuark
, nb
);
413 for(i
= 0 ; i
< nb
; i
++) {
414 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
415 e_name
= ltt_eventtype_name(et
);
416 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
417 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
418 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
421 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
422 "syscall_id", NULL
, NULL
, NULL
, &h
);
423 t
= ltt_field_type(h
.f1
);
424 nb
= ltt_type_element_number(t
);
426 /* CHECK syscalls should be an emun but currently are not!
427 tcs->syscall_names = g_new(GQuark, nb);
429 for(i = 0 ; i < nb ; i++) {
430 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
434 tcs
->syscall_names
= g_new(GQuark
, 256);
435 for(i
= 0 ; i
< 256 ; i
++) {
436 g_string_printf(fe_name
, "syscall %d", i
);
437 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
440 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
441 "trap_id", NULL
, NULL
, NULL
, &h
);
442 t
= ltt_field_type(h
.f1
);
443 nb
= ltt_type_element_number(t
);
446 tcs->trap_names = g_new(GQuark, nb);
447 for(i = 0 ; i < nb ; i++) {
448 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
452 tcs
->trap_names
= g_new(GQuark
, 256);
453 for(i
= 0 ; i
< 256 ; i
++) {
454 g_string_printf(fe_name
, "trap %d", i
);
455 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
458 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
459 "irq_id", NULL
, NULL
, NULL
, &h
);
460 t
= ltt_field_type(h
.f1
);
461 nb
= ltt_type_element_number(t
);
464 tcs->irq_names = g_new(GQuark, nb);
465 for(i = 0 ; i < nb ; i++) {
466 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
470 tcs
->irq_names
= g_new(GQuark
, 256);
471 for(i
= 0 ; i
< 256 ; i
++) {
472 g_string_printf(fe_name
, "irq %d", i
);
473 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
476 g_string_free(fe_name
, TRUE
);
481 free_name_tables(LttvTraceState
*tcs
)
483 g_free(tcs
->eventtype_names
);
484 g_free(tcs
->syscall_names
);
485 g_free(tcs
->trap_names
);
486 g_free(tcs
->irq_names
);
490 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
493 LttvExecutionState
*es
;
495 LttvProcessState
*process
= tfs
->process
;
497 guint depth
= process
->execution_stack
->len
;
499 g_array_set_size(process
->execution_stack
, depth
+ 1);
500 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
503 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
504 es
->s
= process
->state
->s
;
509 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
511 LttvProcessState
*process
= tfs
->process
;
513 guint depth
= process
->execution_stack
->len
- 1;
515 if(process
->state
->t
!= t
){
516 g_warning("Different execution mode type (%d.%09d): ignore it\n",
517 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
518 g_warning("process state has %s when pop_int is %s\n",
519 g_quark_to_string(process
->state
->t
),
520 g_quark_to_string(t
));
521 g_warning("{ %u, %u, %s, %s }\n",
524 g_quark_to_string(process
->name
),
525 g_quark_to_string(process
->state
->s
));
530 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
531 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
535 g_array_remove_index(process
->execution_stack
, depth
);
537 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
539 process
->state
->change
= tfs
->parent
.timestamp
;
543 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
544 LttvProcessState
*parent
, guint pid
)
546 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
548 LttvExecutionState
*es
;
550 LttvTraceContext
*tc
;
556 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
558 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
562 process
->ppid
= parent
->pid
;
563 process
->name
= parent
->name
;
567 process
->name
= LTTV_STATE_UNNAMED
;
570 process
->creation_time
= tfs
->parent
.timestamp
;
571 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
572 process
->creation_time
.tv_nsec
);
573 process
->pid_time
= g_quark_from_string(buffer
);
574 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
575 sizeof(LttvExecutionState
));
576 g_array_set_size(process
->execution_stack
, 1);
577 es
= process
->state
= &g_array_index(process
->execution_stack
,
578 LttvExecutionState
, 0);
579 es
->t
= LTTV_STATE_USER_MODE
;
580 es
->n
= LTTV_STATE_SUBMODE_NONE
;
581 es
->entry
= tfs
->parent
.timestamp
;
582 es
->change
= tfs
->parent
.timestamp
;
583 es
->s
= LTTV_STATE_WAIT_FORK
;
588 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
591 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
592 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
593 GUINT_TO_POINTER(pid
));
594 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
598 LttvProcessState
*lttv_state_find_process_from_trace(LttvTraceState
*ts
,
601 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
602 GUINT_TO_POINTER(pid
));
603 //We do not create a process at this level, because we can be called
604 //from outside of state.c, and therefore cannot assume a tracefile
606 //if(process == NULL) process = create_process_from_trace(ts, NULL, pid);
612 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
614 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
616 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
617 g_array_free(process
->execution_stack
, TRUE
);
622 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
624 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
629 static void lttv_state_free_process_table(GHashTable
*processes
)
631 g_hash_table_foreach(processes
, free_process_state
, NULL
);
632 g_hash_table_destroy(processes
);
636 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
638 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
640 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
642 LttvExecutionSubmode submode
;
644 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
645 ltt_event_get_unsigned(s
->parent
.e
, f
)];
646 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
651 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
653 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
655 pop_state(s
, LTTV_STATE_SYSCALL
);
660 static gboolean
trap_entry(void *hook_data
, void *call_data
)
662 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
664 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
666 LttvExecutionSubmode submode
;
668 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
669 ltt_event_get_unsigned(s
->parent
.e
, f
)];
670 push_state(s
, LTTV_STATE_TRAP
, submode
);
675 static gboolean
trap_exit(void *hook_data
, void *call_data
)
677 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
679 pop_state(s
, LTTV_STATE_TRAP
);
684 static gboolean
irq_entry(void *hook_data
, void *call_data
)
686 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
688 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
690 LttvExecutionSubmode submode
;
692 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
693 ltt_event_get_unsigned(s
->parent
.e
, f
)];
695 /* Do something with the info about being in user or system mode when int? */
696 push_state(s
, LTTV_STATE_IRQ
, submode
);
701 static gboolean
irq_exit(void *hook_data
, void *call_data
)
703 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
705 pop_state(s
, LTTV_STATE_IRQ
);
710 static gboolean
schedchange(void *hook_data
, void *call_data
)
712 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
714 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
716 guint pid_in
, pid_out
, state_out
;
718 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
719 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
720 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
722 if(s
->process
!= NULL
) {
724 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
725 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
726 exit_process(s
, s
->process
);
727 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
729 if(s
->process
->pid
== 0)
730 s
->process
->pid
= pid_out
;
732 s
->process
->state
->change
= s
->parent
.timestamp
;
734 s
->process
= lttv_state_find_process(s
, pid_in
);
735 s
->process
->state
->s
= LTTV_STATE_RUN
;
736 s
->process
->state
->change
= s
->parent
.timestamp
;
741 static gboolean
process_fork(void *hook_data
, void *call_data
)
743 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
745 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
749 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
750 create_process(s
, s
->process
, child_pid
);
755 static gboolean
process_exit(void *hook_data
, void *call_data
)
757 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
759 if(s
->process
!= NULL
) {
760 s
->process
->state
->s
= LTTV_STATE_EXIT
;
766 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
768 LttvTraceset
*traceset
= self
->parent
.ts
;
770 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
774 LttvTracefileState
*tfs
;
780 LttvAttributeValue val
;
782 nb_trace
= lttv_traceset_number(traceset
);
783 for(i
= 0 ; i
< nb_trace
; i
++) {
784 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
786 /* Find the eventtype id for the following events and register the
787 associated by id hooks. */
789 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
790 g_array_set_size(hooks
, 9);
792 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
793 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
795 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
796 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
798 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
799 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
801 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
802 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
804 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
805 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
807 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
808 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
810 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
811 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
813 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
814 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
816 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
817 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
819 /* Add these hooks to each before_event_by_id hooks list */
821 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
822 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
823 nb_tracefile
= nb_control
+ nb_per_cpu
;
824 for(j
= 0 ; j
< nb_tracefile
; j
++) {
826 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
829 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
832 for(k
= 0 ; k
< hooks
->len
; k
++) {
833 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
834 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
835 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
838 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
839 *(val
.v_pointer
) = hooks
;
844 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
846 LttvTraceset
*traceset
= self
->parent
.ts
;
848 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
852 LttvTracefileState
*tfs
;
858 LttvAttributeValue val
;
860 nb_trace
= lttv_traceset_number(traceset
);
861 for(i
= 0 ; i
< nb_trace
; i
++) {
862 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
863 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
864 hooks
= *(val
.v_pointer
);
866 /* Add these hooks to each before_event_by_id hooks list */
868 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
869 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
870 nb_tracefile
= nb_control
+ nb_per_cpu
;
871 for(j
= 0 ; j
< nb_tracefile
; j
++) {
873 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
876 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
879 for(k
= 0 ; k
< hooks
->len
; k
++) {
880 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
881 lttv_hooks_remove_data(
882 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
883 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
886 g_array_free(hooks
, TRUE
);
891 static gboolean
block_end(void *hook_data
, void *call_data
)
893 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
895 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
897 LttEventPosition
*ep
= ltt_event_position_new();
899 guint nb_block
, nb_event
;
903 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
905 LttvAttributeValue value
;
907 ltt_event_position(tfcs
->parent
.e
, ep
);
909 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
910 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
911 tfcs
->saved_position
= 0;
912 if(tcs
->nb_event
>= tcs
->save_interval
) {
913 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
914 LTTV_STATE_SAVED_STATES
);
915 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
916 value
= lttv_attribute_add(saved_states_tree
,
917 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
918 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
919 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
920 *(value
.v_time
) = tfcs
->parent
.timestamp
;
921 lttv_state_save(tcs
, saved_state_tree
);
928 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
930 LttvTraceset
*traceset
= self
->parent
.ts
;
932 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
936 LttvTracefileState
*tfs
;
940 nb_trace
= lttv_traceset_number(traceset
);
941 for(i
= 0 ; i
< nb_trace
; i
++) {
942 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
943 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
944 NULL
, NULL
, block_end
, &hook
);
946 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
947 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
948 nb_tracefile
= nb_control
+ nb_per_cpu
;
949 for(j
= 0 ; j
< nb_tracefile
; j
++) {
951 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
954 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
957 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
958 hook
.id
), hook
.h
, NULL
);
964 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
966 LttvTraceset
*traceset
= self
->parent
.ts
;
968 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
972 LttvTracefileState
*tfs
;
976 nb_trace
= lttv_traceset_number(traceset
);
977 for(i
= 0 ; i
< nb_trace
; i
++) {
978 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
979 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
980 NULL
, NULL
, block_end
, &hook
);
982 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
983 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
984 nb_tracefile
= nb_control
+ nb_per_cpu
;
985 for(j
= 0 ; j
< nb_tracefile
; j
++) {
987 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
990 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
993 lttv_hooks_remove_data(lttv_hooks_by_id_find(
994 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
1000 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1002 LttvTraceset
*traceset
= self
->parent
.ts
;
1004 guint i
, j
, nb_trace
, nb_saved_state
;
1006 int min_pos
, mid_pos
, max_pos
;
1008 LttvTraceState
*tcs
;
1010 LttvAttributeValue value
;
1012 LttvAttributeType type
;
1014 LttvAttributeName name
;
1016 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1018 nb_trace
= lttv_traceset_number(traceset
);
1019 for(i
= 0 ; i
< nb_trace
; i
++) {
1020 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1022 if(tcs
->recompute_state_in_seek
) {
1023 if(tcs
->saved_state_available
) {
1024 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1025 LTTV_STATE_SAVED_STATES
);
1027 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1028 mid_pos
= max_pos
/ 2;
1029 while(min_pos
< max_pos
) {
1030 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1031 g_assert(type
== LTTV_GOBJECT
);
1032 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1033 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1035 g_assert(type
== LTTV_TIME
);
1036 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1038 closest_tree
= saved_state_tree
;
1040 else max_pos
= mid_pos
- 1;
1042 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1045 /* restore the closest earlier saved state */
1046 if(min_pos
!= -1) lttv_state_restore(tcs
, closest_tree
);
1049 /* There is no saved state yet we want to have it. Restart at T0 */
1051 restore_init_state(tcs
);
1052 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1055 /* We want to seek quickly without restoring/updating the state */
1057 restore_init_state(tcs
);
1058 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1065 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1071 traceset_state_finalize (LttvTracesetState
*self
)
1073 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1074 finalize(G_OBJECT(self
));
1079 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1081 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1083 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1084 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1085 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1086 klass
->new_traceset_context
= new_traceset_context
;
1087 klass
->new_trace_context
= new_trace_context
;
1088 klass
->new_tracefile_context
= new_tracefile_context
;
1093 lttv_traceset_state_get_type(void)
1095 static GType type
= 0;
1097 static const GTypeInfo info
= {
1098 sizeof (LttvTracesetStateClass
),
1099 NULL
, /* base_init */
1100 NULL
, /* base_finalize */
1101 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1102 NULL
, /* class_finalize */
1103 NULL
, /* class_data */
1104 sizeof (LttvTracesetContext
),
1105 0, /* n_preallocs */
1106 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1109 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1117 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1123 trace_state_finalize (LttvTraceState
*self
)
1125 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1126 finalize(G_OBJECT(self
));
1131 trace_state_class_init (LttvTraceStateClass
*klass
)
1133 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1135 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1136 klass
->state_save
= state_save
;
1137 klass
->state_restore
= state_restore
;
1138 klass
->state_saved_free
= state_saved_free
;
1143 lttv_trace_state_get_type(void)
1145 static GType type
= 0;
1147 static const GTypeInfo info
= {
1148 sizeof (LttvTraceStateClass
),
1149 NULL
, /* base_init */
1150 NULL
, /* base_finalize */
1151 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1152 NULL
, /* class_finalize */
1153 NULL
, /* class_data */
1154 sizeof (LttvTraceState
),
1155 0, /* n_preallocs */
1156 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1159 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1160 "LttvTraceStateType", &info
, 0);
1167 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1173 tracefile_state_finalize (LttvTracefileState
*self
)
1175 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1176 finalize(G_OBJECT(self
));
1181 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1183 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1185 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1190 lttv_tracefile_state_get_type(void)
1192 static GType type
= 0;
1194 static const GTypeInfo info
= {
1195 sizeof (LttvTracefileStateClass
),
1196 NULL
, /* base_init */
1197 NULL
, /* base_finalize */
1198 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1199 NULL
, /* class_finalize */
1200 NULL
, /* class_data */
1201 sizeof (LttvTracefileState
),
1202 0, /* n_preallocs */
1203 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1206 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1207 "LttvTracefileStateType", &info
, 0);
1213 void lttv_state_init(int argc
, char **argv
)
1215 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1216 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1217 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1218 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1219 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1220 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1221 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1222 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1223 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1224 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1225 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1226 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1227 LTTV_STATE_RUN
= g_quark_from_string("running");
1228 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1229 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1230 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1231 LTTV_STATE_EVENT
= g_quark_from_string("event");
1232 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1233 LTTV_STATE_TIME
= g_quark_from_string("time");
1234 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1237 void lttv_state_destroy()