1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 #include <lttv/lttv.h>
21 #include <lttv/module.h>
22 #include <lttv/state.h>
23 #include <ltt/facility.h>
24 #include <ltt/trace.h>
25 #include <ltt/event.h>
30 LTTV_STATE_MODE_UNKNOWN
,
37 LTTV_STATE_SUBMODE_UNKNOWN
,
38 LTTV_STATE_SUBMODE_NONE
;
50 LTTV_STATE_TRACEFILES
,
54 LTTV_STATE_SAVED_STATES
,
55 LTTV_STATE_SAVED_STATES_TIME
,
58 LTTV_STATE_NAME_TABLES
,
59 LTTV_STATE_TRACE_STATE_USE_COUNT
;
62 static void create_max_time(LttvTraceState
*tcs
);
64 static void get_max_time(LttvTraceState
*tcs
);
66 static void free_max_time(LttvTraceState
*tcs
);
68 static void create_name_tables(LttvTraceState
*tcs
);
70 static void get_name_tables(LttvTraceState
*tcs
);
72 static void free_name_tables(LttvTraceState
*tcs
);
74 static void free_saved_state(LttvTraceState
*tcs
);
76 static void lttv_state_free_process_table(GHashTable
*processes
);
79 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
81 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
85 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
87 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
91 void lttv_state_state_saved_free(LttvTraceState
*self
,
92 LttvAttribute
*container
)
94 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
98 guint
process_hash(gconstpointer key
)
100 return ((const LttvProcessState
*)key
)->pid
;
104 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
106 const LttvProcessState
*process_a
, *process_b
;
108 process_a
= (const LttvProcessState
*)a
;
109 process_b
= (const LttvProcessState
*)b
;
111 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
112 if(process_a
->pid
== 0 &&
113 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
119 restore_init_state(LttvTraceState
*self
)
121 guint i
, nb_tracefile
;
123 LttvTracefileState
*tfcs
;
125 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
126 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
129 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
130 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
132 for(i
= 0 ; i
< nb_tracefile
; i
++) {
133 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
134 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
135 tfcs
->saved_position
= 0;
136 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
137 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
138 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
142 static LttTime time_zero
= {0,0};
145 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
147 guint i
, j
, nb_trace
, nb_tracefile
;
149 LttvTraceContext
*tc
;
153 LttvTracefileState
*tfcs
;
155 LttvAttributeValue v
;
157 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
158 init((LttvTracesetContext
*)self
, ts
);
160 nb_trace
= lttv_traceset_number(ts
);
161 for(i
= 0 ; i
< nb_trace
; i
++) {
162 tc
= self
->parent
.traces
[i
];
163 tcs
= (LttvTraceState
*)tc
;
164 tcs
->save_interval
= 50000;
165 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
169 if(*(v
.v_uint
) == 1) {
170 create_name_tables(tcs
);
171 create_max_time(tcs
);
173 get_name_tables(tcs
);
176 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
177 ltt_trace_per_cpu_tracefile_number(tc
->t
);
179 for(j
= 0 ; j
< nb_tracefile
; j
++) {
180 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
181 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
183 tcs
->processes
= NULL
;
184 restore_init_state(tcs
);
190 fini(LttvTracesetState
*self
)
196 LttvTracefileState
*tfcs
;
198 LttvAttributeValue v
;
200 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
201 for(i
= 0 ; i
< nb_trace
; i
++) {
202 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
203 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
206 g_assert(*(v
.v_uint
) != 0);
209 if(*(v
.v_uint
) == 0) {
210 free_name_tables(tcs
);
212 free_saved_state(tcs
);
214 lttv_state_free_process_table(tcs
->processes
);
215 tcs
->processes
= NULL
;
217 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
218 fini((LttvTracesetContext
*)self
);
222 static LttvTracesetContext
*
223 new_traceset_context(LttvTracesetContext
*self
)
225 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
229 static LttvTraceContext
*
230 new_trace_context(LttvTracesetContext
*self
)
232 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
236 static LttvTracefileContext
*
237 new_tracefile_context(LttvTracesetContext
*self
)
239 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
243 /* Write the process state of the trace */
245 static void write_process_state(gpointer key
, gpointer value
,
248 LttvProcessState
*process
;
250 LttvExecutionState
*es
;
252 FILE *fp
= (FILE *)user_data
;
256 process
= (LttvProcessState
*)value
;
258 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
259 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
260 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
261 g_quark_to_string(process
->last_cpu
));
263 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
264 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
265 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
266 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
267 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
268 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
269 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
271 fprintf(fp
, " </PROCESS>\n");
275 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
277 guint i
, nb_tracefile
, nb_block
, nb_event
;
279 LttvTracefileState
*tfcs
;
283 LttEventPosition
*ep
;
285 ep
= ltt_event_position_new();
287 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
289 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
291 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
292 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
294 for(i
= 0 ; i
< nb_tracefile
; i
++) {
295 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
296 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
297 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
298 tfcs
->parent
.timestamp
.tv_nsec
);
299 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
301 ltt_event_position(tfcs
->parent
.e
, ep
);
302 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
303 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
307 fprintf(fp
,"</PROCESS_STATE>");
311 /* Copy each process from an existing hash table to a new one */
313 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
315 LttvProcessState
*process
, *new_process
;
317 GHashTable
*new_processes
= (GHashTable
*)user_data
;
321 process
= (LttvProcessState
*)value
;
322 new_process
= g_new(LttvProcessState
, 1);
323 *new_process
= *process
;
324 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
325 sizeof(LttvExecutionState
));
326 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
327 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
328 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
329 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
331 new_process
->state
= &g_array_index(new_process
->execution_stack
,
332 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
333 g_hash_table_insert(new_processes
, new_process
, new_process
);
337 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
339 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
341 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
342 return new_processes
;
346 /* The saved state for each trace contains a member "processes", which
347 stores a copy of the process table, and a member "tracefiles" with
348 one entry per tracefile. Each tracefile has a "process" member pointing
349 to the current process and a "position" member storing the tracefile
350 position (needed to seek to the current "next" event. */
352 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
354 guint i
, nb_tracefile
;
356 LttvTracefileState
*tfcs
;
358 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
360 LttvAttributeType type
;
362 LttvAttributeValue value
;
364 LttvAttributeName name
;
366 LttEventPosition
*ep
;
368 tracefiles_tree
= lttv_attribute_find_subdir(container
,
369 LTTV_STATE_TRACEFILES
);
371 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
373 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
375 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
376 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
378 for(i
= 0 ; i
< nb_tracefile
; i
++) {
379 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
380 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
381 value
= lttv_attribute_add(tracefiles_tree
, i
,
383 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
384 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
386 *(value
.v_uint
) = tfcs
->process
->pid
;
387 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
389 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
391 ep
= ltt_event_position_new();
392 ltt_event_position(tfcs
->parent
.e
, ep
);
393 *(value
.v_pointer
) = ep
;
395 guint nb_block
, nb_event
;
397 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
398 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
399 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
405 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
407 guint i
, nb_tracefile
, pid
;
409 LttvTracefileState
*tfcs
;
411 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
413 LttvAttributeType type
;
415 LttvAttributeValue value
;
417 LttvAttributeName name
;
419 LttEventPosition
*ep
;
421 tracefiles_tree
= lttv_attribute_find_subdir(container
,
422 LTTV_STATE_TRACEFILES
);
424 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
426 g_assert(type
== LTTV_POINTER
);
427 lttv_state_free_process_table(self
->processes
);
428 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
430 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
431 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
433 for(i
= 0 ; i
< nb_tracefile
; i
++) {
434 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
435 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
436 g_assert(type
== LTTV_GOBJECT
);
437 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
439 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
441 g_assert(type
== LTTV_UINT
);
442 pid
= *(value
.v_uint
);
443 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
445 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
447 g_assert(type
== LTTV_POINTER
);
448 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
450 ep
= *(value
.v_pointer
);
451 g_assert(tfcs
->parent
.t_context
!= NULL
);
452 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
458 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
460 guint i
, nb_tracefile
;
462 LttvTracefileState
*tfcs
;
464 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
466 LttvAttributeType type
;
468 LttvAttributeValue value
;
470 LttvAttributeName name
;
472 LttEventPosition
*ep
;
474 tracefiles_tree
= lttv_attribute_find_subdir(container
,
475 LTTV_STATE_TRACEFILES
);
476 g_object_ref(G_OBJECT(tracefiles_tree
));
477 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
479 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
481 g_assert(type
== LTTV_POINTER
);
482 lttv_state_free_process_table(*(value
.v_pointer
));
483 *(value
.v_pointer
) = NULL
;
484 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
486 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
487 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
489 for(i
= 0 ; i
< nb_tracefile
; i
++) {
490 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
491 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
492 g_assert(type
== LTTV_GOBJECT
);
493 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
495 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
497 g_assert(type
== LTTV_POINTER
);
498 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
500 g_object_unref(G_OBJECT(tracefiles_tree
));
504 static void free_saved_state(LttvTraceState
*self
)
508 LttvAttributeType type
;
510 LttvAttributeValue value
;
512 LttvAttributeName name
;
514 LttvAttribute
*saved_states
;
516 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
517 LTTV_STATE_SAVED_STATES
);
519 nb
= lttv_attribute_get_number(saved_states
);
520 for(i
= 0 ; i
< nb
; i
++) {
521 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
522 g_assert(type
== LTTV_GOBJECT
);
523 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
526 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
531 create_max_time(LttvTraceState
*tcs
)
533 LttvAttributeValue v
;
535 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
537 g_assert(*(v
.v_pointer
) == NULL
);
538 *(v
.v_pointer
) = g_new(LttTime
,1);
539 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
544 get_max_time(LttvTraceState
*tcs
)
546 LttvAttributeValue v
;
548 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
550 g_assert(*(v
.v_pointer
) != NULL
);
551 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
556 free_max_time(LttvTraceState
*tcs
)
558 LttvAttributeValue v
;
560 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
562 g_free(*(v
.v_pointer
));
563 *(v
.v_pointer
) = NULL
;
567 typedef struct _LttvNameTables
{
568 GQuark
*eventtype_names
;
569 GQuark
*syscall_names
;
576 create_name_tables(LttvTraceState
*tcs
)
580 char *f_name
, *e_name
;
588 GString
*fe_name
= g_string_new("");
590 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
592 LttvAttributeValue v
;
594 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
596 g_assert(*(v
.v_pointer
) == NULL
);
597 *(v
.v_pointer
) = name_tables
;
599 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
600 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
601 for(i
= 0 ; i
< nb
; i
++) {
602 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
603 e_name
= ltt_eventtype_name(et
);
604 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
605 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
606 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
609 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
610 "syscall_id", NULL
, NULL
, NULL
, &h
);
611 t
= ltt_field_type(h
.f1
);
612 nb
= ltt_type_element_number(t
);
614 /* CHECK syscalls should be an emun but currently are not!
615 name_tables->syscall_names = g_new(GQuark, nb);
617 for(i = 0 ; i < nb ; i++) {
618 name_tables->syscall_names[i] = g_quark_from_string(
619 ltt_enum_string_get(t, i));
623 name_tables
->syscall_names
= g_new(GQuark
, 256);
624 for(i
= 0 ; i
< 256 ; i
++) {
625 g_string_printf(fe_name
, "syscall %d", i
);
626 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
629 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
630 "trap_id", NULL
, NULL
, NULL
, &h
);
631 t
= ltt_field_type(h
.f1
);
632 nb
= ltt_type_element_number(t
);
635 name_tables->trap_names = g_new(GQuark, nb);
636 for(i = 0 ; i < nb ; i++) {
637 name_tables->trap_names[i] = g_quark_from_string(
638 ltt_enum_string_get(t, i));
642 name_tables
->trap_names
= g_new(GQuark
, 256);
643 for(i
= 0 ; i
< 256 ; i
++) {
644 g_string_printf(fe_name
, "trap %d", i
);
645 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
648 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
649 "irq_id", NULL
, NULL
, NULL
, &h
);
650 t
= ltt_field_type(h
.f1
);
651 nb
= ltt_type_element_number(t
);
654 name_tables->irq_names = g_new(GQuark, nb);
655 for(i = 0 ; i < nb ; i++) {
656 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
660 name_tables
->irq_names
= g_new(GQuark
, 256);
661 for(i
= 0 ; i
< 256 ; i
++) {
662 g_string_printf(fe_name
, "irq %d", i
);
663 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
666 g_string_free(fe_name
, TRUE
);
671 get_name_tables(LttvTraceState
*tcs
)
673 LttvNameTables
*name_tables
;
675 LttvAttributeValue v
;
677 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
679 g_assert(*(v
.v_pointer
) != NULL
);
680 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
681 tcs
->eventtype_names
= name_tables
->eventtype_names
;
682 tcs
->syscall_names
= name_tables
->syscall_names
;
683 tcs
->trap_names
= name_tables
->trap_names
;
684 tcs
->irq_names
= name_tables
->irq_names
;
689 free_name_tables(LttvTraceState
*tcs
)
691 LttvNameTables
*name_tables
;
693 LttvAttributeValue v
;
695 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
697 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
698 *(v
.v_pointer
) = NULL
;
700 g_free(name_tables
->eventtype_names
);
701 g_free(name_tables
->syscall_names
);
702 g_free(name_tables
->trap_names
);
703 g_free(name_tables
->irq_names
);
708 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
711 LttvExecutionState
*es
;
713 LttvProcessState
*process
= tfs
->process
;
715 guint depth
= process
->execution_stack
->len
;
717 g_array_set_size(process
->execution_stack
, depth
+ 1);
718 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
721 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
722 es
->s
= process
->state
->s
;
727 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
729 LttvProcessState
*process
= tfs
->process
;
731 guint depth
= process
->execution_stack
->len
;
733 if(process
->state
->t
!= t
){
734 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
735 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
736 g_info("process state has %s when pop_int is %s\n",
737 g_quark_to_string(process
->state
->t
),
738 g_quark_to_string(t
));
739 g_info("{ %u, %u, %s, %s }\n",
742 g_quark_to_string(process
->name
),
743 g_quark_to_string(process
->state
->s
));
748 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
749 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
753 g_array_set_size(process
->execution_stack
, depth
- 1);
754 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
756 process
->state
->change
= tfs
->parent
.timestamp
;
761 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
764 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
766 LttvExecutionState
*es
;
768 LttvTraceContext
*tc
;
774 tc
= tfs
->parent
.t_context
;
775 tcs
= (LttvTraceState
*)tc
;
778 process
->last_cpu
= tfs
->cpu_name
;
779 g_warning("Process %u, core %p", process
->pid
, process
);
780 g_hash_table_insert(tcs
->processes
, process
, process
);
783 process
->ppid
= parent
->pid
;
784 process
->name
= parent
->name
;
785 process
->creation_time
= tfs
->parent
.timestamp
;
788 /* No parent. This process exists but we are missing all information about
789 its creation. The birth time is set to zero but we remember the time of
794 process
->name
= LTTV_STATE_UNNAMED
;
795 process
->creation_time
= ltt_time_zero
;
798 process
->insertion_time
= tfs
->parent
.timestamp
;
799 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
800 process
->creation_time
.tv_nsec
);
801 process
->pid_time
= g_quark_from_string(buffer
);
802 process
->last_cpu
= tfs
->cpu_name
;
803 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
804 sizeof(LttvExecutionState
));
805 g_array_set_size(process
->execution_stack
, 1);
806 es
= process
->state
= &g_array_index(process
->execution_stack
,
807 LttvExecutionState
, 0);
808 es
->t
= LTTV_STATE_USER_MODE
;
809 es
->n
= LTTV_STATE_SUBMODE_NONE
;
810 es
->entry
= tfs
->parent
.timestamp
;
811 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
812 es
->change
= tfs
->parent
.timestamp
;
813 es
->s
= LTTV_STATE_WAIT_FORK
;
818 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
821 LttvProcessState key
;
822 LttvProcessState
*process
;
824 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
827 key
.last_cpu
= tfs
->cpu_name
;
828 process
= g_hash_table_lookup(ts
->processes
, &key
);
833 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
835 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
837 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
841 /* FIXME : this function should be called when we receive an event telling that
842 * release_task has been called in the kernel. In happens generally when
843 * the parent waits for its child terminaison, but may also happen in special
844 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
845 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
846 * of a killed thread ground, but isn't the leader.
848 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
850 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
851 LttvProcessState key
;
853 key
.pid
= process
->pid
;
854 key
.last_cpu
= process
->last_cpu
;
855 g_hash_table_remove(ts
->processes
, &key
);
856 g_array_free(process
->execution_stack
, TRUE
);
861 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
863 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
868 static void lttv_state_free_process_table(GHashTable
*processes
)
870 g_hash_table_foreach(processes
, free_process_state
, NULL
);
871 g_hash_table_destroy(processes
);
875 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
877 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
879 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
881 LttvExecutionSubmode submode
;
883 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
884 ltt_event_get_unsigned(s
->parent
.e
, f
)];
885 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
890 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
892 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
894 pop_state(s
, LTTV_STATE_SYSCALL
);
899 static gboolean
trap_entry(void *hook_data
, void *call_data
)
901 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
903 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
905 LttvExecutionSubmode submode
;
907 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
908 ltt_event_get_unsigned(s
->parent
.e
, f
)];
909 push_state(s
, LTTV_STATE_TRAP
, submode
);
914 static gboolean
trap_exit(void *hook_data
, void *call_data
)
916 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
918 pop_state(s
, LTTV_STATE_TRAP
);
923 static gboolean
irq_entry(void *hook_data
, void *call_data
)
925 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
927 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
929 LttvExecutionSubmode submode
;
931 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
932 ltt_event_get_unsigned(s
->parent
.e
, f
)];
934 /* Do something with the info about being in user or system mode when int? */
935 push_state(s
, LTTV_STATE_IRQ
, submode
);
940 static gboolean
irq_exit(void *hook_data
, void *call_data
)
942 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
944 pop_state(s
, LTTV_STATE_IRQ
);
949 static gboolean
schedchange(void *hook_data
, void *call_data
)
951 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
953 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
955 guint pid_in
, pid_out
, state_out
;
957 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
958 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
959 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
961 if(s
->process
!= NULL
) {
963 /* We could not know but it was not the idle process executing.
964 This should only happen at the beginning, before the first schedule
965 event, and when the initial information (current process for each CPU)
966 is missing. It is not obvious how we could, after the fact, compensate
967 the wrongly attributed statistics. */
969 if(s
->process
->pid
!= pid_out
) {
970 g_assert(s
->process
->pid
== 0);
973 if(s
->process
->state
->s
== LTTV_STATE_EXIT
) {
974 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
976 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
977 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
978 } /* FIXME : we do not remove process here, because the kernel
979 * still has them : they may be zombies. We need to know
980 * exactly when release_task is executed on the PID to
981 * know when the zombie is destroyed.
984 // exit_process(s, s->process);
986 s
->process
->state
->change
= s
->parent
.timestamp
;
988 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
989 s
->process
->state
->s
= LTTV_STATE_RUN
;
990 s
->process
->last_cpu
= s
->cpu_name
;
991 s
->process
->state
->change
= s
->parent
.timestamp
;
996 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1000 LttvProcessState
*zombie_process
;
1004 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1006 zombie_process
= lttv_state_find_process(s
, child_pid
);
1008 if(zombie_process
!= NULL
) {
1009 /* Reutilisation of PID. Only now we are sure that the old PID
1010 * has been released. FIXME : sould know when release_task happens instead.
1012 exit_process(s
, zombie_process
);
1014 g_assert(s
->process
->pid
!= child_pid
);
1015 lttv_state_create_process(s
, s
->process
, child_pid
);
1021 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1023 if(s
->process
!= NULL
) {
1024 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1029 gboolean
process(void *hook_data
, void *call_data
)
1031 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1032 LttField
*f
= trace_hook
->f1
;
1034 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1036 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1038 /* CHECK : do not hardcode the sub_id values here ? */
1040 return process_fork(trace_hook
, s
);
1041 } else if(sub_id
== 3) {
1042 return process_exit(trace_hook
, s
);
1047 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1049 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1051 lttv_state_add_event_hooks(tss
);
1056 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1058 LttvTraceset
*traceset
= self
->parent
.ts
;
1060 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1064 LttvTracefileState
*tfs
;
1070 LttvAttributeValue val
;
1072 nb_trace
= lttv_traceset_number(traceset
);
1073 for(i
= 0 ; i
< nb_trace
; i
++) {
1074 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1076 /* Find the eventtype id for the following events and register the
1077 associated by id hooks. */
1079 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1080 g_array_set_size(hooks
, 8);
1082 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1083 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1085 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1086 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1088 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1089 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1091 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1092 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1094 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1095 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1097 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1098 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1100 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1101 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1103 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1104 "event_data1", "event_data2", process
,
1105 &g_array_index(hooks
, LttvTraceHook
, 7));
1108 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1109 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1111 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1112 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1114 /* Add these hooks to each event_by_id hooks list */
1116 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1117 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1119 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1120 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1122 for(k
= 0 ; k
< hooks
->len
; k
++) {
1123 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1124 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1125 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1128 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1129 *(val
.v_pointer
) = hooks
;
1133 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1135 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1137 lttv_state_remove_event_hooks(tss
);
1142 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1144 LttvTraceset
*traceset
= self
->parent
.ts
;
1146 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1150 LttvTracefileState
*tfs
;
1156 LttvAttributeValue val
;
1158 nb_trace
= lttv_traceset_number(traceset
);
1159 for(i
= 0 ; i
< nb_trace
; i
++) {
1160 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1161 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1162 hooks
= *(val
.v_pointer
);
1164 /* Remove these hooks from each event_by_id hooks list */
1166 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1167 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1169 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1170 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1172 for(k
= 0 ; k
< hooks
->len
; k
++) {
1173 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1174 lttv_hooks_remove_data(
1175 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1176 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1179 g_array_free(hooks
, TRUE
);
1184 static gboolean
block_start(void *hook_data
, void *call_data
)
1186 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1188 LttvTracefileState
*tfcs
;
1190 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1192 LttEventPosition
*ep
;
1194 guint i
, nb_block
, nb_event
, nb_tracefile
;
1198 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1200 LttvAttributeValue value
;
1202 ep
= ltt_event_position_new();
1203 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1204 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1206 /* Count the number of events added since the last block end in any
1209 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1210 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1211 ltt_event_position(tfcs
->parent
.e
, ep
);
1212 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1213 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1214 tfcs
->saved_position
= nb_event
;
1218 if(tcs
->nb_event
>= tcs
->save_interval
) {
1219 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1220 LTTV_STATE_SAVED_STATES
);
1221 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1222 value
= lttv_attribute_add(saved_states_tree
,
1223 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1224 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1225 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1226 *(value
.v_time
) = self
->parent
.timestamp
;
1227 lttv_state_save(tcs
, saved_state_tree
);
1229 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1230 self
->parent
.timestamp
.tv_nsec
);
1232 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1237 static gboolean
block_end(void *hook_data
, void *call_data
)
1239 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1241 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1245 LttEventPosition
*ep
;
1247 guint nb_block
, nb_event
;
1249 ep
= ltt_event_position_new();
1250 ltt_event_position(self
->parent
.e
, ep
);
1251 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1252 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1253 self
->saved_position
= 0;
1254 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1261 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1263 LttvTraceset
*traceset
= self
->parent
.ts
;
1265 guint i
, j
, nb_trace
, nb_tracefile
;
1269 LttvTracefileState
*tfs
;
1271 LttvTraceHook hook_start
, hook_end
;
1273 nb_trace
= lttv_traceset_number(traceset
);
1274 for(i
= 0 ; i
< nb_trace
; i
++) {
1275 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1276 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1277 NULL
, NULL
, block_start
, &hook_start
);
1278 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1279 NULL
, NULL
, block_end
, &hook_end
);
1281 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1282 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1284 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1285 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1286 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1287 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1288 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1289 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1294 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1296 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1298 lttv_state_save_add_event_hooks(tss
);
1304 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1306 LttvTraceset
*traceset
= self
->parent
.ts
;
1308 guint i
, j
, nb_trace
, nb_tracefile
;
1312 LttvTracefileState
*tfs
;
1314 LttvTraceHook hook_start
, hook_end
;
1316 nb_trace
= lttv_traceset_number(traceset
);
1317 for(i
= 0 ; i
< nb_trace
; i
++) {
1318 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1319 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1320 NULL
, NULL
, block_start
, &hook_start
);
1322 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1323 NULL
, NULL
, block_end
, &hook_end
);
1325 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1326 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1328 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1329 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1330 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1331 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1332 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1333 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1338 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1340 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1342 lttv_state_save_remove_event_hooks(tss
);
1347 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1349 LttvTraceset
*traceset
= self
->parent
.ts
;
1353 int min_pos
, mid_pos
, max_pos
;
1355 LttvTraceState
*tcs
;
1357 LttvAttributeValue value
;
1359 LttvAttributeType type
;
1361 LttvAttributeName name
;
1363 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1365 nb_trace
= lttv_traceset_number(traceset
);
1366 for(i
= 0 ; i
< nb_trace
; i
++) {
1367 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1369 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1370 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1371 LTTV_STATE_SAVED_STATES
);
1374 if(saved_states_tree
) {
1375 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1376 mid_pos
= max_pos
/ 2;
1377 while(min_pos
< max_pos
) {
1378 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1379 g_assert(type
== LTTV_GOBJECT
);
1380 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1381 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1383 g_assert(type
== LTTV_TIME
);
1384 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1386 closest_tree
= saved_state_tree
;
1388 else max_pos
= mid_pos
- 1;
1390 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1394 /* restore the closest earlier saved state */
1396 lttv_state_restore(tcs
, closest_tree
);
1399 /* There is no saved state, yet we want to have it. Restart at T0 */
1401 restore_init_state(tcs
);
1402 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1405 /* We want to seek quickly without restoring/updating the state */
1407 restore_init_state(tcs
);
1408 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1415 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1421 traceset_state_finalize (LttvTracesetState
*self
)
1423 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1424 finalize(G_OBJECT(self
));
1429 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1431 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1433 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1434 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1435 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1436 klass
->new_traceset_context
= new_traceset_context
;
1437 klass
->new_trace_context
= new_trace_context
;
1438 klass
->new_tracefile_context
= new_tracefile_context
;
1443 lttv_traceset_state_get_type(void)
1445 static GType type
= 0;
1447 static const GTypeInfo info
= {
1448 sizeof (LttvTracesetStateClass
),
1449 NULL
, /* base_init */
1450 NULL
, /* base_finalize */
1451 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1452 NULL
, /* class_finalize */
1453 NULL
, /* class_data */
1454 sizeof (LttvTracesetState
),
1455 0, /* n_preallocs */
1456 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1457 NULL
/* value handling */
1460 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1468 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1474 trace_state_finalize (LttvTraceState
*self
)
1476 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1477 finalize(G_OBJECT(self
));
1482 trace_state_class_init (LttvTraceStateClass
*klass
)
1484 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1486 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1487 klass
->state_save
= state_save
;
1488 klass
->state_restore
= state_restore
;
1489 klass
->state_saved_free
= state_saved_free
;
1494 lttv_trace_state_get_type(void)
1496 static GType type
= 0;
1498 static const GTypeInfo info
= {
1499 sizeof (LttvTraceStateClass
),
1500 NULL
, /* base_init */
1501 NULL
, /* base_finalize */
1502 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1503 NULL
, /* class_finalize */
1504 NULL
, /* class_data */
1505 sizeof (LttvTraceState
),
1506 0, /* n_preallocs */
1507 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1508 NULL
/* value handling */
1511 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1512 "LttvTraceStateType", &info
, 0);
1519 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1525 tracefile_state_finalize (LttvTracefileState
*self
)
1527 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1528 finalize(G_OBJECT(self
));
1533 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1535 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1537 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1542 lttv_tracefile_state_get_type(void)
1544 static GType type
= 0;
1546 static const GTypeInfo info
= {
1547 sizeof (LttvTracefileStateClass
),
1548 NULL
, /* base_init */
1549 NULL
, /* base_finalize */
1550 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1551 NULL
, /* class_finalize */
1552 NULL
, /* class_data */
1553 sizeof (LttvTracefileState
),
1554 0, /* n_preallocs */
1555 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1556 NULL
/* value handling */
1559 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1560 "LttvTracefileStateType", &info
, 0);
1566 static void module_init()
1568 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1569 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1570 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1571 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1572 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1573 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1574 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1575 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1576 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1577 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1578 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1579 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1580 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1581 LTTV_STATE_RUN
= g_quark_from_string("running");
1582 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1583 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1584 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1585 LTTV_STATE_EVENT
= g_quark_from_string("event");
1586 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1587 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1588 LTTV_STATE_TIME
= g_quark_from_string("time");
1589 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1590 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1591 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1592 g_quark_from_string("trace_state_use_count");
1595 static void module_destroy()
1600 LTTV_MODULE("state", "State computation", \
1601 "Update the system state, possibly saving it at intervals", \
1602 module_init
, module_destroy
)