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 * This function is important : it removes the dead PID entry in the hash
848 * table so there is no collision when the OS reuses PID.
850 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
852 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
853 LttvProcessState key
;
855 key
.pid
= process
->pid
;
856 key
.last_cpu
= process
->last_cpu
;
857 g_hash_table_remove(ts
->processes
, &key
);
858 g_array_free(process
->execution_stack
, TRUE
);
863 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
865 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
870 static void lttv_state_free_process_table(GHashTable
*processes
)
872 g_hash_table_foreach(processes
, free_process_state
, NULL
);
873 g_hash_table_destroy(processes
);
877 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
879 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
881 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
883 LttvExecutionSubmode submode
;
885 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
886 ltt_event_get_unsigned(s
->parent
.e
, f
)];
887 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
892 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
894 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
896 pop_state(s
, LTTV_STATE_SYSCALL
);
901 static gboolean
trap_entry(void *hook_data
, void *call_data
)
903 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
905 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
907 LttvExecutionSubmode submode
;
909 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
910 ltt_event_get_unsigned(s
->parent
.e
, f
)];
911 push_state(s
, LTTV_STATE_TRAP
, submode
);
916 static gboolean
trap_exit(void *hook_data
, void *call_data
)
918 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
920 pop_state(s
, LTTV_STATE_TRAP
);
925 static gboolean
irq_entry(void *hook_data
, void *call_data
)
927 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
929 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
931 LttvExecutionSubmode submode
;
933 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
934 ltt_event_get_unsigned(s
->parent
.e
, f
)];
936 /* Do something with the info about being in user or system mode when int? */
937 push_state(s
, LTTV_STATE_IRQ
, submode
);
942 static gboolean
irq_exit(void *hook_data
, void *call_data
)
944 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
946 pop_state(s
, LTTV_STATE_IRQ
);
951 static gboolean
schedchange(void *hook_data
, void *call_data
)
953 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
955 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
957 guint pid_in
, pid_out
, state_out
;
959 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
960 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
961 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
963 if(s
->process
!= NULL
) {
965 /* We could not know but it was not the idle process executing.
966 This should only happen at the beginning, before the first schedule
967 event, and when the initial information (current process for each CPU)
968 is missing. It is not obvious how we could, after the fact, compensate
969 the wrongly attributed statistics. */
971 if(s
->process
->pid
!= pid_out
) {
972 g_assert(s
->process
->pid
== 0);
975 if(s
->process
->state
->s
!= LTTV_STATE_EXIT
) {
976 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
977 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
978 } /* FIXME : we do not remove process here, because the kernel
979 * still has them : they may be zombies. We need to know
980 * exactly when release_task is executed on the PID to
981 * know when the zombie is destroyed. We should rename STATE_EXIT
985 // exit_process(s, s->process);
987 s
->process
->state
->change
= s
->parent
.timestamp
;
989 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
990 s
->process
->state
->s
= LTTV_STATE_RUN
;
991 s
->process
->last_cpu
= s
->cpu_name
;
992 s
->process
->state
->change
= s
->parent
.timestamp
;
997 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1004 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1006 lttv_state_create_process(s
, s
->process
, child_pid
);
1010 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
1012 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1016 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1017 lttv_state_create_process(s
, s
->process
, child_pid
);
1023 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1025 if(s
->process
!= NULL
) {
1026 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1031 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1033 if(s
->process
!= NULL
) {
1034 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1040 gboolean
process(void *hook_data
, void *call_data
)
1042 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1043 LttField
*f
= trace_hook
->f1
;
1045 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1047 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1049 /* CHECK : do not hardcode the sub_id values here ? */
1051 return process_fork(trace_hook
, s
);
1052 } else if(sub_id
== 3) {
1053 return process_exit(trace_hook
, s
);
1058 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1060 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1062 lttv_state_add_event_hooks(tss
);
1067 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1069 LttvTraceset
*traceset
= self
->parent
.ts
;
1071 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1075 LttvTracefileState
*tfs
;
1081 LttvAttributeValue val
;
1083 nb_trace
= lttv_traceset_number(traceset
);
1084 for(i
= 0 ; i
< nb_trace
; i
++) {
1085 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1087 /* Find the eventtype id for the following events and register the
1088 associated by id hooks. */
1090 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1091 g_array_set_size(hooks
, 8);
1093 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1094 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1096 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1097 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1099 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1100 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1102 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1103 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1105 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1106 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1108 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1109 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1111 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1112 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1114 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1115 "event_data1", "event_data2", process
,
1116 &g_array_index(hooks
, LttvTraceHook
, 7));
1119 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1120 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1122 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1123 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1125 /* Add these hooks to each event_by_id hooks list */
1127 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1128 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1130 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1131 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1133 for(k
= 0 ; k
< hooks
->len
; k
++) {
1134 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1135 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1136 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1139 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1140 *(val
.v_pointer
) = hooks
;
1144 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1146 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1148 lttv_state_remove_event_hooks(tss
);
1153 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1155 LttvTraceset
*traceset
= self
->parent
.ts
;
1157 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1161 LttvTracefileState
*tfs
;
1167 LttvAttributeValue val
;
1169 nb_trace
= lttv_traceset_number(traceset
);
1170 for(i
= 0 ; i
< nb_trace
; i
++) {
1171 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1172 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1173 hooks
= *(val
.v_pointer
);
1175 /* Remove these hooks from each event_by_id hooks list */
1177 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1178 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1180 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1181 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1183 for(k
= 0 ; k
< hooks
->len
; k
++) {
1184 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1185 lttv_hooks_remove_data(
1186 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1187 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1190 g_array_free(hooks
, TRUE
);
1195 static gboolean
block_start(void *hook_data
, void *call_data
)
1197 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1199 LttvTracefileState
*tfcs
;
1201 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1203 LttEventPosition
*ep
;
1205 guint i
, nb_block
, nb_event
, nb_tracefile
;
1209 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1211 LttvAttributeValue value
;
1213 ep
= ltt_event_position_new();
1214 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1215 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1217 /* Count the number of events added since the last block end in any
1220 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1221 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1222 ltt_event_position(tfcs
->parent
.e
, ep
);
1223 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1224 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1225 tfcs
->saved_position
= nb_event
;
1229 if(tcs
->nb_event
>= tcs
->save_interval
) {
1230 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1231 LTTV_STATE_SAVED_STATES
);
1232 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1233 value
= lttv_attribute_add(saved_states_tree
,
1234 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1235 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1236 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1237 *(value
.v_time
) = self
->parent
.timestamp
;
1238 lttv_state_save(tcs
, saved_state_tree
);
1240 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1241 self
->parent
.timestamp
.tv_nsec
);
1243 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1248 static gboolean
block_end(void *hook_data
, void *call_data
)
1250 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1252 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1256 LttEventPosition
*ep
;
1258 guint nb_block
, nb_event
;
1260 ep
= ltt_event_position_new();
1261 ltt_event_position(self
->parent
.e
, ep
);
1262 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1263 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1264 self
->saved_position
= 0;
1265 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1272 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1274 LttvTraceset
*traceset
= self
->parent
.ts
;
1276 guint i
, j
, nb_trace
, nb_tracefile
;
1280 LttvTracefileState
*tfs
;
1282 LttvTraceHook hook_start
, hook_end
;
1284 nb_trace
= lttv_traceset_number(traceset
);
1285 for(i
= 0 ; i
< nb_trace
; i
++) {
1286 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1287 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1288 NULL
, NULL
, block_start
, &hook_start
);
1289 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1290 NULL
, NULL
, block_end
, &hook_end
);
1292 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1293 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1295 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1296 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1297 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1298 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1299 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1300 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1305 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1307 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1309 lttv_state_save_add_event_hooks(tss
);
1315 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1317 LttvTraceset
*traceset
= self
->parent
.ts
;
1319 guint i
, j
, nb_trace
, nb_tracefile
;
1323 LttvTracefileState
*tfs
;
1325 LttvTraceHook hook_start
, hook_end
;
1327 nb_trace
= lttv_traceset_number(traceset
);
1328 for(i
= 0 ; i
< nb_trace
; i
++) {
1329 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1330 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1331 NULL
, NULL
, block_start
, &hook_start
);
1333 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1334 NULL
, NULL
, block_end
, &hook_end
);
1336 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1337 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1339 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1340 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1341 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1342 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1343 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1344 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1349 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1351 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1353 lttv_state_save_remove_event_hooks(tss
);
1358 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1360 LttvTraceset
*traceset
= self
->parent
.ts
;
1364 int min_pos
, mid_pos
, max_pos
;
1366 LttvTraceState
*tcs
;
1368 LttvAttributeValue value
;
1370 LttvAttributeType type
;
1372 LttvAttributeName name
;
1374 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1376 nb_trace
= lttv_traceset_number(traceset
);
1377 for(i
= 0 ; i
< nb_trace
; i
++) {
1378 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1380 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1381 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1382 LTTV_STATE_SAVED_STATES
);
1385 if(saved_states_tree
) {
1386 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1387 mid_pos
= max_pos
/ 2;
1388 while(min_pos
< max_pos
) {
1389 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1390 g_assert(type
== LTTV_GOBJECT
);
1391 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1392 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1394 g_assert(type
== LTTV_TIME
);
1395 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1397 closest_tree
= saved_state_tree
;
1399 else max_pos
= mid_pos
- 1;
1401 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1405 /* restore the closest earlier saved state */
1407 lttv_state_restore(tcs
, closest_tree
);
1410 /* There is no saved state, yet we want to have it. Restart at T0 */
1412 restore_init_state(tcs
);
1413 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1416 /* We want to seek quickly without restoring/updating the state */
1418 restore_init_state(tcs
);
1419 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1426 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1432 traceset_state_finalize (LttvTracesetState
*self
)
1434 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1435 finalize(G_OBJECT(self
));
1440 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1442 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1444 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1445 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1446 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1447 klass
->new_traceset_context
= new_traceset_context
;
1448 klass
->new_trace_context
= new_trace_context
;
1449 klass
->new_tracefile_context
= new_tracefile_context
;
1454 lttv_traceset_state_get_type(void)
1456 static GType type
= 0;
1458 static const GTypeInfo info
= {
1459 sizeof (LttvTracesetStateClass
),
1460 NULL
, /* base_init */
1461 NULL
, /* base_finalize */
1462 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1463 NULL
, /* class_finalize */
1464 NULL
, /* class_data */
1465 sizeof (LttvTracesetState
),
1466 0, /* n_preallocs */
1467 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1468 NULL
/* value handling */
1471 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1479 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1485 trace_state_finalize (LttvTraceState
*self
)
1487 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1488 finalize(G_OBJECT(self
));
1493 trace_state_class_init (LttvTraceStateClass
*klass
)
1495 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1497 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1498 klass
->state_save
= state_save
;
1499 klass
->state_restore
= state_restore
;
1500 klass
->state_saved_free
= state_saved_free
;
1505 lttv_trace_state_get_type(void)
1507 static GType type
= 0;
1509 static const GTypeInfo info
= {
1510 sizeof (LttvTraceStateClass
),
1511 NULL
, /* base_init */
1512 NULL
, /* base_finalize */
1513 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1514 NULL
, /* class_finalize */
1515 NULL
, /* class_data */
1516 sizeof (LttvTraceState
),
1517 0, /* n_preallocs */
1518 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1519 NULL
/* value handling */
1522 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1523 "LttvTraceStateType", &info
, 0);
1530 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1536 tracefile_state_finalize (LttvTracefileState
*self
)
1538 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1539 finalize(G_OBJECT(self
));
1544 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1546 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1548 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1553 lttv_tracefile_state_get_type(void)
1555 static GType type
= 0;
1557 static const GTypeInfo info
= {
1558 sizeof (LttvTracefileStateClass
),
1559 NULL
, /* base_init */
1560 NULL
, /* base_finalize */
1561 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1562 NULL
, /* class_finalize */
1563 NULL
, /* class_data */
1564 sizeof (LttvTracefileState
),
1565 0, /* n_preallocs */
1566 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1567 NULL
/* value handling */
1570 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1571 "LttvTracefileStateType", &info
, 0);
1577 static void module_init()
1579 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1580 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1581 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1582 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1583 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1584 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1585 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1586 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1587 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1588 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1589 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1590 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1591 LTTV_STATE_RUN
= g_quark_from_string("running");
1592 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1593 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1594 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1595 LTTV_STATE_EVENT
= g_quark_from_string("event");
1596 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1597 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1598 LTTV_STATE_TIME
= g_quark_from_string("time");
1599 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1600 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1601 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1602 g_quark_from_string("trace_state_use_count");
1605 static void module_destroy()
1610 LTTV_MODULE("state", "State computation", \
1611 "Update the system state, possibly saving it at intervals", \
1612 module_init
, module_destroy
)