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 ((const LttvProcessState
*)key
)->pid
;
103 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
105 const LttvProcessState
*process_a
, *process_b
;
107 process_a
= (const LttvProcessState
*)a
;
108 process_b
= (const 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
)
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
,
205 g_assert(*(v
.v_uint
) != 0);
208 if(*(v
.v_uint
) == 0) {
209 free_name_tables(tcs
);
211 free_saved_state(tcs
);
213 lttv_state_free_process_table(tcs
->processes
);
214 tcs
->processes
= NULL
;
216 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
217 fini((LttvTracesetContext
*)self
);
221 static LttvTracesetContext
*
222 new_traceset_context(LttvTracesetContext
*self
)
224 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
228 static LttvTraceContext
*
229 new_trace_context(LttvTracesetContext
*self
)
231 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
235 static LttvTracefileContext
*
236 new_tracefile_context(LttvTracesetContext
*self
)
238 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
242 /* Write the process state of the trace */
244 static void write_process_state(gpointer key
, gpointer value
,
247 LttvProcessState
*process
;
249 LttvExecutionState
*es
;
251 FILE *fp
= (FILE *)user_data
;
255 process
= (LttvProcessState
*)value
;
257 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
258 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
259 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
260 g_quark_to_string(process
->last_cpu
));
262 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
263 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
264 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
265 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
266 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
267 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
268 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
270 fprintf(fp
, " </PROCESS>\n");
274 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
276 guint i
, nb_tracefile
, nb_block
, nb_event
;
278 LttvTracefileState
*tfcs
;
282 LttEventPosition
*ep
;
284 ep
= ltt_event_position_new();
286 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
288 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
290 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
291 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
293 for(i
= 0 ; i
< nb_tracefile
; i
++) {
294 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
295 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
296 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
297 tfcs
->parent
.timestamp
.tv_nsec
);
298 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
300 ltt_event_position(tfcs
->parent
.e
, ep
);
301 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
302 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
306 fprintf(fp
,"</PROCESS_STATE>");
310 /* Copy each process from an existing hash table to a new one */
312 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
314 LttvProcessState
*process
, *new_process
;
316 GHashTable
*new_processes
= (GHashTable
*)user_data
;
320 process
= (LttvProcessState
*)value
;
321 new_process
= g_new(LttvProcessState
, 1);
322 *new_process
= *process
;
323 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
324 sizeof(LttvExecutionState
));
325 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
326 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
327 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
328 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
330 new_process
->state
= &g_array_index(new_process
->execution_stack
,
331 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
332 g_hash_table_insert(new_processes
, new_process
, new_process
);
336 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
338 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
340 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
341 return new_processes
;
345 /* The saved state for each trace contains a member "processes", which
346 stores a copy of the process table, and a member "tracefiles" with
347 one entry per tracefile. Each tracefile has a "process" member pointing
348 to the current process and a "position" member storing the tracefile
349 position (needed to seek to the current "next" event. */
351 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
353 guint i
, nb_tracefile
;
355 LttvTracefileState
*tfcs
;
357 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
359 LttvAttributeType type
;
361 LttvAttributeValue value
;
363 LttvAttributeName name
;
365 LttEventPosition
*ep
;
367 tracefiles_tree
= lttv_attribute_find_subdir(container
,
368 LTTV_STATE_TRACEFILES
);
370 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
372 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
374 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
375 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
377 for(i
= 0 ; i
< nb_tracefile
; i
++) {
378 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
379 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
380 value
= lttv_attribute_add(tracefiles_tree
, i
,
382 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
383 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
385 *(value
.v_uint
) = tfcs
->process
->pid
;
386 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
388 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
390 ep
= ltt_event_position_new();
391 ltt_event_position(tfcs
->parent
.e
, ep
);
392 *(value
.v_pointer
) = ep
;
394 guint nb_block
, nb_event
;
396 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
397 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
398 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
404 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
406 guint i
, nb_tracefile
, pid
;
408 LttvTracefileState
*tfcs
;
410 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
412 LttvAttributeType type
;
414 LttvAttributeValue value
;
416 LttvAttributeName name
;
418 LttEventPosition
*ep
;
420 tracefiles_tree
= lttv_attribute_find_subdir(container
,
421 LTTV_STATE_TRACEFILES
);
423 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
425 g_assert(type
== LTTV_POINTER
);
426 lttv_state_free_process_table(self
->processes
);
427 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
429 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
430 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
432 for(i
= 0 ; i
< nb_tracefile
; i
++) {
433 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
434 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
435 g_assert(type
== LTTV_GOBJECT
);
436 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
438 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
440 g_assert(type
== LTTV_UINT
);
441 pid
= *(value
.v_uint
);
442 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
444 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
446 g_assert(type
== LTTV_POINTER
);
447 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
449 ep
= *(value
.v_pointer
);
450 g_assert(tfcs
->parent
.t_context
!= NULL
);
451 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
457 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
459 guint i
, nb_tracefile
;
461 LttvTracefileState
*tfcs
;
463 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
465 LttvAttributeType type
;
467 LttvAttributeValue value
;
469 LttvAttributeName name
;
471 LttEventPosition
*ep
;
473 tracefiles_tree
= lttv_attribute_find_subdir(container
,
474 LTTV_STATE_TRACEFILES
);
475 g_object_ref(G_OBJECT(tracefiles_tree
));
476 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
478 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
480 g_assert(type
== LTTV_POINTER
);
481 lttv_state_free_process_table(*(value
.v_pointer
));
482 *(value
.v_pointer
) = NULL
;
483 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
485 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
486 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
488 for(i
= 0 ; i
< nb_tracefile
; i
++) {
489 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
490 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
491 g_assert(type
== LTTV_GOBJECT
);
492 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
494 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
496 g_assert(type
== LTTV_POINTER
);
497 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
499 g_object_unref(G_OBJECT(tracefiles_tree
));
503 static void free_saved_state(LttvTraceState
*self
)
507 LttvAttributeType type
;
509 LttvAttributeValue value
;
511 LttvAttributeName name
;
513 LttvAttribute
*saved_states
;
515 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
516 LTTV_STATE_SAVED_STATES
);
518 nb
= lttv_attribute_get_number(saved_states
);
519 for(i
= 0 ; i
< nb
; i
++) {
520 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
521 g_assert(type
== LTTV_GOBJECT
);
522 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
525 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
530 create_max_time(LttvTraceState
*tcs
)
532 LttvAttributeValue v
;
534 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
536 g_assert(*(v
.v_pointer
) == NULL
);
537 *(v
.v_pointer
) = g_new(LttTime
,1);
538 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
543 get_max_time(LttvTraceState
*tcs
)
545 LttvAttributeValue v
;
547 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
549 g_assert(*(v
.v_pointer
) != NULL
);
550 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
555 free_max_time(LttvTraceState
*tcs
)
557 LttvAttributeValue v
;
559 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
561 g_free(*(v
.v_pointer
));
562 *(v
.v_pointer
) = NULL
;
566 typedef struct _LttvNameTables
{
567 GQuark
*eventtype_names
;
568 GQuark
*syscall_names
;
575 create_name_tables(LttvTraceState
*tcs
)
579 char *f_name
, *e_name
;
587 GString
*fe_name
= g_string_new("");
589 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
591 LttvAttributeValue v
;
593 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
595 g_assert(*(v
.v_pointer
) == NULL
);
596 *(v
.v_pointer
) = name_tables
;
598 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
599 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
600 for(i
= 0 ; i
< nb
; i
++) {
601 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
602 e_name
= ltt_eventtype_name(et
);
603 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
604 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
605 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
608 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
609 "syscall_id", NULL
, NULL
, NULL
, &h
);
610 t
= ltt_field_type(h
.f1
);
611 nb
= ltt_type_element_number(t
);
613 /* CHECK syscalls should be an emun but currently are not!
614 name_tables->syscall_names = g_new(GQuark, nb);
616 for(i = 0 ; i < nb ; i++) {
617 name_tables->syscall_names[i] = g_quark_from_string(
618 ltt_enum_string_get(t, i));
622 name_tables
->syscall_names
= g_new(GQuark
, 256);
623 for(i
= 0 ; i
< 256 ; i
++) {
624 g_string_printf(fe_name
, "syscall %d", i
);
625 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
628 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
629 "trap_id", NULL
, NULL
, NULL
, &h
);
630 t
= ltt_field_type(h
.f1
);
631 nb
= ltt_type_element_number(t
);
634 name_tables->trap_names = g_new(GQuark, nb);
635 for(i = 0 ; i < nb ; i++) {
636 name_tables->trap_names[i] = g_quark_from_string(
637 ltt_enum_string_get(t, i));
641 name_tables
->trap_names
= g_new(GQuark
, 256);
642 for(i
= 0 ; i
< 256 ; i
++) {
643 g_string_printf(fe_name
, "trap %d", i
);
644 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
647 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
648 "irq_id", NULL
, NULL
, NULL
, &h
);
649 t
= ltt_field_type(h
.f1
);
650 nb
= ltt_type_element_number(t
);
653 name_tables->irq_names = g_new(GQuark, nb);
654 for(i = 0 ; i < nb ; i++) {
655 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
659 name_tables
->irq_names
= g_new(GQuark
, 256);
660 for(i
= 0 ; i
< 256 ; i
++) {
661 g_string_printf(fe_name
, "irq %d", i
);
662 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
665 g_string_free(fe_name
, TRUE
);
670 get_name_tables(LttvTraceState
*tcs
)
672 LttvNameTables
*name_tables
;
674 LttvAttributeValue v
;
676 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
678 g_assert(*(v
.v_pointer
) != NULL
);
679 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
680 tcs
->eventtype_names
= name_tables
->eventtype_names
;
681 tcs
->syscall_names
= name_tables
->syscall_names
;
682 tcs
->trap_names
= name_tables
->trap_names
;
683 tcs
->irq_names
= name_tables
->irq_names
;
688 free_name_tables(LttvTraceState
*tcs
)
690 LttvNameTables
*name_tables
;
692 LttvAttributeValue v
;
694 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
696 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
697 *(v
.v_pointer
) = NULL
;
699 g_free(name_tables
->eventtype_names
);
700 g_free(name_tables
->syscall_names
);
701 g_free(name_tables
->trap_names
);
702 g_free(name_tables
->irq_names
);
707 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
710 LttvExecutionState
*es
;
712 LttvProcessState
*process
= tfs
->process
;
714 guint depth
= process
->execution_stack
->len
;
716 g_array_set_size(process
->execution_stack
, depth
+ 1);
717 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
720 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
721 es
->s
= process
->state
->s
;
726 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
728 LttvProcessState
*process
= tfs
->process
;
730 guint depth
= process
->execution_stack
->len
;
732 if(process
->state
->t
!= t
){
733 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
734 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
735 g_info("process state has %s when pop_int is %s\n",
736 g_quark_to_string(process
->state
->t
),
737 g_quark_to_string(t
));
738 g_info("{ %u, %u, %s, %s }\n",
741 g_quark_to_string(process
->name
),
742 g_quark_to_string(process
->state
->s
));
747 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
748 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
752 g_array_set_size(process
->execution_stack
, depth
- 1);
753 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
755 process
->state
->change
= tfs
->parent
.timestamp
;
760 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
763 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
765 LttvExecutionState
*es
;
767 LttvTraceContext
*tc
;
773 tc
= tfs
->parent
.t_context
;
774 tcs
= (LttvTraceState
*)tc
;
777 process
->last_cpu
= tfs
->cpu_name
;
778 g_warning("Process %u, core %p", process
->pid
, process
);
779 g_hash_table_insert(tcs
->processes
, process
, process
);
782 process
->ppid
= parent
->pid
;
783 process
->name
= parent
->name
;
784 process
->creation_time
= tfs
->parent
.timestamp
;
787 /* No parent. This process exists but we are missing all information about
788 its creation. The birth time is set to zero but we remember the time of
793 process
->name
= LTTV_STATE_UNNAMED
;
794 process
->creation_time
= ltt_time_zero
;
797 process
->insertion_time
= tfs
->parent
.timestamp
;
798 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
799 process
->creation_time
.tv_nsec
);
800 process
->pid_time
= g_quark_from_string(buffer
);
801 process
->last_cpu
= tfs
->cpu_name
;
802 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
803 sizeof(LttvExecutionState
));
804 g_array_set_size(process
->execution_stack
, 1);
805 es
= process
->state
= &g_array_index(process
->execution_stack
,
806 LttvExecutionState
, 0);
807 es
->t
= LTTV_STATE_USER_MODE
;
808 es
->n
= LTTV_STATE_SUBMODE_NONE
;
809 es
->entry
= tfs
->parent
.timestamp
;
810 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
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
);
1049 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1051 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1053 lttv_state_add_event_hooks(tss
);
1058 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1060 LttvTraceset
*traceset
= self
->parent
.ts
;
1062 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1066 LttvTracefileState
*tfs
;
1072 LttvAttributeValue val
;
1074 nb_trace
= lttv_traceset_number(traceset
);
1075 for(i
= 0 ; i
< nb_trace
; i
++) {
1076 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1078 /* Find the eventtype id for the following events and register the
1079 associated by id hooks. */
1081 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1082 g_array_set_size(hooks
, 8);
1084 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1085 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1087 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1088 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1090 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1091 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1093 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1094 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1096 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1097 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1099 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1100 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1102 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1103 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1105 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1106 "event_data1", "event_data2", process
,
1107 &g_array_index(hooks
, LttvTraceHook
, 7));
1110 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1111 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1113 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1114 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1116 /* Add these hooks to each event_by_id hooks list */
1118 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1119 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1121 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1122 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1124 for(k
= 0 ; k
< hooks
->len
; k
++) {
1125 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1126 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1127 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1130 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1131 *(val
.v_pointer
) = hooks
;
1135 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1137 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1139 lttv_state_remove_event_hooks(tss
);
1144 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1146 LttvTraceset
*traceset
= self
->parent
.ts
;
1148 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1152 LttvTracefileState
*tfs
;
1158 LttvAttributeValue val
;
1160 nb_trace
= lttv_traceset_number(traceset
);
1161 for(i
= 0 ; i
< nb_trace
; i
++) {
1162 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1163 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1164 hooks
= *(val
.v_pointer
);
1166 /* Remove these hooks from each event_by_id hooks list */
1168 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1169 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1171 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1172 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1174 for(k
= 0 ; k
< hooks
->len
; k
++) {
1175 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1176 lttv_hooks_remove_data(
1177 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1178 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1181 g_array_free(hooks
, TRUE
);
1186 static gboolean
block_start(void *hook_data
, void *call_data
)
1188 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1190 LttvTracefileState
*tfcs
;
1192 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1194 LttEventPosition
*ep
;
1196 guint i
, nb_block
, nb_event
, nb_tracefile
;
1200 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1202 LttvAttributeValue value
;
1204 ep
= ltt_event_position_new();
1205 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1206 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1208 /* Count the number of events added since the last block end in any
1211 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1212 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1213 ltt_event_position(tfcs
->parent
.e
, ep
);
1214 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1215 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1216 tfcs
->saved_position
= nb_event
;
1220 if(tcs
->nb_event
>= tcs
->save_interval
) {
1221 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1222 LTTV_STATE_SAVED_STATES
);
1223 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1224 value
= lttv_attribute_add(saved_states_tree
,
1225 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1226 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1227 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1228 *(value
.v_time
) = self
->parent
.timestamp
;
1229 lttv_state_save(tcs
, saved_state_tree
);
1231 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1232 self
->parent
.timestamp
.tv_nsec
);
1234 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1239 static gboolean
block_end(void *hook_data
, void *call_data
)
1241 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1243 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1247 LttEventPosition
*ep
;
1249 guint nb_block
, nb_event
;
1251 ep
= ltt_event_position_new();
1252 ltt_event_position(self
->parent
.e
, ep
);
1253 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1254 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1255 self
->saved_position
= 0;
1256 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1263 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1265 LttvTraceset
*traceset
= self
->parent
.ts
;
1267 guint i
, j
, nb_trace
, nb_tracefile
;
1271 LttvTracefileState
*tfs
;
1273 LttvTraceHook hook_start
, hook_end
;
1275 nb_trace
= lttv_traceset_number(traceset
);
1276 for(i
= 0 ; i
< nb_trace
; i
++) {
1277 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1278 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1279 NULL
, NULL
, block_start
, &hook_start
);
1280 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1281 NULL
, NULL
, block_end
, &hook_end
);
1283 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1284 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1286 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1287 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1288 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1289 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1290 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1291 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1296 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1298 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1300 lttv_state_save_add_event_hooks(tss
);
1306 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1308 LttvTraceset
*traceset
= self
->parent
.ts
;
1310 guint i
, j
, nb_trace
, nb_tracefile
;
1314 LttvTracefileState
*tfs
;
1316 LttvTraceHook hook_start
, hook_end
;
1318 nb_trace
= lttv_traceset_number(traceset
);
1319 for(i
= 0 ; i
< nb_trace
; i
++) {
1320 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1321 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1322 NULL
, NULL
, block_start
, &hook_start
);
1324 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1325 NULL
, NULL
, block_end
, &hook_end
);
1327 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1328 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1330 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1331 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1332 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1333 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1334 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1335 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1340 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1342 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1344 lttv_state_save_remove_event_hooks(tss
);
1349 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1351 LttvTraceset
*traceset
= self
->parent
.ts
;
1355 int min_pos
, mid_pos
, max_pos
;
1357 LttvTraceState
*tcs
;
1359 LttvAttributeValue value
;
1361 LttvAttributeType type
;
1363 LttvAttributeName name
;
1365 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1367 nb_trace
= lttv_traceset_number(traceset
);
1368 for(i
= 0 ; i
< nb_trace
; i
++) {
1369 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1371 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1372 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1373 LTTV_STATE_SAVED_STATES
);
1376 if(saved_states_tree
) {
1377 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1378 mid_pos
= max_pos
/ 2;
1379 while(min_pos
< max_pos
) {
1380 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1381 g_assert(type
== LTTV_GOBJECT
);
1382 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1383 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1385 g_assert(type
== LTTV_TIME
);
1386 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1388 closest_tree
= saved_state_tree
;
1390 else max_pos
= mid_pos
- 1;
1392 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1396 /* restore the closest earlier saved state */
1398 lttv_state_restore(tcs
, closest_tree
);
1401 /* There is no saved state, yet we want to have it. Restart at T0 */
1403 restore_init_state(tcs
);
1404 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1407 /* We want to seek quickly without restoring/updating the state */
1409 restore_init_state(tcs
);
1410 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1417 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1423 traceset_state_finalize (LttvTracesetState
*self
)
1425 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1426 finalize(G_OBJECT(self
));
1431 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1433 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1435 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1436 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1437 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1438 klass
->new_traceset_context
= new_traceset_context
;
1439 klass
->new_trace_context
= new_trace_context
;
1440 klass
->new_tracefile_context
= new_tracefile_context
;
1445 lttv_traceset_state_get_type(void)
1447 static GType type
= 0;
1449 static const GTypeInfo info
= {
1450 sizeof (LttvTracesetStateClass
),
1451 NULL
, /* base_init */
1452 NULL
, /* base_finalize */
1453 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1454 NULL
, /* class_finalize */
1455 NULL
, /* class_data */
1456 sizeof (LttvTracesetState
),
1457 0, /* n_preallocs */
1458 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1459 NULL
/* value handling */
1462 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1470 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1476 trace_state_finalize (LttvTraceState
*self
)
1478 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1479 finalize(G_OBJECT(self
));
1484 trace_state_class_init (LttvTraceStateClass
*klass
)
1486 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1488 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1489 klass
->state_save
= state_save
;
1490 klass
->state_restore
= state_restore
;
1491 klass
->state_saved_free
= state_saved_free
;
1496 lttv_trace_state_get_type(void)
1498 static GType type
= 0;
1500 static const GTypeInfo info
= {
1501 sizeof (LttvTraceStateClass
),
1502 NULL
, /* base_init */
1503 NULL
, /* base_finalize */
1504 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1505 NULL
, /* class_finalize */
1506 NULL
, /* class_data */
1507 sizeof (LttvTraceState
),
1508 0, /* n_preallocs */
1509 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1510 NULL
/* value handling */
1513 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1514 "LttvTraceStateType", &info
, 0);
1521 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1527 tracefile_state_finalize (LttvTracefileState
*self
)
1529 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1530 finalize(G_OBJECT(self
));
1535 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1537 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1539 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1544 lttv_tracefile_state_get_type(void)
1546 static GType type
= 0;
1548 static const GTypeInfo info
= {
1549 sizeof (LttvTracefileStateClass
),
1550 NULL
, /* base_init */
1551 NULL
, /* base_finalize */
1552 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1553 NULL
, /* class_finalize */
1554 NULL
, /* class_data */
1555 sizeof (LttvTracefileState
),
1556 0, /* n_preallocs */
1557 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1558 NULL
/* value handling */
1561 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1562 "LttvTracefileStateType", &info
, 0);
1568 static void module_init()
1570 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1571 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1572 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1573 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1574 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1575 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1576 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1577 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1578 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1579 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1580 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1581 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1582 LTTV_STATE_RUN
= g_quark_from_string("running");
1583 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1584 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1585 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1586 LTTV_STATE_EVENT
= g_quark_from_string("event");
1587 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1588 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1589 LTTV_STATE_TIME
= g_quark_from_string("time");
1590 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1591 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1592 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1593 g_quark_from_string("trace_state_use_count");
1596 static void module_destroy()
1601 LTTV_MODULE("state", "State computation", \
1602 "Update the system state, possibly saving it at intervals", \
1603 module_init
, module_destroy
)