1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 #include <lttv/lttv.h>
21 #include <lttv/module.h>
22 #include <lttv/state.h>
23 #include <ltt/facility.h>
24 #include <ltt/trace.h>
25 #include <ltt/event.h>
29 #define PREALLOCATED_EXECUTION_STACK 10
32 LTTV_STATE_MODE_UNKNOWN
,
39 LTTV_STATE_SUBMODE_UNKNOWN
,
40 LTTV_STATE_SUBMODE_NONE
;
52 LTTV_STATE_TRACEFILES
,
56 LTTV_STATE_SAVED_STATES
,
57 LTTV_STATE_SAVED_STATES_TIME
,
60 LTTV_STATE_NAME_TABLES
,
61 LTTV_STATE_TRACE_STATE_USE_COUNT
;
64 static void create_max_time(LttvTraceState
*tcs
);
66 static void get_max_time(LttvTraceState
*tcs
);
68 static void free_max_time(LttvTraceState
*tcs
);
70 static void create_name_tables(LttvTraceState
*tcs
);
72 static void get_name_tables(LttvTraceState
*tcs
);
74 static void free_name_tables(LttvTraceState
*tcs
);
76 static void free_saved_state(LttvTraceState
*tcs
);
78 static void lttv_state_free_process_table(GHashTable
*processes
);
81 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
83 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
87 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
89 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
93 void lttv_state_state_saved_free(LttvTraceState
*self
,
94 LttvAttribute
*container
)
96 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
100 guint
process_hash(gconstpointer key
)
102 guint pid
= ((const LttvProcessState
*)key
)->pid
;
103 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
107 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
109 const LttvProcessState
*process_a
, *process_b
;
111 process_a
= (const LttvProcessState
*)a
;
112 process_b
= (const LttvProcessState
*)b
;
114 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
115 if(process_a
->pid
== 0 &&
116 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
122 restore_init_state(LttvTraceState
*self
)
124 guint i
, nb_tracefile
;
126 LttvTracefileState
*tfcs
;
128 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
129 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
132 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
133 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
135 for(i
= 0 ; i
< nb_tracefile
; i
++) {
136 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
137 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
138 tfcs
->saved_position
= 0;
139 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
140 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
141 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
142 tfcs
->process
->last_cpu_index
= ((LttvTracefileContext
*)tfcs
)->index
;
146 static LttTime time_zero
= {0,0};
149 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
151 guint i
, j
, nb_trace
, nb_tracefile
;
153 LttvTraceContext
*tc
;
157 LttvTracefileState
*tfcs
;
159 LttvAttributeValue v
;
161 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
162 init((LttvTracesetContext
*)self
, ts
);
164 nb_trace
= lttv_traceset_number(ts
);
165 for(i
= 0 ; i
< nb_trace
; i
++) {
166 tc
= self
->parent
.traces
[i
];
167 tcs
= (LttvTraceState
*)tc
;
168 tcs
->save_interval
= 50000;
169 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
173 if(*(v
.v_uint
) == 1) {
174 create_name_tables(tcs
);
175 create_max_time(tcs
);
177 get_name_tables(tcs
);
180 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
181 ltt_trace_per_cpu_tracefile_number(tc
->t
);
183 for(j
= 0 ; j
< nb_tracefile
; j
++) {
184 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
185 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
187 tcs
->processes
= NULL
;
188 restore_init_state(tcs
);
194 fini(LttvTracesetState
*self
)
200 LttvTracefileState
*tfcs
;
202 LttvAttributeValue v
;
204 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
205 for(i
= 0 ; i
< nb_trace
; i
++) {
206 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
207 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
210 g_assert(*(v
.v_uint
) != 0);
213 if(*(v
.v_uint
) == 0) {
214 free_name_tables(tcs
);
216 free_saved_state(tcs
);
218 lttv_state_free_process_table(tcs
->processes
);
219 tcs
->processes
= NULL
;
221 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
222 fini((LttvTracesetContext
*)self
);
226 static LttvTracesetContext
*
227 new_traceset_context(LttvTracesetContext
*self
)
229 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
233 static LttvTraceContext
*
234 new_trace_context(LttvTracesetContext
*self
)
236 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
240 static LttvTracefileContext
*
241 new_tracefile_context(LttvTracesetContext
*self
)
243 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
247 /* Write the process state of the trace */
249 static void write_process_state(gpointer key
, gpointer value
,
252 LttvProcessState
*process
;
254 LttvExecutionState
*es
;
256 FILE *fp
= (FILE *)user_data
;
260 process
= (LttvProcessState
*)value
;
262 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
263 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
264 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
265 g_quark_to_string(process
->last_cpu
));
267 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
268 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
269 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
270 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
271 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
272 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
273 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
275 fprintf(fp
, " </PROCESS>\n");
279 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
281 guint i
, nb_tracefile
, nb_block
, nb_event
;
283 LttvTracefileState
*tfcs
;
287 LttEventPosition
*ep
;
289 ep
= ltt_event_position_new();
291 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
293 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
295 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
296 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
298 for(i
= 0 ; i
< nb_tracefile
; i
++) {
299 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
300 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
301 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
302 tfcs
->parent
.timestamp
.tv_nsec
);
303 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
305 ltt_event_position(tfcs
->parent
.e
, ep
);
306 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
307 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
311 fprintf(fp
,"</PROCESS_STATE>");
315 /* Copy each process from an existing hash table to a new one */
317 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
319 LttvProcessState
*process
, *new_process
;
321 GHashTable
*new_processes
= (GHashTable
*)user_data
;
325 process
= (LttvProcessState
*)value
;
326 new_process
= g_new(LttvProcessState
, 1);
327 *new_process
= *process
;
328 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
329 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
330 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
331 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
332 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
333 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
335 new_process
->state
= &g_array_index(new_process
->execution_stack
,
336 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
337 g_hash_table_insert(new_processes
, new_process
, new_process
);
341 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
343 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
345 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
346 return new_processes
;
350 /* The saved state for each trace contains a member "processes", which
351 stores a copy of the process table, and a member "tracefiles" with
352 one entry per tracefile. Each tracefile has a "process" member pointing
353 to the current process and a "position" member storing the tracefile
354 position (needed to seek to the current "next" event. */
356 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
358 guint i
, nb_tracefile
;
360 LttvTracefileState
*tfcs
;
362 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
364 LttvAttributeType type
;
366 LttvAttributeValue value
;
368 LttvAttributeName name
;
370 LttEventPosition
*ep
;
372 tracefiles_tree
= lttv_attribute_find_subdir(container
,
373 LTTV_STATE_TRACEFILES
);
375 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
377 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
379 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
380 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
382 for(i
= 0 ; i
< nb_tracefile
; i
++) {
383 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
384 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
385 value
= lttv_attribute_add(tracefiles_tree
, i
,
387 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
388 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
390 *(value
.v_uint
) = tfcs
->process
->pid
;
391 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
393 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
395 ep
= ltt_event_position_new();
396 ltt_event_position(tfcs
->parent
.e
, ep
);
397 *(value
.v_pointer
) = ep
;
399 guint nb_block
, nb_event
;
401 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
402 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
403 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
409 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
411 guint i
, nb_tracefile
, pid
;
413 LttvTracefileState
*tfcs
;
415 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
417 LttvAttributeType type
;
419 LttvAttributeValue value
;
421 LttvAttributeName name
;
423 LttEventPosition
*ep
;
425 tracefiles_tree
= lttv_attribute_find_subdir(container
,
426 LTTV_STATE_TRACEFILES
);
428 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
430 g_assert(type
== LTTV_POINTER
);
431 lttv_state_free_process_table(self
->processes
);
432 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
434 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
435 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
437 for(i
= 0 ; i
< nb_tracefile
; i
++) {
438 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
439 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
440 g_assert(type
== LTTV_GOBJECT
);
441 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
443 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
445 g_assert(type
== LTTV_UINT
);
446 pid
= *(value
.v_uint
);
447 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
449 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
451 g_assert(type
== LTTV_POINTER
);
452 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
454 ep
= *(value
.v_pointer
);
455 g_assert(tfcs
->parent
.t_context
!= NULL
);
456 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
462 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
464 guint i
, nb_tracefile
;
466 LttvTracefileState
*tfcs
;
468 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
470 LttvAttributeType type
;
472 LttvAttributeValue value
;
474 LttvAttributeName name
;
476 LttEventPosition
*ep
;
478 tracefiles_tree
= lttv_attribute_find_subdir(container
,
479 LTTV_STATE_TRACEFILES
);
480 g_object_ref(G_OBJECT(tracefiles_tree
));
481 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
483 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
485 g_assert(type
== LTTV_POINTER
);
486 lttv_state_free_process_table(*(value
.v_pointer
));
487 *(value
.v_pointer
) = NULL
;
488 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
490 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
491 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
493 for(i
= 0 ; i
< nb_tracefile
; i
++) {
494 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
495 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
496 g_assert(type
== LTTV_GOBJECT
);
497 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
499 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
501 g_assert(type
== LTTV_POINTER
);
502 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
504 g_object_unref(G_OBJECT(tracefiles_tree
));
508 static void free_saved_state(LttvTraceState
*self
)
512 LttvAttributeType type
;
514 LttvAttributeValue value
;
516 LttvAttributeName name
;
518 LttvAttribute
*saved_states
;
520 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
521 LTTV_STATE_SAVED_STATES
);
523 nb
= lttv_attribute_get_number(saved_states
);
524 for(i
= 0 ; i
< nb
; i
++) {
525 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
526 g_assert(type
== LTTV_GOBJECT
);
527 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
530 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
535 create_max_time(LttvTraceState
*tcs
)
537 LttvAttributeValue v
;
539 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
541 g_assert(*(v
.v_pointer
) == NULL
);
542 *(v
.v_pointer
) = g_new(LttTime
,1);
543 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
548 get_max_time(LttvTraceState
*tcs
)
550 LttvAttributeValue v
;
552 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
554 g_assert(*(v
.v_pointer
) != NULL
);
555 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
560 free_max_time(LttvTraceState
*tcs
)
562 LttvAttributeValue v
;
564 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
566 g_free(*(v
.v_pointer
));
567 *(v
.v_pointer
) = NULL
;
571 typedef struct _LttvNameTables
{
572 GQuark
*eventtype_names
;
573 GQuark
*syscall_names
;
580 create_name_tables(LttvTraceState
*tcs
)
584 char *f_name
, *e_name
;
592 GString
*fe_name
= g_string_new("");
594 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
596 LttvAttributeValue v
;
598 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
600 g_assert(*(v
.v_pointer
) == NULL
);
601 *(v
.v_pointer
) = name_tables
;
603 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
604 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
605 for(i
= 0 ; i
< nb
; i
++) {
606 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
607 e_name
= ltt_eventtype_name(et
);
608 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
609 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
610 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
613 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
614 "syscall_id", NULL
, NULL
, NULL
, &h
);
615 t
= ltt_field_type(h
.f1
);
616 nb
= ltt_type_element_number(t
);
618 /* CHECK syscalls should be an emun but currently are not!
619 name_tables->syscall_names = g_new(GQuark, nb);
621 for(i = 0 ; i < nb ; i++) {
622 name_tables->syscall_names[i] = g_quark_from_string(
623 ltt_enum_string_get(t, i));
627 name_tables
->syscall_names
= g_new(GQuark
, 256);
628 for(i
= 0 ; i
< 256 ; i
++) {
629 g_string_printf(fe_name
, "syscall %d", i
);
630 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
633 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
634 "trap_id", NULL
, NULL
, NULL
, &h
);
635 t
= ltt_field_type(h
.f1
);
636 nb
= ltt_type_element_number(t
);
639 name_tables->trap_names = g_new(GQuark, nb);
640 for(i = 0 ; i < nb ; i++) {
641 name_tables->trap_names[i] = g_quark_from_string(
642 ltt_enum_string_get(t, i));
646 name_tables
->trap_names
= g_new(GQuark
, 256);
647 for(i
= 0 ; i
< 256 ; i
++) {
648 g_string_printf(fe_name
, "trap %d", i
);
649 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
652 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
653 "irq_id", NULL
, NULL
, NULL
, &h
);
654 t
= ltt_field_type(h
.f1
);
655 nb
= ltt_type_element_number(t
);
658 name_tables->irq_names = g_new(GQuark, nb);
659 for(i = 0 ; i < nb ; i++) {
660 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
664 name_tables
->irq_names
= g_new(GQuark
, 256);
665 for(i
= 0 ; i
< 256 ; i
++) {
666 g_string_printf(fe_name
, "irq %d", i
);
667 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
670 g_string_free(fe_name
, TRUE
);
675 get_name_tables(LttvTraceState
*tcs
)
677 LttvNameTables
*name_tables
;
679 LttvAttributeValue v
;
681 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
683 g_assert(*(v
.v_pointer
) != NULL
);
684 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
685 tcs
->eventtype_names
= name_tables
->eventtype_names
;
686 tcs
->syscall_names
= name_tables
->syscall_names
;
687 tcs
->trap_names
= name_tables
->trap_names
;
688 tcs
->irq_names
= name_tables
->irq_names
;
693 free_name_tables(LttvTraceState
*tcs
)
695 LttvNameTables
*name_tables
;
697 LttvAttributeValue v
;
699 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
701 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
702 *(v
.v_pointer
) = NULL
;
704 g_free(name_tables
->eventtype_names
);
705 g_free(name_tables
->syscall_names
);
706 g_free(name_tables
->trap_names
);
707 g_free(name_tables
->irq_names
);
712 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
715 LttvExecutionState
*es
;
717 LttvProcessState
*process
= tfs
->process
;
719 guint depth
= process
->execution_stack
->len
;
721 g_array_set_size(process
->execution_stack
, depth
+ 1);
722 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
725 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
726 es
->s
= process
->state
->s
;
731 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
733 LttvProcessState
*process
= tfs
->process
;
735 guint depth
= process
->execution_stack
->len
;
737 if(process
->state
->t
!= t
){
738 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
739 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
740 g_info("process state has %s when pop_int is %s\n",
741 g_quark_to_string(process
->state
->t
),
742 g_quark_to_string(t
));
743 g_info("{ %u, %u, %s, %s }\n",
746 g_quark_to_string(process
->name
),
747 g_quark_to_string(process
->state
->s
));
752 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
753 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
757 g_array_set_size(process
->execution_stack
, depth
- 1);
758 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
760 process
->state
->change
= tfs
->parent
.timestamp
;
765 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
768 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
770 LttvExecutionState
*es
;
772 LttvTraceContext
*tc
;
778 tc
= tfs
->parent
.t_context
;
779 tcs
= (LttvTraceState
*)tc
;
782 process
->last_cpu
= tfs
->cpu_name
;
783 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
784 g_warning("Process %u, core %p", process
->pid
, process
);
785 g_hash_table_insert(tcs
->processes
, process
, process
);
788 process
->ppid
= parent
->pid
;
789 process
->name
= parent
->name
;
790 process
->creation_time
= tfs
->parent
.timestamp
;
793 /* No parent. This process exists but we are missing all information about
794 its creation. The birth time is set to zero but we remember the time of
799 process
->name
= LTTV_STATE_UNNAMED
;
800 process
->creation_time
= ltt_time_zero
;
803 process
->insertion_time
= tfs
->parent
.timestamp
;
804 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
805 process
->creation_time
.tv_nsec
);
806 process
->pid_time
= g_quark_from_string(buffer
);
807 process
->last_cpu
= tfs
->cpu_name
;
808 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
809 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
810 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
811 g_array_set_size(process
->execution_stack
, 1);
812 es
= process
->state
= &g_array_index(process
->execution_stack
,
813 LttvExecutionState
, 0);
814 es
->t
= LTTV_STATE_USER_MODE
;
815 es
->n
= LTTV_STATE_SUBMODE_NONE
;
816 es
->entry
= tfs
->parent
.timestamp
;
817 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
818 es
->change
= tfs
->parent
.timestamp
;
819 es
->s
= LTTV_STATE_WAIT_FORK
;
824 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
827 LttvProcessState key
;
828 LttvProcessState
*process
;
830 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
833 key
.last_cpu
= tfs
->cpu_name
;
834 process
= g_hash_table_lookup(ts
->processes
, &key
);
839 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
841 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
843 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
847 /* FIXME : this function should be called when we receive an event telling that
848 * release_task has been called in the kernel. In happens generally when
849 * the parent waits for its child terminaison, but may also happen in special
850 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
851 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
852 * of a killed thread ground, but isn't the leader.
854 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
856 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
857 LttvProcessState key
;
859 key
.pid
= process
->pid
;
860 key
.last_cpu
= process
->last_cpu
;
861 g_hash_table_remove(ts
->processes
, &key
);
862 g_array_free(process
->execution_stack
, TRUE
);
867 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
869 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
874 static void lttv_state_free_process_table(GHashTable
*processes
)
876 g_hash_table_foreach(processes
, free_process_state
, NULL
);
877 g_hash_table_destroy(processes
);
881 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
883 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
885 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
887 LttvExecutionSubmode submode
;
889 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
890 ltt_event_get_unsigned(s
->parent
.e
, f
)];
891 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
896 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
898 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
900 pop_state(s
, LTTV_STATE_SYSCALL
);
905 static gboolean
trap_entry(void *hook_data
, void *call_data
)
907 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
909 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
911 LttvExecutionSubmode submode
;
913 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
914 ltt_event_get_unsigned(s
->parent
.e
, f
)];
915 push_state(s
, LTTV_STATE_TRAP
, submode
);
920 static gboolean
trap_exit(void *hook_data
, void *call_data
)
922 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
924 pop_state(s
, LTTV_STATE_TRAP
);
929 static gboolean
irq_entry(void *hook_data
, void *call_data
)
931 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
933 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
935 LttvExecutionSubmode submode
;
937 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
938 ltt_event_get_unsigned(s
->parent
.e
, f
)];
940 /* Do something with the info about being in user or system mode when int? */
941 push_state(s
, LTTV_STATE_IRQ
, submode
);
946 static gboolean
irq_exit(void *hook_data
, void *call_data
)
948 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
950 pop_state(s
, LTTV_STATE_IRQ
);
955 static gboolean
schedchange(void *hook_data
, void *call_data
)
957 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
959 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
961 guint pid_in
, pid_out
, state_out
;
963 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
964 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
965 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
967 if(s
->process
!= NULL
) {
969 /* We could not know but it was not the idle process executing.
970 This should only happen at the beginning, before the first schedule
971 event, and when the initial information (current process for each CPU)
972 is missing. It is not obvious how we could, after the fact, compensate
973 the wrongly attributed statistics. */
975 if(s
->process
->pid
!= pid_out
) {
976 g_assert(s
->process
->pid
== 0);
979 if(s
->process
->state
->s
== LTTV_STATE_EXIT
) {
980 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
982 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
983 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
984 } /* FIXME : we do not remove process here, because the kernel
985 * still has them : they may be zombies. We need to know
986 * exactly when release_task is executed on the PID to
987 * know when the zombie is destroyed.
990 // exit_process(s, s->process);
992 s
->process
->state
->change
= s
->parent
.timestamp
;
994 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
995 s
->process
->state
->s
= LTTV_STATE_RUN
;
996 s
->process
->last_cpu
= s
->cpu_name
;
997 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
998 s
->process
->state
->change
= s
->parent
.timestamp
;
1003 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1007 LttvProcessState
*zombie_process
;
1011 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1013 zombie_process
= lttv_state_find_process(s
, child_pid
);
1015 if(zombie_process
!= NULL
) {
1016 /* Reutilisation of PID. Only now we are sure that the old PID
1017 * has been released. FIXME : sould know when release_task happens instead.
1019 exit_process(s
, zombie_process
);
1021 g_assert(s
->process
->pid
!= child_pid
);
1022 lttv_state_create_process(s
, s
->process
, child_pid
);
1028 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1030 if(s
->process
!= NULL
) {
1031 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1036 gboolean
process(void *hook_data
, void *call_data
)
1038 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1039 LttField
*f
= trace_hook
->f1
;
1041 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1043 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1045 /* CHECK : do not hardcode the sub_id values here ? */
1047 return process_fork(trace_hook
, s
);
1048 } else if(sub_id
== 3) {
1049 return process_exit(trace_hook
, s
);
1054 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1056 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1058 lttv_state_add_event_hooks(tss
);
1063 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1065 LttvTraceset
*traceset
= self
->parent
.ts
;
1067 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1071 LttvTracefileState
*tfs
;
1077 LttvAttributeValue val
;
1079 nb_trace
= lttv_traceset_number(traceset
);
1080 for(i
= 0 ; i
< nb_trace
; i
++) {
1081 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1083 /* Find the eventtype id for the following events and register the
1084 associated by id hooks. */
1086 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1087 g_array_set_size(hooks
, 8);
1089 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1090 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1092 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1093 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1095 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1096 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1098 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1099 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1101 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1102 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1104 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1105 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1107 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1108 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1110 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1111 "event_data1", "event_data2", process
,
1112 &g_array_index(hooks
, LttvTraceHook
, 7));
1115 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1116 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1118 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1119 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1121 /* Add these hooks to each event_by_id hooks list */
1123 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1124 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1126 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1127 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1129 for(k
= 0 ; k
< hooks
->len
; k
++) {
1130 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1131 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1132 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1135 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1136 *(val
.v_pointer
) = hooks
;
1140 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1142 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1144 lttv_state_remove_event_hooks(tss
);
1149 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1151 LttvTraceset
*traceset
= self
->parent
.ts
;
1153 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1157 LttvTracefileState
*tfs
;
1163 LttvAttributeValue val
;
1165 nb_trace
= lttv_traceset_number(traceset
);
1166 for(i
= 0 ; i
< nb_trace
; i
++) {
1167 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1168 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1169 hooks
= *(val
.v_pointer
);
1171 /* Remove these hooks from each event_by_id hooks list */
1173 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1174 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1176 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1177 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1179 for(k
= 0 ; k
< hooks
->len
; k
++) {
1180 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1181 lttv_hooks_remove_data(
1182 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1183 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1186 g_array_free(hooks
, TRUE
);
1191 static gboolean
block_start(void *hook_data
, void *call_data
)
1193 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1195 LttvTracefileState
*tfcs
;
1197 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1199 LttEventPosition
*ep
;
1201 guint i
, nb_block
, nb_event
, nb_tracefile
;
1205 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1207 LttvAttributeValue value
;
1209 ep
= ltt_event_position_new();
1210 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1211 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1213 /* Count the number of events added since the last block end in any
1216 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1217 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1218 ltt_event_position(tfcs
->parent
.e
, ep
);
1219 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1220 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1221 tfcs
->saved_position
= nb_event
;
1225 if(tcs
->nb_event
>= tcs
->save_interval
) {
1226 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1227 LTTV_STATE_SAVED_STATES
);
1228 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1229 value
= lttv_attribute_add(saved_states_tree
,
1230 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1231 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1232 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1233 *(value
.v_time
) = self
->parent
.timestamp
;
1234 lttv_state_save(tcs
, saved_state_tree
);
1236 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1237 self
->parent
.timestamp
.tv_nsec
);
1239 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1244 static gboolean
block_end(void *hook_data
, void *call_data
)
1246 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1248 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1252 LttEventPosition
*ep
;
1254 guint nb_block
, nb_event
;
1256 ep
= ltt_event_position_new();
1257 ltt_event_position(self
->parent
.e
, ep
);
1258 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1259 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1260 self
->saved_position
= 0;
1261 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1268 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1270 LttvTraceset
*traceset
= self
->parent
.ts
;
1272 guint i
, j
, nb_trace
, nb_tracefile
;
1276 LttvTracefileState
*tfs
;
1278 LttvTraceHook hook_start
, hook_end
;
1280 nb_trace
= lttv_traceset_number(traceset
);
1281 for(i
= 0 ; i
< nb_trace
; i
++) {
1282 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1283 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1284 NULL
, NULL
, block_start
, &hook_start
);
1285 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1286 NULL
, NULL
, block_end
, &hook_end
);
1288 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1289 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1291 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1292 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1293 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1294 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1295 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1296 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1301 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1303 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1305 lttv_state_save_add_event_hooks(tss
);
1311 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1313 LttvTraceset
*traceset
= self
->parent
.ts
;
1315 guint i
, j
, nb_trace
, nb_tracefile
;
1319 LttvTracefileState
*tfs
;
1321 LttvTraceHook hook_start
, hook_end
;
1323 nb_trace
= lttv_traceset_number(traceset
);
1324 for(i
= 0 ; i
< nb_trace
; i
++) {
1325 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1326 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1327 NULL
, NULL
, block_start
, &hook_start
);
1329 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1330 NULL
, NULL
, block_end
, &hook_end
);
1332 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1333 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1335 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1336 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1337 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1338 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1339 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1340 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1345 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1347 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1349 lttv_state_save_remove_event_hooks(tss
);
1354 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1356 LttvTraceset
*traceset
= self
->parent
.ts
;
1360 int min_pos
, mid_pos
, max_pos
;
1362 LttvTraceState
*tcs
;
1364 LttvAttributeValue value
;
1366 LttvAttributeType type
;
1368 LttvAttributeName name
;
1370 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1372 nb_trace
= lttv_traceset_number(traceset
);
1373 for(i
= 0 ; i
< nb_trace
; i
++) {
1374 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1376 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1377 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1378 LTTV_STATE_SAVED_STATES
);
1381 if(saved_states_tree
) {
1382 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1383 mid_pos
= max_pos
/ 2;
1384 while(min_pos
< max_pos
) {
1385 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1386 g_assert(type
== LTTV_GOBJECT
);
1387 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1388 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1390 g_assert(type
== LTTV_TIME
);
1391 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1393 closest_tree
= saved_state_tree
;
1395 else max_pos
= mid_pos
- 1;
1397 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1401 /* restore the closest earlier saved state */
1403 lttv_state_restore(tcs
, closest_tree
);
1406 /* There is no saved state, yet we want to have it. Restart at T0 */
1408 restore_init_state(tcs
);
1409 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1412 /* We want to seek quickly without restoring/updating the state */
1414 restore_init_state(tcs
);
1415 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1422 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1428 traceset_state_finalize (LttvTracesetState
*self
)
1430 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1431 finalize(G_OBJECT(self
));
1436 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1438 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1440 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1441 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1442 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1443 klass
->new_traceset_context
= new_traceset_context
;
1444 klass
->new_trace_context
= new_trace_context
;
1445 klass
->new_tracefile_context
= new_tracefile_context
;
1450 lttv_traceset_state_get_type(void)
1452 static GType type
= 0;
1454 static const GTypeInfo info
= {
1455 sizeof (LttvTracesetStateClass
),
1456 NULL
, /* base_init */
1457 NULL
, /* base_finalize */
1458 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1459 NULL
, /* class_finalize */
1460 NULL
, /* class_data */
1461 sizeof (LttvTracesetState
),
1462 0, /* n_preallocs */
1463 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1464 NULL
/* value handling */
1467 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1475 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1481 trace_state_finalize (LttvTraceState
*self
)
1483 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1484 finalize(G_OBJECT(self
));
1489 trace_state_class_init (LttvTraceStateClass
*klass
)
1491 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1493 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1494 klass
->state_save
= state_save
;
1495 klass
->state_restore
= state_restore
;
1496 klass
->state_saved_free
= state_saved_free
;
1501 lttv_trace_state_get_type(void)
1503 static GType type
= 0;
1505 static const GTypeInfo info
= {
1506 sizeof (LttvTraceStateClass
),
1507 NULL
, /* base_init */
1508 NULL
, /* base_finalize */
1509 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1510 NULL
, /* class_finalize */
1511 NULL
, /* class_data */
1512 sizeof (LttvTraceState
),
1513 0, /* n_preallocs */
1514 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1515 NULL
/* value handling */
1518 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1519 "LttvTraceStateType", &info
, 0);
1526 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1532 tracefile_state_finalize (LttvTracefileState
*self
)
1534 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1535 finalize(G_OBJECT(self
));
1540 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1542 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1544 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1549 lttv_tracefile_state_get_type(void)
1551 static GType type
= 0;
1553 static const GTypeInfo info
= {
1554 sizeof (LttvTracefileStateClass
),
1555 NULL
, /* base_init */
1556 NULL
, /* base_finalize */
1557 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1558 NULL
, /* class_finalize */
1559 NULL
, /* class_data */
1560 sizeof (LttvTracefileState
),
1561 0, /* n_preallocs */
1562 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1563 NULL
/* value handling */
1566 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1567 "LttvTracefileStateType", &info
, 0);
1573 static void module_init()
1575 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1576 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1577 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1578 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1579 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1580 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1581 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1582 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1583 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1584 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1585 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1586 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1587 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1588 LTTV_STATE_RUN
= g_quark_from_string("running");
1589 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1590 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1591 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1592 LTTV_STATE_EVENT
= g_quark_from_string("event");
1593 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1594 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1595 LTTV_STATE_TIME
= g_quark_from_string("time");
1596 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1597 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1598 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1599 g_quark_from_string("trace_state_use_count");
1602 static void module_destroy()
1607 LTTV_MODULE("state", "State computation", \
1608 "Update the system state, possibly saving it at intervals", \
1609 module_init
, module_destroy
)