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 /* If the hash table hash function is well distributed,
108 * the process_equal should compare different pid */
109 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
111 const LttvProcessState
*process_a
, *process_b
;
114 process_a
= (const LttvProcessState
*)a
;
115 process_b
= (const LttvProcessState
*)b
;
117 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
118 else if(likely(process_a
->pid
== 0 &&
119 process_a
->last_cpu
!= process_b
->last_cpu
)) ret
= FALSE
;
126 restore_init_state(LttvTraceState
*self
)
128 guint i
, nb_tracefile
;
130 LttvTracefileState
*tfcs
;
132 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
133 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
136 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
137 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
139 for(i
= 0 ; i
< nb_tracefile
; i
++) {
140 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
141 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
142 tfcs
->saved_position
= 0;
143 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
144 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
145 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
146 tfcs
->process
->last_cpu_index
= ((LttvTracefileContext
*)tfcs
)->index
;
150 static LttTime time_zero
= {0,0};
153 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
155 guint i
, j
, nb_trace
, nb_tracefile
;
157 LttvTraceContext
*tc
;
161 LttvTracefileState
*tfcs
;
163 LttvAttributeValue v
;
165 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
166 init((LttvTracesetContext
*)self
, ts
);
168 nb_trace
= lttv_traceset_number(ts
);
169 for(i
= 0 ; i
< nb_trace
; i
++) {
170 tc
= self
->parent
.traces
[i
];
171 tcs
= (LttvTraceState
*)tc
;
172 tcs
->save_interval
= 50000;
173 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
177 if(*(v
.v_uint
) == 1) {
178 create_name_tables(tcs
);
179 create_max_time(tcs
);
181 get_name_tables(tcs
);
184 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
185 ltt_trace_per_cpu_tracefile_number(tc
->t
);
187 for(j
= 0 ; j
< nb_tracefile
; j
++) {
188 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
189 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
191 tcs
->processes
= NULL
;
192 restore_init_state(tcs
);
198 fini(LttvTracesetState
*self
)
204 LttvTracefileState
*tfcs
;
206 LttvAttributeValue v
;
208 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
209 for(i
= 0 ; i
< nb_trace
; i
++) {
210 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
211 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
214 g_assert(*(v
.v_uint
) != 0);
217 if(*(v
.v_uint
) == 0) {
218 free_name_tables(tcs
);
220 free_saved_state(tcs
);
222 lttv_state_free_process_table(tcs
->processes
);
223 tcs
->processes
= NULL
;
225 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
226 fini((LttvTracesetContext
*)self
);
230 static LttvTracesetContext
*
231 new_traceset_context(LttvTracesetContext
*self
)
233 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
237 static LttvTraceContext
*
238 new_trace_context(LttvTracesetContext
*self
)
240 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
244 static LttvTracefileContext
*
245 new_tracefile_context(LttvTracesetContext
*self
)
247 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
251 /* Write the process state of the trace */
253 static void write_process_state(gpointer key
, gpointer value
,
256 LttvProcessState
*process
;
258 LttvExecutionState
*es
;
260 FILE *fp
= (FILE *)user_data
;
264 process
= (LttvProcessState
*)value
;
266 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
267 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
268 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
269 g_quark_to_string(process
->last_cpu
));
271 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
272 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
273 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
274 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
275 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
276 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
277 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
279 fprintf(fp
, " </PROCESS>\n");
283 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
285 guint i
, nb_tracefile
, nb_block
, nb_event
;
287 LttvTracefileState
*tfcs
;
291 LttEventPosition
*ep
;
293 ep
= ltt_event_position_new();
295 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
297 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
299 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
300 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
302 for(i
= 0 ; i
< nb_tracefile
; i
++) {
303 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
304 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
305 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
306 tfcs
->parent
.timestamp
.tv_nsec
);
307 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
309 ltt_event_position(tfcs
->parent
.e
, ep
);
310 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
311 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
315 fprintf(fp
,"</PROCESS_STATE>");
319 /* Copy each process from an existing hash table to a new one */
321 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
323 LttvProcessState
*process
, *new_process
;
325 GHashTable
*new_processes
= (GHashTable
*)user_data
;
329 process
= (LttvProcessState
*)value
;
330 new_process
= g_new(LttvProcessState
, 1);
331 *new_process
= *process
;
332 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
333 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
334 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
335 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
336 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
337 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
339 new_process
->state
= &g_array_index(new_process
->execution_stack
,
340 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
341 g_hash_table_insert(new_processes
, new_process
, new_process
);
345 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
347 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
349 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
350 return new_processes
;
354 /* The saved state for each trace contains a member "processes", which
355 stores a copy of the process table, and a member "tracefiles" with
356 one entry per tracefile. Each tracefile has a "process" member pointing
357 to the current process and a "position" member storing the tracefile
358 position (needed to seek to the current "next" event. */
360 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
362 guint i
, nb_tracefile
;
364 LttvTracefileState
*tfcs
;
366 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
368 LttvAttributeType type
;
370 LttvAttributeValue value
;
372 LttvAttributeName name
;
374 LttEventPosition
*ep
;
376 tracefiles_tree
= lttv_attribute_find_subdir(container
,
377 LTTV_STATE_TRACEFILES
);
379 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
381 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
383 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
384 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
386 for(i
= 0 ; i
< nb_tracefile
; i
++) {
387 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
388 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
389 value
= lttv_attribute_add(tracefiles_tree
, i
,
391 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
392 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
394 *(value
.v_uint
) = tfcs
->process
->pid
;
395 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
397 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
399 ep
= ltt_event_position_new();
400 ltt_event_position(tfcs
->parent
.e
, ep
);
401 *(value
.v_pointer
) = ep
;
403 guint nb_block
, nb_event
;
405 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
406 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
407 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
413 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
415 guint i
, nb_tracefile
, pid
;
417 LttvTracefileState
*tfcs
;
419 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
421 LttvAttributeType type
;
423 LttvAttributeValue value
;
425 LttvAttributeName name
;
427 LttEventPosition
*ep
;
429 tracefiles_tree
= lttv_attribute_find_subdir(container
,
430 LTTV_STATE_TRACEFILES
);
432 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
434 g_assert(type
== LTTV_POINTER
);
435 lttv_state_free_process_table(self
->processes
);
436 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
438 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
439 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
441 for(i
= 0 ; i
< nb_tracefile
; i
++) {
442 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
443 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
444 g_assert(type
== LTTV_GOBJECT
);
445 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
447 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
449 g_assert(type
== LTTV_UINT
);
450 pid
= *(value
.v_uint
);
451 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
453 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
455 g_assert(type
== LTTV_POINTER
);
456 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
458 ep
= *(value
.v_pointer
);
459 g_assert(tfcs
->parent
.t_context
!= NULL
);
460 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
466 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
468 guint i
, nb_tracefile
;
470 LttvTracefileState
*tfcs
;
472 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
474 LttvAttributeType type
;
476 LttvAttributeValue value
;
478 LttvAttributeName name
;
480 LttEventPosition
*ep
;
482 tracefiles_tree
= lttv_attribute_find_subdir(container
,
483 LTTV_STATE_TRACEFILES
);
484 g_object_ref(G_OBJECT(tracefiles_tree
));
485 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
487 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
489 g_assert(type
== LTTV_POINTER
);
490 lttv_state_free_process_table(*(value
.v_pointer
));
491 *(value
.v_pointer
) = NULL
;
492 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
494 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
495 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
497 for(i
= 0 ; i
< nb_tracefile
; i
++) {
498 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
499 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
500 g_assert(type
== LTTV_GOBJECT
);
501 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
503 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
505 g_assert(type
== LTTV_POINTER
);
506 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
508 g_object_unref(G_OBJECT(tracefiles_tree
));
512 static void free_saved_state(LttvTraceState
*self
)
516 LttvAttributeType type
;
518 LttvAttributeValue value
;
520 LttvAttributeName name
;
522 LttvAttribute
*saved_states
;
524 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
525 LTTV_STATE_SAVED_STATES
);
527 nb
= lttv_attribute_get_number(saved_states
);
528 for(i
= 0 ; i
< nb
; i
++) {
529 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
530 g_assert(type
== LTTV_GOBJECT
);
531 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
534 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
539 create_max_time(LttvTraceState
*tcs
)
541 LttvAttributeValue v
;
543 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
545 g_assert(*(v
.v_pointer
) == NULL
);
546 *(v
.v_pointer
) = g_new(LttTime
,1);
547 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
552 get_max_time(LttvTraceState
*tcs
)
554 LttvAttributeValue v
;
556 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
558 g_assert(*(v
.v_pointer
) != NULL
);
559 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
564 free_max_time(LttvTraceState
*tcs
)
566 LttvAttributeValue v
;
568 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
570 g_free(*(v
.v_pointer
));
571 *(v
.v_pointer
) = NULL
;
575 typedef struct _LttvNameTables
{
576 GQuark
*eventtype_names
;
577 GQuark
*syscall_names
;
584 create_name_tables(LttvTraceState
*tcs
)
588 char *f_name
, *e_name
;
596 GString
*fe_name
= g_string_new("");
598 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
600 LttvAttributeValue v
;
602 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
604 g_assert(*(v
.v_pointer
) == NULL
);
605 *(v
.v_pointer
) = name_tables
;
607 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
608 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
609 for(i
= 0 ; i
< nb
; i
++) {
610 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
611 e_name
= ltt_eventtype_name(et
);
612 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
613 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
614 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
617 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
618 "syscall_id", NULL
, NULL
, NULL
, &h
);
619 t
= ltt_field_type(h
.f1
);
620 nb
= ltt_type_element_number(t
);
622 /* CHECK syscalls should be an emun but currently are not!
623 name_tables->syscall_names = g_new(GQuark, nb);
625 for(i = 0 ; i < nb ; i++) {
626 name_tables->syscall_names[i] = g_quark_from_string(
627 ltt_enum_string_get(t, i));
631 name_tables
->syscall_names
= g_new(GQuark
, 256);
632 for(i
= 0 ; i
< 256 ; i
++) {
633 g_string_printf(fe_name
, "syscall %d", i
);
634 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
637 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
638 "trap_id", NULL
, NULL
, NULL
, &h
);
639 t
= ltt_field_type(h
.f1
);
640 nb
= ltt_type_element_number(t
);
643 name_tables->trap_names = g_new(GQuark, nb);
644 for(i = 0 ; i < nb ; i++) {
645 name_tables->trap_names[i] = g_quark_from_string(
646 ltt_enum_string_get(t, i));
650 name_tables
->trap_names
= g_new(GQuark
, 256);
651 for(i
= 0 ; i
< 256 ; i
++) {
652 g_string_printf(fe_name
, "trap %d", i
);
653 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
656 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
657 "irq_id", NULL
, NULL
, NULL
, &h
);
658 t
= ltt_field_type(h
.f1
);
659 nb
= ltt_type_element_number(t
);
662 name_tables->irq_names = g_new(GQuark, nb);
663 for(i = 0 ; i < nb ; i++) {
664 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
668 name_tables
->irq_names
= g_new(GQuark
, 256);
669 for(i
= 0 ; i
< 256 ; i
++) {
670 g_string_printf(fe_name
, "irq %d", i
);
671 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
674 g_string_free(fe_name
, TRUE
);
679 get_name_tables(LttvTraceState
*tcs
)
681 LttvNameTables
*name_tables
;
683 LttvAttributeValue v
;
685 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
687 g_assert(*(v
.v_pointer
) != NULL
);
688 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
689 tcs
->eventtype_names
= name_tables
->eventtype_names
;
690 tcs
->syscall_names
= name_tables
->syscall_names
;
691 tcs
->trap_names
= name_tables
->trap_names
;
692 tcs
->irq_names
= name_tables
->irq_names
;
697 free_name_tables(LttvTraceState
*tcs
)
699 LttvNameTables
*name_tables
;
701 LttvAttributeValue v
;
703 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
705 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
706 *(v
.v_pointer
) = NULL
;
708 g_free(name_tables
->eventtype_names
);
709 g_free(name_tables
->syscall_names
);
710 g_free(name_tables
->trap_names
);
711 g_free(name_tables
->irq_names
);
716 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
719 LttvExecutionState
*es
;
721 LttvProcessState
*process
= tfs
->process
;
723 guint depth
= process
->execution_stack
->len
;
725 g_array_set_size(process
->execution_stack
, depth
+ 1);
726 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
729 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
730 es
->s
= process
->state
->s
;
735 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
737 LttvProcessState
*process
= tfs
->process
;
739 guint depth
= process
->execution_stack
->len
;
741 if(process
->state
->t
!= t
){
742 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
743 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
744 g_info("process state has %s when pop_int is %s\n",
745 g_quark_to_string(process
->state
->t
),
746 g_quark_to_string(t
));
747 g_info("{ %u, %u, %s, %s }\n",
750 g_quark_to_string(process
->name
),
751 g_quark_to_string(process
->state
->s
));
756 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
757 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
761 g_array_set_size(process
->execution_stack
, depth
- 1);
762 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
764 process
->state
->change
= tfs
->parent
.timestamp
;
769 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
772 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
774 LttvExecutionState
*es
;
776 LttvTraceContext
*tc
;
782 tc
= tfs
->parent
.t_context
;
783 tcs
= (LttvTraceState
*)tc
;
786 process
->last_cpu
= tfs
->cpu_name
;
787 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
788 g_warning("Process %u, core %p", process
->pid
, process
);
789 g_hash_table_insert(tcs
->processes
, process
, process
);
792 process
->ppid
= parent
->pid
;
793 process
->name
= parent
->name
;
794 process
->creation_time
= tfs
->parent
.timestamp
;
797 /* No parent. This process exists but we are missing all information about
798 its creation. The birth time is set to zero but we remember the time of
803 process
->name
= LTTV_STATE_UNNAMED
;
804 process
->creation_time
= ltt_time_zero
;
807 process
->insertion_time
= tfs
->parent
.timestamp
;
808 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
809 process
->creation_time
.tv_nsec
);
810 process
->pid_time
= g_quark_from_string(buffer
);
811 process
->last_cpu
= tfs
->cpu_name
;
812 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
813 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
814 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
815 g_array_set_size(process
->execution_stack
, 1);
816 es
= process
->state
= &g_array_index(process
->execution_stack
,
817 LttvExecutionState
, 0);
818 es
->t
= LTTV_STATE_USER_MODE
;
819 es
->n
= LTTV_STATE_SUBMODE_NONE
;
820 es
->entry
= tfs
->parent
.timestamp
;
821 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
822 es
->change
= tfs
->parent
.timestamp
;
823 es
->s
= LTTV_STATE_WAIT_FORK
;
828 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
831 LttvProcessState key
;
832 LttvProcessState
*process
;
834 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
837 key
.last_cpu
= tfs
->cpu_name
;
838 process
= g_hash_table_lookup(ts
->processes
, &key
);
843 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
845 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
847 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
851 /* FIXME : this function should be called when we receive an event telling that
852 * release_task has been called in the kernel. In happens generally when
853 * the parent waits for its child terminaison, but may also happen in special
854 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
855 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
856 * of a killed thread ground, but isn't the leader.
858 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
860 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
861 LttvProcessState key
;
863 key
.pid
= process
->pid
;
864 key
.last_cpu
= process
->last_cpu
;
865 g_hash_table_remove(ts
->processes
, &key
);
866 g_array_free(process
->execution_stack
, TRUE
);
871 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
873 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
878 static void lttv_state_free_process_table(GHashTable
*processes
)
880 g_hash_table_foreach(processes
, free_process_state
, NULL
);
881 g_hash_table_destroy(processes
);
885 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
887 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
889 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
891 LttvExecutionSubmode submode
;
893 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
894 ltt_event_get_unsigned(s
->parent
.e
, f
)];
895 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
900 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
902 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
904 pop_state(s
, LTTV_STATE_SYSCALL
);
909 static gboolean
trap_entry(void *hook_data
, void *call_data
)
911 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
913 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
915 LttvExecutionSubmode submode
;
917 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
918 ltt_event_get_unsigned(s
->parent
.e
, f
)];
919 push_state(s
, LTTV_STATE_TRAP
, submode
);
924 static gboolean
trap_exit(void *hook_data
, void *call_data
)
926 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
928 pop_state(s
, LTTV_STATE_TRAP
);
933 static gboolean
irq_entry(void *hook_data
, void *call_data
)
935 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
937 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
939 LttvExecutionSubmode submode
;
941 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
942 ltt_event_get_unsigned(s
->parent
.e
, f
)];
944 /* Do something with the info about being in user or system mode when int? */
945 push_state(s
, LTTV_STATE_IRQ
, submode
);
950 static gboolean
irq_exit(void *hook_data
, void *call_data
)
952 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
954 pop_state(s
, LTTV_STATE_IRQ
);
959 static gboolean
schedchange(void *hook_data
, void *call_data
)
961 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
963 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
965 guint pid_in
, pid_out
, state_out
;
967 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
968 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
969 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
971 if(likely(s
->process
!= NULL
)) {
973 /* We could not know but it was not the idle process executing.
974 This should only happen at the beginning, before the first schedule
975 event, and when the initial information (current process for each CPU)
976 is missing. It is not obvious how we could, after the fact, compensate
977 the wrongly attributed statistics. */
979 if(unlikely(s
->process
->pid
!= pid_out
)) {
980 g_assert(s
->process
->pid
== 0);
983 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
984 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
986 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
987 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
988 } /* FIXME : we do not remove process here, because the kernel
989 * still has them : they may be zombies. We need to know
990 * exactly when release_task is executed on the PID to
991 * know when the zombie is destroyed.
994 // exit_process(s, s->process);
996 s
->process
->state
->change
= s
->parent
.timestamp
;
998 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
999 s
->process
->state
->s
= LTTV_STATE_RUN
;
1000 s
->process
->last_cpu
= s
->cpu_name
;
1001 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1002 s
->process
->state
->change
= s
->parent
.timestamp
;
1007 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1011 LttvProcessState
*zombie_process
;
1015 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1017 zombie_process
= lttv_state_find_process(s
, child_pid
);
1019 if(unlikely(zombie_process
!= NULL
)) {
1020 /* Reutilisation of PID. Only now we are sure that the old PID
1021 * has been released. FIXME : sould know when release_task happens instead.
1023 exit_process(s
, zombie_process
);
1025 g_assert(s
->process
->pid
!= child_pid
);
1026 lttv_state_create_process(s
, s
->process
, child_pid
);
1032 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1034 if(likely(s
->process
!= NULL
)) {
1035 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1040 static gboolean
process_release(LttvTraceHook
*trace_hook
,
1041 LttvTracefileState
*s
)
1045 LttvProcessState
*process
;
1047 /* PID of the process to release */
1049 release_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1051 process
= lttv_state_find_process(s
, release_pid
);
1053 if(likely(process
!= NULL
)) {
1054 /* release_task is happening at kernel level : we can now safely release
1055 * the data structure of the process */
1056 exit_process(s
, process
);
1062 gboolean
process(void *hook_data
, void *call_data
)
1064 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1065 LttField
*f
= trace_hook
->f1
;
1067 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1069 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1071 /* CHECK : do not hardcode the sub_id values here ? */
1073 return process_fork(trace_hook
, s
);
1074 } else if(sub_id
== 3) {
1075 return process_exit(trace_hook
, s
);
1076 } else if(sub_id
== 7) {
1077 return process_release(trace_hook
, s
);
1082 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1084 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1086 lttv_state_add_event_hooks(tss
);
1091 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1093 LttvTraceset
*traceset
= self
->parent
.ts
;
1095 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1099 LttvTracefileState
*tfs
;
1105 LttvAttributeValue val
;
1107 nb_trace
= lttv_traceset_number(traceset
);
1108 for(i
= 0 ; i
< nb_trace
; i
++) {
1109 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1111 /* Find the eventtype id for the following events and register the
1112 associated by id hooks. */
1114 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1115 g_array_set_size(hooks
, 8);
1117 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1118 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1120 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1121 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1123 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1124 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1126 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1127 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1129 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1130 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1132 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1133 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1135 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1136 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1138 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1139 "event_data1", "event_data2", process
,
1140 &g_array_index(hooks
, LttvTraceHook
, 7));
1143 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1144 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1146 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1147 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1149 /* Add these hooks to each event_by_id hooks list */
1151 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1152 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1154 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1155 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1157 for(k
= 0 ; k
< hooks
->len
; k
++) {
1158 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1159 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1160 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1163 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1164 *(val
.v_pointer
) = hooks
;
1168 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1170 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1172 lttv_state_remove_event_hooks(tss
);
1177 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1179 LttvTraceset
*traceset
= self
->parent
.ts
;
1181 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1185 LttvTracefileState
*tfs
;
1191 LttvAttributeValue val
;
1193 nb_trace
= lttv_traceset_number(traceset
);
1194 for(i
= 0 ; i
< nb_trace
; i
++) {
1195 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1196 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1197 hooks
= *(val
.v_pointer
);
1199 /* Remove these hooks from each event_by_id hooks list */
1201 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1202 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1204 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1205 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1207 for(k
= 0 ; k
< hooks
->len
; k
++) {
1208 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1209 lttv_hooks_remove_data(
1210 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1211 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1214 g_array_free(hooks
, TRUE
);
1219 static gboolean
block_start(void *hook_data
, void *call_data
)
1221 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1223 LttvTracefileState
*tfcs
;
1225 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1227 LttEventPosition
*ep
;
1229 guint i
, nb_block
, nb_event
, nb_tracefile
;
1233 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1235 LttvAttributeValue value
;
1237 ep
= ltt_event_position_new();
1238 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1239 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1241 /* Count the number of events added since the last block end in any
1244 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1245 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1246 ltt_event_position(tfcs
->parent
.e
, ep
);
1247 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1248 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1249 tfcs
->saved_position
= nb_event
;
1253 if(tcs
->nb_event
>= tcs
->save_interval
) {
1254 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1255 LTTV_STATE_SAVED_STATES
);
1256 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1257 value
= lttv_attribute_add(saved_states_tree
,
1258 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1259 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1260 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1261 *(value
.v_time
) = self
->parent
.timestamp
;
1262 lttv_state_save(tcs
, saved_state_tree
);
1264 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1265 self
->parent
.timestamp
.tv_nsec
);
1267 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1272 static gboolean
block_end(void *hook_data
, void *call_data
)
1274 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1276 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1280 LttEventPosition
*ep
;
1282 guint nb_block
, nb_event
;
1284 ep
= ltt_event_position_new();
1285 ltt_event_position(self
->parent
.e
, ep
);
1286 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1287 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1288 self
->saved_position
= 0;
1289 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1296 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1298 LttvTraceset
*traceset
= self
->parent
.ts
;
1300 guint i
, j
, nb_trace
, nb_tracefile
;
1304 LttvTracefileState
*tfs
;
1306 LttvTraceHook hook_start
, hook_end
;
1308 nb_trace
= lttv_traceset_number(traceset
);
1309 for(i
= 0 ; i
< nb_trace
; i
++) {
1310 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1311 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1312 NULL
, NULL
, block_start
, &hook_start
);
1313 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1314 NULL
, NULL
, block_end
, &hook_end
);
1316 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1317 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1319 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1320 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1321 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1322 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1323 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1324 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1329 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1331 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1333 lttv_state_save_add_event_hooks(tss
);
1339 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1341 LttvTraceset
*traceset
= self
->parent
.ts
;
1343 guint i
, j
, nb_trace
, nb_tracefile
;
1347 LttvTracefileState
*tfs
;
1349 LttvTraceHook hook_start
, hook_end
;
1351 nb_trace
= lttv_traceset_number(traceset
);
1352 for(i
= 0 ; i
< nb_trace
; i
++) {
1353 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1354 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1355 NULL
, NULL
, block_start
, &hook_start
);
1357 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1358 NULL
, NULL
, block_end
, &hook_end
);
1360 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1361 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1363 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1364 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1365 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1366 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1367 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1368 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1373 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1375 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1377 lttv_state_save_remove_event_hooks(tss
);
1382 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1384 LttvTraceset
*traceset
= self
->parent
.ts
;
1388 int min_pos
, mid_pos
, max_pos
;
1390 LttvTraceState
*tcs
;
1392 LttvAttributeValue value
;
1394 LttvAttributeType type
;
1396 LttvAttributeName name
;
1398 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1400 nb_trace
= lttv_traceset_number(traceset
);
1401 for(i
= 0 ; i
< nb_trace
; i
++) {
1402 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1404 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1405 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1406 LTTV_STATE_SAVED_STATES
);
1409 if(saved_states_tree
) {
1410 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1411 mid_pos
= max_pos
/ 2;
1412 while(min_pos
< max_pos
) {
1413 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1414 g_assert(type
== LTTV_GOBJECT
);
1415 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1416 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1418 g_assert(type
== LTTV_TIME
);
1419 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1421 closest_tree
= saved_state_tree
;
1423 else max_pos
= mid_pos
- 1;
1425 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1429 /* restore the closest earlier saved state */
1431 lttv_state_restore(tcs
, closest_tree
);
1434 /* There is no saved state, yet we want to have it. Restart at T0 */
1436 restore_init_state(tcs
);
1437 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1440 /* We want to seek quickly without restoring/updating the state */
1442 restore_init_state(tcs
);
1443 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1450 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1456 traceset_state_finalize (LttvTracesetState
*self
)
1458 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1459 finalize(G_OBJECT(self
));
1464 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1466 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1468 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1469 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1470 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1471 klass
->new_traceset_context
= new_traceset_context
;
1472 klass
->new_trace_context
= new_trace_context
;
1473 klass
->new_tracefile_context
= new_tracefile_context
;
1478 lttv_traceset_state_get_type(void)
1480 static GType type
= 0;
1482 static const GTypeInfo info
= {
1483 sizeof (LttvTracesetStateClass
),
1484 NULL
, /* base_init */
1485 NULL
, /* base_finalize */
1486 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1487 NULL
, /* class_finalize */
1488 NULL
, /* class_data */
1489 sizeof (LttvTracesetState
),
1490 0, /* n_preallocs */
1491 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1492 NULL
/* value handling */
1495 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1503 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1509 trace_state_finalize (LttvTraceState
*self
)
1511 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1512 finalize(G_OBJECT(self
));
1517 trace_state_class_init (LttvTraceStateClass
*klass
)
1519 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1521 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1522 klass
->state_save
= state_save
;
1523 klass
->state_restore
= state_restore
;
1524 klass
->state_saved_free
= state_saved_free
;
1529 lttv_trace_state_get_type(void)
1531 static GType type
= 0;
1533 static const GTypeInfo info
= {
1534 sizeof (LttvTraceStateClass
),
1535 NULL
, /* base_init */
1536 NULL
, /* base_finalize */
1537 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1538 NULL
, /* class_finalize */
1539 NULL
, /* class_data */
1540 sizeof (LttvTraceState
),
1541 0, /* n_preallocs */
1542 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1543 NULL
/* value handling */
1546 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1547 "LttvTraceStateType", &info
, 0);
1554 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1560 tracefile_state_finalize (LttvTracefileState
*self
)
1562 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1563 finalize(G_OBJECT(self
));
1568 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1570 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1572 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1577 lttv_tracefile_state_get_type(void)
1579 static GType type
= 0;
1581 static const GTypeInfo info
= {
1582 sizeof (LttvTracefileStateClass
),
1583 NULL
, /* base_init */
1584 NULL
, /* base_finalize */
1585 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1586 NULL
, /* class_finalize */
1587 NULL
, /* class_data */
1588 sizeof (LttvTracefileState
),
1589 0, /* n_preallocs */
1590 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1591 NULL
/* value handling */
1594 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1595 "LttvTracefileStateType", &info
, 0);
1601 static void module_init()
1603 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1604 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1605 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1606 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1607 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1608 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1609 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1610 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1611 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1612 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1613 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1614 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1615 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1616 LTTV_STATE_RUN
= g_quark_from_string("running");
1617 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1618 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1619 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1620 LTTV_STATE_EVENT
= g_quark_from_string("event");
1621 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1622 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1623 LTTV_STATE_TIME
= g_quark_from_string("time");
1624 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1625 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1626 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1627 g_quark_from_string("trace_state_use_count");
1630 static void module_destroy()
1635 LTTV_MODULE("state", "State computation", \
1636 "Update the system state, possibly saving it at intervals", \
1637 module_init
, module_destroy
)