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/lttv.h>
21 #include <lttv/module.h>
22 #include <lttv/state.h>
23 #include <ltt/facility.h>
24 #include <ltt/trace.h>
25 #include <ltt/event.h>
30 LTTV_STATE_MODE_UNKNOWN
,
37 LTTV_STATE_SUBMODE_UNKNOWN
,
38 LTTV_STATE_SUBMODE_NONE
;
49 LTTV_STATE_TRACEFILES
,
53 LTTV_STATE_SAVED_STATES
,
54 LTTV_STATE_SAVED_STATES_TIME
,
57 LTTV_STATE_NAME_TABLES
,
58 LTTV_STATE_TRACE_STATE_USE_COUNT
;
61 static void create_max_time(LttvTraceState
*tcs
);
63 static void get_max_time(LttvTraceState
*tcs
);
65 static void free_max_time(LttvTraceState
*tcs
);
67 static void create_name_tables(LttvTraceState
*tcs
);
69 static void get_name_tables(LttvTraceState
*tcs
);
71 static void free_name_tables(LttvTraceState
*tcs
);
73 static void free_saved_state(LttvTraceState
*tcs
);
75 static void lttv_state_free_process_table(GHashTable
*processes
);
78 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
80 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
84 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
86 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
90 void lttv_state_state_saved_free(LttvTraceState
*self
,
91 LttvAttribute
*container
)
93 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
97 guint
process_hash(gconstpointer key
)
99 return ((LttvProcessState
*)key
)->pid
;
103 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
105 LttvProcessState
*process_a
, *process_b
;
107 process_a
= (LttvProcessState
*)a
;
108 process_b
= (LttvProcessState
*)b
;
110 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
111 if(process_a
->pid
== 0 &&
112 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
118 restore_init_state(LttvTraceState
*self
)
120 guint i
, nb_tracefile
;
122 LttvTracefileState
*tfcs
;
124 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
125 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
128 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
129 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
131 for(i
= 0 ; i
< nb_tracefile
; i
++) {
132 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
133 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
134 tfcs
->saved_position
= 0;
135 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
136 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
137 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
141 static LttTime time_zero
= {0,0};
144 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
146 guint i
, j
, nb_trace
, nb_tracefile
;
148 LttvTraceContext
*tc
;
152 LttvTracefileState
*tfcs
;
154 LttvAttributeValue v
;
156 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
157 init((LttvTracesetContext
*)self
, ts
);
159 nb_trace
= lttv_traceset_number(ts
);
160 for(i
= 0 ; i
< nb_trace
; i
++) {
161 tc
= self
->parent
.traces
[i
];
162 tcs
= (LttvTraceState
*)tc
;
163 tcs
->save_interval
= 50000;
164 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
168 if(*(v
.v_uint
) == 1) {
169 create_name_tables(tcs
);
170 create_max_time(tcs
);
172 get_name_tables(tcs
);
175 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
176 ltt_trace_per_cpu_tracefile_number(tc
->t
);
178 for(j
= 0 ; j
< nb_tracefile
; j
++) {
179 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
180 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
182 tcs
->processes
= NULL
;
183 restore_init_state(tcs
);
189 fini(LttvTracesetState
*self
)
191 guint i
, j
, nb_trace
;
195 LttvTracefileState
*tfcs
;
197 LttvAttributeValue v
;
199 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
200 for(i
= 0 ; i
< nb_trace
; i
++) {
201 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
202 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
206 g_assert(*(v
.v_uint
) >= 0);
207 if(*(v
.v_uint
) == 0) {
208 free_name_tables(tcs
);
210 free_saved_state(tcs
);
212 lttv_state_free_process_table(tcs
->processes
);
213 tcs
->processes
= NULL
;
215 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
216 fini((LttvTracesetContext
*)self
);
220 static LttvTracesetContext
*
221 new_traceset_context(LttvTracesetContext
*self
)
223 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
227 static LttvTraceContext
*
228 new_trace_context(LttvTracesetContext
*self
)
230 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
234 static LttvTracefileContext
*
235 new_tracefile_context(LttvTracesetContext
*self
)
237 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
241 /* Write the process state of the trace */
243 static void write_process_state(gpointer key
, gpointer value
,
246 LttvProcessState
*process
;
248 LttvExecutionState
*es
;
250 FILE *fp
= (FILE *)user_data
;
254 process
= (LttvProcessState
*)value
;
256 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
257 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
258 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
259 g_quark_to_string(process
->last_cpu
));
261 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
262 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
263 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
264 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
265 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
266 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
267 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
269 fprintf(fp
, " </PROCESS>\n");
273 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
275 guint i
, nb_tracefile
, nb_block
, nb_event
;
277 LttvTracefileState
*tfcs
;
281 LttEventPosition
*ep
;
283 ep
= ltt_event_position_new();
285 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
287 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
289 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
290 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
292 for(i
= 0 ; i
< nb_tracefile
; i
++) {
293 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
294 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
295 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
296 tfcs
->parent
.timestamp
.tv_nsec
);
297 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
299 ltt_event_position(tfcs
->parent
.e
, ep
);
300 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
301 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
305 fprintf(fp
,"</PROCESS_STATE>");
309 /* Copy each process from an existing hash table to a new one */
311 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
313 LttvProcessState
*process
, *new_process
;
315 GHashTable
*new_processes
= (GHashTable
*)user_data
;
319 process
= (LttvProcessState
*)value
;
320 new_process
= g_new(LttvProcessState
, 1);
321 *new_process
= *process
;
322 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
323 sizeof(LttvExecutionState
));
324 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
325 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
326 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
327 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
329 new_process
->state
= &g_array_index(new_process
->execution_stack
,
330 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
331 g_hash_table_insert(new_processes
, new_process
, new_process
);
335 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
337 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
339 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
340 return new_processes
;
344 /* The saved state for each trace contains a member "processes", which
345 stores a copy of the process table, and a member "tracefiles" with
346 one entry per tracefile. Each tracefile has a "process" member pointing
347 to the current process and a "position" member storing the tracefile
348 position (needed to seek to the current "next" event. */
350 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
352 guint i
, nb_tracefile
;
354 LttvTracefileState
*tfcs
;
356 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
358 LttvAttributeType type
;
360 LttvAttributeValue value
;
362 LttvAttributeName name
;
364 LttEventPosition
*ep
;
366 tracefiles_tree
= lttv_attribute_find_subdir(container
,
367 LTTV_STATE_TRACEFILES
);
369 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
371 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
373 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
374 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
376 for(i
= 0 ; i
< nb_tracefile
; i
++) {
377 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
378 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
379 value
= lttv_attribute_add(tracefiles_tree
, i
,
381 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
382 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
384 *(value
.v_uint
) = tfcs
->process
->pid
;
385 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
387 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
389 ep
= ltt_event_position_new();
390 ltt_event_position(tfcs
->parent
.e
, ep
);
391 *(value
.v_pointer
) = ep
;
393 guint nb_block
, nb_event
;
395 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
396 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
397 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
403 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
405 guint i
, nb_tracefile
, pid
;
407 LttvTracefileState
*tfcs
;
409 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
411 LttvAttributeType type
;
413 LttvAttributeValue value
;
415 LttvAttributeName name
;
417 LttEventPosition
*ep
;
419 tracefiles_tree
= lttv_attribute_find_subdir(container
,
420 LTTV_STATE_TRACEFILES
);
422 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
424 g_assert(type
== LTTV_POINTER
);
425 lttv_state_free_process_table(self
->processes
);
426 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
428 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
429 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
431 for(i
= 0 ; i
< nb_tracefile
; i
++) {
432 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
433 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
434 g_assert(type
== LTTV_GOBJECT
);
435 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
437 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
439 g_assert(type
== LTTV_UINT
);
440 pid
= *(value
.v_uint
);
441 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
443 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
445 g_assert(type
== LTTV_POINTER
);
446 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
448 ep
= *(value
.v_pointer
);
449 g_assert(tfcs
->parent
.t_context
!= NULL
);
450 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
456 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
458 guint i
, nb_tracefile
;
460 LttvTracefileState
*tfcs
;
462 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
464 LttvAttributeType type
;
466 LttvAttributeValue value
;
468 LttvAttributeName name
;
470 LttEventPosition
*ep
;
472 tracefiles_tree
= lttv_attribute_find_subdir(container
,
473 LTTV_STATE_TRACEFILES
);
474 g_object_ref(G_OBJECT(tracefiles_tree
));
475 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
477 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
479 g_assert(type
== LTTV_POINTER
);
480 lttv_state_free_process_table(*(value
.v_pointer
));
481 *(value
.v_pointer
) = NULL
;
482 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
484 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
485 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
487 for(i
= 0 ; i
< nb_tracefile
; i
++) {
488 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
489 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
490 g_assert(type
== LTTV_GOBJECT
);
491 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
493 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
495 g_assert(type
== LTTV_POINTER
);
496 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
498 g_object_unref(G_OBJECT(tracefiles_tree
));
502 static void free_saved_state(LttvTraceState
*self
)
506 LttvAttributeType type
;
508 LttvAttributeValue value
;
510 LttvAttributeName name
;
512 LttvAttribute
*saved_states
;
514 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
515 LTTV_STATE_SAVED_STATES
);
517 nb
= lttv_attribute_get_number(saved_states
);
518 for(i
= 0 ; i
< nb
; i
++) {
519 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
520 g_assert(type
== LTTV_GOBJECT
);
521 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
524 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
529 create_max_time(LttvTraceState
*tcs
)
531 LttvAttributeValue v
;
533 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
535 g_assert(*(v
.v_pointer
) == NULL
);
536 *(v
.v_pointer
) = g_new(LttTime
,1);
537 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
542 get_max_time(LttvTraceState
*tcs
)
544 LttvAttributeValue v
;
546 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
548 g_assert(*(v
.v_pointer
) != NULL
);
549 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
554 free_max_time(LttvTraceState
*tcs
)
556 LttvAttributeValue v
;
558 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
560 g_free(*(v
.v_pointer
));
561 *(v
.v_pointer
) = NULL
;
565 typedef struct _LttvNameTables
{
566 GQuark
*eventtype_names
;
567 GQuark
*syscall_names
;
574 create_name_tables(LttvTraceState
*tcs
)
578 char *f_name
, *e_name
;
586 GString
*fe_name
= g_string_new("");
588 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
590 LttvAttributeValue v
;
592 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
594 g_assert(*(v
.v_pointer
) == NULL
);
595 *(v
.v_pointer
) = name_tables
;
597 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
598 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
599 for(i
= 0 ; i
< nb
; i
++) {
600 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
601 e_name
= ltt_eventtype_name(et
);
602 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
603 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
604 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
607 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
608 "syscall_id", NULL
, NULL
, NULL
, &h
);
609 t
= ltt_field_type(h
.f1
);
610 nb
= ltt_type_element_number(t
);
612 /* CHECK syscalls should be an emun but currently are not!
613 name_tables->syscall_names = g_new(GQuark, nb);
615 for(i = 0 ; i < nb ; i++) {
616 name_tables->syscall_names[i] = g_quark_from_string(
617 ltt_enum_string_get(t, i));
621 name_tables
->syscall_names
= g_new(GQuark
, 256);
622 for(i
= 0 ; i
< 256 ; i
++) {
623 g_string_printf(fe_name
, "syscall %d", i
);
624 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
627 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
628 "trap_id", NULL
, NULL
, NULL
, &h
);
629 t
= ltt_field_type(h
.f1
);
630 nb
= ltt_type_element_number(t
);
633 name_tables->trap_names = g_new(GQuark, nb);
634 for(i = 0 ; i < nb ; i++) {
635 name_tables->trap_names[i] = g_quark_from_string(
636 ltt_enum_string_get(t, i));
640 name_tables
->trap_names
= g_new(GQuark
, 256);
641 for(i
= 0 ; i
< 256 ; i
++) {
642 g_string_printf(fe_name
, "trap %d", i
);
643 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
646 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
647 "irq_id", NULL
, NULL
, NULL
, &h
);
648 t
= ltt_field_type(h
.f1
);
649 nb
= ltt_type_element_number(t
);
652 name_tables->irq_names = g_new(GQuark, nb);
653 for(i = 0 ; i < nb ; i++) {
654 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
658 name_tables
->irq_names
= g_new(GQuark
, 256);
659 for(i
= 0 ; i
< 256 ; i
++) {
660 g_string_printf(fe_name
, "irq %d", i
);
661 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
664 g_string_free(fe_name
, TRUE
);
669 get_name_tables(LttvTraceState
*tcs
)
671 LttvNameTables
*name_tables
;
673 LttvAttributeValue v
;
675 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
677 g_assert(*(v
.v_pointer
) != NULL
);
678 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
679 tcs
->eventtype_names
= name_tables
->eventtype_names
;
680 tcs
->syscall_names
= name_tables
->syscall_names
;
681 tcs
->trap_names
= name_tables
->trap_names
;
682 tcs
->irq_names
= name_tables
->irq_names
;
687 free_name_tables(LttvTraceState
*tcs
)
689 LttvNameTables
*name_tables
;
691 LttvAttributeValue v
;
693 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
695 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
696 *(v
.v_pointer
) = NULL
;
698 g_free(name_tables
->eventtype_names
);
699 g_free(name_tables
->syscall_names
);
700 g_free(name_tables
->trap_names
);
701 g_free(name_tables
->irq_names
);
706 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
709 LttvExecutionState
*es
;
711 LttvProcessState
*process
= tfs
->process
;
713 guint depth
= process
->execution_stack
->len
;
715 g_array_set_size(process
->execution_stack
, depth
+ 1);
716 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
719 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
720 es
->s
= process
->state
->s
;
725 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
727 LttvProcessState
*process
= tfs
->process
;
729 guint depth
= process
->execution_stack
->len
;
731 if(process
->state
->t
!= t
){
732 g_info("Different execution mode type (%d.%09d): ignore it\n",
733 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
734 g_info("process state has %s when pop_int is %s\n",
735 g_quark_to_string(process
->state
->t
),
736 g_quark_to_string(t
));
737 g_info("{ %u, %u, %s, %s }\n",
740 g_quark_to_string(process
->name
),
741 g_quark_to_string(process
->state
->s
));
746 g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
747 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
751 g_array_set_size(process
->execution_stack
, depth
- 1);
752 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
754 process
->state
->change
= tfs
->parent
.timestamp
;
759 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
762 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
764 LttvExecutionState
*es
;
766 LttvTraceContext
*tc
;
772 tc
= tfs
->parent
.t_context
;
773 tcs
= (LttvTraceState
*)tc
;
776 process
->last_cpu
= tfs
->cpu_name
;
777 g_warning("Process %u, core %p", process
->pid
, process
);
778 g_hash_table_insert(tcs
->processes
, process
, process
);
781 process
->ppid
= parent
->pid
;
782 process
->name
= parent
->name
;
783 process
->creation_time
= tfs
->parent
.timestamp
;
786 /* No parent. This process exists but we are missing all information about
787 its creation. The birth time is set to zero but we remember the time of
792 process
->name
= LTTV_STATE_UNNAMED
;
793 process
->creation_time
= ltt_time_zero
;
796 process
->insertion_time
= tfs
->parent
.timestamp
;
797 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
798 process
->creation_time
.tv_nsec
);
799 process
->pid_time
= g_quark_from_string(buffer
);
800 process
->last_cpu
= tfs
->cpu_name
;
801 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
802 sizeof(LttvExecutionState
));
803 g_array_set_size(process
->execution_stack
, 1);
804 es
= process
->state
= &g_array_index(process
->execution_stack
,
805 LttvExecutionState
, 0);
806 es
->t
= LTTV_STATE_USER_MODE
;
807 es
->n
= LTTV_STATE_SUBMODE_NONE
;
808 es
->entry
= tfs
->parent
.timestamp
;
809 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
810 es
->change
= tfs
->parent
.timestamp
;
811 es
->s
= LTTV_STATE_WAIT_FORK
;
817 lttv_state_find_process_from_trace(LttvTraceState
*ts
, GQuark cpu
, guint pid
)
819 LttvProcessState key
;
820 LttvProcessState
*process
;
824 process
= g_hash_table_lookup(ts
->processes
, &key
);
829 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
832 LttvTraceState
*ts
=(LttvTraceState
*)tfs
->parent
.t_context
;
833 return lttv_state_find_process_from_trace(ts
, tfs
->cpu_name
, pid
);
838 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
840 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
842 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
847 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
849 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
850 LttvProcessState key
;
852 key
.pid
= process
->pid
;
853 key
.last_cpu
= process
->last_cpu
;
854 g_hash_table_remove(ts
->processes
, &key
);
855 g_array_free(process
->execution_stack
, TRUE
);
860 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
862 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
867 static void lttv_state_free_process_table(GHashTable
*processes
)
869 g_hash_table_foreach(processes
, free_process_state
, NULL
);
870 g_hash_table_destroy(processes
);
874 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
876 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
878 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
880 LttvExecutionSubmode submode
;
882 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
883 ltt_event_get_unsigned(s
->parent
.e
, f
)];
884 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
889 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
891 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
893 pop_state(s
, LTTV_STATE_SYSCALL
);
898 static gboolean
trap_entry(void *hook_data
, void *call_data
)
900 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
902 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
904 LttvExecutionSubmode submode
;
906 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
907 ltt_event_get_unsigned(s
->parent
.e
, f
)];
908 push_state(s
, LTTV_STATE_TRAP
, submode
);
913 static gboolean
trap_exit(void *hook_data
, void *call_data
)
915 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
917 pop_state(s
, LTTV_STATE_TRAP
);
922 static gboolean
irq_entry(void *hook_data
, void *call_data
)
924 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
926 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
928 LttvExecutionSubmode submode
;
930 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
931 ltt_event_get_unsigned(s
->parent
.e
, f
)];
933 /* Do something with the info about being in user or system mode when int? */
934 push_state(s
, LTTV_STATE_IRQ
, submode
);
939 static gboolean
irq_exit(void *hook_data
, void *call_data
)
941 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
943 pop_state(s
, LTTV_STATE_IRQ
);
948 static gboolean
schedchange(void *hook_data
, void *call_data
)
950 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
952 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
954 guint pid_in
, pid_out
, state_out
;
956 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
957 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
958 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
960 if(s
->process
!= NULL
) {
962 /* We could not know but it was not the idle process executing.
963 This should only happen at the beginning, before the first schedule
964 event, and when the initial information (current process for each CPU)
965 is missing. It is not obvious how we could, after the fact, compensate
966 the wrongly attributed statistics. */
968 if(s
->process
->pid
!= pid_out
) {
969 g_assert(s
->process
->pid
== 0);
972 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
973 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
974 exit_process(s
, s
->process
);
975 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
977 s
->process
->state
->change
= s
->parent
.timestamp
;
979 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
980 s
->process
->state
->s
= LTTV_STATE_RUN
;
981 s
->process
->last_cpu
= s
->cpu_name
;
982 s
->process
->state
->change
= s
->parent
.timestamp
;
987 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
994 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
996 lttv_state_create_process(s
, s
->process
, child_pid
);
1000 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
1002 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1006 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1007 lttv_state_create_process(s
, s
->process
, child_pid
);
1013 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1015 if(s
->process
!= NULL
) {
1016 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1021 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1023 if(s
->process
!= NULL
) {
1024 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1030 gboolean
process(void *hook_data
, void *call_data
)
1032 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1033 LttField
*f
= trace_hook
->f1
;
1035 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1037 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1039 /* CHECK : do not hardcode the sub_id values here ? */
1041 return process_fork(trace_hook
, s
);
1042 } else if(sub_id
== 3) {
1043 return process_exit(trace_hook
, s
);
1049 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1051 LttvTraceset
*traceset
= self
->parent
.ts
;
1053 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1057 LttvTracefileState
*tfs
;
1063 LttvAttributeValue val
;
1065 nb_trace
= lttv_traceset_number(traceset
);
1066 for(i
= 0 ; i
< nb_trace
; i
++) {
1067 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1069 /* Find the eventtype id for the following events and register the
1070 associated by id hooks. */
1072 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1073 g_array_set_size(hooks
, 8);
1075 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1076 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1078 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1079 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1081 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1082 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1084 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1085 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1087 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1088 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1090 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1091 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1093 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1094 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1096 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1097 "event_data1", "event_data2", process
,
1098 &g_array_index(hooks
, LttvTraceHook
, 7));
1101 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1102 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1104 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1105 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1107 /* Add these hooks to each event_by_id hooks list */
1109 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1110 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1112 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1113 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1115 for(k
= 0 ; k
< hooks
->len
; k
++) {
1116 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1117 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1118 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1121 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1122 *(val
.v_pointer
) = hooks
;
1127 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1129 LttvTraceset
*traceset
= self
->parent
.ts
;
1131 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1135 LttvTracefileState
*tfs
;
1141 LttvAttributeValue val
;
1143 nb_trace
= lttv_traceset_number(traceset
);
1144 for(i
= 0 ; i
< nb_trace
; i
++) {
1145 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1146 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1147 hooks
= *(val
.v_pointer
);
1149 /* Remove these hooks from each event_by_id hooks list */
1151 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1152 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1154 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1155 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1157 for(k
= 0 ; k
< hooks
->len
; k
++) {
1158 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1159 lttv_hooks_remove_data(
1160 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1161 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1164 g_array_free(hooks
, TRUE
);
1169 static gboolean
block_start(void *hook_data
, void *call_data
)
1171 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1173 LttvTracefileState
*tfcs
;
1175 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1177 LttEventPosition
*ep
;
1179 guint i
, nb_block
, nb_event
, nb_tracefile
;
1183 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1185 LttvAttributeValue value
;
1187 ep
= ltt_event_position_new();
1188 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1189 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1191 /* Count the number of events added since the last block end in any
1194 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1195 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1196 ltt_event_position(tfcs
->parent
.e
, ep
);
1197 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1198 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1199 tfcs
->saved_position
= nb_event
;
1203 if(tcs
->nb_event
>= tcs
->save_interval
) {
1204 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1205 LTTV_STATE_SAVED_STATES
);
1206 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1207 value
= lttv_attribute_add(saved_states_tree
,
1208 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1209 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1210 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1211 *(value
.v_time
) = self
->parent
.timestamp
;
1212 lttv_state_save(tcs
, saved_state_tree
);
1214 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1215 self
->parent
.timestamp
.tv_nsec
);
1217 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1222 static gboolean
block_end(void *hook_data
, void *call_data
)
1224 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1226 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1230 LttEventPosition
*ep
;
1232 guint nb_block
, nb_event
;
1234 ep
= ltt_event_position_new();
1235 ltt_event_position(self
->parent
.e
, ep
);
1236 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1237 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1238 self
->saved_position
= 0;
1239 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1244 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1246 LttvTraceset
*traceset
= self
->parent
.ts
;
1248 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1252 LttvTracefileState
*tfs
;
1254 LttvTraceHook hook_start
, hook_end
;
1256 lttv_state_add_event_hooks(self
);
1258 nb_trace
= lttv_traceset_number(traceset
);
1259 for(i
= 0 ; i
< nb_trace
; i
++) {
1260 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1261 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1262 NULL
, NULL
, block_start
, &hook_start
);
1263 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1264 NULL
, NULL
, block_end
, &hook_end
);
1266 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1267 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1269 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1270 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1271 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1272 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1273 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1274 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1279 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1281 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1283 lttv_state_save_add_event_hooks(tss
);
1289 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1291 LttvTraceset
*traceset
= self
->parent
.ts
;
1293 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1297 LttvTracefileState
*tfs
;
1299 LttvTraceHook hook_start
, hook_end
;
1301 nb_trace
= lttv_traceset_number(traceset
);
1302 for(i
= 0 ; i
< nb_trace
; i
++) {
1303 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1304 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1305 NULL
, NULL
, block_start
, &hook_start
);
1307 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1308 NULL
, NULL
, block_end
, &hook_end
);
1310 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1311 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1313 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1314 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1315 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1316 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1317 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1318 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1322 lttv_state_remove_event_hooks(self
);
1325 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1327 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1329 lttv_state_save_remove_event_hooks(tss
);
1334 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1336 LttvTraceset
*traceset
= self
->parent
.ts
;
1338 guint i
, j
, nb_trace
, nb_saved_state
;
1340 int min_pos
, mid_pos
, max_pos
;
1342 LttvTraceState
*tcs
;
1344 LttvAttributeValue value
;
1346 LttvAttributeType type
;
1348 LttvAttributeName name
;
1350 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1352 nb_trace
= lttv_traceset_number(traceset
);
1353 for(i
= 0 ; i
< nb_trace
; i
++) {
1354 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1356 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1357 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1358 LTTV_STATE_SAVED_STATES
);
1361 if(saved_states_tree
) {
1362 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1363 mid_pos
= max_pos
/ 2;
1364 while(min_pos
< max_pos
) {
1365 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1366 g_assert(type
== LTTV_GOBJECT
);
1367 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1368 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1370 g_assert(type
== LTTV_TIME
);
1371 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1373 closest_tree
= saved_state_tree
;
1375 else max_pos
= mid_pos
- 1;
1377 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1381 /* restore the closest earlier saved state */
1383 lttv_state_restore(tcs
, closest_tree
);
1386 /* There is no saved state, yet we want to have it. Restart at T0 */
1388 restore_init_state(tcs
);
1389 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1392 /* We want to seek quickly without restoring/updating the state */
1394 restore_init_state(tcs
);
1395 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1402 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1408 traceset_state_finalize (LttvTracesetState
*self
)
1410 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1411 finalize(G_OBJECT(self
));
1416 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1418 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1420 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1421 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1422 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1423 klass
->new_traceset_context
= new_traceset_context
;
1424 klass
->new_trace_context
= new_trace_context
;
1425 klass
->new_tracefile_context
= new_tracefile_context
;
1430 lttv_traceset_state_get_type(void)
1432 static GType type
= 0;
1434 static const GTypeInfo info
= {
1435 sizeof (LttvTracesetStateClass
),
1436 NULL
, /* base_init */
1437 NULL
, /* base_finalize */
1438 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1439 NULL
, /* class_finalize */
1440 NULL
, /* class_data */
1441 sizeof (LttvTracesetState
),
1442 0, /* n_preallocs */
1443 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1446 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1454 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1460 trace_state_finalize (LttvTraceState
*self
)
1462 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1463 finalize(G_OBJECT(self
));
1468 trace_state_class_init (LttvTraceStateClass
*klass
)
1470 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1472 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1473 klass
->state_save
= state_save
;
1474 klass
->state_restore
= state_restore
;
1475 klass
->state_saved_free
= state_saved_free
;
1480 lttv_trace_state_get_type(void)
1482 static GType type
= 0;
1484 static const GTypeInfo info
= {
1485 sizeof (LttvTraceStateClass
),
1486 NULL
, /* base_init */
1487 NULL
, /* base_finalize */
1488 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1489 NULL
, /* class_finalize */
1490 NULL
, /* class_data */
1491 sizeof (LttvTraceState
),
1492 0, /* n_preallocs */
1493 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1496 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1497 "LttvTraceStateType", &info
, 0);
1504 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1510 tracefile_state_finalize (LttvTracefileState
*self
)
1512 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1513 finalize(G_OBJECT(self
));
1518 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1520 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1522 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1527 lttv_tracefile_state_get_type(void)
1529 static GType type
= 0;
1531 static const GTypeInfo info
= {
1532 sizeof (LttvTracefileStateClass
),
1533 NULL
, /* base_init */
1534 NULL
, /* base_finalize */
1535 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1536 NULL
, /* class_finalize */
1537 NULL
, /* class_data */
1538 sizeof (LttvTracefileState
),
1539 0, /* n_preallocs */
1540 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1543 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1544 "LttvTracefileStateType", &info
, 0);
1550 static void module_init()
1552 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1553 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1554 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1555 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1556 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1557 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1558 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1559 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1560 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1561 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1562 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1563 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1564 LTTV_STATE_RUN
= g_quark_from_string("running");
1565 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1566 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1567 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1568 LTTV_STATE_EVENT
= g_quark_from_string("event");
1569 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1570 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1571 LTTV_STATE_TIME
= g_quark_from_string("time");
1572 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1573 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1574 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1575 g_quark_from_string("trace_state_use_count");
1578 static void module_destroy()
1583 LTTV_MODULE("state", "State computation", \
1584 "Update the system state, possibly saving it at intervals", \
1585 module_init
, module_destroy
)