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_EXIT
) {
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. We should rename STATE_EXIT
982 // exit_process(s, s->process);
984 s
->process
->state
->change
= s
->parent
.timestamp
;
986 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
987 s
->process
->state
->s
= LTTV_STATE_RUN
;
988 s
->process
->last_cpu
= s
->cpu_name
;
989 s
->process
->state
->change
= s
->parent
.timestamp
;
994 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
998 LttvProcessState
*zombie_process
;
1002 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1004 zombie_process
= lttv_state_find_process(s
, child_pid
);
1006 if(zombie_process
!= NULL
) {
1007 /* Reutilisation of PID. Only now we are sure that the old PID
1008 * has been released. FIXME : sould know when release_task happens instead.
1010 exit_process(s
, zombie_process
);
1012 lttv_state_create_process(s
, s
->process
, child_pid
);
1018 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1020 if(s
->process
!= NULL
) {
1021 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1026 gboolean
process(void *hook_data
, void *call_data
)
1028 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1029 LttField
*f
= trace_hook
->f1
;
1031 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1033 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1035 /* CHECK : do not hardcode the sub_id values here ? */
1037 return process_fork(trace_hook
, s
);
1038 } else if(sub_id
== 3) {
1039 return process_exit(trace_hook
, s
);
1044 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1046 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1048 lttv_state_add_event_hooks(tss
);
1053 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1055 LttvTraceset
*traceset
= self
->parent
.ts
;
1057 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1061 LttvTracefileState
*tfs
;
1067 LttvAttributeValue val
;
1069 nb_trace
= lttv_traceset_number(traceset
);
1070 for(i
= 0 ; i
< nb_trace
; i
++) {
1071 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1073 /* Find the eventtype id for the following events and register the
1074 associated by id hooks. */
1076 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1077 g_array_set_size(hooks
, 8);
1079 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1080 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1082 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1083 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1085 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1086 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1088 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1089 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1091 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1092 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1094 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1095 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1097 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1098 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1100 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1101 "event_data1", "event_data2", process
,
1102 &g_array_index(hooks
, LttvTraceHook
, 7));
1105 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1106 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1108 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1109 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1111 /* Add these hooks to each event_by_id hooks list */
1113 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1114 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1116 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1117 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1119 for(k
= 0 ; k
< hooks
->len
; k
++) {
1120 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1121 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1122 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1125 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1126 *(val
.v_pointer
) = hooks
;
1130 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1132 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1134 lttv_state_remove_event_hooks(tss
);
1139 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1141 LttvTraceset
*traceset
= self
->parent
.ts
;
1143 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1147 LttvTracefileState
*tfs
;
1153 LttvAttributeValue val
;
1155 nb_trace
= lttv_traceset_number(traceset
);
1156 for(i
= 0 ; i
< nb_trace
; i
++) {
1157 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1158 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1159 hooks
= *(val
.v_pointer
);
1161 /* Remove these hooks from each event_by_id hooks list */
1163 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1164 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1166 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1167 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1169 for(k
= 0 ; k
< hooks
->len
; k
++) {
1170 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1171 lttv_hooks_remove_data(
1172 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1173 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1176 g_array_free(hooks
, TRUE
);
1181 static gboolean
block_start(void *hook_data
, void *call_data
)
1183 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1185 LttvTracefileState
*tfcs
;
1187 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1189 LttEventPosition
*ep
;
1191 guint i
, nb_block
, nb_event
, nb_tracefile
;
1195 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1197 LttvAttributeValue value
;
1199 ep
= ltt_event_position_new();
1200 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1201 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1203 /* Count the number of events added since the last block end in any
1206 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1207 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1208 ltt_event_position(tfcs
->parent
.e
, ep
);
1209 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1210 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1211 tfcs
->saved_position
= nb_event
;
1215 if(tcs
->nb_event
>= tcs
->save_interval
) {
1216 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1217 LTTV_STATE_SAVED_STATES
);
1218 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1219 value
= lttv_attribute_add(saved_states_tree
,
1220 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1221 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1222 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1223 *(value
.v_time
) = self
->parent
.timestamp
;
1224 lttv_state_save(tcs
, saved_state_tree
);
1226 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1227 self
->parent
.timestamp
.tv_nsec
);
1229 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1234 static gboolean
block_end(void *hook_data
, void *call_data
)
1236 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1238 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1242 LttEventPosition
*ep
;
1244 guint nb_block
, nb_event
;
1246 ep
= ltt_event_position_new();
1247 ltt_event_position(self
->parent
.e
, ep
);
1248 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1249 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1250 self
->saved_position
= 0;
1251 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1258 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1260 LttvTraceset
*traceset
= self
->parent
.ts
;
1262 guint i
, j
, nb_trace
, nb_tracefile
;
1266 LttvTracefileState
*tfs
;
1268 LttvTraceHook hook_start
, hook_end
;
1270 nb_trace
= lttv_traceset_number(traceset
);
1271 for(i
= 0 ; i
< nb_trace
; i
++) {
1272 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1273 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1274 NULL
, NULL
, block_start
, &hook_start
);
1275 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1276 NULL
, NULL
, block_end
, &hook_end
);
1278 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1279 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1281 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1282 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1283 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1284 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1285 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1286 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1291 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1293 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1295 lttv_state_save_add_event_hooks(tss
);
1301 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1303 LttvTraceset
*traceset
= self
->parent
.ts
;
1305 guint i
, j
, nb_trace
, nb_tracefile
;
1309 LttvTracefileState
*tfs
;
1311 LttvTraceHook hook_start
, hook_end
;
1313 nb_trace
= lttv_traceset_number(traceset
);
1314 for(i
= 0 ; i
< nb_trace
; i
++) {
1315 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1316 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1317 NULL
, NULL
, block_start
, &hook_start
);
1319 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1320 NULL
, NULL
, block_end
, &hook_end
);
1322 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1323 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1325 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1326 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1327 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1328 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1329 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1330 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1335 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1337 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1339 lttv_state_save_remove_event_hooks(tss
);
1344 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1346 LttvTraceset
*traceset
= self
->parent
.ts
;
1350 int min_pos
, mid_pos
, max_pos
;
1352 LttvTraceState
*tcs
;
1354 LttvAttributeValue value
;
1356 LttvAttributeType type
;
1358 LttvAttributeName name
;
1360 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1362 nb_trace
= lttv_traceset_number(traceset
);
1363 for(i
= 0 ; i
< nb_trace
; i
++) {
1364 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1366 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1367 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1368 LTTV_STATE_SAVED_STATES
);
1371 if(saved_states_tree
) {
1372 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1373 mid_pos
= max_pos
/ 2;
1374 while(min_pos
< max_pos
) {
1375 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1376 g_assert(type
== LTTV_GOBJECT
);
1377 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1378 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1380 g_assert(type
== LTTV_TIME
);
1381 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1383 closest_tree
= saved_state_tree
;
1385 else max_pos
= mid_pos
- 1;
1387 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1391 /* restore the closest earlier saved state */
1393 lttv_state_restore(tcs
, closest_tree
);
1396 /* There is no saved state, yet we want to have it. Restart at T0 */
1398 restore_init_state(tcs
);
1399 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1402 /* We want to seek quickly without restoring/updating the state */
1404 restore_init_state(tcs
);
1405 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1412 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1418 traceset_state_finalize (LttvTracesetState
*self
)
1420 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1421 finalize(G_OBJECT(self
));
1426 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1428 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1430 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1431 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1432 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1433 klass
->new_traceset_context
= new_traceset_context
;
1434 klass
->new_trace_context
= new_trace_context
;
1435 klass
->new_tracefile_context
= new_tracefile_context
;
1440 lttv_traceset_state_get_type(void)
1442 static GType type
= 0;
1444 static const GTypeInfo info
= {
1445 sizeof (LttvTracesetStateClass
),
1446 NULL
, /* base_init */
1447 NULL
, /* base_finalize */
1448 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1449 NULL
, /* class_finalize */
1450 NULL
, /* class_data */
1451 sizeof (LttvTracesetState
),
1452 0, /* n_preallocs */
1453 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1454 NULL
/* value handling */
1457 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1465 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1471 trace_state_finalize (LttvTraceState
*self
)
1473 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1474 finalize(G_OBJECT(self
));
1479 trace_state_class_init (LttvTraceStateClass
*klass
)
1481 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1483 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1484 klass
->state_save
= state_save
;
1485 klass
->state_restore
= state_restore
;
1486 klass
->state_saved_free
= state_saved_free
;
1491 lttv_trace_state_get_type(void)
1493 static GType type
= 0;
1495 static const GTypeInfo info
= {
1496 sizeof (LttvTraceStateClass
),
1497 NULL
, /* base_init */
1498 NULL
, /* base_finalize */
1499 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1500 NULL
, /* class_finalize */
1501 NULL
, /* class_data */
1502 sizeof (LttvTraceState
),
1503 0, /* n_preallocs */
1504 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1505 NULL
/* value handling */
1508 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1509 "LttvTraceStateType", &info
, 0);
1516 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1522 tracefile_state_finalize (LttvTracefileState
*self
)
1524 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1525 finalize(G_OBJECT(self
));
1530 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1532 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1534 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1539 lttv_tracefile_state_get_type(void)
1541 static GType type
= 0;
1543 static const GTypeInfo info
= {
1544 sizeof (LttvTracefileStateClass
),
1545 NULL
, /* base_init */
1546 NULL
, /* base_finalize */
1547 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1548 NULL
, /* class_finalize */
1549 NULL
, /* class_data */
1550 sizeof (LttvTracefileState
),
1551 0, /* n_preallocs */
1552 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1553 NULL
/* value handling */
1556 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1557 "LttvTracefileStateType", &info
, 0);
1563 static void module_init()
1565 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1566 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1567 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1568 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1569 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1570 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1571 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1572 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1573 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1574 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1575 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1576 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1577 LTTV_STATE_RUN
= g_quark_from_string("running");
1578 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1579 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1580 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1581 LTTV_STATE_EVENT
= g_quark_from_string("event");
1582 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1583 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1584 LTTV_STATE_TIME
= g_quark_from_string("time");
1585 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1586 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1587 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1588 g_quark_from_string("trace_state_use_count");
1591 static void module_destroy()
1596 LTTV_MODULE("state", "State computation", \
1597 "Update the system state, possibly saving it at intervals", \
1598 module_init
, module_destroy
)