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 static LttvProcessState
*create_process_from_trace(LttvTraceState
*ts
,
65 LttvProcessState
*parent
, guint pid
);
67 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
69 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
73 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
75 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
79 void lttv_state_saved_state_free(LttvTraceState
*self
,
80 LttvAttribute
*container
)
82 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
87 restore_init_state(LttvTraceState
*self
)
89 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
91 LttvTracefileState
*tfcs
;
93 LttTime null_time
= {0,0};
95 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
96 self
->processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
99 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
100 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
101 nb_tracefile
= nb_control
+ nb_per_cpu
;
102 for(i
= 0 ; i
< nb_tracefile
; i
++) {
104 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.control_tracefiles
[i
]);
107 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.per_cpu_tracefiles
[i
- nb_control
]);
110 tfcs
->parent
.timestamp
= null_time
;
111 tfcs
->saved_position
= 0;
112 tfcs
->process
= create_process(tfcs
, NULL
,0);
118 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
120 guint i
, j
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
122 LttvTraceContext
*tc
;
126 LttvTracefileState
*tfcs
;
128 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
129 init((LttvTracesetContext
*)self
, ts
);
131 nb_trace
= lttv_traceset_number(ts
);
132 for(i
= 0 ; i
< nb_trace
; i
++) {
133 tc
= self
->parent
.traces
[i
];
134 tcs
= (LttvTraceState
*)tc
;
135 tcs
->save_interval
= 100000;
136 tcs
->recompute_state_in_seek
= TRUE
;
137 tcs
->saved_state_ready
= FALSE
;
138 fill_name_tables(tcs
);
140 nb_control
= ltt_trace_control_tracefile_number(tc
->t
);
141 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(tc
->t
);
142 nb_tracefile
= nb_control
+ nb_per_cpu
;
143 for(j
= 0 ; j
< nb_tracefile
; j
++) {
145 tfcs
= LTTV_TRACEFILE_STATE(tc
->control_tracefiles
[j
]);
148 tfcs
= LTTV_TRACEFILE_STATE(tc
->per_cpu_tracefiles
[j
- nb_control
]);
150 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
152 tcs
->processes
= NULL
;
153 restore_init_state(tcs
);
159 fini(LttvTracesetState
*self
)
161 guint i
, j
, nb_trace
, nb_tracefile
;
165 LttvTracefileState
*tfcs
;
167 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
168 for(i
= 0 ; i
< nb_trace
; i
++) {
169 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
170 lttv_state_free_process_table(tcs
->processes
);
171 tcs
->processes
= NULL
;
172 free_name_tables(tcs
);
174 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
175 fini((LttvTracesetContext
*)self
);
179 static LttvTracesetContext
*
180 new_traceset_context(LttvTracesetContext
*self
)
182 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
186 static LttvTraceContext
*
187 new_trace_context(LttvTracesetContext
*self
)
189 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
193 static LttvTracefileContext
*
194 new_tracefile_context(LttvTracesetContext
*self
)
196 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
200 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
202 LttvProcessState
*process
, *new_process
;
204 GHashTable
*new_processes
= (GHashTable
*)user_data
;
208 process
= (LttvProcessState
*)value
;
209 new_process
= g_new(LttvProcessState
, 1);
210 *new_process
= *process
;
211 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
212 sizeof(LttvExecutionState
));
213 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
214 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
215 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
216 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
218 new_process
->state
= &g_array_index(new_process
->execution_stack
,
219 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
220 g_hash_table_insert(new_processes
, GUINT_TO_POINTER(new_process
->pid
),
225 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
227 GHashTable
*new_processes
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
229 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
230 return new_processes
;
234 /* The saved state for each trace contains a member "processes", which
235 stores a copy of the process table, and a member "tracefiles" with
236 one entry per tracefile. Each tracefile has a "process" member pointing
237 to the current process and a "position" member storing the tracefile
238 position (needed to seek to the current "next" event. */
240 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
242 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
244 LttvTracefileState
*tfcs
;
246 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
248 LttvAttributeType type
;
250 LttvAttributeValue value
;
252 LttvAttributeName name
;
254 LttEventPosition
*ep
;
256 tracefiles_tree
= lttv_attribute_find_subdir(container
,
257 LTTV_STATE_TRACEFILES
);
259 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
261 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
263 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
264 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
265 nb_tracefile
= nb_control
+ nb_per_cpu
;
267 for(i
= 0 ; i
< nb_tracefile
; i
++) {
269 tfcs
= (LttvTracefileState
*)self
->parent
.control_tracefiles
[i
];
270 else tfcs
= (LttvTracefileState
*)
271 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
273 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
274 value
= lttv_attribute_add(tracefiles_tree
, i
,
276 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
277 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
279 *(value
.v_uint
) = tfcs
->process
->pid
;
280 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
282 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
284 ep
= ltt_event_position_new();
285 ltt_event_position(tfcs
->parent
.e
, ep
);
286 *(value
.v_pointer
) = ep
;
292 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
294 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
296 LttvTracefileState
*tfcs
;
298 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
300 LttvAttributeType type
;
302 LttvAttributeValue value
;
304 LttvAttributeName name
;
306 LttEventPosition
*ep
;
308 tracefiles_tree
= lttv_attribute_find_subdir(container
,
309 LTTV_STATE_TRACEFILES
);
311 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
313 g_assert(type
== LTTV_POINTER
);
314 lttv_state_free_process_table(self
->processes
);
315 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
317 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
318 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
319 nb_tracefile
= nb_control
+ nb_per_cpu
;
321 for(i
= 0 ; i
< nb_tracefile
; i
++) {
322 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
323 self
->parent
.control_tracefiles
[i
];
324 else tfcs
= (LttvTracefileState
*)
325 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
327 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
328 g_assert(type
== LTTV_GOBJECT
);
329 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
331 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
333 g_assert(type
== LTTV_UINT
);
334 tfcs
->process
= lttv_state_find_process(tfcs
, *(value
.v_uint
));
335 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
337 g_assert(type
== LTTV_POINTER
);
338 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
340 ep
= *(value
.v_pointer
);
341 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
342 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
343 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
349 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
351 guint i
, nb_control
, nb_per_cpu
, nb_tracefile
;
353 LttvTracefileState
*tfcs
;
355 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
357 LttvAttributeType type
;
359 LttvAttributeValue value
;
361 LttvAttributeName name
;
363 LttEventPosition
*ep
;
365 tracefiles_tree
= lttv_attribute_find_subdir(container
,
366 LTTV_STATE_TRACEFILES
);
367 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
369 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
371 g_assert(type
== LTTV_POINTER
);
372 lttv_state_free_process_table(*(value
.v_pointer
));
373 *(value
.v_pointer
) = NULL
;
374 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
376 nb_control
= ltt_trace_control_tracefile_number(self
->parent
.t
);
377 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
378 nb_tracefile
= nb_control
+ nb_per_cpu
;
380 for(i
= 0 ; i
< nb_tracefile
; i
++) {
381 if(i
< nb_control
) tfcs
= (LttvTracefileState
*)
382 self
->parent
.control_tracefiles
[i
];
383 else tfcs
= (LttvTracefileState
*)
384 self
->parent
.per_cpu_tracefiles
[i
- nb_control
];
386 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
387 g_assert(type
== LTTV_GOBJECT
);
388 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
390 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
392 g_assert(type
== LTTV_POINTER
);
393 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
395 lttv_attribute_recursive_free(tracefiles_tree
);
400 fill_name_tables(LttvTraceState
*tcs
)
404 char *f_name
, *e_name
;
412 GString
*fe_name
= g_string_new("");
414 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
415 tcs
->eventtype_names
= g_new(GQuark
, nb
);
416 for(i
= 0 ; i
< nb
; i
++) {
417 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
418 e_name
= ltt_eventtype_name(et
);
419 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
420 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
421 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
424 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
425 "syscall_id", NULL
, NULL
, NULL
, &h
);
426 t
= ltt_field_type(h
.f1
);
427 nb
= ltt_type_element_number(t
);
429 /* CHECK syscalls should be an emun but currently are not!
430 tcs->syscall_names = g_new(GQuark, nb);
432 for(i = 0 ; i < nb ; i++) {
433 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
437 tcs
->syscall_names
= g_new(GQuark
, 256);
438 for(i
= 0 ; i
< 256 ; i
++) {
439 g_string_printf(fe_name
, "syscall %d", i
);
440 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
443 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
444 "trap_id", NULL
, NULL
, NULL
, &h
);
445 t
= ltt_field_type(h
.f1
);
446 nb
= ltt_type_element_number(t
);
449 tcs->trap_names = g_new(GQuark, nb);
450 for(i = 0 ; i < nb ; i++) {
451 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
455 tcs
->trap_names
= g_new(GQuark
, 256);
456 for(i
= 0 ; i
< 256 ; i
++) {
457 g_string_printf(fe_name
, "trap %d", i
);
458 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
461 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
462 "irq_id", NULL
, NULL
, NULL
, &h
);
463 t
= ltt_field_type(h
.f1
);
464 nb
= ltt_type_element_number(t
);
467 tcs->irq_names = g_new(GQuark, nb);
468 for(i = 0 ; i < nb ; i++) {
469 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
473 tcs
->irq_names
= g_new(GQuark
, 256);
474 for(i
= 0 ; i
< 256 ; i
++) {
475 g_string_printf(fe_name
, "irq %d", i
);
476 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
479 g_string_free(fe_name
, TRUE
);
484 free_name_tables(LttvTraceState
*tcs
)
486 g_free(tcs
->eventtype_names
);
487 g_free(tcs
->syscall_names
);
488 g_free(tcs
->trap_names
);
489 g_free(tcs
->irq_names
);
493 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
496 LttvExecutionState
*es
;
498 LttvProcessState
*process
= tfs
->process
;
500 guint depth
= process
->execution_stack
->len
;
502 g_array_set_size(process
->execution_stack
, depth
+ 1);
503 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
506 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
507 es
->s
= process
->state
->s
;
512 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
514 LttvProcessState
*process
= tfs
->process
;
516 guint depth
= process
->execution_stack
->len
- 1;
518 if(process
->state
->t
!= t
){
519 g_warning("Different execution mode type (%d.%09d): ignore it\n",
520 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
521 g_warning("process state has %s when pop_int is %s\n",
522 g_quark_to_string(process
->state
->t
),
523 g_quark_to_string(t
));
524 g_warning("{ %u, %u, %s, %s }\n",
527 g_quark_to_string(process
->name
),
528 g_quark_to_string(process
->state
->s
));
533 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
534 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
538 g_array_remove_index(process
->execution_stack
, depth
);
540 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
542 process
->state
->change
= tfs
->parent
.timestamp
;
546 static LttvProcessState
*create_process(LttvTracefileState
*tfs
,
547 LttvProcessState
*parent
, guint pid
)
549 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
551 LttvExecutionState
*es
;
553 LttvTraceContext
*tc
;
559 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
561 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
565 process
->ppid
= parent
->pid
;
566 process
->name
= parent
->name
;
570 process
->name
= LTTV_STATE_UNNAMED
;
573 process
->creation_time
= tfs
->parent
.timestamp
;
574 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
575 process
->creation_time
.tv_nsec
);
576 process
->pid_time
= g_quark_from_string(buffer
);
577 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
578 sizeof(LttvExecutionState
));
579 g_array_set_size(process
->execution_stack
, 1);
580 es
= process
->state
= &g_array_index(process
->execution_stack
,
581 LttvExecutionState
, 0);
582 es
->t
= LTTV_STATE_USER_MODE
;
583 es
->n
= LTTV_STATE_SUBMODE_NONE
;
584 es
->entry
= tfs
->parent
.timestamp
;
585 es
->change
= tfs
->parent
.timestamp
;
586 es
->s
= LTTV_STATE_WAIT_FORK
;
591 static LttvProcessState
*create_process_from_trace(LttvTraceState
*tcs
,
592 LttvProcessState
*parent
, guint pid
)
594 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
596 LttvExecutionState
*es
;
598 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
602 g_hash_table_insert(tcs
->processes
, GUINT_TO_POINTER(pid
), process
);
606 process
->ppid
= parent
->pid
;
607 process
->name
= parent
->name
;
611 process
->name
= LTTV_STATE_UNNAMED
;
614 //FIXME timestamp should come from trace
615 process
->creation_time
.tv_sec
= 0;
616 process
->creation_time
.tv_nsec
= 0;
617 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
618 process
->creation_time
.tv_nsec
);
619 process
->pid_time
= g_quark_from_string(buffer
);
620 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
621 sizeof(LttvExecutionState
));
622 g_array_set_size(process
->execution_stack
, 1);
623 es
= process
->state
= &g_array_index(process
->execution_stack
,
624 LttvExecutionState
, 0);
625 es
->t
= LTTV_STATE_USER_MODE
;
626 es
->n
= LTTV_STATE_SUBMODE_NONE
;
627 //FIXME es->entry = tfs->parent.timestamp;
628 es
->entry
.tv_sec
= 0;
629 es
->entry
.tv_nsec
= 0;
630 //FIXME es->change = tfs->parent.timestamp;
631 es
->change
.tv_sec
= 0;
632 es
->change
.tv_nsec
= 0;
633 es
->s
= LTTV_STATE_WAIT_FORK
;
640 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
643 LttvTraceState
*ts
=(LttvTraceState
*)LTTV_TRACEFILE_CONTEXT(tfs
)->t_context
;
644 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
645 GUINT_TO_POINTER(pid
));
646 if(process
== NULL
) process
= create_process(tfs
, NULL
, pid
);
650 LttvProcessState
*lttv_state_find_process_from_trace(LttvTraceState
*ts
,
653 LttvProcessState
*process
= g_hash_table_lookup(ts
->processes
,
654 GUINT_TO_POINTER(pid
));
656 if(process
== NULL
) process
= create_process_from_trace(ts
, NULL
, pid
);
662 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
664 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
666 g_hash_table_remove(ts
->processes
, GUINT_TO_POINTER(process
->pid
));
667 g_array_free(process
->execution_stack
, TRUE
);
672 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
674 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
679 static void lttv_state_free_process_table(GHashTable
*processes
)
681 g_hash_table_foreach(processes
, free_process_state
, NULL
);
682 g_hash_table_destroy(processes
);
686 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
688 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
690 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
692 LttvExecutionSubmode submode
;
694 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
695 ltt_event_get_unsigned(s
->parent
.e
, f
)];
696 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
701 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
703 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
705 pop_state(s
, LTTV_STATE_SYSCALL
);
710 static gboolean
trap_entry(void *hook_data
, void *call_data
)
712 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
714 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
716 LttvExecutionSubmode submode
;
718 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
719 ltt_event_get_unsigned(s
->parent
.e
, f
)];
720 push_state(s
, LTTV_STATE_TRAP
, submode
);
725 static gboolean
trap_exit(void *hook_data
, void *call_data
)
727 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
729 pop_state(s
, LTTV_STATE_TRAP
);
734 static gboolean
irq_entry(void *hook_data
, void *call_data
)
736 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
738 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
740 LttvExecutionSubmode submode
;
742 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
743 ltt_event_get_unsigned(s
->parent
.e
, f
)];
745 /* Do something with the info about being in user or system mode when int? */
746 push_state(s
, LTTV_STATE_IRQ
, submode
);
751 static gboolean
irq_exit(void *hook_data
, void *call_data
)
753 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
755 pop_state(s
, LTTV_STATE_IRQ
);
760 static gboolean
schedchange(void *hook_data
, void *call_data
)
762 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
766 guint pid_in
, pid_out
, state_out
;
768 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
769 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
770 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
772 if(s
->process
!= NULL
) {
774 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
775 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
776 exit_process(s
, s
->process
);
777 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
779 if(s
->process
->pid
== 0)
780 s
->process
->pid
= pid_out
;
782 s
->process
->state
->change
= s
->parent
.timestamp
;
784 s
->process
= lttv_state_find_process(s
, pid_in
);
785 s
->process
->state
->s
= LTTV_STATE_RUN
;
786 s
->process
->state
->change
= s
->parent
.timestamp
;
791 static gboolean
process_fork(void *hook_data
, void *call_data
)
793 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
795 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
799 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
800 create_process(s
, s
->process
, child_pid
);
805 static gboolean
process_exit(void *hook_data
, void *call_data
)
807 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
809 if(s
->process
!= NULL
) {
810 s
->process
->state
->s
= LTTV_STATE_EXIT
;
816 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
818 LttvTraceset
*traceset
= self
->parent
.ts
;
820 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
824 LttvTracefileState
*tfs
;
830 LttvAttributeValue val
;
832 nb_trace
= lttv_traceset_number(traceset
);
833 for(i
= 0 ; i
< nb_trace
; i
++) {
834 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
836 /* Find the eventtype id for the following events and register the
837 associated by id hooks. */
839 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
840 g_array_set_size(hooks
, 9);
842 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
843 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
845 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
846 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
848 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
849 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
851 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
852 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
854 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
855 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
857 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
858 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
860 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
861 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
863 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
864 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
866 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
867 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
869 /* Add these hooks to each before_event_by_id hooks list */
871 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
872 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
873 nb_tracefile
= nb_control
+ nb_per_cpu
;
874 for(j
= 0 ; j
< nb_tracefile
; j
++) {
876 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
879 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
882 for(k
= 0 ; k
< hooks
->len
; k
++) {
883 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
884 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
885 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
888 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
889 *(val
.v_pointer
) = hooks
;
894 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
896 LttvTraceset
*traceset
= self
->parent
.ts
;
898 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
902 LttvTracefileState
*tfs
;
908 LttvAttributeValue val
;
910 nb_trace
= lttv_traceset_number(traceset
);
911 for(i
= 0 ; i
< nb_trace
; i
++) {
912 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
913 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
914 hooks
= *(val
.v_pointer
);
916 /* Add these hooks to each before_event_by_id hooks list */
918 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
919 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
920 nb_tracefile
= nb_control
+ nb_per_cpu
;
921 for(j
= 0 ; j
< nb_tracefile
; j
++) {
923 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
926 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
929 for(k
= 0 ; k
< hooks
->len
; k
++) {
930 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
931 lttv_hooks_remove_data(
932 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
933 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
936 g_array_free(hooks
, TRUE
);
941 static gboolean
block_end(void *hook_data
, void *call_data
)
943 LttvTracefileState
*tfcs
= (LttvTracefileState
*)call_data
;
945 LttvTraceState
*tcs
= (LttvTraceState
*)(tfcs
->parent
.t_context
);
947 LttEventPosition
*ep
= ltt_event_position_new();
949 guint nb_block
, nb_event
;
953 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
955 LttvAttributeValue value
;
957 ltt_event_position(tfcs
->parent
.e
, ep
);
959 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
960 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
961 tfcs
->saved_position
= 0;
962 if(tcs
->nb_event
>= tcs
->save_interval
) {
963 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
964 LTTV_STATE_SAVED_STATES
);
965 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
966 value
= lttv_attribute_add(saved_states_tree
,
967 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
968 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
969 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
970 *(value
.v_time
) = tfcs
->parent
.timestamp
;
971 lttv_state_save(tcs
, saved_state_tree
);
978 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
980 LttvTraceset
*traceset
= self
->parent
.ts
;
982 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
986 LttvTracefileState
*tfs
;
990 nb_trace
= lttv_traceset_number(traceset
);
991 for(i
= 0 ; i
< nb_trace
; i
++) {
992 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
993 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
994 NULL
, NULL
, block_end
, &hook
);
996 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
997 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
998 nb_tracefile
= nb_control
+ nb_per_cpu
;
999 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1000 if(j
< nb_control
) {
1001 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
1004 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
1007 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
1008 hook
.id
), hook
.h
, NULL
);
1014 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1016 LttvTraceset
*traceset
= self
->parent
.ts
;
1018 guint i
, j
, k
, nb_trace
, nb_control
, nb_per_cpu
, nb_tracefile
;
1022 LttvTracefileState
*tfs
;
1026 nb_trace
= lttv_traceset_number(traceset
);
1027 for(i
= 0 ; i
< nb_trace
; i
++) {
1028 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1029 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1030 NULL
, NULL
, block_end
, &hook
);
1032 nb_control
= ltt_trace_control_tracefile_number(ts
->parent
.t
);
1033 nb_per_cpu
= ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1034 nb_tracefile
= nb_control
+ nb_per_cpu
;
1035 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1036 if(j
< nb_control
) {
1037 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.control_tracefiles
[j
]);
1040 tfs
=LTTV_TRACEFILE_STATE(ts
->parent
.per_cpu_tracefiles
[j
-nb_control
]);
1043 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1044 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
1050 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1052 LttvTraceset
*traceset
= self
->parent
.ts
;
1054 guint i
, j
, nb_trace
, nb_saved_state
;
1056 int min_pos
, mid_pos
, max_pos
;
1058 LttvTraceState
*tcs
;
1060 LttvAttributeValue value
;
1062 LttvAttributeType type
;
1064 LttvAttributeName name
;
1066 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1068 nb_trace
= lttv_traceset_number(traceset
);
1069 for(i
= 0 ; i
< nb_trace
; i
++) {
1070 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1072 if(tcs
->recompute_state_in_seek
) {
1073 if(tcs
->saved_state_available
) {
1074 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1075 LTTV_STATE_SAVED_STATES
);
1077 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1078 mid_pos
= max_pos
/ 2;
1079 while(min_pos
< max_pos
) {
1080 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1081 g_assert(type
== LTTV_GOBJECT
);
1082 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1083 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1085 g_assert(type
== LTTV_TIME
);
1086 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1088 closest_tree
= saved_state_tree
;
1090 else max_pos
= mid_pos
- 1;
1092 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1095 /* restore the closest earlier saved state */
1096 if(min_pos
!= -1) lttv_state_restore(tcs
, closest_tree
);
1099 /* There is no saved state yet we want to have it. Restart at T0 */
1101 restore_init_state(tcs
);
1102 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1105 /* We want to seek quickly without restoring/updating the state */
1107 restore_init_state(tcs
);
1108 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1115 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1121 traceset_state_finalize (LttvTracesetState
*self
)
1123 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1124 finalize(G_OBJECT(self
));
1129 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1131 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1133 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1134 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1135 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1136 klass
->new_traceset_context
= new_traceset_context
;
1137 klass
->new_trace_context
= new_trace_context
;
1138 klass
->new_tracefile_context
= new_tracefile_context
;
1143 lttv_traceset_state_get_type(void)
1145 static GType type
= 0;
1147 static const GTypeInfo info
= {
1148 sizeof (LttvTracesetStateClass
),
1149 NULL
, /* base_init */
1150 NULL
, /* base_finalize */
1151 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1152 NULL
, /* class_finalize */
1153 NULL
, /* class_data */
1154 sizeof (LttvTracesetContext
),
1155 0, /* n_preallocs */
1156 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1159 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1167 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1173 trace_state_finalize (LttvTraceState
*self
)
1175 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1176 finalize(G_OBJECT(self
));
1181 trace_state_class_init (LttvTraceStateClass
*klass
)
1183 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1185 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1186 klass
->state_save
= state_save
;
1187 klass
->state_restore
= state_restore
;
1188 klass
->state_saved_free
= state_saved_free
;
1193 lttv_trace_state_get_type(void)
1195 static GType type
= 0;
1197 static const GTypeInfo info
= {
1198 sizeof (LttvTraceStateClass
),
1199 NULL
, /* base_init */
1200 NULL
, /* base_finalize */
1201 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1202 NULL
, /* class_finalize */
1203 NULL
, /* class_data */
1204 sizeof (LttvTraceState
),
1205 0, /* n_preallocs */
1206 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1209 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1210 "LttvTraceStateType", &info
, 0);
1217 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1223 tracefile_state_finalize (LttvTracefileState
*self
)
1225 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1226 finalize(G_OBJECT(self
));
1231 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1233 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1235 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1240 lttv_tracefile_state_get_type(void)
1242 static GType type
= 0;
1244 static const GTypeInfo info
= {
1245 sizeof (LttvTracefileStateClass
),
1246 NULL
, /* base_init */
1247 NULL
, /* base_finalize */
1248 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1249 NULL
, /* class_finalize */
1250 NULL
, /* class_data */
1251 sizeof (LttvTracefileState
),
1252 0, /* n_preallocs */
1253 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1256 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1257 "LttvTracefileStateType", &info
, 0);
1263 void lttv_state_init(int argc
, char **argv
)
1265 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1266 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1267 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1268 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1269 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1270 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1271 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1272 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1273 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1274 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1275 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1276 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1277 LTTV_STATE_RUN
= g_quark_from_string("running");
1278 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1279 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1280 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1281 LTTV_STATE_EVENT
= g_quark_from_string("event");
1282 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1283 LTTV_STATE_TIME
= g_quark_from_string("time");
1284 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1287 void lttv_state_destroy()