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
);
62 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
64 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
68 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
70 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
74 void lttv_state_saved_state_free(LttvTraceState
*self
,
75 LttvAttribute
*container
)
77 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
81 guint
process_hash(gconstpointer key
)
83 return ((LttvProcessState
*)key
)->pid
;
87 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
89 LttvProcessState
*process_a
, *process_b
;
91 process_a
= (LttvProcessState
*)a
;
92 process_b
= (LttvProcessState
*)b
;
94 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
95 if(process_a
->pid
== 0 &&
96 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
102 restore_init_state(LttvTraceState
*self
)
104 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
106 LttvTracefileState
*tfcs
;
108 LttTime null_time
= {0,0};
110 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
111 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
114 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
115 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
116 nb_tracefile
= nb_control
+ nb_per_cpu
;
117 for(i
= 0 ; i
< nb_tracefile
; i
++) {
119 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.control_tracefiles
[i
]);
122 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.per_cpu_tracefiles
[i
- nb_control
]);
125 tfcs
->parent
.timestamp
= null_time
;
126 tfcs
->saved_position
= 0;
127 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
128 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
129 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
133 static LttTime time_zero
= {0,0};
136 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
138 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
140 LttvTraceContext
*tc
;
144 LttvTracefileState
*tfcs
;
146 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
147 init((LttvTracesetContext
*)self
, ts
);
149 nb_trace
= lttv_traceset_number(ts
);
150 for(i
= 0 ; i
< nb_trace
; i
++) {
151 tc
= self
->parent
.traces
[i
];
152 tcs
= (LttvTraceState
*)tc
;
153 tcs
->save_interval
= 100000;
154 tcs
->max_time_state_recomputed_in_seek
= &time_zero
;
155 fill_name_tables(tcs
);
157 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
158 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
159 nb_tracefile
= nb_control
+ nb_per_cpu
;
160 for(j
= 0 ; j
< nb_tracefile
; j
++) {
162 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
165 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
167 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
169 tcs
->processes
= NULL
;
170 restore_init_state(tcs
);
176 fini(LttvTracesetState
*self
)
178 guint i
, j
, nb_trace
, nb_tracefile
;
182 LttvTracefileState
*tfcs
;
184 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
185 for(i
= 0 ; i
< nb_trace
; i
++) {
186 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
187 lttv_state_free_process_table(tcs
->processes
);
188 tcs
->processes
= NULL
;
189 free_name_tables(tcs
);
191 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
192 fini((LttvTracesetContext
*)self
);
196 static LttvTracesetContext
*
197 new_traceset_context(LttvTracesetContext
*self
)
199 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
203 static LttvTraceContext
*
204 new_trace_context(LttvTracesetContext
*self
)
206 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
210 static LttvTracefileContext
*
211 new_tracefile_context(LttvTracesetContext
*self
)
213 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
217 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
219 LttvProcessState
*process
, *new_process
;
221 GHashTable
*new_processes
= (GHashTable
*)user_data
;
225 process
= (LttvProcessState
*)value
;
226 new_process
= g_new(LttvProcessState
, 1);
227 *new_process
= *process
;
228 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
229 sizeof(LttvExecutionState
));
230 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
231 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
232 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
233 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
235 new_process
->state
= &g_array_index(new_process
->execution_stack
,
236 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
237 g_hash_table_insert(new_processes
, new_process
, new_process
);
241 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
243 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
245 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
246 return new_processes
;
250 /* The saved state for each trace contains a member "processes", which
251 stores a copy of the process table, and a member "tracefiles" with
252 one entry per tracefile. Each tracefile has a "process" member pointing
253 to the current process and a "position" member storing the tracefile
254 position (needed to seek to the current "next" event. */
256 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
258 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
260 LttvTracefileState
*tfcs
;
262 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
264 LttvAttributeType type
;
266 LttvAttributeValue value
;
268 LttvAttributeName name
;
270 LttEventPosition
*ep
;
272 tracefiles_tree
= lttv_attribute_find_subdir(container
,
273 LTTV_STATE_TRACEFILES
);
275 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
277 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
279 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
280 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
281 nb_tracefile
= nb_control
+ nb_per_cpu
;
283 for(i
= 0 ; i
< nb_tracefile
; i
++) {
285 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
286 else tfcs
= (LttvTracefileState
*)
287 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
289 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
290 value
= lttv_attribute_add(tracefiles_tree
, i
,
292 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
293 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
295 *(value
.v_uint
) = tfcs
->process
->pid
;
296 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
298 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
300 ep
= ltt_event_position_new();
301 ltt_event_position(tfcs
->parent
.e
, ep
);
302 *(value
.v_pointer
) = ep
;
308 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
310 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
, pid
;
312 LttvTracefileState
*tfcs
;
314 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
316 LttvAttributeType type
;
318 LttvAttributeValue value
;
320 LttvAttributeName name
;
322 LttEventPosition
*ep
;
324 tracefiles_tree
= lttv_attribute_find_subdir(container
,
325 LTTV_STATE_TRACEFILES
);
327 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
329 g_assert(type
== LTTV_POINTER
);
330 lttv_state_free_process_table(self
->processes
);
331 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
333 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
334 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
335 nb_tracefile
= nb_control
+ nb_per_cpu
;
337 for(i
= 0 ; i
< nb_tracefile
; i
++) {
338 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
339 self
->parent
.control_tracefiles
[i
];
340 else tfcs
= (LttvTracefileState
*)
341 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
343 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
344 g_assert(type
== LTTV_GOBJECT
);
345 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
347 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
349 g_assert(type
== LTTV_UINT
);
350 pid
= *(value
.v_uint
);
351 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
353 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
355 g_assert(type
== LTTV_POINTER
);
356 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
358 ep
= *(value
.v_pointer
);
359 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
360 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
361 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
367 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
369 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
371 LttvTracefileState
*tfcs
;
373 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
375 LttvAttributeType type
;
377 LttvAttributeValue value
;
379 LttvAttributeName name
;
381 LttEventPosition
*ep
;
383 tracefiles_tree
= lttv_attribute_find_subdir(container
,
384 LTTV_STATE_TRACEFILES
);
385 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
387 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
389 g_assert(type
== LTTV_POINTER
);
390 lttv_state_free_process_table(*(value
.v_pointer
));
391 *(value
.v_pointer
) = NULL
;
392 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
394 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
395 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
396 nb_tracefile
= nb_control
+ nb_per_cpu
;
398 for(i
= 0 ; i
< nb_tracefile
; i
++) {
399 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
400 self
->parent
.control_tracefiles
[i
];
401 else tfcs
= (LttvTracefileState
*)
402 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
404 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
405 g_assert(type
== LTTV_GOBJECT
);
406 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
408 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
410 g_assert(type
== LTTV_POINTER
);
411 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
413 lttv_attribute_recursive_free(tracefiles_tree
);
418 fill_name_tables(LttvTraceState
*tcs
)
422 char *f_name
, *e_name
;
430 GString
*fe_name
= g_string_new("");
432 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
433 tcs
->eventtype_names
= g_new(GQuark
, nb
);
434 for(i
= 0 ; i
< nb
; i
++) {
435 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
436 e_name
= ltt_eventtype_name(et
);
437 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
438 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
439 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
442 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
443 "syscall_id", NULL
, NULL
, NULL
, &h
);
444 t
= ltt_field_type(h
.f1
);
445 nb
= ltt_type_element_number(t
);
447 /* CHECK syscalls should be an emun but currently are not!
448 tcs->syscall_names = g_new(GQuark, nb);
450 for(i = 0 ; i < nb ; i++) {
451 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
455 tcs
->syscall_names
= g_new(GQuark
, 256);
456 for(i
= 0 ; i
< 256 ; i
++) {
457 g_string_printf(fe_name
, "syscall %d", i
);
458 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
461 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
462 "trap_id", NULL
, NULL
, NULL
, &h
);
463 t
= ltt_field_type(h
.f1
);
464 nb
= ltt_type_element_number(t
);
467 tcs->trap_names = g_new(GQuark, nb);
468 for(i = 0 ; i < nb ; i++) {
469 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
473 tcs
->trap_names
= g_new(GQuark
, 256);
474 for(i
= 0 ; i
< 256 ; i
++) {
475 g_string_printf(fe_name
, "trap %d", i
);
476 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
479 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
480 "irq_id", NULL
, NULL
, NULL
, &h
);
481 t
= ltt_field_type(h
.f1
);
482 nb
= ltt_type_element_number(t
);
485 tcs->irq_names = g_new(GQuark, nb);
486 for(i = 0 ; i < nb ; i++) {
487 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
491 tcs
->irq_names
= g_new(GQuark
, 256);
492 for(i
= 0 ; i
< 256 ; i
++) {
493 g_string_printf(fe_name
, "irq %d", i
);
494 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
497 g_string_free(fe_name
, TRUE
);
502 free_name_tables(LttvTraceState
*tcs
)
504 g_free(tcs
->eventtype_names
);
505 g_free(tcs
->syscall_names
);
506 g_free(tcs
->trap_names
);
507 g_free(tcs
->irq_names
);
511 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
514 LttvExecutionState
*es
;
516 LttvProcessState
*process
= tfs
->process
;
518 guint depth
= process
->execution_stack
->len
;
520 g_array_set_size(process
->execution_stack
, depth
+ 1);
521 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
524 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
525 es
->s
= process
->state
->s
;
530 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
532 LttvProcessState
*process
= tfs
->process
;
534 guint depth
= process
->execution_stack
->len
- 1;
536 if(process
->state
->t
!= t
){
537 g_warning("Different execution mode type (%d.%09d): ignore it\n",
538 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
539 g_warning("process state has %s when pop_int is %s\n",
540 g_quark_to_string(process
->state
->t
),
541 g_quark_to_string(t
));
542 g_warning("{ %u, %u, %s, %s }\n",
545 g_quark_to_string(process
->name
),
546 g_quark_to_string(process
->state
->s
));
551 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
552 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
556 g_array_remove_index(process
->execution_stack
, depth
);
558 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
560 process
->state
->change
= tfs
->parent
.timestamp
;
565 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
568 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
570 LttvExecutionState
*es
;
572 LttvTraceContext
*tc
;
578 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
581 process
->last_cpu
= tfs
->cpu_name
;
582 g_hash_table_insert(tcs
->processes
, process
, process
);
585 process
->ppid
= parent
->pid
;
586 process
->name
= parent
->name
;
587 process
->creation_time
= tfs
->parent
.timestamp
;
590 /* No parent. This process exists but we are missing all information about
591 its creation. The birth time is set to zero but we remember the time of
596 process
->name
= LTTV_STATE_UNNAMED
;
597 process
->creation_time
= ltt_time_zero
;
600 process
->insertion_time
= tfs
->parent
.timestamp
;
601 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
602 process
->creation_time
.tv_nsec
);
603 process
->pid_time
= g_quark_from_string(buffer
);
604 process
->last_cpu
= tfs
->cpu_name
;
605 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
606 sizeof(LttvExecutionState
));
607 g_array_set_size(process
->execution_stack
, 1);
608 es
= process
->state
= &g_array_index(process
->execution_stack
,
609 LttvExecutionState
, 0);
610 es
->t
= LTTV_STATE_USER_MODE
;
611 es
->n
= LTTV_STATE_SUBMODE_NONE
;
612 es
->entry
= tfs
->parent
.timestamp
;
613 es
->change
= tfs
->parent
.timestamp
;
614 es
->s
= LTTV_STATE_WAIT_FORK
;
621 lttv_state_find_process_from_trace(LttvTraceState
*ts
, GQuark cpu
, guint pid
)
623 LttvProcessState key
;
624 LttvProcessState
*process
;
628 process
= g_hash_table_lookup(ts
->processes
, &key
);
633 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
636 LttvTraceState
*ts
=(LttvTraceState
*)tfs
->parent
.t_context
;
637 return lttv_state_find_process_from_trace(ts
, tfs
->cpu_name
, pid
);
642 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
644 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
646 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
651 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
653 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
654 LttvProcessState key
;
656 key
.pid
= process
->pid
;
657 key
.last_cpu
= process
->last_cpu
;
658 g_hash_table_remove(ts
->processes
, &key
);
659 g_array_free(process
->execution_stack
, TRUE
);
664 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
666 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
671 static void lttv_state_free_process_table(GHashTable
*processes
)
673 g_hash_table_foreach(processes
, free_process_state
, NULL
);
674 g_hash_table_destroy(processes
);
678 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
680 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
682 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
684 LttvExecutionSubmode submode
;
686 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
687 ltt_event_get_unsigned(s
->parent
.e
, f
)];
688 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
693 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
695 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
697 pop_state(s
, LTTV_STATE_SYSCALL
);
702 static gboolean
trap_entry(void *hook_data
, void *call_data
)
704 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
706 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
708 LttvExecutionSubmode submode
;
710 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
711 ltt_event_get_unsigned(s
->parent
.e
, f
)];
712 push_state(s
, LTTV_STATE_TRAP
, submode
);
717 static gboolean
trap_exit(void *hook_data
, void *call_data
)
719 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
721 pop_state(s
, LTTV_STATE_TRAP
);
726 static gboolean
irq_entry(void *hook_data
, void *call_data
)
728 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
732 LttvExecutionSubmode submode
;
734 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
735 ltt_event_get_unsigned(s
->parent
.e
, f
)];
737 /* Do something with the info about being in user or system mode when int? */
738 push_state(s
, LTTV_STATE_IRQ
, submode
);
743 static gboolean
irq_exit(void *hook_data
, void *call_data
)
745 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
747 pop_state(s
, LTTV_STATE_IRQ
);
752 static gboolean
schedchange(void *hook_data
, void *call_data
)
754 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
756 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
758 guint pid_in
, pid_out
, state_out
;
760 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
761 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
762 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
764 if(s
->process
!= NULL
) {
766 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
767 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
768 exit_process(s
, s
->process
);
769 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
771 if(s
->process
->pid
== 0)
772 s
->process
->pid
= pid_out
;
774 s
->process
->state
->change
= s
->parent
.timestamp
;
776 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
777 s
->process
->state
->s
= LTTV_STATE_RUN
;
778 s
->process
->last_cpu
= s
->cpu_name
;
779 s
->process
->state
->change
= s
->parent
.timestamp
;
784 static gboolean
process_fork(void *hook_data
, void *call_data
)
786 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
788 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
792 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
793 lttv_state_create_process(s
, s
->process
, child_pid
);
798 static gboolean
process_exit(void *hook_data
, void *call_data
)
800 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
802 if(s
->process
!= NULL
) {
803 s
->process
->state
->s
= LTTV_STATE_EXIT
;
809 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
811 LttvTraceset
*traceset
= self
->parent
.ts
;
813 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
817 LttvTracefileState
*tfs
;
823 LttvAttributeValue val
;
825 nb_trace
= lttv_traceset_number(traceset
);
826 for(i
= 0 ; i
< nb_trace
; i
++) {
827 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
829 /* Find the eventtype id for the following events and register the
830 associated by id hooks. */
832 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
833 g_array_set_size(hooks
, 9);
835 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
836 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
838 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
839 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
841 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
842 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
844 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
845 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
847 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
848 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
850 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
851 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
853 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
854 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
856 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
857 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
859 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
860 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
862 /* Add these hooks to each before_event_by_id hooks list */
864 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
865 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
866 nb_tracefile
= nb_control
+ nb_per_cpu
;
867 for(j
= 0 ; j
< nb_tracefile
; j
++) {
869 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
872 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
875 for(k
= 0 ; k
< hooks
->len
; k
++) {
876 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
877 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
878 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
881 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
882 *(val
.v_pointer
) = hooks
;
887 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
889 LttvTraceset
*traceset
= self
->parent
.ts
;
891 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
895 LttvTracefileState
*tfs
;
901 LttvAttributeValue val
;
903 nb_trace
= lttv_traceset_number(traceset
);
904 for(i
= 0 ; i
< nb_trace
; i
++) {
905 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
906 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
907 hooks
= *(val
.v_pointer
);
909 /* Add these hooks to each before_event_by_id hooks list */
911 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
912 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
913 nb_tracefile
= nb_control
+ nb_per_cpu
;
914 for(j
= 0 ; j
< nb_tracefile
; j
++) {
916 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
919 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
922 for(k
= 0 ; k
< hooks
->len
; k
++) {
923 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
924 lttv_hooks_remove_data(
925 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
926 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
929 g_array_free(hooks
, TRUE
);
934 static gboolean
block_end(void *hook_data
, void *call_data
)
936 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
938 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
940 LttEventPosition
*ep
= ltt_event_position_new();
942 guint nb_block
, nb_event
;
946 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
948 LttvAttributeValue value
;
950 ltt_event_position(tfcs
->parent
.e
, ep
);
952 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
953 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
954 tfcs
->saved_position
= 0;
955 if(tcs
->nb_event
>= tcs
->save_interval
) {
956 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
957 LTTV_STATE_SAVED_STATES
);
958 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
959 value
= lttv_attribute_add(saved_states_tree
,
960 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
961 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
962 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
963 *(value
.v_time
) = tfcs
->parent
.timestamp
;
964 lttv_state_save(tcs
, saved_state_tree
);
971 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
973 LttvTraceset
*traceset
= self
->parent
.ts
;
975 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
979 LttvTracefileState
*tfs
;
983 nb_trace
= lttv_traceset_number(traceset
);
984 for(i
= 0 ; i
< nb_trace
; i
++) {
985 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
986 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
987 NULL
, NULL
, block_end
, &hook
);
989 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
990 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
991 nb_tracefile
= nb_control
+ nb_per_cpu
;
992 for(j
= 0 ; j
< nb_tracefile
; j
++) {
994 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
997 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
1000 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
1001 hook
.id
), hook
.h
, NULL
);
1007 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1009 LttvTraceset
*traceset
= self
->parent
.ts
;
1011 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
1015 LttvTracefileState
*tfs
;
1019 nb_trace
= lttv_traceset_number(traceset
);
1020 for(i
= 0 ; i
< nb_trace
; i
++) {
1021 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1022 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1023 NULL
, NULL
, block_end
, &hook
);
1025 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
1026 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1027 nb_tracefile
= nb_control
+ nb_per_cpu
;
1028 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1029 if(j
< nb_control
) {
1030 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
1033 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
1036 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1037 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
1043 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1045 LttvTraceset
*traceset
= self
->parent
.ts
;
1047 guint i
, j
, nb_trace
, nb_saved_state
;
1049 int min_pos
, mid_pos
, max_pos
;
1051 LttvTraceState
*tcs
;
1053 LttvAttributeValue value
;
1055 LttvAttributeType type
;
1057 LttvAttributeName name
;
1059 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1061 nb_trace
= lttv_traceset_number(traceset
);
1062 for(i
= 0 ; i
< nb_trace
; i
++) {
1063 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1065 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1066 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1067 LTTV_STATE_SAVED_STATES
);
1070 if(saved_states_tree
) {
1071 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1072 mid_pos
= max_pos
/ 2;
1073 while(min_pos
< max_pos
) {
1074 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1075 g_assert(type
== LTTV_GOBJECT
);
1076 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1077 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1079 g_assert(type
== LTTV_TIME
);
1080 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1082 closest_tree
= saved_state_tree
;
1084 else max_pos
= mid_pos
- 1;
1086 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1090 /* restore the closest earlier saved state */
1091 if(min_pos
!= -1) lttv_state_restore(tcs
, closest_tree
);
1093 /* There is no saved state, yet we want to have it. Restart at T0 */
1095 restore_init_state(tcs
);
1096 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1099 /* We want to seek quickly without restoring/updating the state */
1101 restore_init_state(tcs
);
1102 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1109 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1115 traceset_state_finalize (LttvTracesetState
*self
)
1117 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1118 finalize(G_OBJECT(self
));
1123 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1125 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1127 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1128 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1129 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1130 klass
->new_traceset_context
= new_traceset_context
;
1131 klass
->new_trace_context
= new_trace_context
;
1132 klass
->new_tracefile_context
= new_tracefile_context
;
1137 lttv_traceset_state_get_type(void)
1139 static GType type
= 0;
1141 static const GTypeInfo info
= {
1142 sizeof (LttvTracesetStateClass
),
1143 NULL
, /* base_init */
1144 NULL
, /* base_finalize */
1145 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1146 NULL
, /* class_finalize */
1147 NULL
, /* class_data */
1148 sizeof (LttvTracesetContext
),
1149 0, /* n_preallocs */
1150 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1153 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1161 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1167 trace_state_finalize (LttvTraceState
*self
)
1169 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1170 finalize(G_OBJECT(self
));
1175 trace_state_class_init (LttvTraceStateClass
*klass
)
1177 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1179 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1180 klass
->state_save
= state_save
;
1181 klass
->state_restore
= state_restore
;
1182 klass
->state_saved_free
= state_saved_free
;
1187 lttv_trace_state_get_type(void)
1189 static GType type
= 0;
1191 static const GTypeInfo info
= {
1192 sizeof (LttvTraceStateClass
),
1193 NULL
, /* base_init */
1194 NULL
, /* base_finalize */
1195 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1196 NULL
, /* class_finalize */
1197 NULL
, /* class_data */
1198 sizeof (LttvTraceState
),
1199 0, /* n_preallocs */
1200 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1203 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1204 "LttvTraceStateType", &info
, 0);
1211 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1217 tracefile_state_finalize (LttvTracefileState
*self
)
1219 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1220 finalize(G_OBJECT(self
));
1225 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1227 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1229 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1234 lttv_tracefile_state_get_type(void)
1236 static GType type
= 0;
1238 static const GTypeInfo info
= {
1239 sizeof (LttvTracefileStateClass
),
1240 NULL
, /* base_init */
1241 NULL
, /* base_finalize */
1242 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1243 NULL
, /* class_finalize */
1244 NULL
, /* class_data */
1245 sizeof (LttvTracefileState
),
1246 0, /* n_preallocs */
1247 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1250 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1251 "LttvTracefileStateType", &info
, 0);
1257 void lttv_state_init(int argc
, char **argv
)
1259 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1260 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1261 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1262 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1263 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1264 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1265 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1266 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1267 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1268 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1269 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1270 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1271 LTTV_STATE_RUN
= g_quark_from_string("running");
1272 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1273 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1274 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1275 LTTV_STATE_EVENT
= g_quark_from_string("event");
1276 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1277 LTTV_STATE_TIME
= g_quark_from_string("time");
1278 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1281 void lttv_state_destroy()