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
;
817 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
820 LttvProcessState key
;
821 LttvProcessState
*process
;
823 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
826 key
.last_cpu
= tfs
->cpu_name
;
827 process
= g_hash_table_lookup(ts
->processes
, &key
);
832 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
834 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
836 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
840 /* FIXME : this function should be called when we receive an event telling that
841 * release_task has been called in the kernel. In happens generally when
842 * the parent waits for its child terminaison, but may also happen in special
843 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
844 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
845 * of a killed thread ground, but isn't the leader.
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(s
->process
->state
->s
!= LTTV_STATE_ZOMBIE
) {
973 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
974 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
975 } /* FIXME : we do not remove process here, because the kernel
976 * still has them : they may be zombies. We need to know
977 * exactly when release_task is executed on the PID to
978 * know when the zombie is destroyed.
981 // exit_process(s, s->process);
983 s
->process
->state
->change
= s
->parent
.timestamp
;
985 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
986 s
->process
->state
->s
= LTTV_STATE_RUN
;
987 s
->process
->last_cpu
= s
->cpu_name
;
988 s
->process
->state
->change
= s
->parent
.timestamp
;
993 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
997 LttvProcessState
*zombie_process
;
1001 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1003 zombie_process
= lttv_state_find_process(s
, child_pid
);
1005 if(zombie_process
!= NULL
) {
1006 /* Reutilisation of PID. Only now we are sure that the old PID
1007 * has been released. FIXME : sould know when release_task happens instead.
1009 exit_process(s
, zombie_process
);
1011 lttv_state_create_process(s
, s
->process
, child_pid
);
1017 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1019 if(s
->process
!= NULL
) {
1020 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1025 gboolean
process(void *hook_data
, void *call_data
)
1027 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1028 LttField
*f
= trace_hook
->f1
;
1030 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1032 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1034 /* CHECK : do not hardcode the sub_id values here ? */
1036 return process_fork(trace_hook
, s
);
1037 } else if(sub_id
== 3) {
1038 return process_exit(trace_hook
, s
);
1043 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1045 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1047 lttv_state_add_event_hooks(tss
);
1052 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1054 LttvTraceset
*traceset
= self
->parent
.ts
;
1056 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1060 LttvTracefileState
*tfs
;
1066 LttvAttributeValue val
;
1068 nb_trace
= lttv_traceset_number(traceset
);
1069 for(i
= 0 ; i
< nb_trace
; i
++) {
1070 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1072 /* Find the eventtype id for the following events and register the
1073 associated by id hooks. */
1075 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1076 g_array_set_size(hooks
, 8);
1078 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1079 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1081 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1082 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1084 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1085 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1087 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1088 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1090 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1091 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1093 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1094 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1096 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1097 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1099 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1100 "event_data1", "event_data2", process
,
1101 &g_array_index(hooks
, LttvTraceHook
, 7));
1104 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1105 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1107 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1108 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1110 /* Add these hooks to each event_by_id hooks list */
1112 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1113 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1115 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1116 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1118 for(k
= 0 ; k
< hooks
->len
; k
++) {
1119 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1120 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1121 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1124 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1125 *(val
.v_pointer
) = hooks
;
1129 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1131 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1133 lttv_state_remove_event_hooks(tss
);
1138 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1140 LttvTraceset
*traceset
= self
->parent
.ts
;
1142 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1146 LttvTracefileState
*tfs
;
1152 LttvAttributeValue val
;
1154 nb_trace
= lttv_traceset_number(traceset
);
1155 for(i
= 0 ; i
< nb_trace
; i
++) {
1156 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1157 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1158 hooks
= *(val
.v_pointer
);
1160 /* Remove these hooks from each event_by_id hooks list */
1162 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1163 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1165 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1166 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1168 for(k
= 0 ; k
< hooks
->len
; k
++) {
1169 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1170 lttv_hooks_remove_data(
1171 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1172 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1175 g_array_free(hooks
, TRUE
);
1180 static gboolean
block_start(void *hook_data
, void *call_data
)
1182 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1184 LttvTracefileState
*tfcs
;
1186 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1188 LttEventPosition
*ep
;
1190 guint i
, nb_block
, nb_event
, nb_tracefile
;
1194 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1196 LttvAttributeValue value
;
1198 ep
= ltt_event_position_new();
1199 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1200 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1202 /* Count the number of events added since the last block end in any
1205 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1206 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1207 ltt_event_position(tfcs
->parent
.e
, ep
);
1208 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1209 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1210 tfcs
->saved_position
= nb_event
;
1214 if(tcs
->nb_event
>= tcs
->save_interval
) {
1215 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1216 LTTV_STATE_SAVED_STATES
);
1217 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1218 value
= lttv_attribute_add(saved_states_tree
,
1219 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1220 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1221 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1222 *(value
.v_time
) = self
->parent
.timestamp
;
1223 lttv_state_save(tcs
, saved_state_tree
);
1225 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1226 self
->parent
.timestamp
.tv_nsec
);
1228 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1233 static gboolean
block_end(void *hook_data
, void *call_data
)
1235 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1237 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1241 LttEventPosition
*ep
;
1243 guint nb_block
, nb_event
;
1245 ep
= ltt_event_position_new();
1246 ltt_event_position(self
->parent
.e
, ep
);
1247 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1248 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1249 self
->saved_position
= 0;
1250 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1257 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1259 LttvTraceset
*traceset
= self
->parent
.ts
;
1261 guint i
, j
, nb_trace
, nb_tracefile
;
1265 LttvTracefileState
*tfs
;
1267 LttvTraceHook hook_start
, hook_end
;
1269 nb_trace
= lttv_traceset_number(traceset
);
1270 for(i
= 0 ; i
< nb_trace
; i
++) {
1271 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1272 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1273 NULL
, NULL
, block_start
, &hook_start
);
1274 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1275 NULL
, NULL
, block_end
, &hook_end
);
1277 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1278 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1280 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1281 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1282 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1283 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1284 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1285 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1290 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1292 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1294 lttv_state_save_add_event_hooks(tss
);
1300 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1302 LttvTraceset
*traceset
= self
->parent
.ts
;
1304 guint i
, j
, nb_trace
, nb_tracefile
;
1308 LttvTracefileState
*tfs
;
1310 LttvTraceHook hook_start
, hook_end
;
1312 nb_trace
= lttv_traceset_number(traceset
);
1313 for(i
= 0 ; i
< nb_trace
; i
++) {
1314 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1315 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1316 NULL
, NULL
, block_start
, &hook_start
);
1318 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1319 NULL
, NULL
, block_end
, &hook_end
);
1321 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1322 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1324 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1325 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1326 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1327 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1328 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1329 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1334 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1336 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1338 lttv_state_save_remove_event_hooks(tss
);
1343 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1345 LttvTraceset
*traceset
= self
->parent
.ts
;
1349 int min_pos
, mid_pos
, max_pos
;
1351 LttvTraceState
*tcs
;
1353 LttvAttributeValue value
;
1355 LttvAttributeType type
;
1357 LttvAttributeName name
;
1359 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1361 nb_trace
= lttv_traceset_number(traceset
);
1362 for(i
= 0 ; i
< nb_trace
; i
++) {
1363 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1365 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1366 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1367 LTTV_STATE_SAVED_STATES
);
1370 if(saved_states_tree
) {
1371 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1372 mid_pos
= max_pos
/ 2;
1373 while(min_pos
< max_pos
) {
1374 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1375 g_assert(type
== LTTV_GOBJECT
);
1376 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1377 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1379 g_assert(type
== LTTV_TIME
);
1380 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1382 closest_tree
= saved_state_tree
;
1384 else max_pos
= mid_pos
- 1;
1386 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1390 /* restore the closest earlier saved state */
1392 lttv_state_restore(tcs
, closest_tree
);
1395 /* There is no saved state, yet we want to have it. Restart at T0 */
1397 restore_init_state(tcs
);
1398 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1401 /* We want to seek quickly without restoring/updating the state */
1403 restore_init_state(tcs
);
1404 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1411 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1417 traceset_state_finalize (LttvTracesetState
*self
)
1419 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1420 finalize(G_OBJECT(self
));
1425 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1427 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1429 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1430 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1431 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1432 klass
->new_traceset_context
= new_traceset_context
;
1433 klass
->new_trace_context
= new_trace_context
;
1434 klass
->new_tracefile_context
= new_tracefile_context
;
1439 lttv_traceset_state_get_type(void)
1441 static GType type
= 0;
1443 static const GTypeInfo info
= {
1444 sizeof (LttvTracesetStateClass
),
1445 NULL
, /* base_init */
1446 NULL
, /* base_finalize */
1447 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1448 NULL
, /* class_finalize */
1449 NULL
, /* class_data */
1450 sizeof (LttvTracesetState
),
1451 0, /* n_preallocs */
1452 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1453 NULL
/* value handling */
1456 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1464 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1470 trace_state_finalize (LttvTraceState
*self
)
1472 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1473 finalize(G_OBJECT(self
));
1478 trace_state_class_init (LttvTraceStateClass
*klass
)
1480 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1482 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1483 klass
->state_save
= state_save
;
1484 klass
->state_restore
= state_restore
;
1485 klass
->state_saved_free
= state_saved_free
;
1490 lttv_trace_state_get_type(void)
1492 static GType type
= 0;
1494 static const GTypeInfo info
= {
1495 sizeof (LttvTraceStateClass
),
1496 NULL
, /* base_init */
1497 NULL
, /* base_finalize */
1498 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1499 NULL
, /* class_finalize */
1500 NULL
, /* class_data */
1501 sizeof (LttvTraceState
),
1502 0, /* n_preallocs */
1503 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1504 NULL
/* value handling */
1507 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1508 "LttvTraceStateType", &info
, 0);
1515 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1521 tracefile_state_finalize (LttvTracefileState
*self
)
1523 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1524 finalize(G_OBJECT(self
));
1529 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1531 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1533 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1538 lttv_tracefile_state_get_type(void)
1540 static GType type
= 0;
1542 static const GTypeInfo info
= {
1543 sizeof (LttvTracefileStateClass
),
1544 NULL
, /* base_init */
1545 NULL
, /* base_finalize */
1546 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1547 NULL
, /* class_finalize */
1548 NULL
, /* class_data */
1549 sizeof (LttvTracefileState
),
1550 0, /* n_preallocs */
1551 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1552 NULL
/* value handling */
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_ZOMBIE
= g_quark_from_string("zombie");
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
)