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,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
32 #define PREALLOCATED_EXECUTION_STACK 10
35 LTTV_STATE_MODE_UNKNOWN
,
42 LTTV_STATE_SUBMODE_UNKNOWN
,
43 LTTV_STATE_SUBMODE_NONE
;
55 LTTV_STATE_TRACEFILES
,
59 LTTV_STATE_SAVED_STATES
,
60 LTTV_STATE_SAVED_STATES_TIME
,
63 LTTV_STATE_NAME_TABLES
,
64 LTTV_STATE_TRACE_STATE_USE_COUNT
;
67 static void create_max_time(LttvTraceState
*tcs
);
69 static void get_max_time(LttvTraceState
*tcs
);
71 static void free_max_time(LttvTraceState
*tcs
);
73 static void create_name_tables(LttvTraceState
*tcs
);
75 static void get_name_tables(LttvTraceState
*tcs
);
77 static void free_name_tables(LttvTraceState
*tcs
);
79 static void free_saved_state(LttvTraceState
*tcs
);
81 static void lttv_state_free_process_table(GHashTable
*processes
);
84 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
86 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
90 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
92 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
96 void lttv_state_state_saved_free(LttvTraceState
*self
,
97 LttvAttribute
*container
)
99 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
103 guint
process_hash(gconstpointer key
)
105 guint pid
= ((const LttvProcessState
*)key
)->pid
;
106 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
110 /* If the hash table hash function is well distributed,
111 * the process_equal should compare different pid */
112 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
114 const LttvProcessState
*process_a
, *process_b
;
117 process_a
= (const LttvProcessState
*)a
;
118 process_b
= (const LttvProcessState
*)b
;
120 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
121 else if(likely(process_a
->pid
== 0 &&
122 process_a
->last_cpu
!= process_b
->last_cpu
)) ret
= FALSE
;
129 restore_init_state(LttvTraceState
*self
)
131 guint i
, nb_tracefile
;
133 LttvTracefileState
*tfcs
;
135 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
136 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
139 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
140 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
142 for(i
= 0 ; i
< nb_tracefile
; i
++) {
143 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
144 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
145 tfcs
->saved_position
= 0;
146 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
147 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
148 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
149 tfcs
->process
->last_cpu_index
= ((LttvTracefileContext
*)tfcs
)->index
;
153 static LttTime time_zero
= {0,0};
156 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
158 guint i
, j
, nb_trace
, nb_tracefile
;
160 LttvTraceContext
*tc
;
164 LttvTracefileState
*tfcs
;
166 LttvAttributeValue v
;
168 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
169 init((LttvTracesetContext
*)self
, ts
);
171 nb_trace
= lttv_traceset_number(ts
);
172 for(i
= 0 ; i
< nb_trace
; i
++) {
173 tc
= self
->parent
.traces
[i
];
174 tcs
= (LttvTraceState
*)tc
;
175 tcs
->save_interval
= 50000;
176 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
180 if(*(v
.v_uint
) == 1) {
181 create_name_tables(tcs
);
182 create_max_time(tcs
);
184 get_name_tables(tcs
);
187 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
188 ltt_trace_per_cpu_tracefile_number(tc
->t
);
190 for(j
= 0 ; j
< nb_tracefile
; j
++) {
191 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
192 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
194 tcs
->processes
= NULL
;
195 restore_init_state(tcs
);
201 fini(LttvTracesetState
*self
)
207 LttvTracefileState
*tfcs
;
209 LttvAttributeValue v
;
211 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
212 for(i
= 0 ; i
< nb_trace
; i
++) {
213 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
214 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
217 g_assert(*(v
.v_uint
) != 0);
220 if(*(v
.v_uint
) == 0) {
221 free_name_tables(tcs
);
223 free_saved_state(tcs
);
225 lttv_state_free_process_table(tcs
->processes
);
226 tcs
->processes
= NULL
;
228 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
229 fini((LttvTracesetContext
*)self
);
233 static LttvTracesetContext
*
234 new_traceset_context(LttvTracesetContext
*self
)
236 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
240 static LttvTraceContext
*
241 new_trace_context(LttvTracesetContext
*self
)
243 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
247 static LttvTracefileContext
*
248 new_tracefile_context(LttvTracesetContext
*self
)
250 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
254 /* Write the process state of the trace */
256 static void write_process_state(gpointer key
, gpointer value
,
259 LttvProcessState
*process
;
261 LttvExecutionState
*es
;
263 FILE *fp
= (FILE *)user_data
;
267 process
= (LttvProcessState
*)value
;
269 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
270 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
271 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
272 g_quark_to_string(process
->last_cpu
));
274 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
275 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
276 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
277 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
278 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
279 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
280 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
282 fprintf(fp
, " </PROCESS>\n");
286 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
288 guint i
, nb_tracefile
, nb_block
, nb_event
;
290 LttvTracefileState
*tfcs
;
294 LttEventPosition
*ep
;
296 ep
= ltt_event_position_new();
298 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
300 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
302 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
303 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
305 for(i
= 0 ; i
< nb_tracefile
; i
++) {
306 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
307 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
308 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
309 tfcs
->parent
.timestamp
.tv_nsec
);
310 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
312 ltt_event_position(tfcs
->parent
.e
, ep
);
313 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
314 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
318 fprintf(fp
,"</PROCESS_STATE>");
322 /* Copy each process from an existing hash table to a new one */
324 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
326 LttvProcessState
*process
, *new_process
;
328 GHashTable
*new_processes
= (GHashTable
*)user_data
;
332 process
= (LttvProcessState
*)value
;
333 new_process
= g_new(LttvProcessState
, 1);
334 *new_process
= *process
;
335 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
336 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
337 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
338 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
339 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
340 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
342 new_process
->state
= &g_array_index(new_process
->execution_stack
,
343 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
344 g_hash_table_insert(new_processes
, new_process
, new_process
);
348 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
350 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
352 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
353 return new_processes
;
357 /* The saved state for each trace contains a member "processes", which
358 stores a copy of the process table, and a member "tracefiles" with
359 one entry per tracefile. Each tracefile has a "process" member pointing
360 to the current process and a "position" member storing the tracefile
361 position (needed to seek to the current "next" event. */
363 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
365 guint i
, nb_tracefile
;
367 LttvTracefileState
*tfcs
;
369 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
371 LttvAttributeType type
;
373 LttvAttributeValue value
;
375 LttvAttributeName name
;
377 LttEventPosition
*ep
;
379 tracefiles_tree
= lttv_attribute_find_subdir(container
,
380 LTTV_STATE_TRACEFILES
);
382 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
384 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
386 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
387 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
389 for(i
= 0 ; i
< nb_tracefile
; i
++) {
390 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
391 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
392 value
= lttv_attribute_add(tracefiles_tree
, i
,
394 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
395 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
397 *(value
.v_uint
) = tfcs
->process
->pid
;
398 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
400 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
402 ep
= ltt_event_position_new();
403 ltt_event_position(tfcs
->parent
.e
, ep
);
404 *(value
.v_pointer
) = ep
;
406 guint nb_block
, nb_event
;
408 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
409 g_debug("Block %u event %u time %lu.%lu", nb_block
, nb_event
,
410 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
416 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
418 guint i
, nb_tracefile
, pid
;
420 LttvTracefileState
*tfcs
;
422 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
424 LttvAttributeType type
;
426 LttvAttributeValue value
;
428 LttvAttributeName name
;
430 LttEventPosition
*ep
;
432 tracefiles_tree
= lttv_attribute_find_subdir(container
,
433 LTTV_STATE_TRACEFILES
);
435 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
437 g_assert(type
== LTTV_POINTER
);
438 lttv_state_free_process_table(self
->processes
);
439 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
441 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
442 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
444 for(i
= 0 ; i
< nb_tracefile
; i
++) {
445 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
446 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
447 g_assert(type
== LTTV_GOBJECT
);
448 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
450 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
452 g_assert(type
== LTTV_UINT
);
453 pid
= *(value
.v_uint
);
454 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
456 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
458 g_assert(type
== LTTV_POINTER
);
459 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
461 ep
= *(value
.v_pointer
);
462 g_assert(tfcs
->parent
.t_context
!= NULL
);
463 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs
), ep
);
469 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
471 guint i
, nb_tracefile
;
473 LttvTracefileState
*tfcs
;
475 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
477 LttvAttributeType type
;
479 LttvAttributeValue value
;
481 LttvAttributeName name
;
483 LttEventPosition
*ep
;
485 tracefiles_tree
= lttv_attribute_find_subdir(container
,
486 LTTV_STATE_TRACEFILES
);
487 g_object_ref(G_OBJECT(tracefiles_tree
));
488 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
490 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
492 g_assert(type
== LTTV_POINTER
);
493 lttv_state_free_process_table(*(value
.v_pointer
));
494 *(value
.v_pointer
) = NULL
;
495 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
497 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
498 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
500 for(i
= 0 ; i
< nb_tracefile
; i
++) {
501 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
502 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
503 g_assert(type
== LTTV_GOBJECT
);
504 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
506 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
508 g_assert(type
== LTTV_POINTER
);
509 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
511 g_object_unref(G_OBJECT(tracefiles_tree
));
515 static void free_saved_state(LttvTraceState
*self
)
519 LttvAttributeType type
;
521 LttvAttributeValue value
;
523 LttvAttributeName name
;
525 LttvAttribute
*saved_states
;
527 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
528 LTTV_STATE_SAVED_STATES
);
530 nb
= lttv_attribute_get_number(saved_states
);
531 for(i
= 0 ; i
< nb
; i
++) {
532 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
533 g_assert(type
== LTTV_GOBJECT
);
534 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
537 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
542 create_max_time(LttvTraceState
*tcs
)
544 LttvAttributeValue v
;
546 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
548 g_assert(*(v
.v_pointer
) == NULL
);
549 *(v
.v_pointer
) = g_new(LttTime
,1);
550 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
555 get_max_time(LttvTraceState
*tcs
)
557 LttvAttributeValue v
;
559 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
561 g_assert(*(v
.v_pointer
) != NULL
);
562 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
567 free_max_time(LttvTraceState
*tcs
)
569 LttvAttributeValue v
;
571 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
573 g_free(*(v
.v_pointer
));
574 *(v
.v_pointer
) = NULL
;
578 typedef struct _LttvNameTables
{
579 GQuark
*eventtype_names
;
580 GQuark
*syscall_names
;
587 create_name_tables(LttvTraceState
*tcs
)
591 char *f_name
, *e_name
;
599 GString
*fe_name
= g_string_new("");
601 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
603 LttvAttributeValue v
;
605 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
607 g_assert(*(v
.v_pointer
) == NULL
);
608 *(v
.v_pointer
) = name_tables
;
610 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
611 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
612 for(i
= 0 ; i
< nb
; i
++) {
613 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
614 e_name
= ltt_eventtype_name(et
);
615 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
616 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
617 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
620 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
621 "syscall_id", NULL
, NULL
, NULL
, &h
);
622 t
= ltt_field_type(h
.f1
);
623 nb
= ltt_type_element_number(t
);
625 /* CHECK syscalls should be an emun but currently are not!
626 name_tables->syscall_names = g_new(GQuark, nb);
628 for(i = 0 ; i < nb ; i++) {
629 name_tables->syscall_names[i] = g_quark_from_string(
630 ltt_enum_string_get(t, i));
634 name_tables
->syscall_names
= g_new(GQuark
, 256);
635 for(i
= 0 ; i
< 256 ; i
++) {
636 g_string_printf(fe_name
, "syscall %d", i
);
637 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
640 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
641 "trap_id", NULL
, NULL
, NULL
, &h
);
642 t
= ltt_field_type(h
.f1
);
643 nb
= ltt_type_element_number(t
);
646 name_tables->trap_names = g_new(GQuark, nb);
647 for(i = 0 ; i < nb ; i++) {
648 name_tables->trap_names[i] = g_quark_from_string(
649 ltt_enum_string_get(t, i));
653 name_tables
->trap_names
= g_new(GQuark
, 256);
654 for(i
= 0 ; i
< 256 ; i
++) {
655 g_string_printf(fe_name
, "trap %d", i
);
656 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
659 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
660 "irq_id", NULL
, NULL
, NULL
, &h
);
661 t
= ltt_field_type(h
.f1
);
662 nb
= ltt_type_element_number(t
);
665 name_tables->irq_names = g_new(GQuark, nb);
666 for(i = 0 ; i < nb ; i++) {
667 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
671 name_tables
->irq_names
= g_new(GQuark
, 256);
672 for(i
= 0 ; i
< 256 ; i
++) {
673 g_string_printf(fe_name
, "irq %d", i
);
674 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
677 g_string_free(fe_name
, TRUE
);
682 get_name_tables(LttvTraceState
*tcs
)
684 LttvNameTables
*name_tables
;
686 LttvAttributeValue v
;
688 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
690 g_assert(*(v
.v_pointer
) != NULL
);
691 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
692 tcs
->eventtype_names
= name_tables
->eventtype_names
;
693 tcs
->syscall_names
= name_tables
->syscall_names
;
694 tcs
->trap_names
= name_tables
->trap_names
;
695 tcs
->irq_names
= name_tables
->irq_names
;
700 free_name_tables(LttvTraceState
*tcs
)
702 LttvNameTables
*name_tables
;
704 LttvAttributeValue v
;
706 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
708 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
709 *(v
.v_pointer
) = NULL
;
711 g_free(name_tables
->eventtype_names
);
712 g_free(name_tables
->syscall_names
);
713 g_free(name_tables
->trap_names
);
714 g_free(name_tables
->irq_names
);
719 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
722 LttvExecutionState
*es
;
724 LttvProcessState
*process
= tfs
->process
;
726 guint depth
= process
->execution_stack
->len
;
728 g_array_set_size(process
->execution_stack
, depth
+ 1);
729 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
732 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
733 es
->s
= process
->state
->s
;
738 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
740 LttvProcessState
*process
= tfs
->process
;
742 guint depth
= process
->execution_stack
->len
;
744 if(process
->state
->t
!= t
){
745 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
746 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
747 g_info("process state has %s when pop_int is %s\n",
748 g_quark_to_string(process
->state
->t
),
749 g_quark_to_string(t
));
750 g_info("{ %u, %u, %s, %s }\n",
753 g_quark_to_string(process
->name
),
754 g_quark_to_string(process
->state
->s
));
759 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
760 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
764 g_array_set_size(process
->execution_stack
, depth
- 1);
765 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
767 process
->state
->change
= tfs
->parent
.timestamp
;
772 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
775 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
777 LttvExecutionState
*es
;
779 LttvTraceContext
*tc
;
785 tc
= tfs
->parent
.t_context
;
786 tcs
= (LttvTraceState
*)tc
;
789 process
->last_cpu
= tfs
->cpu_name
;
790 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
791 g_warning("Process %u, core %p", process
->pid
, process
);
792 g_hash_table_insert(tcs
->processes
, process
, process
);
795 process
->ppid
= parent
->pid
;
796 process
->name
= parent
->name
;
797 process
->creation_time
= tfs
->parent
.timestamp
;
800 /* No parent. This process exists but we are missing all information about
801 its creation. The birth time is set to zero but we remember the time of
806 process
->name
= LTTV_STATE_UNNAMED
;
807 process
->creation_time
= ltt_time_zero
;
810 process
->insertion_time
= tfs
->parent
.timestamp
;
811 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
812 process
->creation_time
.tv_nsec
);
813 process
->pid_time
= g_quark_from_string(buffer
);
814 process
->last_cpu
= tfs
->cpu_name
;
815 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
816 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
817 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
818 g_array_set_size(process
->execution_stack
, 1);
819 es
= process
->state
= &g_array_index(process
->execution_stack
,
820 LttvExecutionState
, 0);
821 es
->t
= LTTV_STATE_USER_MODE
;
822 es
->n
= LTTV_STATE_SUBMODE_NONE
;
823 es
->entry
= tfs
->parent
.timestamp
;
824 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
825 es
->change
= tfs
->parent
.timestamp
;
826 es
->s
= LTTV_STATE_WAIT_FORK
;
831 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
834 LttvProcessState key
;
835 LttvProcessState
*process
;
837 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
840 key
.last_cpu
= tfs
->cpu_name
;
841 process
= g_hash_table_lookup(ts
->processes
, &key
);
846 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
848 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
850 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
854 /* FIXME : this function should be called when we receive an event telling that
855 * release_task has been called in the kernel. In happens generally when
856 * the parent waits for its child terminaison, but may also happen in special
857 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
858 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
859 * of a killed thread ground, but isn't the leader.
861 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
863 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
864 LttvProcessState key
;
866 key
.pid
= process
->pid
;
867 key
.last_cpu
= process
->last_cpu
;
868 g_hash_table_remove(ts
->processes
, &key
);
869 g_array_free(process
->execution_stack
, TRUE
);
874 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
876 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
881 static void lttv_state_free_process_table(GHashTable
*processes
)
883 g_hash_table_foreach(processes
, free_process_state
, NULL
);
884 g_hash_table_destroy(processes
);
888 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
890 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
892 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
894 LttvExecutionSubmode submode
;
896 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
897 ltt_event_get_unsigned(s
->parent
.e
, f
)];
898 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
903 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
905 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
907 pop_state(s
, LTTV_STATE_SYSCALL
);
912 static gboolean
trap_entry(void *hook_data
, void *call_data
)
914 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
916 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
918 LttvExecutionSubmode submode
;
920 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
921 ltt_event_get_unsigned(s
->parent
.e
, f
)];
922 push_state(s
, LTTV_STATE_TRAP
, submode
);
927 static gboolean
trap_exit(void *hook_data
, void *call_data
)
929 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
931 pop_state(s
, LTTV_STATE_TRAP
);
936 static gboolean
irq_entry(void *hook_data
, void *call_data
)
938 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
940 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
942 LttvExecutionSubmode submode
;
944 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
945 ltt_event_get_unsigned(s
->parent
.e
, f
)];
947 /* Do something with the info about being in user or system mode when int? */
948 push_state(s
, LTTV_STATE_IRQ
, submode
);
953 static gboolean
irq_exit(void *hook_data
, void *call_data
)
955 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
957 pop_state(s
, LTTV_STATE_IRQ
);
962 static gboolean
schedchange(void *hook_data
, void *call_data
)
964 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
966 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
968 guint pid_in
, pid_out
, state_out
;
970 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
971 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
972 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
974 if(likely(s
->process
!= NULL
)) {
976 /* We could not know but it was not the idle process executing.
977 This should only happen at the beginning, before the first schedule
978 event, and when the initial information (current process for each CPU)
979 is missing. It is not obvious how we could, after the fact, compensate
980 the wrongly attributed statistics. */
982 if(unlikely(s
->process
->pid
!= pid_out
)) {
983 g_assert(s
->process
->pid
== 0);
986 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
987 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
989 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
990 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
991 } /* FIXME : we do not remove process here, because the kernel
992 * still has them : they may be zombies. We need to know
993 * exactly when release_task is executed on the PID to
994 * know when the zombie is destroyed.
997 // exit_process(s, s->process);
999 s
->process
->state
->change
= s
->parent
.timestamp
;
1001 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1002 s
->process
->state
->s
= LTTV_STATE_RUN
;
1003 s
->process
->last_cpu
= s
->cpu_name
;
1004 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1005 s
->process
->state
->change
= s
->parent
.timestamp
;
1010 static gboolean
process_fork(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1014 LttvProcessState
*zombie_process
;
1018 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1020 zombie_process
= lttv_state_find_process(s
, child_pid
);
1022 if(unlikely(zombie_process
!= NULL
)) {
1023 /* Reutilisation of PID. Only now we are sure that the old PID
1024 * has been released. FIXME : sould know when release_task happens instead.
1026 exit_process(s
, zombie_process
);
1028 g_assert(s
->process
->pid
!= child_pid
);
1029 lttv_state_create_process(s
, s
->process
, child_pid
);
1035 static gboolean
process_exit(LttvTraceHook
*trace_hook
, LttvTracefileState
*s
)
1037 if(likely(s
->process
!= NULL
)) {
1038 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1043 static gboolean
process_release(LttvTraceHook
*trace_hook
,
1044 LttvTracefileState
*s
)
1048 LttvProcessState
*process
;
1050 /* PID of the process to release */
1052 release_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1054 process
= lttv_state_find_process(s
, release_pid
);
1056 if(likely(process
!= NULL
)) {
1057 /* release_task is happening at kernel level : we can now safely release
1058 * the data structure of the process */
1059 exit_process(s
, process
);
1065 gboolean
process(void *hook_data
, void *call_data
)
1067 LttvTraceHook
*trace_hook
= (LttvTraceHook
*)hook_data
;
1068 LttField
*f
= trace_hook
->f1
;
1070 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1072 guint sub_id
= ltt_event_get_unsigned(s
->parent
.e
, f
);
1074 /* CHECK : do not hardcode the sub_id values here ? */
1076 return process_fork(trace_hook
, s
);
1077 } else if(sub_id
== 3) {
1078 return process_exit(trace_hook
, s
);
1079 } else if(sub_id
== 7) {
1080 return process_release(trace_hook
, s
);
1085 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1087 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1089 lttv_state_add_event_hooks(tss
);
1094 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1096 LttvTraceset
*traceset
= self
->parent
.ts
;
1098 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1102 LttvTracefileState
*tfs
;
1108 LttvAttributeValue val
;
1110 nb_trace
= lttv_traceset_number(traceset
);
1111 for(i
= 0 ; i
< nb_trace
; i
++) {
1112 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1114 /* Find the eventtype id for the following events and register the
1115 associated by id hooks. */
1117 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
1118 g_array_set_size(hooks
, 8);
1120 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
1121 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1123 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
1124 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1126 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
1127 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1129 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
1130 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1132 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
1133 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1135 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
1136 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1138 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
1139 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1141 lttv_trace_find_hook(ts
->parent
.t
, "core", "process", "event_sub_id",
1142 "event_data1", "event_data2", process
,
1143 &g_array_index(hooks
, LttvTraceHook
, 7));
1146 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
1147 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1149 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
1150 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1152 /* Add these hooks to each event_by_id hooks list */
1154 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1155 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1157 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1158 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1160 for(k
= 0 ; k
< hooks
->len
; k
++) {
1161 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1162 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1163 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
), LTTV_PRIO_STATE
);
1166 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1167 *(val
.v_pointer
) = hooks
;
1171 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1173 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1175 lttv_state_remove_event_hooks(tss
);
1180 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1182 LttvTraceset
*traceset
= self
->parent
.ts
;
1184 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1188 LttvTracefileState
*tfs
;
1194 LttvAttributeValue val
;
1196 nb_trace
= lttv_traceset_number(traceset
);
1197 for(i
= 0 ; i
< nb_trace
; i
++) {
1198 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1199 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1200 hooks
= *(val
.v_pointer
);
1202 /* Remove these hooks from each event_by_id hooks list */
1204 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1205 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1207 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1208 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1210 for(k
= 0 ; k
< hooks
->len
; k
++) {
1211 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
1212 lttv_hooks_remove_data(
1213 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1214 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
1217 g_array_free(hooks
, TRUE
);
1222 static gboolean
block_start(void *hook_data
, void *call_data
)
1224 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1226 LttvTracefileState
*tfcs
;
1228 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1230 LttEventPosition
*ep
;
1232 guint i
, nb_block
, nb_event
, nb_tracefile
;
1236 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1238 LttvAttributeValue value
;
1240 ep
= ltt_event_position_new();
1241 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
1242 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
1244 /* Count the number of events added since the last block end in any
1247 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1248 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1249 ltt_event_position(tfcs
->parent
.e
, ep
);
1250 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1251 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1252 tfcs
->saved_position
= nb_event
;
1256 if(tcs
->nb_event
>= tcs
->save_interval
) {
1257 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1258 LTTV_STATE_SAVED_STATES
);
1259 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1260 value
= lttv_attribute_add(saved_states_tree
,
1261 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1262 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1263 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1264 *(value
.v_time
) = self
->parent
.timestamp
;
1265 lttv_state_save(tcs
, saved_state_tree
);
1267 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1268 self
->parent
.timestamp
.tv_nsec
);
1270 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1275 static gboolean
block_end(void *hook_data
, void *call_data
)
1277 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1279 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1283 LttEventPosition
*ep
;
1285 guint nb_block
, nb_event
;
1287 ep
= ltt_event_position_new();
1288 ltt_event_position(self
->parent
.e
, ep
);
1289 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1290 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1291 self
->saved_position
= 0;
1292 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1299 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1301 LttvTraceset
*traceset
= self
->parent
.ts
;
1303 guint i
, j
, nb_trace
, nb_tracefile
;
1307 LttvTracefileState
*tfs
;
1309 LttvTraceHook hook_start
, hook_end
;
1311 nb_trace
= lttv_traceset_number(traceset
);
1312 for(i
= 0 ; i
< nb_trace
; i
++) {
1313 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1314 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1315 NULL
, NULL
, block_start
, &hook_start
);
1316 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1317 NULL
, NULL
, block_end
, &hook_end
);
1319 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1320 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1322 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1323 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1324 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1325 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1326 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1327 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1332 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1334 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1336 lttv_state_save_add_event_hooks(tss
);
1342 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1344 LttvTraceset
*traceset
= self
->parent
.ts
;
1346 guint i
, j
, nb_trace
, nb_tracefile
;
1350 LttvTracefileState
*tfs
;
1352 LttvTraceHook hook_start
, hook_end
;
1354 nb_trace
= lttv_traceset_number(traceset
);
1355 for(i
= 0 ; i
< nb_trace
; i
++) {
1356 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1357 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1358 NULL
, NULL
, block_start
, &hook_start
);
1360 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1361 NULL
, NULL
, block_end
, &hook_end
);
1363 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1364 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1366 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1367 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1368 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1369 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1370 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1371 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1376 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1378 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1380 lttv_state_save_remove_event_hooks(tss
);
1385 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1387 LttvTraceset
*traceset
= self
->parent
.ts
;
1391 int min_pos
, mid_pos
, max_pos
;
1393 LttvTraceState
*tcs
;
1395 LttvAttributeValue value
;
1397 LttvAttributeType type
;
1399 LttvAttributeName name
;
1401 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1403 nb_trace
= lttv_traceset_number(traceset
);
1404 for(i
= 0 ; i
< nb_trace
; i
++) {
1405 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1407 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1408 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1409 LTTV_STATE_SAVED_STATES
);
1412 if(saved_states_tree
) {
1413 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1414 mid_pos
= max_pos
/ 2;
1415 while(min_pos
< max_pos
) {
1416 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1417 g_assert(type
== LTTV_GOBJECT
);
1418 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1419 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1421 g_assert(type
== LTTV_TIME
);
1422 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1424 closest_tree
= saved_state_tree
;
1426 else max_pos
= mid_pos
- 1;
1428 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1432 /* restore the closest earlier saved state */
1434 lttv_state_restore(tcs
, closest_tree
);
1437 /* There is no saved state, yet we want to have it. Restart at T0 */
1439 restore_init_state(tcs
);
1440 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1443 /* We want to seek quickly without restoring/updating the state */
1445 restore_init_state(tcs
);
1446 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1453 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1459 traceset_state_finalize (LttvTracesetState
*self
)
1461 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1462 finalize(G_OBJECT(self
));
1467 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1469 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1471 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1472 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1473 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1474 klass
->new_traceset_context
= new_traceset_context
;
1475 klass
->new_trace_context
= new_trace_context
;
1476 klass
->new_tracefile_context
= new_tracefile_context
;
1481 lttv_traceset_state_get_type(void)
1483 static GType type
= 0;
1485 static const GTypeInfo info
= {
1486 sizeof (LttvTracesetStateClass
),
1487 NULL
, /* base_init */
1488 NULL
, /* base_finalize */
1489 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1490 NULL
, /* class_finalize */
1491 NULL
, /* class_data */
1492 sizeof (LttvTracesetState
),
1493 0, /* n_preallocs */
1494 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1495 NULL
/* value handling */
1498 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1506 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1512 trace_state_finalize (LttvTraceState
*self
)
1514 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1515 finalize(G_OBJECT(self
));
1520 trace_state_class_init (LttvTraceStateClass
*klass
)
1522 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1524 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1525 klass
->state_save
= state_save
;
1526 klass
->state_restore
= state_restore
;
1527 klass
->state_saved_free
= state_saved_free
;
1532 lttv_trace_state_get_type(void)
1534 static GType type
= 0;
1536 static const GTypeInfo info
= {
1537 sizeof (LttvTraceStateClass
),
1538 NULL
, /* base_init */
1539 NULL
, /* base_finalize */
1540 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1541 NULL
, /* class_finalize */
1542 NULL
, /* class_data */
1543 sizeof (LttvTraceState
),
1544 0, /* n_preallocs */
1545 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1546 NULL
/* value handling */
1549 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1550 "LttvTraceStateType", &info
, 0);
1557 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1563 tracefile_state_finalize (LttvTracefileState
*self
)
1565 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1566 finalize(G_OBJECT(self
));
1571 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1573 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1575 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1580 lttv_tracefile_state_get_type(void)
1582 static GType type
= 0;
1584 static const GTypeInfo info
= {
1585 sizeof (LttvTracefileStateClass
),
1586 NULL
, /* base_init */
1587 NULL
, /* base_finalize */
1588 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1589 NULL
, /* class_finalize */
1590 NULL
, /* class_data */
1591 sizeof (LttvTracefileState
),
1592 0, /* n_preallocs */
1593 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1594 NULL
/* value handling */
1597 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1598 "LttvTracefileStateType", &info
, 0);
1604 static void module_init()
1606 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1607 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1608 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1609 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1610 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1611 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1612 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1613 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1614 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1615 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1616 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1617 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1618 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1619 LTTV_STATE_RUN
= g_quark_from_string("running");
1620 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1621 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1622 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1623 LTTV_STATE_EVENT
= g_quark_from_string("event");
1624 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1625 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1626 LTTV_STATE_TIME
= g_quark_from_string("time");
1627 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1628 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1629 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1630 g_quark_from_string("trace_state_use_count");
1633 static void module_destroy()
1638 LTTV_MODULE("state", "State computation", \
1639 "Update the system state, possibly saving it at intervals", \
1640 module_init
, module_destroy
)