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>
29 #define PREALLOCATED_EXECUTION_STACK 10
32 LTTV_STATE_MODE_UNKNOWN
,
39 LTTV_STATE_SUBMODE_UNKNOWN
,
40 LTTV_STATE_SUBMODE_NONE
;
52 LTTV_STATE_TRACEFILES
,
56 LTTV_STATE_SAVED_STATES
,
57 LTTV_STATE_SAVED_STATES_TIME
,
60 LTTV_STATE_NAME_TABLES
,
61 LTTV_STATE_TRACE_STATE_USE_COUNT
;
64 static void create_max_time(LttvTraceState
*tcs
);
66 static void get_max_time(LttvTraceState
*tcs
);
68 static void free_max_time(LttvTraceState
*tcs
);
70 static void create_name_tables(LttvTraceState
*tcs
);
72 static void get_name_tables(LttvTraceState
*tcs
);
74 static void free_name_tables(LttvTraceState
*tcs
);
76 static void free_saved_state(LttvTraceState
*tcs
);
78 static void lttv_state_free_process_table(GHashTable
*processes
);
81 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
83 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
87 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
89 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
93 void lttv_state_state_saved_free(LttvTraceState
*self
,
94 LttvAttribute
*container
)
96 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
100 guint
process_hash(gconstpointer key
)
102 guint pid
= ((const LttvProcessState
*)key
)->pid
;
103 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
107 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
109 const LttvProcessState
*process_a
, *process_b
;
111 process_a
= (const LttvProcessState
*)a
;
112 process_b
= (const LttvProcessState
*)b
;
114 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
115 if(process_a
->pid
== 0 &&
116 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
122 restore_init_state(LttvTraceState
*self
)
124 guint i
, nb_tracefile
;
126 LttvTracefileState
*tfcs
;
128 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
129 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
132 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
133 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
135 for(i
= 0 ; i
< nb_tracefile
; i
++) {
136 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
137 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
138 tfcs
->saved_position
= 0;
139 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
140 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
141 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
145 static LttTime time_zero
= {0,0};
148 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
150 guint i
, j
, nb_trace
, nb_tracefile
;
152 LttvTraceContext
*tc
;
156 LttvTracefileState
*tfcs
;
158 LttvAttributeValue v
;
160 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
161 init((LttvTracesetContext
*)self
, ts
);
163 nb_trace
= lttv_traceset_number(ts
);
164 for(i
= 0 ; i
< nb_trace
; i
++) {
165 tc
= self
->parent
.traces
[i
];
166 tcs
= (LttvTraceState
*)tc
;
167 tcs
->save_interval
= 50000;
168 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
172 if(*(v
.v_uint
) == 1) {
173 create_name_tables(tcs
);
174 create_max_time(tcs
);
176 get_name_tables(tcs
);
179 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
180 ltt_trace_per_cpu_tracefile_number(tc
->t
);
182 for(j
= 0 ; j
< nb_tracefile
; j
++) {
183 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
184 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
186 tcs
->processes
= NULL
;
187 restore_init_state(tcs
);
193 fini(LttvTracesetState
*self
)
199 LttvTracefileState
*tfcs
;
201 LttvAttributeValue v
;
203 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
204 for(i
= 0 ; i
< nb_trace
; i
++) {
205 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
206 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
209 g_assert(*(v
.v_uint
) != 0);
212 if(*(v
.v_uint
) == 0) {
213 free_name_tables(tcs
);
215 free_saved_state(tcs
);
217 lttv_state_free_process_table(tcs
->processes
);
218 tcs
->processes
= NULL
;
220 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
221 fini((LttvTracesetContext
*)self
);
225 static LttvTracesetContext
*
226 new_traceset_context(LttvTracesetContext
*self
)
228 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
232 static LttvTraceContext
*
233 new_trace_context(LttvTracesetContext
*self
)
235 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
239 static LttvTracefileContext
*
240 new_tracefile_context(LttvTracesetContext
*self
)
242 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
246 /* Write the process state of the trace */
248 static void write_process_state(gpointer key
, gpointer value
,
251 LttvProcessState
*process
;
253 LttvExecutionState
*es
;
255 FILE *fp
= (FILE *)user_data
;
259 process
= (LttvProcessState
*)value
;
261 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
262 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
263 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
264 g_quark_to_string(process
->last_cpu
));
266 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
267 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
268 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
269 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
270 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
271 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
272 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
274 fprintf(fp
, " </PROCESS>\n");
278 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
280 guint i
, nb_tracefile
, nb_block
, nb_event
;
282 LttvTracefileState
*tfcs
;
286 LttEventPosition
*ep
;
288 ep
= ltt_event_position_new();
290 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
292 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
294 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
295 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
297 for(i
= 0 ; i
< nb_tracefile
; i
++) {
298 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
299 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
300 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
301 tfcs
->parent
.timestamp
.tv_nsec
);
302 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
304 ltt_event_position(tfcs
->parent
.e
, ep
);
305 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
306 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
310 fprintf(fp
,"</PROCESS_STATE>");
314 /* Copy each process from an existing hash table to a new one */
316 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
318 LttvProcessState
*process
, *new_process
;
320 GHashTable
*new_processes
= (GHashTable
*)user_data
;
324 process
= (LttvProcessState
*)value
;
325 new_process
= g_new(LttvProcessState
, 1);
326 *new_process
= *process
;
327 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
328 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
329 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
330 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
331 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
332 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
334 new_process
->state
= &g_array_index(new_process
->execution_stack
,
335 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
336 g_hash_table_insert(new_processes
, new_process
, new_process
);
340 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
342 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
344 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
345 return new_processes
;
349 /* The saved state for each trace contains a member "processes", which
350 stores a copy of the process table, and a member "tracefiles" with
351 one entry per tracefile. Each tracefile has a "process" member pointing
352 to the current process and a "position" member storing the tracefile
353 position (needed to seek to the current "next" event. */
355 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
357 guint i
, nb_tracefile
;
359 LttvTracefileState
*tfcs
;
361 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
363 LttvAttributeType type
;
365 LttvAttributeValue value
;
367 LttvAttributeName name
;
369 LttEventPosition
*ep
;
371 tracefiles_tree
= lttv_attribute_find_subdir(container
,
372 LTTV_STATE_TRACEFILES
);
374 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
376 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
378 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
379 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
381 for(i
= 0 ; i
< nb_tracefile
; i
++) {
382 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
383 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
384 value
= lttv_attribute_add(tracefiles_tree
, i
,
386 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
387 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
389 *(value
.v_uint
) = tfcs
->process
->pid
;
390 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
392 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
394 ep
= ltt_event_position_new();
395 ltt_event_position(tfcs
->parent
.e
, ep
);
396 *(value
.v_pointer
) = ep
;
398 guint nb_block
, nb_event
;
400 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
401 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
402 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
408 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
410 guint i
, nb_tracefile
, pid
;
412 LttvTracefileState
*tfcs
;
414 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
416 LttvAttributeType type
;
418 LttvAttributeValue value
;
420 LttvAttributeName name
;
422 LttEventPosition
*ep
;
424 tracefiles_tree
= lttv_attribute_find_subdir(container
,
425 LTTV_STATE_TRACEFILES
);
427 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
429 g_assert(type
== LTTV_POINTER
);
430 lttv_state_free_process_table(self
->processes
);
431 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
433 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
434 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
436 for(i
= 0 ; i
< nb_tracefile
; i
++) {
437 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
438 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
439 g_assert(type
== LTTV_GOBJECT
);
440 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
442 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
444 g_assert(type
== LTTV_UINT
);
445 pid
= *(value
.v_uint
);
446 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
448 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
450 g_assert(type
== LTTV_POINTER
);
451 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
453 ep
= *(value
.v_pointer
);
454 g_assert(tfcs
->parent
.t_context
!= NULL
);
455 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
461 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
463 guint i
, nb_tracefile
;
465 LttvTracefileState
*tfcs
;
467 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
469 LttvAttributeType type
;
471 LttvAttributeValue value
;
473 LttvAttributeName name
;
475 LttEventPosition
*ep
;
477 tracefiles_tree
= lttv_attribute_find_subdir(container
,
478 LTTV_STATE_TRACEFILES
);
479 g_object_ref(G_OBJECT(tracefiles_tree
));
480 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
482 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
484 g_assert(type
== LTTV_POINTER
);
485 lttv_state_free_process_table(*(value
.v_pointer
));
486 *(value
.v_pointer
) = NULL
;
487 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
489 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
490 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
492 for(i
= 0 ; i
< nb_tracefile
; i
++) {
493 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
494 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
495 g_assert(type
== LTTV_GOBJECT
);
496 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
498 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
500 g_assert(type
== LTTV_POINTER
);
501 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
503 g_object_unref(G_OBJECT(tracefiles_tree
));
507 static void free_saved_state(LttvTraceState
*self
)
511 LttvAttributeType type
;
513 LttvAttributeValue value
;
515 LttvAttributeName name
;
517 LttvAttribute
*saved_states
;
519 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
520 LTTV_STATE_SAVED_STATES
);
522 nb
= lttv_attribute_get_number(saved_states
);
523 for(i
= 0 ; i
< nb
; i
++) {
524 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
525 g_assert(type
== LTTV_GOBJECT
);
526 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
529 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
534 create_max_time(LttvTraceState
*tcs
)
536 LttvAttributeValue v
;
538 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
540 g_assert(*(v
.v_pointer
) == NULL
);
541 *(v
.v_pointer
) = g_new(LttTime
,1);
542 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
547 get_max_time(LttvTraceState
*tcs
)
549 LttvAttributeValue v
;
551 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
553 g_assert(*(v
.v_pointer
) != NULL
);
554 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
559 free_max_time(LttvTraceState
*tcs
)
561 LttvAttributeValue v
;
563 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
565 g_free(*(v
.v_pointer
));
566 *(v
.v_pointer
) = NULL
;
570 typedef struct _LttvNameTables
{
571 GQuark
*eventtype_names
;
572 GQuark
*syscall_names
;
579 create_name_tables(LttvTraceState
*tcs
)
583 char *f_name
, *e_name
;
591 GString
*fe_name
= g_string_new("");
593 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
595 LttvAttributeValue v
;
597 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
599 g_assert(*(v
.v_pointer
) == NULL
);
600 *(v
.v_pointer
) = name_tables
;
602 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
603 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
604 for(i
= 0 ; i
< nb
; i
++) {
605 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
606 e_name
= ltt_eventtype_name(et
);
607 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
608 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
609 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
612 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
613 "syscall_id", NULL
, NULL
, NULL
, &h
);
614 t
= ltt_field_type(h
.f1
);
615 nb
= ltt_type_element_number(t
);
617 /* CHECK syscalls should be an emun but currently are not!
618 name_tables->syscall_names = g_new(GQuark, nb);
620 for(i = 0 ; i < nb ; i++) {
621 name_tables->syscall_names[i] = g_quark_from_string(
622 ltt_enum_string_get(t, i));
626 name_tables
->syscall_names
= g_new(GQuark
, 256);
627 for(i
= 0 ; i
< 256 ; i
++) {
628 g_string_printf(fe_name
, "syscall %d", i
);
629 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
632 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
633 "trap_id", NULL
, NULL
, NULL
, &h
);
634 t
= ltt_field_type(h
.f1
);
635 nb
= ltt_type_element_number(t
);
638 name_tables->trap_names = g_new(GQuark, nb);
639 for(i = 0 ; i < nb ; i++) {
640 name_tables->trap_names[i] = g_quark_from_string(
641 ltt_enum_string_get(t, i));
645 name_tables
->trap_names
= g_new(GQuark
, 256);
646 for(i
= 0 ; i
< 256 ; i
++) {
647 g_string_printf(fe_name
, "trap %d", i
);
648 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
651 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
652 "irq_id", NULL
, NULL
, NULL
, &h
);
653 t
= ltt_field_type(h
.f1
);
654 nb
= ltt_type_element_number(t
);
657 name_tables->irq_names = g_new(GQuark, nb);
658 for(i = 0 ; i < nb ; i++) {
659 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
663 name_tables
->irq_names
= g_new(GQuark
, 256);
664 for(i
= 0 ; i
< 256 ; i
++) {
665 g_string_printf(fe_name
, "irq %d", i
);
666 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
669 g_string_free(fe_name
, TRUE
);
674 get_name_tables(LttvTraceState
*tcs
)
676 LttvNameTables
*name_tables
;
678 LttvAttributeValue v
;
680 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
682 g_assert(*(v
.v_pointer
) != NULL
);
683 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
684 tcs
->eventtype_names
= name_tables
->eventtype_names
;
685 tcs
->syscall_names
= name_tables
->syscall_names
;
686 tcs
->trap_names
= name_tables
->trap_names
;
687 tcs
->irq_names
= name_tables
->irq_names
;
692 free_name_tables(LttvTraceState
*tcs
)
694 LttvNameTables
*name_tables
;
696 LttvAttributeValue v
;
698 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
700 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
701 *(v
.v_pointer
) = NULL
;
703 g_free(name_tables
->eventtype_names
);
704 g_free(name_tables
->syscall_names
);
705 g_free(name_tables
->trap_names
);
706 g_free(name_tables
->irq_names
);
711 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
714 LttvExecutionState
*es
;
716 LttvProcessState
*process
= tfs
->process
;
718 guint depth
= process
->execution_stack
->len
;
720 g_array_set_size(process
->execution_stack
, depth
+ 1);
721 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
724 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
725 es
->s
= process
->state
->s
;
730 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
732 LttvProcessState
*process
= tfs
->process
;
734 guint depth
= process
->execution_stack
->len
;
736 if(process
->state
->t
!= t
){
737 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
738 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
739 g_info("process state has %s when pop_int is %s\n",
740 g_quark_to_string(process
->state
->t
),
741 g_quark_to_string(t
));
742 g_info("{ %u, %u, %s, %s }\n",
745 g_quark_to_string(process
->name
),
746 g_quark_to_string(process
->state
->s
));
751 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
752 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
756 g_array_set_size(process
->execution_stack
, depth
- 1);
757 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
759 process
->state
->change
= tfs
->parent
.timestamp
;
764 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
767 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
769 LttvExecutionState
*es
;
771 LttvTraceContext
*tc
;
777 tc
= tfs
->parent
.t_context
;
778 tcs
= (LttvTraceState
*)tc
;
781 process
->last_cpu
= tfs
->cpu_name
;
782 g_warning("Process %u, core %p", process
->pid
, process
);
783 g_hash_table_insert(tcs
->processes
, process
, process
);
786 process
->ppid
= parent
->pid
;
787 process
->name
= parent
->name
;
788 process
->creation_time
= tfs
->parent
.timestamp
;
791 /* No parent. This process exists but we are missing all information about
792 its creation. The birth time is set to zero but we remember the time of
797 process
->name
= LTTV_STATE_UNNAMED
;
798 process
->creation_time
= ltt_time_zero
;
801 process
->insertion_time
= tfs
->parent
.timestamp
;
802 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
803 process
->creation_time
.tv_nsec
);
804 process
->pid_time
= g_quark_from_string(buffer
);
805 process
->last_cpu
= tfs
->cpu_name
;
806 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
807 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
808 g_array_set_size(process
->execution_stack
, 1);
809 es
= process
->state
= &g_array_index(process
->execution_stack
,
810 LttvExecutionState
, 0);
811 es
->t
= LTTV_STATE_USER_MODE
;
812 es
->n
= LTTV_STATE_SUBMODE_NONE
;
813 es
->entry
= tfs
->parent
.timestamp
;
814 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
815 es
->change
= tfs
->parent
.timestamp
;
816 es
->s
= LTTV_STATE_WAIT_FORK
;
821 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
824 LttvProcessState key
;
825 LttvProcessState
*process
;
827 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
830 key
.last_cpu
= tfs
->cpu_name
;
831 process
= g_hash_table_lookup(ts
->processes
, &key
);
836 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
838 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
840 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
844 /* FIXME : this function should be called when we receive an event telling that
845 * release_task has been called in the kernel. In happens generally when
846 * the parent waits for its child terminaison, but may also happen in special
847 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
848 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
849 * of a killed thread ground, but isn't the leader.
851 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
853 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
854 LttvProcessState key
;
856 key
.pid
= process
->pid
;
857 key
.last_cpu
= process
->last_cpu
;
858 g_hash_table_remove(ts
->processes
, &key
);
859 g_array_free(process
->execution_stack
, TRUE
);
864 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
866 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
871 static void lttv_state_free_process_table(GHashTable
*processes
)
873 g_hash_table_foreach(processes
, free_process_state
, NULL
);
874 g_hash_table_destroy(processes
);
878 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
880 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
882 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
884 LttvExecutionSubmode submode
;
886 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
887 ltt_event_get_unsigned(s
->parent
.e
, f
)];
888 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
893 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
895 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
897 pop_state(s
, LTTV_STATE_SYSCALL
);
902 static gboolean
trap_entry(void *hook_data
, void *call_data
)
904 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
906 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
908 LttvExecutionSubmode submode
;
910 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
911 ltt_event_get_unsigned(s
->parent
.e
, f
)];
912 push_state(s
, LTTV_STATE_TRAP
, submode
);
917 static gboolean
trap_exit(void *hook_data
, void *call_data
)
919 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
921 pop_state(s
, LTTV_STATE_TRAP
);
926 static gboolean
irq_entry(void *hook_data
, void *call_data
)
928 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
930 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
932 LttvExecutionSubmode submode
;
934 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
935 ltt_event_get_unsigned(s
->parent
.e
, f
)];
937 /* Do something with the info about being in user or system mode when int? */
938 push_state(s
, LTTV_STATE_IRQ
, submode
);
943 static gboolean
irq_exit(void *hook_data
, void *call_data
)
945 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
947 pop_state(s
, LTTV_STATE_IRQ
);
952 static gboolean
schedchange(void *hook_data
, void *call_data
)
954 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
956 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
958 guint pid_in
, pid_out
, state_out
;
960 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
961 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
962 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
964 if(s
->process
!= NULL
) {
966 /* We could not know but it was not the idle process executing.
967 This should only happen at the beginning, before the first schedule
968 event, and when the initial information (current process for each CPU)
969 is missing. It is not obvious how we could, after the fact, compensate
970 the wrongly attributed statistics. */
972 if(s
->process
->pid
!= pid_out
) {
973 g_assert(s
->process
->pid
== 0);
976 if(s
->process
->state
->s
== LTTV_STATE_EXIT
) {
977 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
979 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
980 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
981 } /* FIXME : we do not remove process here, because the kernel
982 * still has them : they may be zombies. We need to know
983 * exactly when release_task is executed on the PID to
984 * know when the zombie is destroyed.
987 // exit_process(s, s->process);
989 s
->process
->state
->change
= s
->parent
.timestamp
;
991 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
992 s
->process
->state
->s
= LTTV_STATE_RUN
;
993 s
->process
->last_cpu
= s
->cpu_name
;
994 s
->process
->state
->change
= s
->parent
.timestamp
;
999 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1003 LttvProcessState
*zombie_process
;
1007 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1009 zombie_process
= lttv_state_find_process(s
, child_pid
);
1011 if(zombie_process
!= NULL
) {
1012 /* Reutilisation of PID. Only now we are sure that the old PID
1013 * has been released. FIXME : sould know when release_task happens instead.
1015 exit_process(s
, zombie_process
);
1017 g_assert(s
->process
->pid
!= child_pid
);
1018 lttv_state_create_process(s
, s
->process
, child_pid
);
1024 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1026 if(s
->process
!= NULL
) {
1027 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1032 gboolean
process(void *hook_data
, void *call_data
)
1034 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1035 LttField
*f
= trace_hook
->f1
;
1037 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1039 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1041 /* CHECK : do not hardcode the sub_id values here ? */
1043 return process_fork(trace_hook
, s
);
1044 } else if(sub_id
== 3) {
1045 return process_exit(trace_hook
, s
);
1050 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1052 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1054 lttv_state_add_event_hooks(tss
);
1059 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1061 LttvTraceset
*traceset
= self
->parent
.ts
;
1063 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1067 LttvTracefileState
*tfs
;
1073 LttvAttributeValue val
;
1075 nb_trace
= lttv_traceset_number(traceset
);
1076 for(i
= 0 ; i
< nb_trace
; i
++) {
1077 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1079 /* Find the eventtype id for the following events and register the
1080 associated by id hooks. */
1082 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1083 g_array_set_size(hooks
, 8);
1085 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1086 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1088 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1089 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1091 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1092 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1094 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1095 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1097 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1098 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1100 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1101 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1103 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1104 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1106 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1107 "event_data1", "event_data2", process
,
1108 &g_array_index(hooks
, LttvTraceHook
, 7));
1111 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1112 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1114 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1115 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1117 /* Add these hooks to each event_by_id hooks list */
1119 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1120 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1122 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1123 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1125 for(k
= 0 ; k
< hooks
->len
; k
++) {
1126 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1127 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1128 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1131 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1132 *(val
.v_pointer
) = hooks
;
1136 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1138 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1140 lttv_state_remove_event_hooks(tss
);
1145 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1147 LttvTraceset
*traceset
= self
->parent
.ts
;
1149 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1153 LttvTracefileState
*tfs
;
1159 LttvAttributeValue val
;
1161 nb_trace
= lttv_traceset_number(traceset
);
1162 for(i
= 0 ; i
< nb_trace
; i
++) {
1163 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1164 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1165 hooks
= *(val
.v_pointer
);
1167 /* Remove these hooks from each event_by_id hooks list */
1169 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1170 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1172 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1173 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1175 for(k
= 0 ; k
< hooks
->len
; k
++) {
1176 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1177 lttv_hooks_remove_data(
1178 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1179 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1182 g_array_free(hooks
, TRUE
);
1187 static gboolean
block_start(void *hook_data
, void *call_data
)
1189 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1191 LttvTracefileState
*tfcs
;
1193 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1195 LttEventPosition
*ep
;
1197 guint i
, nb_block
, nb_event
, nb_tracefile
;
1201 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1203 LttvAttributeValue value
;
1205 ep
= ltt_event_position_new();
1206 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1207 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1209 /* Count the number of events added since the last block end in any
1212 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1213 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1214 ltt_event_position(tfcs
->parent
.e
, ep
);
1215 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1216 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1217 tfcs
->saved_position
= nb_event
;
1221 if(tcs
->nb_event
>= tcs
->save_interval
) {
1222 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1223 LTTV_STATE_SAVED_STATES
);
1224 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1225 value
= lttv_attribute_add(saved_states_tree
,
1226 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1227 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1228 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1229 *(value
.v_time
) = self
->parent
.timestamp
;
1230 lttv_state_save(tcs
, saved_state_tree
);
1232 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1233 self
->parent
.timestamp
.tv_nsec
);
1235 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1240 static gboolean
block_end(void *hook_data
, void *call_data
)
1242 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1244 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1248 LttEventPosition
*ep
;
1250 guint nb_block
, nb_event
;
1252 ep
= ltt_event_position_new();
1253 ltt_event_position(self
->parent
.e
, ep
);
1254 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1255 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1256 self
->saved_position
= 0;
1257 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1264 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1266 LttvTraceset
*traceset
= self
->parent
.ts
;
1268 guint i
, j
, nb_trace
, nb_tracefile
;
1272 LttvTracefileState
*tfs
;
1274 LttvTraceHook hook_start
, hook_end
;
1276 nb_trace
= lttv_traceset_number(traceset
);
1277 for(i
= 0 ; i
< nb_trace
; i
++) {
1278 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1279 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1280 NULL
, NULL
, block_start
, &hook_start
);
1281 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1282 NULL
, NULL
, block_end
, &hook_end
);
1284 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1285 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1287 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1288 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1289 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1290 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1291 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1292 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1297 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1299 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1301 lttv_state_save_add_event_hooks(tss
);
1307 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1309 LttvTraceset
*traceset
= self
->parent
.ts
;
1311 guint i
, j
, nb_trace
, nb_tracefile
;
1315 LttvTracefileState
*tfs
;
1317 LttvTraceHook hook_start
, hook_end
;
1319 nb_trace
= lttv_traceset_number(traceset
);
1320 for(i
= 0 ; i
< nb_trace
; i
++) {
1321 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1322 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1323 NULL
, NULL
, block_start
, &hook_start
);
1325 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1326 NULL
, NULL
, block_end
, &hook_end
);
1328 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1329 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1331 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1332 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1333 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1334 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1335 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1336 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1341 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1343 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1345 lttv_state_save_remove_event_hooks(tss
);
1350 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1352 LttvTraceset
*traceset
= self
->parent
.ts
;
1356 int min_pos
, mid_pos
, max_pos
;
1358 LttvTraceState
*tcs
;
1360 LttvAttributeValue value
;
1362 LttvAttributeType type
;
1364 LttvAttributeName name
;
1366 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1368 nb_trace
= lttv_traceset_number(traceset
);
1369 for(i
= 0 ; i
< nb_trace
; i
++) {
1370 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1372 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1373 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1374 LTTV_STATE_SAVED_STATES
);
1377 if(saved_states_tree
) {
1378 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1379 mid_pos
= max_pos
/ 2;
1380 while(min_pos
< max_pos
) {
1381 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1382 g_assert(type
== LTTV_GOBJECT
);
1383 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1384 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1386 g_assert(type
== LTTV_TIME
);
1387 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1389 closest_tree
= saved_state_tree
;
1391 else max_pos
= mid_pos
- 1;
1393 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1397 /* restore the closest earlier saved state */
1399 lttv_state_restore(tcs
, closest_tree
);
1402 /* There is no saved state, yet we want to have it. Restart at T0 */
1404 restore_init_state(tcs
);
1405 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1408 /* We want to seek quickly without restoring/updating the state */
1410 restore_init_state(tcs
);
1411 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1418 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1424 traceset_state_finalize (LttvTracesetState
*self
)
1426 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1427 finalize(G_OBJECT(self
));
1432 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1434 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1436 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1437 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1438 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1439 klass
->new_traceset_context
= new_traceset_context
;
1440 klass
->new_trace_context
= new_trace_context
;
1441 klass
->new_tracefile_context
= new_tracefile_context
;
1446 lttv_traceset_state_get_type(void)
1448 static GType type
= 0;
1450 static const GTypeInfo info
= {
1451 sizeof (LttvTracesetStateClass
),
1452 NULL
, /* base_init */
1453 NULL
, /* base_finalize */
1454 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1455 NULL
, /* class_finalize */
1456 NULL
, /* class_data */
1457 sizeof (LttvTracesetState
),
1458 0, /* n_preallocs */
1459 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1460 NULL
/* value handling */
1463 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1471 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1477 trace_state_finalize (LttvTraceState
*self
)
1479 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1480 finalize(G_OBJECT(self
));
1485 trace_state_class_init (LttvTraceStateClass
*klass
)
1487 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1489 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1490 klass
->state_save
= state_save
;
1491 klass
->state_restore
= state_restore
;
1492 klass
->state_saved_free
= state_saved_free
;
1497 lttv_trace_state_get_type(void)
1499 static GType type
= 0;
1501 static const GTypeInfo info
= {
1502 sizeof (LttvTraceStateClass
),
1503 NULL
, /* base_init */
1504 NULL
, /* base_finalize */
1505 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1506 NULL
, /* class_finalize */
1507 NULL
, /* class_data */
1508 sizeof (LttvTraceState
),
1509 0, /* n_preallocs */
1510 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1511 NULL
/* value handling */
1514 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1515 "LttvTraceStateType", &info
, 0);
1522 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1528 tracefile_state_finalize (LttvTracefileState
*self
)
1530 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1531 finalize(G_OBJECT(self
));
1536 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1538 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1540 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1545 lttv_tracefile_state_get_type(void)
1547 static GType type
= 0;
1549 static const GTypeInfo info
= {
1550 sizeof (LttvTracefileStateClass
),
1551 NULL
, /* base_init */
1552 NULL
, /* base_finalize */
1553 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1554 NULL
, /* class_finalize */
1555 NULL
, /* class_data */
1556 sizeof (LttvTracefileState
),
1557 0, /* n_preallocs */
1558 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1559 NULL
/* value handling */
1562 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1563 "LttvTracefileStateType", &info
, 0);
1569 static void module_init()
1571 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1572 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1573 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1574 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1575 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1576 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1577 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1578 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1579 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1580 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1581 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1582 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1583 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1584 LTTV_STATE_RUN
= g_quark_from_string("running");
1585 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1586 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1587 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1588 LTTV_STATE_EVENT
= g_quark_from_string("event");
1589 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1590 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1591 LTTV_STATE_TIME
= g_quark_from_string("time");
1592 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1593 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1594 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1595 g_quark_from_string("trace_state_use_count");
1598 static void module_destroy()
1603 LTTV_MODULE("state", "State computation", \
1604 "Update the system state, possibly saving it at intervals", \
1605 module_init
, module_destroy
)