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
34 /* Facilities Quarks */
43 LTT_EVENT_SYSCALL_ENTRY
,
44 LTT_EVENT_SYSCALL_EXIT
,
49 LTT_EVENT_SCHEDCHANGE
,
68 LTTV_STATE_MODE_UNKNOWN
,
75 LTTV_STATE_SUBMODE_UNKNOWN
,
76 LTTV_STATE_SUBMODE_NONE
;
88 LTTV_STATE_TRACEFILES
,
92 LTTV_STATE_SAVED_STATES
,
93 LTTV_STATE_SAVED_STATES_TIME
,
96 LTTV_STATE_NAME_TABLES
,
97 LTTV_STATE_TRACE_STATE_USE_COUNT
;
99 static void create_max_time(LttvTraceState
*tcs
);
101 static void get_max_time(LttvTraceState
*tcs
);
103 static void free_max_time(LttvTraceState
*tcs
);
105 static void create_name_tables(LttvTraceState
*tcs
);
107 static void get_name_tables(LttvTraceState
*tcs
);
109 static void free_name_tables(LttvTraceState
*tcs
);
111 static void free_saved_state(LttvTraceState
*tcs
);
113 static void lttv_state_free_process_table(GHashTable
*processes
);
116 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
118 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
122 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
124 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
128 void lttv_state_state_saved_free(LttvTraceState
*self
,
129 LttvAttribute
*container
)
131 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
135 guint
process_hash(gconstpointer key
)
137 guint pid
= ((const LttvProcessState
*)key
)->pid
;
138 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
142 /* If the hash table hash function is well distributed,
143 * the process_equal should compare different pid */
144 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
146 const LttvProcessState
*process_a
, *process_b
;
149 process_a
= (const LttvProcessState
*)a
;
150 process_b
= (const LttvProcessState
*)b
;
152 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
153 else if(likely(process_a
->pid
== 0 &&
154 process_a
->last_cpu
!= process_b
->last_cpu
)) ret
= FALSE
;
161 restore_init_state(LttvTraceState
*self
)
163 guint i
, nb_tracefile
;
165 LttvTracefileState
*tfcs
;
167 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
168 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
171 nb_tracefile
= self
->parent
.tracefiles
->len
;
173 for(i
= 0 ; i
< nb_tracefile
; i
++) {
175 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
176 LttvTracefileContext
*, i
));
177 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
178 // tfcs->saved_position = 0;
179 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
180 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
181 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
182 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
186 static LttTime time_zero
= {0,0};
189 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
191 guint i
, j
, nb_trace
, nb_tracefile
;
193 LttvTraceContext
*tc
;
197 LttvTracefileState
*tfcs
;
199 LttvAttributeValue v
;
201 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
202 init((LttvTracesetContext
*)self
, ts
);
204 nb_trace
= lttv_traceset_number(ts
);
205 for(i
= 0 ; i
< nb_trace
; i
++) {
206 tc
= self
->parent
.traces
[i
];
207 tcs
= LTTV_TRACE_STATE(tc
);
208 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
209 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
213 if(*(v
.v_uint
) == 1) {
214 create_name_tables(tcs
);
215 create_max_time(tcs
);
217 get_name_tables(tcs
);
220 nb_tracefile
= tc
->tracefiles
->len
;
222 for(j
= 0 ; j
< nb_tracefile
; j
++) {
224 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
225 LttvTracefileContext
*, j
));
226 tfcs
->cpu_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
228 tcs
->processes
= NULL
;
229 restore_init_state(tcs
);
235 fini(LttvTracesetState
*self
)
241 LttvTracefileState
*tfcs
;
243 LttvAttributeValue v
;
245 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
246 for(i
= 0 ; i
< nb_trace
; i
++) {
247 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
248 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
251 g_assert(*(v
.v_uint
) != 0);
254 if(*(v
.v_uint
) == 0) {
255 free_name_tables(tcs
);
257 free_saved_state(tcs
);
259 lttv_state_free_process_table(tcs
->processes
);
260 tcs
->processes
= NULL
;
262 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
263 fini((LttvTracesetContext
*)self
);
267 static LttvTracesetContext
*
268 new_traceset_context(LttvTracesetContext
*self
)
270 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
274 static LttvTraceContext
*
275 new_trace_context(LttvTracesetContext
*self
)
277 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
281 static LttvTracefileContext
*
282 new_tracefile_context(LttvTracesetContext
*self
)
284 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
288 /* Write the process state of the trace */
290 static void write_process_state(gpointer key
, gpointer value
,
293 LttvProcessState
*process
;
295 LttvExecutionState
*es
;
297 FILE *fp
= (FILE *)user_data
;
301 process
= (LttvProcessState
*)value
;
303 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
304 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
305 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
306 g_quark_to_string(process
->last_cpu
));
308 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
309 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
310 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
311 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
312 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
313 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
314 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
316 fprintf(fp
, " </PROCESS>\n");
320 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
322 guint i
, nb_tracefile
, nb_block
, offset
;
325 LttvTracefileState
*tfcs
;
329 LttEventPosition
*ep
;
331 ep
= ltt_event_position_new();
333 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
335 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
337 nb_tracefile
= self
->parent
.tracefiles
->len
;
339 for(i
= 0 ; i
< nb_tracefile
; i
++) {
341 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
342 LttvTracefileContext
*, i
));
343 fprintf(fp
, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
344 tfcs
->process
->pid
, tfcs
->parent
.timestamp
.tv_sec
,
345 tfcs
->parent
.timestamp
.tv_nsec
);
346 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
347 if(e
== NULL
) fprintf(fp
,"/>\n");
349 ltt_event_position(e
, ep
);
350 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
351 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
356 fprintf(fp
,"</PROCESS_STATE>");
360 /* Copy each process from an existing hash table to a new one */
362 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
364 LttvProcessState
*process
, *new_process
;
366 GHashTable
*new_processes
= (GHashTable
*)user_data
;
370 process
= (LttvProcessState
*)value
;
371 new_process
= g_new(LttvProcessState
, 1);
372 *new_process
= *process
;
373 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
374 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
375 new_process
->execution_stack
=
376 g_array_set_size(new_process
->execution_stack
,
377 process
->execution_stack
->len
);
378 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
379 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
380 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
382 new_process
->state
= &g_array_index(new_process
->execution_stack
,
383 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
384 g_hash_table_insert(new_processes
, new_process
, new_process
);
388 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
390 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
392 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
393 return new_processes
;
397 /* The saved state for each trace contains a member "processes", which
398 stores a copy of the process table, and a member "tracefiles" with
399 one entry per tracefile. Each tracefile has a "process" member pointing
400 to the current process and a "position" member storing the tracefile
401 position (needed to seek to the current "next" event. */
403 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
405 guint i
, nb_tracefile
;
407 LttvTracefileState
*tfcs
;
409 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
411 LttvAttributeType type
;
413 LttvAttributeValue value
;
415 LttvAttributeName name
;
417 LttEventPosition
*ep
;
419 tracefiles_tree
= lttv_attribute_find_subdir(container
,
420 LTTV_STATE_TRACEFILES
);
422 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
424 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
426 nb_tracefile
= self
->parent
.tracefiles
->len
;
428 for(i
= 0 ; i
< nb_tracefile
; i
++) {
430 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
431 LttvTracefileContext
*, i
));
432 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
433 value
= lttv_attribute_add(tracefiles_tree
, i
,
435 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
436 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
438 *(value
.v_uint
) = tfcs
->process
->pid
;
439 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
441 /* Only save the position of the tfs is in the pqueue */
442 if(!g_tree_lookup(self
->parent
.ts_context
->pqueue
, &tfcs
->parent
)) {
443 *(value
.v_pointer
) = NULL
;
445 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
446 ep
= ltt_event_position_new();
447 ltt_event_position(e
, ep
);
448 *(value
.v_pointer
) = ep
;
450 guint nb_block
, offset
;
453 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
454 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
456 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
462 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
464 guint i
, nb_tracefile
, pid
;
466 LttvTracefileState
*tfcs
;
468 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
470 LttvAttributeType type
;
472 LttvAttributeValue value
;
474 LttvAttributeName name
;
476 LttEventPosition
*ep
;
478 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
480 tracefiles_tree
= lttv_attribute_find_subdir(container
,
481 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(self
->processes
);
487 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
489 nb_tracefile
= self
->parent
.tracefiles
->len
;
491 for(i
= 0 ; i
< nb_tracefile
; i
++) {
493 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
494 LttvTracefileContext
*, 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_PROCESS
,
501 g_assert(type
== LTTV_UINT
);
502 pid
= *(value
.v_uint
);
503 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
505 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
507 g_assert(type
== LTTV_POINTER
);
508 g_assert(*(value
.v_pointer
) != NULL
);
509 ep
= *(value
.v_pointer
);
510 g_assert(tfcs
->parent
.t_context
!= NULL
);
512 g_tree_destroy(tsc
->pqueue
);
513 tsc
->pqueue
= g_tree_new(compare_tracefile
);
515 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
518 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
519 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
520 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
522 tfc
->timestamp
= ltt_time_infinite
;
528 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
530 guint i
, nb_tracefile
;
532 LttvTracefileState
*tfcs
;
534 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
536 LttvAttributeType type
;
538 LttvAttributeValue value
;
540 LttvAttributeName name
;
542 LttEventPosition
*ep
;
544 tracefiles_tree
= lttv_attribute_find_subdir(container
,
545 LTTV_STATE_TRACEFILES
);
546 g_object_ref(G_OBJECT(tracefiles_tree
));
547 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
549 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
551 g_assert(type
== LTTV_POINTER
);
552 lttv_state_free_process_table(*(value
.v_pointer
));
553 *(value
.v_pointer
) = NULL
;
554 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
556 nb_tracefile
= self
->parent
.tracefiles
->len
;
558 for(i
= 0 ; i
< nb_tracefile
; i
++) {
560 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
561 LttvTracefileContext
*, i
));
562 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
563 g_assert(type
== LTTV_GOBJECT
);
564 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
566 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
568 g_assert(type
== LTTV_POINTER
);
569 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
571 g_object_unref(G_OBJECT(tracefiles_tree
));
575 static void free_saved_state(LttvTraceState
*self
)
579 LttvAttributeType type
;
581 LttvAttributeValue value
;
583 LttvAttributeName name
;
585 LttvAttribute
*saved_states
;
587 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
588 LTTV_STATE_SAVED_STATES
);
590 nb
= lttv_attribute_get_number(saved_states
);
591 for(i
= 0 ; i
< nb
; i
++) {
592 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
593 g_assert(type
== LTTV_GOBJECT
);
594 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
597 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
602 create_max_time(LttvTraceState
*tcs
)
604 LttvAttributeValue v
;
606 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
608 g_assert(*(v
.v_pointer
) == NULL
);
609 *(v
.v_pointer
) = g_new(LttTime
,1);
610 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
615 get_max_time(LttvTraceState
*tcs
)
617 LttvAttributeValue v
;
619 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
621 g_assert(*(v
.v_pointer
) != NULL
);
622 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
627 free_max_time(LttvTraceState
*tcs
)
629 LttvAttributeValue v
;
631 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
633 g_free(*(v
.v_pointer
));
634 *(v
.v_pointer
) = NULL
;
638 typedef struct _LttvNameTables
{
639 // FIXME GQuark *eventtype_names;
640 GQuark
*syscall_names
;
647 create_name_tables(LttvTraceState
*tcs
)
651 GQuark f_name
, e_name
;
655 LttvTraceHookByFacility
*thf
;
661 GString
*fe_name
= g_string_new("");
663 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
665 LttvAttributeValue v
;
667 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
669 g_assert(*(v
.v_pointer
) == NULL
);
670 *(v
.v_pointer
) = name_tables
;
671 #if 0 // Use iteration over the facilities_by_name and then list all event
672 // types of each facility
673 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
674 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
675 for(i
= 0 ; i
< nb
; i
++) {
676 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
677 e_name
= ltt_eventtype_name(et
);
678 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
679 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
680 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
683 if(lttv_trace_find_hook(tcs
->parent
.t
,
684 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
685 LTT_FIELD_SYSCALL_ID
, 0, 0,
689 thf
= lttv_trace_hook_get_first(&h
);
691 t
= ltt_field_type(thf
->f1
);
692 nb
= ltt_type_element_number(t
);
694 lttv_trace_hook_destroy(&h
);
696 /* CHECK syscalls should be an enum but currently are not!
697 name_tables->syscall_names = g_new(GQuark, nb);
699 for(i = 0 ; i < nb ; i++) {
700 name_tables->syscall_names[i] = g_quark_from_string(
701 ltt_enum_string_get(t, i));
705 name_tables
->syscall_names
= g_new(GQuark
, 256);
706 for(i
= 0 ; i
< 256 ; i
++) {
707 g_string_printf(fe_name
, "syscall %d", i
);
708 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
711 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
712 LTT_EVENT_TRAP_ENTRY
,
713 LTT_FIELD_TRAP_ID
, 0, 0,
717 thf
= lttv_trace_hook_get_first(&h
);
719 t
= ltt_field_type(thf
->f1
);
720 nb
= ltt_type_element_number(t
);
722 lttv_trace_hook_destroy(&h
);
725 name_tables->trap_names = g_new(GQuark, nb);
726 for(i = 0 ; i < nb ; i++) {
727 name_tables->trap_names[i] = g_quark_from_string(
728 ltt_enum_string_get(t, i));
732 name_tables
->trap_names
= g_new(GQuark
, 256);
733 for(i
= 0 ; i
< 256 ; i
++) {
734 g_string_printf(fe_name
, "trap %d", i
);
735 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
738 if(lttv_trace_find_hook(tcs
->parent
.t
,
739 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
740 LTT_FIELD_IRQ_ID
, 0, 0,
744 thf
= lttv_trace_hook_get_first(&h
);
746 t
= ltt_field_type(thf
->f1
);
747 nb
= ltt_type_element_number(t
);
749 lttv_trace_hook_destroy(&h
);
752 name_tables->irq_names = g_new(GQuark, nb);
753 for(i = 0 ; i < nb ; i++) {
754 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
758 name_tables
->irq_names
= g_new(GQuark
, 256);
759 for(i
= 0 ; i
< 256 ; i
++) {
760 g_string_printf(fe_name
, "irq %d", i
);
761 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
764 g_string_free(fe_name
, TRUE
);
769 get_name_tables(LttvTraceState
*tcs
)
771 LttvNameTables
*name_tables
;
773 LttvAttributeValue v
;
775 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
777 g_assert(*(v
.v_pointer
) != NULL
);
778 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
779 //tcs->eventtype_names = name_tables->eventtype_names;
780 tcs
->syscall_names
= name_tables
->syscall_names
;
781 tcs
->trap_names
= name_tables
->trap_names
;
782 tcs
->irq_names
= name_tables
->irq_names
;
787 free_name_tables(LttvTraceState
*tcs
)
789 LttvNameTables
*name_tables
;
791 LttvAttributeValue v
;
793 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
795 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
796 *(v
.v_pointer
) = NULL
;
798 // g_free(name_tables->eventtype_names);
799 g_free(name_tables
->syscall_names
);
800 g_free(name_tables
->trap_names
);
801 g_free(name_tables
->irq_names
);
805 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
808 LttvExecutionState
*es
;
810 LttvProcessState
*process
= tfs
->process
;
812 guint depth
= process
->execution_stack
->len
;
814 process
->execution_stack
=
815 g_array_set_size(process
->execution_stack
, depth
+ 1);
818 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
820 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
823 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
824 es
->s
= process
->state
->s
;
829 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
831 LttvProcessState
*process
= tfs
->process
;
833 guint depth
= process
->execution_stack
->len
;
835 if(process
->state
->t
!= t
){
836 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
837 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
838 g_info("process state has %s when pop_int is %s\n",
839 g_quark_to_string(process
->state
->t
),
840 g_quark_to_string(t
));
841 g_info("{ %u, %u, %s, %s }\n",
844 g_quark_to_string(process
->name
),
845 g_quark_to_string(process
->state
->s
));
850 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
851 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
855 process
->execution_stack
=
856 g_array_set_size(process
->execution_stack
, depth
- 1);
857 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
859 process
->state
->change
= tfs
->parent
.timestamp
;
864 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
867 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
869 LttvExecutionState
*es
;
871 LttvTraceContext
*tc
;
877 tc
= tfs
->parent
.t_context
;
878 tcs
= (LttvTraceState
*)tc
;
881 process
->last_cpu
= tfs
->cpu_name
;
882 process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfs
)->tf
);
883 g_info("Process %u, core %p", process
->pid
, process
);
884 g_hash_table_insert(tcs
->processes
, process
, process
);
887 process
->ppid
= parent
->pid
;
888 process
->name
= parent
->name
;
889 process
->creation_time
= tfs
->parent
.timestamp
;
892 /* No parent. This process exists but we are missing all information about
893 its creation. The birth time is set to zero but we remember the time of
898 process
->name
= LTTV_STATE_UNNAMED
;
899 process
->creation_time
= ltt_time_zero
;
902 process
->insertion_time
= tfs
->parent
.timestamp
;
903 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
904 process
->creation_time
.tv_nsec
);
905 process
->pid_time
= g_quark_from_string(buffer
);
906 process
->last_cpu
= tfs
->cpu_name
;
907 process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfs
)->tf
);
908 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
909 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
910 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
911 es
= process
->state
= &g_array_index(process
->execution_stack
,
912 LttvExecutionState
, 0);
913 es
->t
= LTTV_STATE_USER_MODE
;
914 es
->n
= LTTV_STATE_SUBMODE_NONE
;
915 es
->entry
= tfs
->parent
.timestamp
;
916 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
917 es
->change
= tfs
->parent
.timestamp
;
918 es
->s
= LTTV_STATE_WAIT_FORK
;
923 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
926 LttvProcessState key
;
927 LttvProcessState
*process
;
929 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
932 key
.last_cpu
= tfs
->cpu_name
;
933 process
= g_hash_table_lookup(ts
->processes
, &key
);
938 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
940 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
942 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
946 /* FIXME : this function should be called when we receive an event telling that
947 * release_task has been called in the kernel. In happens generally when
948 * the parent waits for its child terminaison, but may also happen in special
949 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
950 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
951 * of a killed thread ground, but isn't the leader.
953 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
955 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
956 LttvProcessState key
;
958 key
.pid
= process
->pid
;
959 key
.last_cpu
= process
->last_cpu
;
960 g_hash_table_remove(ts
->processes
, &key
);
961 g_array_free(process
->execution_stack
, TRUE
);
966 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
968 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
973 static void lttv_state_free_process_table(GHashTable
*processes
)
975 g_hash_table_foreach(processes
, free_process_state
, NULL
);
976 g_hash_table_destroy(processes
);
980 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
982 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
983 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
984 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
985 LttField
*f
= thf
->f1
;
987 LttvExecutionSubmode submode
;
989 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
990 ltt_event_get_unsigned(e
, f
)];
991 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
996 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
998 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1000 pop_state(s
, LTTV_STATE_SYSCALL
);
1005 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1007 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1008 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1009 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1010 LttField
*f
= thf
->f1
;
1012 LttvExecutionSubmode submode
;
1014 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1015 ltt_event_get_unsigned(e
, f
)];
1016 push_state(s
, LTTV_STATE_TRAP
, submode
);
1021 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1023 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1025 pop_state(s
, LTTV_STATE_TRAP
);
1030 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1032 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1033 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1034 guint8 fac_id
= ltt_event_facility_id(e
);
1035 guint8 ev_id
= ltt_event_eventtype_id(e
);
1036 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1037 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1038 g_assert(thf
->f1
!= NULL
);
1039 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1040 LttField
*f
= thf
->f1
;
1042 LttvExecutionSubmode submode
;
1044 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1045 ltt_event_get_unsigned(e
, f
)];
1047 /* Do something with the info about being in user or system mode when int? */
1048 push_state(s
, LTTV_STATE_IRQ
, submode
);
1053 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1055 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1057 pop_state(s
, LTTV_STATE_IRQ
);
1062 static gboolean
schedchange(void *hook_data
, void *call_data
)
1064 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1065 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1066 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1067 guint pid_in
, pid_out
;
1070 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1071 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1072 state_out
= ltt_event_get_int(e
, thf
->f3
);
1074 if(likely(s
->process
!= NULL
)) {
1076 /* We could not know but it was not the idle process executing.
1077 This should only happen at the beginning, before the first schedule
1078 event, and when the initial information (current process for each CPU)
1079 is missing. It is not obvious how we could, after the fact, compensate
1080 the wrongly attributed statistics. */
1082 //This test only makes sense once the state is known and if there is no
1084 //if(unlikely(s->process->pid != pid_out)) {
1085 // g_assert(s->process->pid == 0);
1088 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1089 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1091 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1092 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1093 } /* FIXME : we do not remove process here, because the kernel
1094 * still has them : they may be zombies. We need to know
1095 * exactly when release_task is executed on the PID to
1096 * know when the zombie is destroyed.
1099 // exit_process(s, s->process);
1101 s
->process
->state
->change
= s
->parent
.timestamp
;
1103 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1104 s
->process
->state
->s
= LTTV_STATE_RUN
;
1105 s
->process
->last_cpu
= s
->cpu_name
;
1106 s
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)s
)->tf
);
1107 s
->process
->state
->change
= s
->parent
.timestamp
;
1111 static gboolean
process_fork(void *hook_data
, void *call_data
)
1113 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1114 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1115 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1119 LttvProcessState
*zombie_process
;
1123 parent_pid
= ltt_event_get_unsigned(e
, f
);
1127 child_pid
= ltt_event_get_unsigned(e
, f
);
1129 zombie_process
= lttv_state_find_process(s
, child_pid
);
1131 if(unlikely(zombie_process
!= NULL
)) {
1132 /* Reutilisation of PID. Only now we are sure that the old PID
1133 * has been released. FIXME : should know when release_task happens instead.
1135 exit_process(s
, zombie_process
);
1137 g_assert(s
->process
->pid
!= child_pid
);
1138 // FIXME : Add this test in the "known state" section
1139 // g_assert(s->process->pid == parent_pid);
1140 lttv_state_create_process(s
, s
->process
, child_pid
);
1146 static gboolean
process_exit(void *hook_data
, void *call_data
)
1148 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1149 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1150 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1154 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1156 // FIXME : Add this test in the "known state" section
1157 // g_assert(s->process->pid == pid);
1159 if(likely(s
->process
!= NULL
)) {
1160 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1165 static gboolean
process_free(void *hook_data
, void *call_data
)
1167 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1168 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1169 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1171 LttvProcessState
*process
;
1173 /* PID of the process to release */
1174 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1176 process
= lttv_state_find_process(s
, release_pid
);
1178 if(likely(process
!= NULL
)) {
1179 /* release_task is happening at kernel level : we can now safely release
1180 * the data structure of the process */
1181 exit_process(s
, process
);
1187 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1189 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1191 lttv_state_add_event_hooks(tss
);
1196 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1198 LttvTraceset
*traceset
= self
->parent
.ts
;
1200 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1204 LttvTracefileState
*tfs
;
1208 LttvTraceHookByFacility
*thf
;
1210 LttvTraceHook
*hook
;
1212 LttvAttributeValue val
;
1216 nb_trace
= lttv_traceset_number(traceset
);
1217 for(i
= 0 ; i
< nb_trace
; i
++) {
1218 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1220 /* Find the eventtype id for the following events and register the
1221 associated by id hooks. */
1223 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1224 hooks
= g_array_set_size(hooks
, 10);
1226 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1227 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1228 LTT_FIELD_SYSCALL_ID
, 0, 0,
1229 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1232 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1233 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1235 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1238 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1239 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1240 LTT_FIELD_TRAP_ID
, 0, 0,
1241 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1244 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1245 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1247 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1250 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1251 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1252 LTT_FIELD_IRQ_ID
, 0, 0,
1253 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1256 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1257 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1259 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1262 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1263 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1264 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1265 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1268 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1269 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1270 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1271 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1274 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1275 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1276 LTT_FIELD_PID
, 0, 0,
1277 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1280 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1281 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1282 LTT_FIELD_PID
, 0, 0,
1283 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1287 /* Add these hooks to each event_by_id hooks list */
1289 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1291 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1293 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1294 LttvTracefileContext
*, j
));
1296 for(k
= 0 ; k
< hooks
->len
; k
++) {
1297 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1298 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1299 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1301 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1308 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1309 *(val
.v_pointer
) = hooks
;
1313 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1315 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1317 lttv_state_remove_event_hooks(tss
);
1322 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1324 LttvTraceset
*traceset
= self
->parent
.ts
;
1326 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1330 LttvTracefileState
*tfs
;
1334 LttvTraceHook
*hook
;
1336 LttvTraceHookByFacility
*thf
;
1338 LttvAttributeValue val
;
1340 nb_trace
= lttv_traceset_number(traceset
);
1341 for(i
= 0 ; i
< nb_trace
; i
++) {
1342 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1343 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1344 hooks
= *(val
.v_pointer
);
1346 /* Remove these hooks from each event_by_id hooks list */
1348 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1350 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1352 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1353 LttvTracefileContext
*, j
));
1355 for(k
= 0 ; k
< hooks
->len
; k
++) {
1356 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1357 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1358 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1360 lttv_hooks_remove_data(
1361 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1367 for(k
= 0 ; k
< hooks
->len
; k
++)
1368 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1369 g_array_free(hooks
, TRUE
);
1374 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1376 guint
*event_count
= (guint
*)hook_data
;
1378 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1379 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1384 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1386 LttvTracefileState
*tfcs
;
1388 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1390 LttEventPosition
*ep
;
1396 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1398 LttvAttributeValue value
;
1400 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1401 LTTV_STATE_SAVED_STATES
);
1402 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1403 value
= lttv_attribute_add(saved_states_tree
,
1404 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1405 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1406 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1407 *(value
.v_time
) = self
->parent
.timestamp
;
1408 lttv_state_save(tcs
, saved_state_tree
);
1409 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1410 self
->parent
.timestamp
.tv_nsec
);
1412 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1418 static gboolean
block_start(void *hook_data
, void *call_data
)
1420 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1422 LttvTracefileState
*tfcs
;
1424 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1426 LttEventPosition
*ep
;
1428 guint i
, nb_block
, nb_event
, nb_tracefile
;
1432 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1434 LttvAttributeValue value
;
1436 ep
= ltt_event_position_new();
1438 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1440 /* Count the number of events added since the last block end in any
1443 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1445 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1446 LttvTracefileContext
, i
));
1447 ltt_event_position(tfcs
->parent
.e
, ep
);
1448 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1449 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1450 tfcs
->saved_position
= nb_event
;
1454 if(tcs
->nb_event
>= tcs
->save_interval
) {
1455 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1456 LTTV_STATE_SAVED_STATES
);
1457 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1458 value
= lttv_attribute_add(saved_states_tree
,
1459 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1460 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1461 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1462 *(value
.v_time
) = self
->parent
.timestamp
;
1463 lttv_state_save(tcs
, saved_state_tree
);
1465 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1466 self
->parent
.timestamp
.tv_nsec
);
1468 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1474 static gboolean
block_end(void *hook_data
, void *call_data
)
1476 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1478 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1482 LttEventPosition
*ep
;
1484 guint nb_block
, nb_event
;
1486 ep
= ltt_event_position_new();
1487 ltt_event_position(self
->parent
.e
, ep
);
1488 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1489 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1490 self
->saved_position
= 0;
1491 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1498 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1500 LttvTraceset
*traceset
= self
->parent
.ts
;
1502 guint i
, j
, nb_trace
, nb_tracefile
;
1506 LttvTracefileState
*tfs
;
1508 LttvTraceHook hook_start
, hook_end
;
1510 nb_trace
= lttv_traceset_number(traceset
);
1511 for(i
= 0 ; i
< nb_trace
; i
++) {
1512 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1514 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1515 NULL
, NULL
, block_start
, &hook_start
);
1516 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1517 NULL
, NULL
, block_end
, &hook_end
);
1519 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1521 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1523 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1524 LttvTracefileContext
, j
));
1525 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1526 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1527 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1528 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1534 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1536 LttvTraceset
*traceset
= self
->parent
.ts
;
1538 guint i
, j
, nb_trace
, nb_tracefile
;
1542 LttvTracefileState
*tfs
;
1545 nb_trace
= lttv_traceset_number(traceset
);
1546 for(i
= 0 ; i
< nb_trace
; i
++) {
1548 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1549 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1551 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1552 guint
*event_count
= g_new(guint
, 1);
1555 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1556 LttvTracefileContext
*, j
));
1557 lttv_hooks_add(tfs
->parent
.event
,
1558 state_save_event_hook
,
1566 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1568 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1570 lttv_state_save_add_event_hooks(tss
);
1577 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1579 LttvTraceset
*traceset
= self
->parent
.ts
;
1581 guint i
, j
, nb_trace
, nb_tracefile
;
1585 LttvTracefileState
*tfs
;
1587 LttvTraceHook hook_start
, hook_end
;
1589 nb_trace
= lttv_traceset_number(traceset
);
1590 for(i
= 0 ; i
< nb_trace
; i
++) {
1591 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1593 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1594 NULL
, NULL
, block_start
, &hook_start
);
1596 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1597 NULL
, NULL
, block_end
, &hook_end
);
1599 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1601 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1603 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1604 LttvTracefileContext
, j
));
1605 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1606 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1607 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1608 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1614 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1616 LttvTraceset
*traceset
= self
->parent
.ts
;
1618 guint i
, j
, nb_trace
, nb_tracefile
;
1622 LttvTracefileState
*tfs
;
1625 nb_trace
= lttv_traceset_number(traceset
);
1626 for(i
= 0 ; i
< nb_trace
; i
++) {
1628 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1629 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1633 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1635 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1636 LttvTracefileContext
*, j
));
1637 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1638 state_save_event_hook
);
1639 g_free(event_count
);
1645 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1647 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1649 lttv_state_save_remove_event_hooks(tss
);
1654 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1656 LttvTraceset
*traceset
= self
->parent
.ts
;
1660 int min_pos
, mid_pos
, max_pos
;
1662 LttvTraceState
*tcs
;
1664 LttvAttributeValue value
;
1666 LttvAttributeType type
;
1668 LttvAttributeName name
;
1670 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1672 nb_trace
= lttv_traceset_number(traceset
);
1673 for(i
= 0 ; i
< nb_trace
; i
++) {
1674 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1676 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1677 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1678 LTTV_STATE_SAVED_STATES
);
1681 if(saved_states_tree
) {
1682 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1683 mid_pos
= max_pos
/ 2;
1684 while(min_pos
< max_pos
) {
1685 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1686 g_assert(type
== LTTV_GOBJECT
);
1687 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1688 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1690 g_assert(type
== LTTV_TIME
);
1691 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1693 closest_tree
= saved_state_tree
;
1695 else max_pos
= mid_pos
- 1;
1697 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1701 /* restore the closest earlier saved state */
1703 lttv_state_restore(tcs
, closest_tree
);
1706 /* There is no saved state, yet we want to have it. Restart at T0 */
1708 restore_init_state(tcs
);
1709 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1712 /* We want to seek quickly without restoring/updating the state */
1714 restore_init_state(tcs
);
1715 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1722 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1728 traceset_state_finalize (LttvTracesetState
*self
)
1730 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1731 finalize(G_OBJECT(self
));
1736 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1738 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1740 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1741 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1742 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1743 klass
->new_traceset_context
= new_traceset_context
;
1744 klass
->new_trace_context
= new_trace_context
;
1745 klass
->new_tracefile_context
= new_tracefile_context
;
1750 lttv_traceset_state_get_type(void)
1752 static GType type
= 0;
1754 static const GTypeInfo info
= {
1755 sizeof (LttvTracesetStateClass
),
1756 NULL
, /* base_init */
1757 NULL
, /* base_finalize */
1758 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1759 NULL
, /* class_finalize */
1760 NULL
, /* class_data */
1761 sizeof (LttvTracesetState
),
1762 0, /* n_preallocs */
1763 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1764 NULL
/* value handling */
1767 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1775 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1781 trace_state_finalize (LttvTraceState
*self
)
1783 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1784 finalize(G_OBJECT(self
));
1789 trace_state_class_init (LttvTraceStateClass
*klass
)
1791 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1793 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1794 klass
->state_save
= state_save
;
1795 klass
->state_restore
= state_restore
;
1796 klass
->state_saved_free
= state_saved_free
;
1801 lttv_trace_state_get_type(void)
1803 static GType type
= 0;
1805 static const GTypeInfo info
= {
1806 sizeof (LttvTraceStateClass
),
1807 NULL
, /* base_init */
1808 NULL
, /* base_finalize */
1809 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1810 NULL
, /* class_finalize */
1811 NULL
, /* class_data */
1812 sizeof (LttvTraceState
),
1813 0, /* n_preallocs */
1814 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1815 NULL
/* value handling */
1818 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1819 "LttvTraceStateType", &info
, 0);
1826 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1832 tracefile_state_finalize (LttvTracefileState
*self
)
1834 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1835 finalize(G_OBJECT(self
));
1840 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1842 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1844 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1849 lttv_tracefile_state_get_type(void)
1851 static GType type
= 0;
1853 static const GTypeInfo info
= {
1854 sizeof (LttvTracefileStateClass
),
1855 NULL
, /* base_init */
1856 NULL
, /* base_finalize */
1857 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1858 NULL
, /* class_finalize */
1859 NULL
, /* class_data */
1860 sizeof (LttvTracefileState
),
1861 0, /* n_preallocs */
1862 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1863 NULL
/* value handling */
1866 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1867 "LttvTracefileStateType", &info
, 0);
1873 static void module_init()
1875 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1876 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1877 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1878 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1879 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1880 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1881 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1882 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1883 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1884 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1885 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1886 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1887 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1888 LTTV_STATE_RUN
= g_quark_from_string("running");
1889 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1890 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1891 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1892 LTTV_STATE_EVENT
= g_quark_from_string("event");
1893 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1894 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1895 LTTV_STATE_TIME
= g_quark_from_string("time");
1896 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1897 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1898 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1899 g_quark_from_string("trace_state_use_count");
1902 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1903 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1906 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1907 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1908 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1909 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1910 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1911 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1912 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1913 LTT_EVENT_FORK
= g_quark_from_string("fork");
1914 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1915 LTT_EVENT_FREE
= g_quark_from_string("free");
1918 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1919 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1920 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1921 LTT_FIELD_OUT
= g_quark_from_string("out");
1922 LTT_FIELD_IN
= g_quark_from_string("in");
1923 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1924 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1925 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1926 LTT_FIELD_PID
= g_quark_from_string("pid");
1930 static void module_destroy()
1935 LTTV_MODULE("state", "State computation", \
1936 "Update the system state, possibly saving it at intervals", \
1937 module_init
, module_destroy
)