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 LttTime null_time
= {0,0};
126 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
127 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
130 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
131 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
133 for(i
= 0 ; i
< nb_tracefile
; i
++) {
134 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
135 tfcs
->parent
.timestamp
= null_time
;
136 tfcs
->saved_position
= 0;
137 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
138 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
139 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
143 static LttTime time_zero
= {0,0};
146 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
148 guint i
, j
, nb_trace
, nb_tracefile
;
150 LttvTraceContext
*tc
;
154 LttvTracefileState
*tfcs
;
156 LttvAttributeValue v
;
158 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
159 init((LttvTracesetContext
*)self
, ts
);
161 nb_trace
= lttv_traceset_number(ts
);
162 for(i
= 0 ; i
< nb_trace
; i
++) {
163 tc
= self
->parent
.traces
[i
];
164 tcs
= (LttvTraceState
*)tc
;
165 tcs
->save_interval
= 50000;
166 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
170 if(*(v
.v_uint
) == 1) {
171 create_name_tables(tcs
);
172 create_max_time(tcs
);
174 get_name_tables(tcs
);
177 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
178 ltt_trace_per_cpu_tracefile_number(tc
->t
);
180 for(j
= 0 ; j
< nb_tracefile
; j
++) {
181 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
182 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
184 tcs
->processes
= NULL
;
185 restore_init_state(tcs
);
191 fini(LttvTracesetState
*self
)
193 guint i
, j
, nb_trace
;
197 LttvTracefileState
*tfcs
;
199 LttvAttributeValue v
;
201 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
202 for(i
= 0 ; i
< nb_trace
; i
++) {
203 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
204 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
208 g_assert(*(v
.v_uint
) >= 0);
209 if(*(v
.v_uint
) == 0) {
210 free_name_tables(tcs
);
212 free_saved_state(tcs
);
214 lttv_state_free_process_table(tcs
->processes
);
215 tcs
->processes
= NULL
;
217 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
218 fini((LttvTracesetContext
*)self
);
222 static LttvTracesetContext
*
223 new_traceset_context(LttvTracesetContext
*self
)
225 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
229 static LttvTraceContext
*
230 new_trace_context(LttvTracesetContext
*self
)
232 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
236 static LttvTracefileContext
*
237 new_tracefile_context(LttvTracesetContext
*self
)
239 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
243 /* Write the process state of the trace */
245 static void write_process_state(gpointer key
, gpointer value
,
248 LttvProcessState
*process
;
250 LttvExecutionState
*es
;
252 FILE *fp
= (FILE *)user_data
;
256 process
= (LttvProcessState
*)value
;
258 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
259 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
260 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
261 g_quark_to_string(process
->last_cpu
));
263 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
264 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
265 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
266 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
267 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
268 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
269 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
271 fprintf(fp
, " </PROCESS>\n");
275 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
277 guint i
, nb_tracefile
, nb_block
, nb_event
;
279 LttvTracefileState
*tfcs
;
283 LttEventPosition
*ep
;
285 ep
= ltt_event_position_new();
287 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
289 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
291 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
292 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
294 for(i
= 0 ; i
< nb_tracefile
; i
++) {
295 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
296 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
297 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
298 tfcs
->parent
.timestamp
.tv_nsec
);
299 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
301 ltt_event_position(tfcs
->parent
.e
, ep
);
302 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
303 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
307 fprintf(fp
,"</PROCESS_STATE>");
311 /* Copy each process from an existing hash table to a new one */
313 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
315 LttvProcessState
*process
, *new_process
;
317 GHashTable
*new_processes
= (GHashTable
*)user_data
;
321 process
= (LttvProcessState
*)value
;
322 new_process
= g_new(LttvProcessState
, 1);
323 *new_process
= *process
;
324 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
325 sizeof(LttvExecutionState
));
326 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
327 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
328 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
329 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
331 new_process
->state
= &g_array_index(new_process
->execution_stack
,
332 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
333 g_hash_table_insert(new_processes
, new_process
, new_process
);
337 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
339 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
341 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
342 return new_processes
;
346 /* The saved state for each trace contains a member "processes", which
347 stores a copy of the process table, and a member "tracefiles" with
348 one entry per tracefile. Each tracefile has a "process" member pointing
349 to the current process and a "position" member storing the tracefile
350 position (needed to seek to the current "next" event. */
352 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
354 guint i
, nb_tracefile
;
356 LttvTracefileState
*tfcs
;
358 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
360 LttvAttributeType type
;
362 LttvAttributeValue value
;
364 LttvAttributeName name
;
366 LttEventPosition
*ep
;
368 tracefiles_tree
= lttv_attribute_find_subdir(container
,
369 LTTV_STATE_TRACEFILES
);
371 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
373 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
375 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
376 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
378 for(i
= 0 ; i
< nb_tracefile
; i
++) {
379 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
380 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
381 value
= lttv_attribute_add(tracefiles_tree
, i
,
383 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
384 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
386 *(value
.v_uint
) = tfcs
->process
->pid
;
387 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
389 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
391 ep
= ltt_event_position_new();
392 ltt_event_position(tfcs
->parent
.e
, ep
);
393 *(value
.v_pointer
) = ep
;
395 guint nb_block
, nb_event
;
397 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
398 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
399 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
405 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
407 guint i
, nb_tracefile
, pid
;
409 LttvTracefileState
*tfcs
;
411 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
413 LttvAttributeType type
;
415 LttvAttributeValue value
;
417 LttvAttributeName name
;
419 LttEventPosition
*ep
;
421 tracefiles_tree
= lttv_attribute_find_subdir(container
,
422 LTTV_STATE_TRACEFILES
);
424 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
426 g_assert(type
== LTTV_POINTER
);
427 lttv_state_free_process_table(self
->processes
);
428 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
430 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
431 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
433 for(i
= 0 ; i
< nb_tracefile
; i
++) {
434 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
435 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
436 g_assert(type
== LTTV_GOBJECT
);
437 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
439 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
441 g_assert(type
== LTTV_UINT
);
442 pid
= *(value
.v_uint
);
443 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
445 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
447 g_assert(type
== LTTV_POINTER
);
448 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
450 ep
= *(value
.v_pointer
);
451 g_assert(tfcs
->parent
.t_context
!= NULL
);
452 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
458 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
460 guint i
, nb_tracefile
;
462 LttvTracefileState
*tfcs
;
464 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
466 LttvAttributeType type
;
468 LttvAttributeValue value
;
470 LttvAttributeName name
;
472 LttEventPosition
*ep
;
474 tracefiles_tree
= lttv_attribute_find_subdir(container
,
475 LTTV_STATE_TRACEFILES
);
476 g_object_ref(G_OBJECT(tracefiles_tree
));
477 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
479 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
481 g_assert(type
== LTTV_POINTER
);
482 lttv_state_free_process_table(*(value
.v_pointer
));
483 *(value
.v_pointer
) = NULL
;
484 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
486 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
487 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
489 for(i
= 0 ; i
< nb_tracefile
; i
++) {
490 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
491 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
492 g_assert(type
== LTTV_GOBJECT
);
493 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
495 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
497 g_assert(type
== LTTV_POINTER
);
498 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
500 g_object_unref(G_OBJECT(tracefiles_tree
));
504 static void free_saved_state(LttvTraceState
*self
)
508 LttvAttributeType type
;
510 LttvAttributeValue value
;
512 LttvAttributeName name
;
514 LttvAttribute
*saved_states
;
516 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
517 LTTV_STATE_SAVED_STATES
);
519 nb
= lttv_attribute_get_number(saved_states
);
520 for(i
= 0 ; i
< nb
; i
++) {
521 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
522 g_assert(type
== LTTV_GOBJECT
);
523 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
526 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
531 create_max_time(LttvTraceState
*tcs
)
533 LttvAttributeValue v
;
535 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
537 g_assert(*(v
.v_pointer
) == NULL
);
538 *(v
.v_pointer
) = g_new(LttTime
,1);
539 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
544 get_max_time(LttvTraceState
*tcs
)
546 LttvAttributeValue v
;
548 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
550 g_assert(*(v
.v_pointer
) != NULL
);
551 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
556 free_max_time(LttvTraceState
*tcs
)
558 LttvAttributeValue v
;
560 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
562 g_free(*(v
.v_pointer
));
563 *(v
.v_pointer
) = NULL
;
567 typedef struct _LttvNameTables
{
568 GQuark
*eventtype_names
;
569 GQuark
*syscall_names
;
576 create_name_tables(LttvTraceState
*tcs
)
580 char *f_name
, *e_name
;
588 GString
*fe_name
= g_string_new("");
590 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
592 LttvAttributeValue v
;
594 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
596 g_assert(*(v
.v_pointer
) == NULL
);
597 *(v
.v_pointer
) = name_tables
;
599 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
600 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
601 for(i
= 0 ; i
< nb
; i
++) {
602 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
603 e_name
= ltt_eventtype_name(et
);
604 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
605 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
606 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
609 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
610 "syscall_id", NULL
, NULL
, NULL
, &h
);
611 t
= ltt_field_type(h
.f1
);
612 nb
= ltt_type_element_number(t
);
614 /* CHECK syscalls should be an emun but currently are not!
615 name_tables->syscall_names = g_new(GQuark, nb);
617 for(i = 0 ; i < nb ; i++) {
618 name_tables->syscall_names[i] = g_quark_from_string(
619 ltt_enum_string_get(t, i));
623 name_tables
->syscall_names
= g_new(GQuark
, 256);
624 for(i
= 0 ; i
< 256 ; i
++) {
625 g_string_printf(fe_name
, "syscall %d", i
);
626 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
629 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
630 "trap_id", NULL
, NULL
, NULL
, &h
);
631 t
= ltt_field_type(h
.f1
);
632 nb
= ltt_type_element_number(t
);
635 name_tables->trap_names = g_new(GQuark, nb);
636 for(i = 0 ; i < nb ; i++) {
637 name_tables->trap_names[i] = g_quark_from_string(
638 ltt_enum_string_get(t, i));
642 name_tables
->trap_names
= g_new(GQuark
, 256);
643 for(i
= 0 ; i
< 256 ; i
++) {
644 g_string_printf(fe_name
, "trap %d", i
);
645 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
648 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
649 "irq_id", NULL
, NULL
, NULL
, &h
);
650 t
= ltt_field_type(h
.f1
);
651 nb
= ltt_type_element_number(t
);
654 name_tables->irq_names = g_new(GQuark, nb);
655 for(i = 0 ; i < nb ; i++) {
656 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
660 name_tables
->irq_names
= g_new(GQuark
, 256);
661 for(i
= 0 ; i
< 256 ; i
++) {
662 g_string_printf(fe_name
, "irq %d", i
);
663 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
666 g_string_free(fe_name
, TRUE
);
671 get_name_tables(LttvTraceState
*tcs
)
673 LttvNameTables
*name_tables
;
675 LttvAttributeValue v
;
677 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
679 g_assert(*(v
.v_pointer
) != NULL
);
680 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
681 tcs
->eventtype_names
= name_tables
->eventtype_names
;
682 tcs
->syscall_names
= name_tables
->syscall_names
;
683 tcs
->trap_names
= name_tables
->trap_names
;
684 tcs
->irq_names
= name_tables
->irq_names
;
689 free_name_tables(LttvTraceState
*tcs
)
691 LttvNameTables
*name_tables
;
693 LttvAttributeValue v
;
695 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
697 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
698 *(v
.v_pointer
) = NULL
;
700 g_free(name_tables
->eventtype_names
);
701 g_free(name_tables
->syscall_names
);
702 g_free(name_tables
->trap_names
);
703 g_free(name_tables
->irq_names
);
708 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
711 LttvExecutionState
*es
;
713 LttvProcessState
*process
= tfs
->process
;
715 guint depth
= process
->execution_stack
->len
;
717 g_array_set_size(process
->execution_stack
, depth
+ 1);
718 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
721 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
722 es
->s
= process
->state
->s
;
727 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
729 LttvProcessState
*process
= tfs
->process
;
731 guint depth
= process
->execution_stack
->len
;
733 if(process
->state
->t
!= t
){
734 g_info("Different execution mode type (%d.%09d): ignore it\n",
735 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
736 g_info("process state has %s when pop_int is %s\n",
737 g_quark_to_string(process
->state
->t
),
738 g_quark_to_string(t
));
739 g_info("{ %u, %u, %s, %s }\n",
742 g_quark_to_string(process
->name
),
743 g_quark_to_string(process
->state
->s
));
748 g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
749 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
753 g_array_set_size(process
->execution_stack
, depth
- 1);
754 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
756 process
->state
->change
= tfs
->parent
.timestamp
;
761 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
764 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
766 LttvExecutionState
*es
;
768 LttvTraceContext
*tc
;
774 tc
= tfs
->parent
.t_context
;
775 tcs
= (LttvTraceState
*)tc
;
778 process
->last_cpu
= tfs
->cpu_name
;
779 g_warning("Process %u, core %p", process
->pid
, process
);
780 g_hash_table_insert(tcs
->processes
, process
, process
);
783 process
->ppid
= parent
->pid
;
784 process
->name
= parent
->name
;
785 process
->creation_time
= tfs
->parent
.timestamp
;
788 /* No parent. This process exists but we are missing all information about
789 its creation. The birth time is set to zero but we remember the time of
794 process
->name
= LTTV_STATE_UNNAMED
;
795 process
->creation_time
= ltt_time_zero
;
798 process
->insertion_time
= tfs
->parent
.timestamp
;
799 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
800 process
->creation_time
.tv_nsec
);
801 process
->pid_time
= g_quark_from_string(buffer
);
802 process
->last_cpu
= tfs
->cpu_name
;
803 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
804 sizeof(LttvExecutionState
));
805 g_array_set_size(process
->execution_stack
, 1);
806 es
= process
->state
= &g_array_index(process
->execution_stack
,
807 LttvExecutionState
, 0);
808 es
->t
= LTTV_STATE_USER_MODE
;
809 es
->n
= LTTV_STATE_SUBMODE_NONE
;
810 es
->entry
= tfs
->parent
.timestamp
;
811 es
->change
= tfs
->parent
.timestamp
;
812 es
->s
= LTTV_STATE_WAIT_FORK
;
818 lttv_state_find_process_from_trace(LttvTraceState
*ts
, GQuark cpu
, guint pid
)
820 LttvProcessState key
;
821 LttvProcessState
*process
;
825 process
= g_hash_table_lookup(ts
->processes
, &key
);
830 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
833 LttvTraceState
*ts
=(LttvTraceState
*)tfs
->parent
.t_context
;
834 return lttv_state_find_process_from_trace(ts
, tfs
->cpu_name
, pid
);
839 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
841 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
843 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
848 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
850 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
851 LttvProcessState key
;
853 key
.pid
= process
->pid
;
854 key
.last_cpu
= process
->last_cpu
;
855 g_hash_table_remove(ts
->processes
, &key
);
856 g_array_free(process
->execution_stack
, TRUE
);
861 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
863 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
868 static void lttv_state_free_process_table(GHashTable
*processes
)
870 g_hash_table_foreach(processes
, free_process_state
, NULL
);
871 g_hash_table_destroy(processes
);
875 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
877 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
879 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
881 LttvExecutionSubmode submode
;
883 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
884 ltt_event_get_unsigned(s
->parent
.e
, f
)];
885 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
890 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
892 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
894 pop_state(s
, LTTV_STATE_SYSCALL
);
899 static gboolean
trap_entry(void *hook_data
, void *call_data
)
901 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
903 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
905 LttvExecutionSubmode submode
;
907 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
908 ltt_event_get_unsigned(s
->parent
.e
, f
)];
909 push_state(s
, LTTV_STATE_TRAP
, submode
);
914 static gboolean
trap_exit(void *hook_data
, void *call_data
)
916 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
918 pop_state(s
, LTTV_STATE_TRAP
);
923 static gboolean
irq_entry(void *hook_data
, void *call_data
)
925 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
927 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
929 LttvExecutionSubmode submode
;
931 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
932 ltt_event_get_unsigned(s
->parent
.e
, f
)];
934 /* Do something with the info about being in user or system mode when int? */
935 push_state(s
, LTTV_STATE_IRQ
, submode
);
940 static gboolean
irq_exit(void *hook_data
, void *call_data
)
942 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
944 pop_state(s
, LTTV_STATE_IRQ
);
949 static gboolean
schedchange(void *hook_data
, void *call_data
)
951 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
953 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
955 guint pid_in
, pid_out
, state_out
;
957 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
958 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
959 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
961 if(s
->process
!= NULL
) {
963 /* We could not know but it was not the idle process executing.
964 This should only happen at the beginning, before the first schedule
965 event, and when the initial information (current process for each CPU)
966 is missing. It is not obvious how we could, after the fact, compensate
967 the wrongly attributed statistics. */
969 if(s
->process
->pid
!= pid_out
) {
970 g_assert(s
->process
->pid
== 0);
973 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
974 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
975 exit_process(s
, s
->process
);
976 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
978 s
->process
->state
->change
= s
->parent
.timestamp
;
980 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
981 s
->process
->state
->s
= LTTV_STATE_RUN
;
982 s
->process
->last_cpu
= s
->cpu_name
;
983 s
->process
->state
->change
= s
->parent
.timestamp
;
988 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
995 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
997 lttv_state_create_process(s
, s
->process
, child_pid
);
1001 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
1003 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1007 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1008 lttv_state_create_process(s
, s
->process
, child_pid
);
1014 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1016 if(s
->process
!= NULL
) {
1017 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1022 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1024 if(s
->process
!= NULL
) {
1025 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1031 gboolean
process(void *hook_data
, void *call_data
)
1033 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1034 LttField
*f
= trace_hook
->f1
;
1036 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1038 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1040 /* CHECK : do not hardcode the sub_id values here ? */
1042 return process_fork(trace_hook
, s
);
1043 } else if(sub_id
== 3) {
1044 return process_exit(trace_hook
, s
);
1050 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1052 LttvTraceset
*traceset
= self
->parent
.ts
;
1054 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1058 LttvTracefileState
*tfs
;
1064 LttvAttributeValue val
;
1066 nb_trace
= lttv_traceset_number(traceset
);
1067 for(i
= 0 ; i
< nb_trace
; i
++) {
1068 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1070 /* Find the eventtype id for the following events and register the
1071 associated by id hooks. */
1073 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1074 g_array_set_size(hooks
, 8);
1076 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1077 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1079 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1080 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1082 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1083 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1085 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1086 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1088 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1089 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1091 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1092 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1094 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1095 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1097 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1098 "event_data1", "event_data2", process
,
1099 &g_array_index(hooks
, LttvTraceHook
, 7));
1102 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1103 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1105 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1106 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1108 /* Add these hooks to each event_by_id hooks list */
1110 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1111 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1113 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1114 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1116 for(k
= 0 ; k
< hooks
->len
; k
++) {
1117 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1118 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1119 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1122 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1123 *(val
.v_pointer
) = hooks
;
1128 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1130 LttvTraceset
*traceset
= self
->parent
.ts
;
1132 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1136 LttvTracefileState
*tfs
;
1142 LttvAttributeValue val
;
1144 nb_trace
= lttv_traceset_number(traceset
);
1145 for(i
= 0 ; i
< nb_trace
; i
++) {
1146 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1147 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1148 hooks
= *(val
.v_pointer
);
1150 /* Remove these hooks from each event_by_id hooks list */
1152 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1153 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1155 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1156 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1158 for(k
= 0 ; k
< hooks
->len
; k
++) {
1159 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1160 lttv_hooks_remove_data(
1161 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1162 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1165 g_array_free(hooks
, TRUE
);
1170 static gboolean
block_start(void *hook_data
, void *call_data
)
1172 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1174 LttvTracefileState
*tfcs
;
1176 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1178 LttEventPosition
*ep
;
1180 guint i
, nb_block
, nb_event
, nb_tracefile
;
1184 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1186 LttvAttributeValue value
;
1188 ep
= ltt_event_position_new();
1189 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1190 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1192 /* Count the number of events added since the last block end in any
1195 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1196 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1197 ltt_event_position(tfcs
->parent
.e
, ep
);
1198 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1199 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1200 tfcs
->saved_position
= nb_event
;
1204 if(tcs
->nb_event
>= tcs
->save_interval
) {
1205 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1206 LTTV_STATE_SAVED_STATES
);
1207 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1208 value
= lttv_attribute_add(saved_states_tree
,
1209 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1210 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1211 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1212 *(value
.v_time
) = self
->parent
.timestamp
;
1213 lttv_state_save(tcs
, saved_state_tree
);
1215 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1216 self
->parent
.timestamp
.tv_nsec
);
1218 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1223 static gboolean
block_end(void *hook_data
, void *call_data
)
1225 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1227 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1231 LttEventPosition
*ep
;
1233 guint nb_block
, nb_event
;
1235 ep
= ltt_event_position_new();
1236 ltt_event_position(self
->parent
.e
, ep
);
1237 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1238 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1239 self
->saved_position
= 0;
1240 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1245 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1247 LttvTraceset
*traceset
= self
->parent
.ts
;
1249 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1253 LttvTracefileState
*tfs
;
1255 LttvTraceHook hook_start
, hook_end
;
1257 nb_trace
= lttv_traceset_number(traceset
);
1258 for(i
= 0 ; i
< nb_trace
; i
++) {
1259 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1260 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1261 NULL
, NULL
, block_start
, &hook_start
);
1262 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1263 NULL
, NULL
, block_end
, &hook_end
);
1265 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1266 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1268 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1269 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1270 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1271 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1272 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1273 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1278 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1280 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1282 lttv_state_save_add_event_hooks(tss
);
1288 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1290 LttvTraceset
*traceset
= self
->parent
.ts
;
1292 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1296 LttvTracefileState
*tfs
;
1298 LttvTraceHook hook_start
, hook_end
;
1300 nb_trace
= lttv_traceset_number(traceset
);
1301 for(i
= 0 ; i
< nb_trace
; i
++) {
1302 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1303 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1304 NULL
, NULL
, block_start
, &hook_start
);
1306 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1307 NULL
, NULL
, block_end
, &hook_end
);
1309 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1310 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1312 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1313 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1314 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1315 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1316 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1317 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1322 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1324 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1326 lttv_state_save_remove_event_hooks(tss
);
1331 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1333 LttvTraceset
*traceset
= self
->parent
.ts
;
1335 guint i
, j
, nb_trace
, nb_saved_state
;
1337 int min_pos
, mid_pos
, max_pos
;
1339 LttvTraceState
*tcs
;
1341 LttvAttributeValue value
;
1343 LttvAttributeType type
;
1345 LttvAttributeName name
;
1347 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1349 nb_trace
= lttv_traceset_number(traceset
);
1350 for(i
= 0 ; i
< nb_trace
; i
++) {
1351 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1353 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1354 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1355 LTTV_STATE_SAVED_STATES
);
1358 if(saved_states_tree
) {
1359 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1360 mid_pos
= max_pos
/ 2;
1361 while(min_pos
< max_pos
) {
1362 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1363 g_assert(type
== LTTV_GOBJECT
);
1364 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1365 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1367 g_assert(type
== LTTV_TIME
);
1368 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1370 closest_tree
= saved_state_tree
;
1372 else max_pos
= mid_pos
- 1;
1374 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1378 /* restore the closest earlier saved state */
1380 lttv_state_restore(tcs
, closest_tree
);
1383 /* There is no saved state, yet we want to have it. Restart at T0 */
1385 restore_init_state(tcs
);
1386 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1389 /* We want to seek quickly without restoring/updating the state */
1391 restore_init_state(tcs
);
1392 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1399 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1405 traceset_state_finalize (LttvTracesetState
*self
)
1407 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1408 finalize(G_OBJECT(self
));
1413 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1415 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1417 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1418 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1419 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1420 klass
->new_traceset_context
= new_traceset_context
;
1421 klass
->new_trace_context
= new_trace_context
;
1422 klass
->new_tracefile_context
= new_tracefile_context
;
1427 lttv_traceset_state_get_type(void)
1429 static GType type
= 0;
1431 static const GTypeInfo info
= {
1432 sizeof (LttvTracesetStateClass
),
1433 NULL
, /* base_init */
1434 NULL
, /* base_finalize */
1435 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1436 NULL
, /* class_finalize */
1437 NULL
, /* class_data */
1438 sizeof (LttvTracesetState
),
1439 0, /* n_preallocs */
1440 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1443 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1451 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1457 trace_state_finalize (LttvTraceState
*self
)
1459 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1460 finalize(G_OBJECT(self
));
1465 trace_state_class_init (LttvTraceStateClass
*klass
)
1467 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1469 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1470 klass
->state_save
= state_save
;
1471 klass
->state_restore
= state_restore
;
1472 klass
->state_saved_free
= state_saved_free
;
1477 lttv_trace_state_get_type(void)
1479 static GType type
= 0;
1481 static const GTypeInfo info
= {
1482 sizeof (LttvTraceStateClass
),
1483 NULL
, /* base_init */
1484 NULL
, /* base_finalize */
1485 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1486 NULL
, /* class_finalize */
1487 NULL
, /* class_data */
1488 sizeof (LttvTraceState
),
1489 0, /* n_preallocs */
1490 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1493 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1494 "LttvTraceStateType", &info
, 0);
1501 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1507 tracefile_state_finalize (LttvTracefileState
*self
)
1509 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1510 finalize(G_OBJECT(self
));
1515 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1517 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1519 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1524 lttv_tracefile_state_get_type(void)
1526 static GType type
= 0;
1528 static const GTypeInfo info
= {
1529 sizeof (LttvTracefileStateClass
),
1530 NULL
, /* base_init */
1531 NULL
, /* base_finalize */
1532 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1533 NULL
, /* class_finalize */
1534 NULL
, /* class_data */
1535 sizeof (LttvTracefileState
),
1536 0, /* n_preallocs */
1537 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1540 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1541 "LttvTracefileStateType", &info
, 0);
1547 static void module_init()
1549 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1550 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1551 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1552 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1553 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1554 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1555 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1556 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1557 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1558 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1559 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1560 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1561 LTTV_STATE_RUN
= g_quark_from_string("running");
1562 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1563 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1564 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1565 LTTV_STATE_EVENT
= g_quark_from_string("event");
1566 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1567 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1568 LTTV_STATE_TIME
= g_quark_from_string("time");
1569 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1570 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1571 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1572 g_quark_from_string("trace_state_use_count");
1575 static void module_destroy()
1580 LTTV_MODULE("state", "State computation", \
1581 "Update the system state, possibly saving it at intervals", \
1582 module_init
, module_destroy
)