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
= false;
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
;
589 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
592 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
593 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
594 GUINT_TO_POINTER(pid
));
595 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
600 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
602 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
604 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
605 g_array_free(process
->execution_stack
, TRUE
);
610 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
612 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
617 static void lttv_state_free_process_table(GHashTable
*processes
)
619 g_hash_table_foreach(processes
, free_process_state
, NULL
);
620 g_hash_table_destroy(processes
);
624 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
626 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
628 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
630 LttvExecutionSubmode submode
;
632 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
633 ltt_event_get_unsigned(s
->parent
.e
, f
)];
634 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
639 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
641 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
643 pop_state(s
, LTTV_STATE_SYSCALL
);
648 static gboolean
trap_entry(void *hook_data
, void *call_data
)
650 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
652 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
654 LttvExecutionSubmode submode
;
656 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
657 ltt_event_get_unsigned(s
->parent
.e
, f
)];
658 push_state(s
, LTTV_STATE_TRAP
, submode
);
663 static gboolean
trap_exit(void *hook_data
, void *call_data
)
665 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
667 pop_state(s
, LTTV_STATE_TRAP
);
672 static gboolean
irq_entry(void *hook_data
, void *call_data
)
674 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
676 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
678 LttvExecutionSubmode submode
;
680 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
681 ltt_event_get_unsigned(s
->parent
.e
, f
)];
683 /* Do something with the info about being in user or system mode when int? */
684 push_state(s
, LTTV_STATE_IRQ
, submode
);
689 static gboolean
irq_exit(void *hook_data
, void *call_data
)
691 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
693 pop_state(s
, LTTV_STATE_IRQ
);
698 static gboolean
schedchange(void *hook_data
, void *call_data
)
700 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
702 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
704 guint pid_in
, pid_out
, state_out
;
706 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
707 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
708 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
710 if(s
->process
!= NULL
) {
712 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
713 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
714 exit_process(s
, s
->process
);
715 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
717 if(s
->process
->pid
== 0)
718 s
->process
->pid
= pid_out
;
720 s
->process
->state
->change
= s
->parent
.timestamp
;
722 s
->process
= lttv_state_find_process(s
, pid_in
);
723 s
->process
->state
->s
= LTTV_STATE_RUN
;
724 s
->process
->state
->change
= s
->parent
.timestamp
;
729 static gboolean
process_fork(void *hook_data
, void *call_data
)
731 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
733 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
737 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
738 create_process(s
, s
->process
, child_pid
);
743 static gboolean
process_exit(void *hook_data
, void *call_data
)
745 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
747 if(s
->process
!= NULL
) {
748 s
->process
->state
->s
= LTTV_STATE_EXIT
;
754 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
756 LttvTraceset
*traceset
= self
->parent
.ts
;
758 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
762 LttvTracefileState
*tfs
;
768 LttvAttributeValue val
;
770 nb_trace
= lttv_traceset_number(traceset
);
771 for(i
= 0 ; i
< nb_trace
; i
++) {
772 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
774 /* Find the eventtype id for the following events and register the
775 associated by id hooks. */
777 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
778 g_array_set_size(hooks
, 9);
780 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
781 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
783 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
784 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
786 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
787 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
789 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
790 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
792 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
793 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
795 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
796 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
798 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
799 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
801 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
802 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
804 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
805 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
807 /* Add these hooks to each before_event_by_id hooks list */
809 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
810 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
811 nb_tracefile
= nb_control
+ nb_per_cpu
;
812 for(j
= 0 ; j
< nb_tracefile
; j
++) {
814 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
817 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
820 for(k
= 0 ; k
< hooks
->len
; k
++) {
821 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
822 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
823 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
826 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
827 *(val
.v_pointer
) = hooks
;
832 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
834 LttvTraceset
*traceset
= self
->parent
.ts
;
836 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
840 LttvTracefileState
*tfs
;
846 LttvAttributeValue val
;
848 nb_trace
= lttv_traceset_number(traceset
);
849 for(i
= 0 ; i
< nb_trace
; i
++) {
850 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
851 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
852 hooks
= *(val
.v_pointer
);
854 /* Add these hooks to each before_event_by_id hooks list */
856 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
857 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
858 nb_tracefile
= nb_control
+ nb_per_cpu
;
859 for(j
= 0 ; j
< nb_tracefile
; j
++) {
861 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
864 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
867 for(k
= 0 ; k
< hooks
->len
; k
++) {
868 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
869 lttv_hooks_remove_data(
870 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
871 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
874 g_array_free(hooks
, TRUE
);
879 static gboolean
block_end(void *hook_data
, void *call_data
)
881 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
883 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
885 LttEventPosition
*ep
= ltt_event_position_new();
887 guint nb_block
, nb_event
;
891 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
893 LttvAttributeValue value
;
895 ltt_event_position(tfcs
->parent
.e
, ep
);
897 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
898 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
899 tfcs
->saved_position
= 0;
900 if(tcs
->nb_event
>= tcs
->save_interval
) {
901 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
902 LTTV_STATE_SAVED_STATES
);
903 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
904 value
= lttv_attribute_add(saved_states_tree
,
905 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
906 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
907 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
908 *(value
.v_time
) = tfcs
->parent
.timestamp
;
909 lttv_state_save(tcs
, saved_state_tree
);
916 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
918 LttvTraceset
*traceset
= self
->parent
.ts
;
920 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
924 LttvTracefileState
*tfs
;
928 nb_trace
= lttv_traceset_number(traceset
);
929 for(i
= 0 ; i
< nb_trace
; i
++) {
930 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
931 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
932 NULL
, NULL
, block_end
, &hook
);
934 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
935 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
936 nb_tracefile
= nb_control
+ nb_per_cpu
;
937 for(j
= 0 ; j
< nb_tracefile
; j
++) {
939 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
942 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
945 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
946 hook
.id
), hook
.h
, NULL
);
952 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
954 LttvTraceset
*traceset
= self
->parent
.ts
;
956 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
960 LttvTracefileState
*tfs
;
964 nb_trace
= lttv_traceset_number(traceset
);
965 for(i
= 0 ; i
< nb_trace
; i
++) {
966 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
967 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
968 NULL
, NULL
, block_end
, &hook
);
970 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
971 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
972 nb_tracefile
= nb_control
+ nb_per_cpu
;
973 for(j
= 0 ; j
< nb_tracefile
; j
++) {
975 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
978 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
981 lttv_hooks_remove_data(lttv_hooks_by_id_find(
982 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
988 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
990 LttvTraceset
*traceset
= self
->parent
.ts
;
992 guint i
, j
, nb_trace
, nb_saved_state
;
994 int min_pos
, mid_pos
, max_pos
;
998 LttvAttributeValue value
;
1000 LttvAttributeType type
;
1002 LttvAttributeName name
;
1004 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1006 nb_trace
= lttv_traceset_number(traceset
);
1007 for(i
= 0 ; i
< nb_trace
; i
++) {
1008 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1010 if(tcs
->recompute_state_in_seek
) {
1011 if(tcs
->saved_state_available
) {
1012 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1013 LTTV_STATE_SAVED_STATES
);
1015 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1016 mid_pos
= max_pos
/ 2;
1017 while(min_pos
< max_pos
) {
1018 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1019 g_assert(type
== LTTV_GOBJECT
);
1020 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1021 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1023 g_assert(type
== LTTV_TIME
);
1024 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1026 closest_tree
= saved_state_tree
;
1028 else max_pos
= mid_pos
- 1;
1030 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1033 /* restore the closest earlier saved state */
1034 if(min_pos
!= -1) lttv_state_restore(tcs
, closest_tree
);
1036 /* there is no earlier saved state, restart at T0 */
1038 restore_init_state(tcs
);
1039 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1042 /* There is no saved state yet we want to have it. Restart at T0 */
1044 restore_init_state(tcs
);
1045 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1048 /* We want to seek quickly without restoring/updating the state */
1050 restore_init_state(tcs
);
1051 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1058 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1064 traceset_state_finalize (LttvTracesetState
*self
)
1066 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1067 finalize(G_OBJECT(self
));
1072 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1074 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1076 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1077 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1078 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1079 klass
->new_traceset_context
= new_traceset_context
;
1080 klass
->new_trace_context
= new_trace_context
;
1081 klass
->new_tracefile_context
= new_tracefile_context
;
1086 lttv_traceset_state_get_type(void)
1088 static GType type
= 0;
1090 static const GTypeInfo info
= {
1091 sizeof (LttvTracesetStateClass
),
1092 NULL
, /* base_init */
1093 NULL
, /* base_finalize */
1094 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1095 NULL
, /* class_finalize */
1096 NULL
, /* class_data */
1097 sizeof (LttvTracesetContext
),
1098 0, /* n_preallocs */
1099 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1102 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1110 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1116 trace_state_finalize (LttvTraceState
*self
)
1118 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1119 finalize(G_OBJECT(self
));
1124 trace_state_class_init (LttvTraceStateClass
*klass
)
1126 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1128 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1129 klass
->state_save
= state_save
;
1130 klass
->state_restore
= state_restore
;
1131 klass
->state_saved_free
= state_saved_free
;
1136 lttv_trace_state_get_type(void)
1138 static GType type
= 0;
1140 static const GTypeInfo info
= {
1141 sizeof (LttvTraceStateClass
),
1142 NULL
, /* base_init */
1143 NULL
, /* base_finalize */
1144 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1145 NULL
, /* class_finalize */
1146 NULL
, /* class_data */
1147 sizeof (LttvTraceState
),
1148 0, /* n_preallocs */
1149 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1152 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1153 "LttvTraceStateType", &info
, 0);
1160 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1166 tracefile_state_finalize (LttvTracefileState
*self
)
1168 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1169 finalize(G_OBJECT(self
));
1174 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1176 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1178 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1183 lttv_tracefile_state_get_type(void)
1185 static GType type
= 0;
1187 static const GTypeInfo info
= {
1188 sizeof (LttvTracefileStateClass
),
1189 NULL
, /* base_init */
1190 NULL
, /* base_finalize */
1191 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1192 NULL
, /* class_finalize */
1193 NULL
, /* class_data */
1194 sizeof (LttvTracefileState
),
1195 0, /* n_preallocs */
1196 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1199 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1200 "LttvTracefileStateType", &info
, 0);
1206 void lttv_state_init(int argc
, char **argv
)
1208 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1209 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1210 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1211 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1212 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1213 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1214 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1215 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1216 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1217 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1218 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1219 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1220 LTTV_STATE_RUN
= g_quark_from_string("running");
1221 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1222 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1223 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1224 LTTV_STATE_EVENT
= g_quark_from_string("event");
1225 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1226 LTTV_STATE_TIME
= g_quark_from_string("time");
1227 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1230 void lttv_state_destroy()