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
);
1048 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1050 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1052 lttv_state_add_event_hooks(tss
);
1057 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1059 LttvTraceset
*traceset
= self
->parent
.ts
;
1061 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1065 LttvTracefileState
*tfs
;
1071 LttvAttributeValue val
;
1073 nb_trace
= lttv_traceset_number(traceset
);
1074 for(i
= 0 ; i
< nb_trace
; i
++) {
1075 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1077 /* Find the eventtype id for the following events and register the
1078 associated by id hooks. */
1080 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1081 g_array_set_size(hooks
, 8);
1083 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1084 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1086 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1087 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1089 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1090 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1092 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1093 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1095 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1096 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1098 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1099 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1101 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1102 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1104 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1105 "event_data1", "event_data2", process
,
1106 &g_array_index(hooks
, LttvTraceHook
, 7));
1109 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1110 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1112 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1113 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1115 /* Add these hooks to each event_by_id hooks list */
1117 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1118 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1120 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1121 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1123 for(k
= 0 ; k
< hooks
->len
; k
++) {
1124 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1125 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1126 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1129 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1130 *(val
.v_pointer
) = hooks
;
1134 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1136 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1138 lttv_state_remove_event_hooks(tss
);
1143 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1145 LttvTraceset
*traceset
= self
->parent
.ts
;
1147 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1151 LttvTracefileState
*tfs
;
1157 LttvAttributeValue val
;
1159 nb_trace
= lttv_traceset_number(traceset
);
1160 for(i
= 0 ; i
< nb_trace
; i
++) {
1161 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1162 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1163 hooks
= *(val
.v_pointer
);
1165 /* Remove these hooks from each event_by_id hooks list */
1167 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1168 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1170 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1171 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1173 for(k
= 0 ; k
< hooks
->len
; k
++) {
1174 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1175 lttv_hooks_remove_data(
1176 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1177 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1180 g_array_free(hooks
, TRUE
);
1185 static gboolean
block_start(void *hook_data
, void *call_data
)
1187 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1189 LttvTracefileState
*tfcs
;
1191 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1193 LttEventPosition
*ep
;
1195 guint i
, nb_block
, nb_event
, nb_tracefile
;
1199 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1201 LttvAttributeValue value
;
1203 ep
= ltt_event_position_new();
1204 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1205 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1207 /* Count the number of events added since the last block end in any
1210 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1211 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1212 ltt_event_position(tfcs
->parent
.e
, ep
);
1213 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1214 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1215 tfcs
->saved_position
= nb_event
;
1219 if(tcs
->nb_event
>= tcs
->save_interval
) {
1220 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1221 LTTV_STATE_SAVED_STATES
);
1222 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1223 value
= lttv_attribute_add(saved_states_tree
,
1224 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1225 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1226 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1227 *(value
.v_time
) = self
->parent
.timestamp
;
1228 lttv_state_save(tcs
, saved_state_tree
);
1230 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1231 self
->parent
.timestamp
.tv_nsec
);
1233 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1238 static gboolean
block_end(void *hook_data
, void *call_data
)
1240 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1242 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1246 LttEventPosition
*ep
;
1248 guint nb_block
, nb_event
;
1250 ep
= ltt_event_position_new();
1251 ltt_event_position(self
->parent
.e
, ep
);
1252 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1253 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1254 self
->saved_position
= 0;
1255 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1260 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1262 LttvTraceset
*traceset
= self
->parent
.ts
;
1264 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1268 LttvTracefileState
*tfs
;
1270 LttvTraceHook hook_start
, hook_end
;
1272 nb_trace
= lttv_traceset_number(traceset
);
1273 for(i
= 0 ; i
< nb_trace
; i
++) {
1274 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1275 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1276 NULL
, NULL
, block_start
, &hook_start
);
1277 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1278 NULL
, NULL
, block_end
, &hook_end
);
1280 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1281 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1283 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1284 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1285 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1286 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1287 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1288 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1293 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1295 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1297 lttv_state_save_add_event_hooks(tss
);
1303 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1305 LttvTraceset
*traceset
= self
->parent
.ts
;
1307 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1311 LttvTracefileState
*tfs
;
1313 LttvTraceHook hook_start
, hook_end
;
1315 nb_trace
= lttv_traceset_number(traceset
);
1316 for(i
= 0 ; i
< nb_trace
; i
++) {
1317 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1318 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1319 NULL
, NULL
, block_start
, &hook_start
);
1321 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1322 NULL
, NULL
, block_end
, &hook_end
);
1324 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1325 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1327 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1328 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1329 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1330 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1331 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1332 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1337 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1339 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1341 lttv_state_save_remove_event_hooks(tss
);
1346 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1348 LttvTraceset
*traceset
= self
->parent
.ts
;
1350 guint i
, j
, nb_trace
, nb_saved_state
;
1352 int min_pos
, mid_pos
, max_pos
;
1354 LttvTraceState
*tcs
;
1356 LttvAttributeValue value
;
1358 LttvAttributeType type
;
1360 LttvAttributeName name
;
1362 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1364 nb_trace
= lttv_traceset_number(traceset
);
1365 for(i
= 0 ; i
< nb_trace
; i
++) {
1366 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1368 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1369 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1370 LTTV_STATE_SAVED_STATES
);
1373 if(saved_states_tree
) {
1374 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1375 mid_pos
= max_pos
/ 2;
1376 while(min_pos
< max_pos
) {
1377 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1378 g_assert(type
== LTTV_GOBJECT
);
1379 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1380 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1382 g_assert(type
== LTTV_TIME
);
1383 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1385 closest_tree
= saved_state_tree
;
1387 else max_pos
= mid_pos
- 1;
1389 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1393 /* restore the closest earlier saved state */
1395 lttv_state_restore(tcs
, closest_tree
);
1398 /* There is no saved state, yet we want to have it. Restart at T0 */
1400 restore_init_state(tcs
);
1401 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1404 /* We want to seek quickly without restoring/updating the state */
1406 restore_init_state(tcs
);
1407 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1414 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1420 traceset_state_finalize (LttvTracesetState
*self
)
1422 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1423 finalize(G_OBJECT(self
));
1428 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1430 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1432 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1433 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1434 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1435 klass
->new_traceset_context
= new_traceset_context
;
1436 klass
->new_trace_context
= new_trace_context
;
1437 klass
->new_tracefile_context
= new_tracefile_context
;
1442 lttv_traceset_state_get_type(void)
1444 static GType type
= 0;
1446 static const GTypeInfo info
= {
1447 sizeof (LttvTracesetStateClass
),
1448 NULL
, /* base_init */
1449 NULL
, /* base_finalize */
1450 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1451 NULL
, /* class_finalize */
1452 NULL
, /* class_data */
1453 sizeof (LttvTracesetState
),
1454 0, /* n_preallocs */
1455 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1458 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1466 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1472 trace_state_finalize (LttvTraceState
*self
)
1474 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1475 finalize(G_OBJECT(self
));
1480 trace_state_class_init (LttvTraceStateClass
*klass
)
1482 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1484 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1485 klass
->state_save
= state_save
;
1486 klass
->state_restore
= state_restore
;
1487 klass
->state_saved_free
= state_saved_free
;
1492 lttv_trace_state_get_type(void)
1494 static GType type
= 0;
1496 static const GTypeInfo info
= {
1497 sizeof (LttvTraceStateClass
),
1498 NULL
, /* base_init */
1499 NULL
, /* base_finalize */
1500 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1501 NULL
, /* class_finalize */
1502 NULL
, /* class_data */
1503 sizeof (LttvTraceState
),
1504 0, /* n_preallocs */
1505 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1508 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1509 "LttvTraceStateType", &info
, 0);
1516 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1522 tracefile_state_finalize (LttvTracefileState
*self
)
1524 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1525 finalize(G_OBJECT(self
));
1530 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1532 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1534 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1539 lttv_tracefile_state_get_type(void)
1541 static GType type
= 0;
1543 static const GTypeInfo info
= {
1544 sizeof (LttvTracefileStateClass
),
1545 NULL
, /* base_init */
1546 NULL
, /* base_finalize */
1547 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1548 NULL
, /* class_finalize */
1549 NULL
, /* class_data */
1550 sizeof (LttvTracefileState
),
1551 0, /* n_preallocs */
1552 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1555 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1556 "LttvTracefileStateType", &info
, 0);
1562 static void module_init()
1564 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1565 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1566 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1567 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1568 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1569 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1570 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1571 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1572 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1573 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1574 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1575 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1576 LTTV_STATE_RUN
= g_quark_from_string("running");
1577 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1578 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1579 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1580 LTTV_STATE_EVENT
= g_quark_from_string("event");
1581 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1582 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1583 LTTV_STATE_TIME
= g_quark_from_string("time");
1584 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1585 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1586 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1587 g_quark_from_string("trace_state_use_count");
1590 static void module_destroy()
1595 LTTV_MODULE("state", "State computation", \
1596 "Update the system state, possibly saving it at intervals", \
1597 module_init
, module_destroy
)