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 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_ZOMBIE
= g_quark_from_string("zombie");
1591 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1592 LTTV_STATE_RUN
= g_quark_from_string("running");
1593 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1594 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1595 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1596 LTTV_STATE_EVENT
= g_quark_from_string("event");
1597 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1598 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1599 LTTV_STATE_TIME
= g_quark_from_string("time");
1600 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1601 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1602 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1603 g_quark_from_string("trace_state_use_count");
1606 static void module_destroy()
1611 LTTV_MODULE("state", "State computation", \
1612 "Update the system state, possibly saving it at intervals", \
1613 module_init
, module_destroy
)