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
= ((LttvTracefileContext
*)tfcs
)->index
;
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 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
376 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
377 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
378 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
380 new_process
->state
= &g_array_index(new_process
->execution_stack
,
381 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
382 g_hash_table_insert(new_processes
, new_process
, new_process
);
386 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
388 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
390 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
391 return new_processes
;
395 /* The saved state for each trace contains a member "processes", which
396 stores a copy of the process table, and a member "tracefiles" with
397 one entry per tracefile. Each tracefile has a "process" member pointing
398 to the current process and a "position" member storing the tracefile
399 position (needed to seek to the current "next" event. */
401 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
403 guint i
, nb_tracefile
;
405 LttvTracefileState
*tfcs
;
407 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
409 LttvAttributeType type
;
411 LttvAttributeValue value
;
413 LttvAttributeName name
;
415 LttEventPosition
*ep
;
417 tracefiles_tree
= lttv_attribute_find_subdir(container
,
418 LTTV_STATE_TRACEFILES
);
420 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
422 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
424 nb_tracefile
= self
->parent
.tracefiles
->len
;
426 for(i
= 0 ; i
< nb_tracefile
; i
++) {
428 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
429 LttvTracefileContext
*, i
));
430 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
431 value
= lttv_attribute_add(tracefiles_tree
, i
,
433 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
434 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
436 *(value
.v_uint
) = tfcs
->process
->pid
;
437 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
439 /* Only save the position of the tfs is in the pqueue */
440 if(!g_tree_lookup(self
->parent
.ts_context
->pqueue
, &tfcs
->parent
)) {
441 *(value
.v_pointer
) = NULL
;
443 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
444 ep
= ltt_event_position_new();
445 ltt_event_position(e
, ep
);
446 *(value
.v_pointer
) = ep
;
448 guint nb_block
, offset
;
451 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
452 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
454 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
460 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
462 guint i
, nb_tracefile
, pid
;
464 LttvTracefileState
*tfcs
;
466 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
468 LttvAttributeType type
;
470 LttvAttributeValue value
;
472 LttvAttributeName name
;
474 LttEventPosition
*ep
;
476 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
478 tracefiles_tree
= lttv_attribute_find_subdir(container
,
479 LTTV_STATE_TRACEFILES
);
481 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
483 g_assert(type
== LTTV_POINTER
);
484 lttv_state_free_process_table(self
->processes
);
485 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
487 nb_tracefile
= self
->parent
.tracefiles
->len
;
489 for(i
= 0 ; i
< nb_tracefile
; i
++) {
491 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
492 LttvTracefileContext
*, i
));
493 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
494 g_assert(type
== LTTV_GOBJECT
);
495 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
497 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
499 g_assert(type
== LTTV_UINT
);
500 pid
= *(value
.v_uint
);
501 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
503 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
505 g_assert(type
== LTTV_POINTER
);
506 g_assert(*(value
.v_pointer
) != NULL
);
507 ep
= *(value
.v_pointer
);
508 g_assert(tfcs
->parent
.t_context
!= NULL
);
510 g_tree_destroy(tsc
->pqueue
);
511 tsc
->pqueue
= g_tree_new(compare_tracefile
);
513 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
516 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
517 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
518 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
520 tfc
->timestamp
= ltt_time_infinite
;
526 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
528 guint i
, nb_tracefile
;
530 LttvTracefileState
*tfcs
;
532 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
534 LttvAttributeType type
;
536 LttvAttributeValue value
;
538 LttvAttributeName name
;
540 LttEventPosition
*ep
;
542 tracefiles_tree
= lttv_attribute_find_subdir(container
,
543 LTTV_STATE_TRACEFILES
);
544 g_object_ref(G_OBJECT(tracefiles_tree
));
545 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
547 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
549 g_assert(type
== LTTV_POINTER
);
550 lttv_state_free_process_table(*(value
.v_pointer
));
551 *(value
.v_pointer
) = NULL
;
552 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
554 nb_tracefile
= self
->parent
.tracefiles
->len
;
556 for(i
= 0 ; i
< nb_tracefile
; i
++) {
558 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
559 LttvTracefileContext
*, i
));
560 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
561 g_assert(type
== LTTV_GOBJECT
);
562 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
564 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
566 g_assert(type
== LTTV_POINTER
);
567 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
569 g_object_unref(G_OBJECT(tracefiles_tree
));
573 static void free_saved_state(LttvTraceState
*self
)
577 LttvAttributeType type
;
579 LttvAttributeValue value
;
581 LttvAttributeName name
;
583 LttvAttribute
*saved_states
;
585 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
586 LTTV_STATE_SAVED_STATES
);
588 nb
= lttv_attribute_get_number(saved_states
);
589 for(i
= 0 ; i
< nb
; i
++) {
590 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
591 g_assert(type
== LTTV_GOBJECT
);
592 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
595 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
600 create_max_time(LttvTraceState
*tcs
)
602 LttvAttributeValue v
;
604 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
606 g_assert(*(v
.v_pointer
) == NULL
);
607 *(v
.v_pointer
) = g_new(LttTime
,1);
608 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
613 get_max_time(LttvTraceState
*tcs
)
615 LttvAttributeValue v
;
617 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
619 g_assert(*(v
.v_pointer
) != NULL
);
620 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
625 free_max_time(LttvTraceState
*tcs
)
627 LttvAttributeValue v
;
629 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
631 g_free(*(v
.v_pointer
));
632 *(v
.v_pointer
) = NULL
;
636 typedef struct _LttvNameTables
{
637 // FIXME GQuark *eventtype_names;
638 GQuark
*syscall_names
;
645 create_name_tables(LttvTraceState
*tcs
)
649 GQuark f_name
, e_name
;
653 LttvTraceHookByFacility
*thf
;
659 GString
*fe_name
= g_string_new("");
661 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
663 LttvAttributeValue v
;
665 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
667 g_assert(*(v
.v_pointer
) == NULL
);
668 *(v
.v_pointer
) = name_tables
;
669 #if 0 // Use iteration over the facilities_by_name and then list all event
670 // types of each facility
671 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
672 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
673 for(i
= 0 ; i
< nb
; i
++) {
674 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
675 e_name
= ltt_eventtype_name(et
);
676 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
677 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
678 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
681 if(lttv_trace_find_hook(tcs
->parent
.t
,
682 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
683 LTT_FIELD_SYSCALL_ID
, 0, 0,
687 thf
= lttv_trace_hook_get_first(&h
);
689 t
= ltt_field_type(thf
->f1
);
690 nb
= ltt_type_element_number(t
);
692 lttv_trace_hook_destroy(&h
);
694 /* CHECK syscalls should be an enum but currently are not!
695 name_tables->syscall_names = g_new(GQuark, nb);
697 for(i = 0 ; i < nb ; i++) {
698 name_tables->syscall_names[i] = g_quark_from_string(
699 ltt_enum_string_get(t, i));
703 name_tables
->syscall_names
= g_new(GQuark
, 256);
704 for(i
= 0 ; i
< 256 ; i
++) {
705 g_string_printf(fe_name
, "syscall %d", i
);
706 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
709 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
710 LTT_EVENT_TRAP_ENTRY
,
711 LTT_FIELD_TRAP_ID
, 0, 0,
715 thf
= lttv_trace_hook_get_first(&h
);
717 t
= ltt_field_type(thf
->f1
);
718 nb
= ltt_type_element_number(t
);
720 lttv_trace_hook_destroy(&h
);
723 name_tables->trap_names = g_new(GQuark, nb);
724 for(i = 0 ; i < nb ; i++) {
725 name_tables->trap_names[i] = g_quark_from_string(
726 ltt_enum_string_get(t, i));
730 name_tables
->trap_names
= g_new(GQuark
, 256);
731 for(i
= 0 ; i
< 256 ; i
++) {
732 g_string_printf(fe_name
, "trap %d", i
);
733 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
736 if(lttv_trace_find_hook(tcs
->parent
.t
,
737 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
738 LTT_FIELD_IRQ_ID
, 0, 0,
742 thf
= lttv_trace_hook_get_first(&h
);
744 t
= ltt_field_type(thf
->f1
);
745 nb
= ltt_type_element_number(t
);
747 lttv_trace_hook_destroy(&h
);
750 name_tables->irq_names = g_new(GQuark, nb);
751 for(i = 0 ; i < nb ; i++) {
752 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
756 name_tables
->irq_names
= g_new(GQuark
, 256);
757 for(i
= 0 ; i
< 256 ; i
++) {
758 g_string_printf(fe_name
, "irq %d", i
);
759 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
762 g_string_free(fe_name
, TRUE
);
767 get_name_tables(LttvTraceState
*tcs
)
769 LttvNameTables
*name_tables
;
771 LttvAttributeValue v
;
773 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
775 g_assert(*(v
.v_pointer
) != NULL
);
776 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
777 //tcs->eventtype_names = name_tables->eventtype_names;
778 tcs
->syscall_names
= name_tables
->syscall_names
;
779 tcs
->trap_names
= name_tables
->trap_names
;
780 tcs
->irq_names
= name_tables
->irq_names
;
785 free_name_tables(LttvTraceState
*tcs
)
787 LttvNameTables
*name_tables
;
789 LttvAttributeValue v
;
791 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
793 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
794 *(v
.v_pointer
) = NULL
;
796 // g_free(name_tables->eventtype_names);
797 g_free(name_tables
->syscall_names
);
798 g_free(name_tables
->trap_names
);
799 g_free(name_tables
->irq_names
);
804 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
807 LttvExecutionState
*es
;
809 LttvProcessState
*process
= tfs
->process
;
811 guint depth
= process
->execution_stack
->len
;
813 g_array_set_size(process
->execution_stack
, depth
+ 1);
814 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
817 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
818 es
->s
= process
->state
->s
;
823 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
825 LttvProcessState
*process
= tfs
->process
;
827 guint depth
= process
->execution_stack
->len
;
829 if(process
->state
->t
!= t
){
830 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
831 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
832 g_info("process state has %s when pop_int is %s\n",
833 g_quark_to_string(process
->state
->t
),
834 g_quark_to_string(t
));
835 g_info("{ %u, %u, %s, %s }\n",
838 g_quark_to_string(process
->name
),
839 g_quark_to_string(process
->state
->s
));
844 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
845 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
849 g_array_set_size(process
->execution_stack
, depth
- 1);
850 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
852 process
->state
->change
= tfs
->parent
.timestamp
;
857 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
860 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
862 LttvExecutionState
*es
;
864 LttvTraceContext
*tc
;
870 tc
= tfs
->parent
.t_context
;
871 tcs
= (LttvTraceState
*)tc
;
874 process
->last_cpu
= tfs
->cpu_name
;
875 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
876 g_info("Process %u, core %p", process
->pid
, process
);
877 g_hash_table_insert(tcs
->processes
, process
, process
);
880 process
->ppid
= parent
->pid
;
881 process
->name
= parent
->name
;
882 process
->creation_time
= tfs
->parent
.timestamp
;
885 /* No parent. This process exists but we are missing all information about
886 its creation. The birth time is set to zero but we remember the time of
891 process
->name
= LTTV_STATE_UNNAMED
;
892 process
->creation_time
= ltt_time_zero
;
895 process
->insertion_time
= tfs
->parent
.timestamp
;
896 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
897 process
->creation_time
.tv_nsec
);
898 process
->pid_time
= g_quark_from_string(buffer
);
899 process
->last_cpu
= tfs
->cpu_name
;
900 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
901 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
902 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
903 g_array_set_size(process
->execution_stack
, 1);
904 es
= process
->state
= &g_array_index(process
->execution_stack
,
905 LttvExecutionState
, 0);
906 es
->t
= LTTV_STATE_USER_MODE
;
907 es
->n
= LTTV_STATE_SUBMODE_NONE
;
908 es
->entry
= tfs
->parent
.timestamp
;
909 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
910 es
->change
= tfs
->parent
.timestamp
;
911 es
->s
= LTTV_STATE_WAIT_FORK
;
916 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
919 LttvProcessState key
;
920 LttvProcessState
*process
;
922 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
925 key
.last_cpu
= tfs
->cpu_name
;
926 process
= g_hash_table_lookup(ts
->processes
, &key
);
931 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
933 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
935 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
939 /* FIXME : this function should be called when we receive an event telling that
940 * release_task has been called in the kernel. In happens generally when
941 * the parent waits for its child terminaison, but may also happen in special
942 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
943 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
944 * of a killed thread ground, but isn't the leader.
946 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
948 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
949 LttvProcessState key
;
951 key
.pid
= process
->pid
;
952 key
.last_cpu
= process
->last_cpu
;
953 g_hash_table_remove(ts
->processes
, &key
);
954 g_array_free(process
->execution_stack
, TRUE
);
959 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
961 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
966 static void lttv_state_free_process_table(GHashTable
*processes
)
968 g_hash_table_foreach(processes
, free_process_state
, NULL
);
969 g_hash_table_destroy(processes
);
973 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
975 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
976 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
977 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
978 LttField
*f
= thf
->f1
;
980 LttvExecutionSubmode submode
;
982 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
983 ltt_event_get_unsigned(e
, f
)];
984 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
989 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
991 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
993 pop_state(s
, LTTV_STATE_SYSCALL
);
998 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1000 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1001 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1002 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1003 LttField
*f
= thf
->f1
;
1005 LttvExecutionSubmode submode
;
1007 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1008 ltt_event_get_unsigned(e
, f
)];
1009 push_state(s
, LTTV_STATE_TRAP
, submode
);
1014 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1016 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1018 pop_state(s
, LTTV_STATE_TRAP
);
1023 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1025 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1026 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1027 guint8 fac_id
= ltt_event_facility_id(e
);
1028 guint8 ev_id
= ltt_event_eventtype_id(e
);
1029 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1030 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1031 g_assert(thf
->f1
!= NULL
);
1032 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1033 LttField
*f
= thf
->f1
;
1035 LttvExecutionSubmode submode
;
1037 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1038 ltt_event_get_unsigned(e
, f
)];
1040 /* Do something with the info about being in user or system mode when int? */
1041 push_state(s
, LTTV_STATE_IRQ
, submode
);
1046 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1048 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1050 pop_state(s
, LTTV_STATE_IRQ
);
1055 static gboolean
schedchange(void *hook_data
, void *call_data
)
1057 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1058 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1059 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1060 guint pid_in
, pid_out
;
1063 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1064 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1065 state_out
= ltt_event_get_int(e
, thf
->f3
);
1067 if(likely(s
->process
!= NULL
)) {
1069 /* We could not know but it was not the idle process executing.
1070 This should only happen at the beginning, before the first schedule
1071 event, and when the initial information (current process for each CPU)
1072 is missing. It is not obvious how we could, after the fact, compensate
1073 the wrongly attributed statistics. */
1075 if(unlikely(s
->process
->pid
!= pid_out
)) {
1076 g_assert(s
->process
->pid
== 0);
1079 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1080 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1082 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1083 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1084 } /* FIXME : we do not remove process here, because the kernel
1085 * still has them : they may be zombies. We need to know
1086 * exactly when release_task is executed on the PID to
1087 * know when the zombie is destroyed.
1090 // exit_process(s, s->process);
1092 s
->process
->state
->change
= s
->parent
.timestamp
;
1094 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1095 s
->process
->state
->s
= LTTV_STATE_RUN
;
1096 s
->process
->last_cpu
= s
->cpu_name
;
1097 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1098 s
->process
->state
->change
= s
->parent
.timestamp
;
1102 static gboolean
process_fork(void *hook_data
, void *call_data
)
1104 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1105 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1106 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1110 LttvProcessState
*zombie_process
;
1114 parent_pid
= ltt_event_get_unsigned(e
, f
);
1118 child_pid
= ltt_event_get_unsigned(e
, f
);
1120 zombie_process
= lttv_state_find_process(s
, child_pid
);
1122 if(unlikely(zombie_process
!= NULL
)) {
1123 /* Reutilisation of PID. Only now we are sure that the old PID
1124 * has been released. FIXME : should know when release_task happens instead.
1126 exit_process(s
, zombie_process
);
1128 g_assert(s
->process
->pid
!= child_pid
);
1129 // FIXME : Add this test in the "known state" section
1130 // g_assert(s->process->pid == parent_pid);
1131 lttv_state_create_process(s
, s
->process
, child_pid
);
1137 static gboolean
process_exit(void *hook_data
, void *call_data
)
1139 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1140 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1141 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1145 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1147 // FIXME : Add this test in the "known state" section
1148 // g_assert(s->process->pid == pid);
1150 if(likely(s
->process
!= NULL
)) {
1151 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1156 static gboolean
process_free(void *hook_data
, void *call_data
)
1158 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1159 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1160 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1162 LttvProcessState
*process
;
1164 /* PID of the process to release */
1165 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1167 process
= lttv_state_find_process(s
, release_pid
);
1169 if(likely(process
!= NULL
)) {
1170 /* release_task is happening at kernel level : we can now safely release
1171 * the data structure of the process */
1172 exit_process(s
, process
);
1178 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1180 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1182 lttv_state_add_event_hooks(tss
);
1187 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1189 LttvTraceset
*traceset
= self
->parent
.ts
;
1191 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1195 LttvTracefileState
*tfs
;
1199 LttvTraceHookByFacility
*thf
;
1201 LttvTraceHook
*hook
;
1203 LttvAttributeValue val
;
1207 nb_trace
= lttv_traceset_number(traceset
);
1208 for(i
= 0 ; i
< nb_trace
; i
++) {
1209 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1211 /* Find the eventtype id for the following events and register the
1212 associated by id hooks. */
1214 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1215 g_array_set_size(hooks
, 10);
1217 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1218 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1219 LTT_FIELD_SYSCALL_ID
, 0, 0,
1220 syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1223 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1224 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1226 syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1229 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1230 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1231 LTT_FIELD_TRAP_ID
, 0, 0,
1232 trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1235 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1236 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1238 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1241 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1242 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1243 LTT_FIELD_IRQ_ID
, 0, 0,
1244 irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1247 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1248 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1250 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1253 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1254 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1255 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1256 schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1259 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1260 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1261 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1262 process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1265 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1266 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1267 LTT_FIELD_PID
, 0, 0,
1268 process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1271 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1272 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1273 LTT_FIELD_PID
, 0, 0,
1274 process_free
, &g_array_index(hooks
, LttvTraceHook
, 9));
1278 /* Add these hooks to each event_by_id hooks list */
1280 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1282 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1284 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1285 LttvTracefileContext
*, j
));
1287 for(k
= 0 ; k
< hooks
->len
; k
++) {
1288 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1289 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1290 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1292 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1299 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1300 *(val
.v_pointer
) = hooks
;
1304 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1306 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1308 lttv_state_remove_event_hooks(tss
);
1313 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1315 LttvTraceset
*traceset
= self
->parent
.ts
;
1317 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1321 LttvTracefileState
*tfs
;
1325 LttvTraceHook
*hook
;
1327 LttvTraceHookByFacility
*thf
;
1329 LttvAttributeValue val
;
1331 nb_trace
= lttv_traceset_number(traceset
);
1332 for(i
= 0 ; i
< nb_trace
; i
++) {
1333 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1334 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1335 hooks
= *(val
.v_pointer
);
1337 /* Remove these hooks from each event_by_id hooks list */
1339 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1341 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1343 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1344 LttvTracefileContext
*, j
));
1346 for(k
= 0 ; k
< hooks
->len
; k
++) {
1347 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1348 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1349 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1351 lttv_hooks_remove_data(
1352 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1358 for(k
= 0 ; k
< hooks
->len
; k
++)
1359 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1360 g_array_free(hooks
, TRUE
);
1365 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1367 guint
*event_count
= (guint
*)hook_data
;
1369 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1370 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1375 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1377 LttvTracefileState
*tfcs
;
1379 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1381 LttEventPosition
*ep
;
1387 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1389 LttvAttributeValue value
;
1391 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1392 LTTV_STATE_SAVED_STATES
);
1393 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1394 value
= lttv_attribute_add(saved_states_tree
,
1395 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1396 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1397 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1398 *(value
.v_time
) = self
->parent
.timestamp
;
1399 lttv_state_save(tcs
, saved_state_tree
);
1400 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1401 self
->parent
.timestamp
.tv_nsec
);
1403 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1409 static gboolean
block_start(void *hook_data
, void *call_data
)
1411 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1413 LttvTracefileState
*tfcs
;
1415 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1417 LttEventPosition
*ep
;
1419 guint i
, nb_block
, nb_event
, nb_tracefile
;
1423 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1425 LttvAttributeValue value
;
1427 ep
= ltt_event_position_new();
1429 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1431 /* Count the number of events added since the last block end in any
1434 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1436 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1437 LttvTracefileContext
, i
));
1438 ltt_event_position(tfcs
->parent
.e
, ep
);
1439 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1440 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1441 tfcs
->saved_position
= nb_event
;
1445 if(tcs
->nb_event
>= tcs
->save_interval
) {
1446 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1447 LTTV_STATE_SAVED_STATES
);
1448 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1449 value
= lttv_attribute_add(saved_states_tree
,
1450 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1451 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1452 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1453 *(value
.v_time
) = self
->parent
.timestamp
;
1454 lttv_state_save(tcs
, saved_state_tree
);
1456 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1457 self
->parent
.timestamp
.tv_nsec
);
1459 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1465 static gboolean
block_end(void *hook_data
, void *call_data
)
1467 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1469 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1473 LttEventPosition
*ep
;
1475 guint nb_block
, nb_event
;
1477 ep
= ltt_event_position_new();
1478 ltt_event_position(self
->parent
.e
, ep
);
1479 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1480 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1481 self
->saved_position
= 0;
1482 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1489 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1491 LttvTraceset
*traceset
= self
->parent
.ts
;
1493 guint i
, j
, nb_trace
, nb_tracefile
;
1497 LttvTracefileState
*tfs
;
1499 LttvTraceHook hook_start
, hook_end
;
1501 nb_trace
= lttv_traceset_number(traceset
);
1502 for(i
= 0 ; i
< nb_trace
; i
++) {
1503 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1505 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1506 NULL
, NULL
, block_start
, &hook_start
);
1507 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1508 NULL
, NULL
, block_end
, &hook_end
);
1510 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1512 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1514 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1515 LttvTracefileContext
, j
));
1516 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1517 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1518 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1519 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1525 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1527 LttvTraceset
*traceset
= self
->parent
.ts
;
1529 guint i
, j
, nb_trace
, nb_tracefile
;
1533 LttvTracefileState
*tfs
;
1536 nb_trace
= lttv_traceset_number(traceset
);
1537 for(i
= 0 ; i
< nb_trace
; i
++) {
1539 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1540 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1542 guint
*event_count
= g_new(guint
, 1);
1545 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1547 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1548 LttvTracefileContext
*, j
));
1549 lttv_hooks_add(tfs
->parent
.event
,
1550 state_save_event_hook
,
1558 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1560 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1562 lttv_state_save_add_event_hooks(tss
);
1569 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1571 LttvTraceset
*traceset
= self
->parent
.ts
;
1573 guint i
, j
, nb_trace
, nb_tracefile
;
1577 LttvTracefileState
*tfs
;
1579 LttvTraceHook hook_start
, hook_end
;
1581 nb_trace
= lttv_traceset_number(traceset
);
1582 for(i
= 0 ; i
< nb_trace
; i
++) {
1583 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1585 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1586 NULL
, NULL
, block_start
, &hook_start
);
1588 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1589 NULL
, NULL
, block_end
, &hook_end
);
1591 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1593 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1595 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1596 LttvTracefileContext
, j
));
1597 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1598 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1599 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1600 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1606 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1608 LttvTraceset
*traceset
= self
->parent
.ts
;
1610 guint i
, j
, nb_trace
, nb_tracefile
;
1614 LttvTracefileState
*tfs
;
1617 nb_trace
= lttv_traceset_number(traceset
);
1618 for(i
= 0 ; i
< nb_trace
; i
++) {
1620 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1621 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1625 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1627 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1628 LttvTracefileContext
*, j
));
1629 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1630 state_save_event_hook
);
1631 g_free(event_count
);
1637 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1639 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1641 lttv_state_save_remove_event_hooks(tss
);
1646 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1648 LttvTraceset
*traceset
= self
->parent
.ts
;
1652 int min_pos
, mid_pos
, max_pos
;
1654 LttvTraceState
*tcs
;
1656 LttvAttributeValue value
;
1658 LttvAttributeType type
;
1660 LttvAttributeName name
;
1662 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1664 nb_trace
= lttv_traceset_number(traceset
);
1665 for(i
= 0 ; i
< nb_trace
; i
++) {
1666 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1668 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1669 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1670 LTTV_STATE_SAVED_STATES
);
1673 if(saved_states_tree
) {
1674 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1675 mid_pos
= max_pos
/ 2;
1676 while(min_pos
< max_pos
) {
1677 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1678 g_assert(type
== LTTV_GOBJECT
);
1679 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1680 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1682 g_assert(type
== LTTV_TIME
);
1683 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1685 closest_tree
= saved_state_tree
;
1687 else max_pos
= mid_pos
- 1;
1689 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1693 /* restore the closest earlier saved state */
1695 lttv_state_restore(tcs
, closest_tree
);
1698 /* There is no saved state, yet we want to have it. Restart at T0 */
1700 restore_init_state(tcs
);
1701 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1704 /* We want to seek quickly without restoring/updating the state */
1706 restore_init_state(tcs
);
1707 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1714 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1720 traceset_state_finalize (LttvTracesetState
*self
)
1722 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1723 finalize(G_OBJECT(self
));
1728 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1730 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1732 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1733 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1734 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1735 klass
->new_traceset_context
= new_traceset_context
;
1736 klass
->new_trace_context
= new_trace_context
;
1737 klass
->new_tracefile_context
= new_tracefile_context
;
1742 lttv_traceset_state_get_type(void)
1744 static GType type
= 0;
1746 static const GTypeInfo info
= {
1747 sizeof (LttvTracesetStateClass
),
1748 NULL
, /* base_init */
1749 NULL
, /* base_finalize */
1750 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1751 NULL
, /* class_finalize */
1752 NULL
, /* class_data */
1753 sizeof (LttvTracesetState
),
1754 0, /* n_preallocs */
1755 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1756 NULL
/* value handling */
1759 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1767 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1773 trace_state_finalize (LttvTraceState
*self
)
1775 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1776 finalize(G_OBJECT(self
));
1781 trace_state_class_init (LttvTraceStateClass
*klass
)
1783 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1785 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1786 klass
->state_save
= state_save
;
1787 klass
->state_restore
= state_restore
;
1788 klass
->state_saved_free
= state_saved_free
;
1793 lttv_trace_state_get_type(void)
1795 static GType type
= 0;
1797 static const GTypeInfo info
= {
1798 sizeof (LttvTraceStateClass
),
1799 NULL
, /* base_init */
1800 NULL
, /* base_finalize */
1801 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1802 NULL
, /* class_finalize */
1803 NULL
, /* class_data */
1804 sizeof (LttvTraceState
),
1805 0, /* n_preallocs */
1806 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1807 NULL
/* value handling */
1810 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1811 "LttvTraceStateType", &info
, 0);
1818 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1824 tracefile_state_finalize (LttvTracefileState
*self
)
1826 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1827 finalize(G_OBJECT(self
));
1832 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1834 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1836 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1841 lttv_tracefile_state_get_type(void)
1843 static GType type
= 0;
1845 static const GTypeInfo info
= {
1846 sizeof (LttvTracefileStateClass
),
1847 NULL
, /* base_init */
1848 NULL
, /* base_finalize */
1849 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1850 NULL
, /* class_finalize */
1851 NULL
, /* class_data */
1852 sizeof (LttvTracefileState
),
1853 0, /* n_preallocs */
1854 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1855 NULL
/* value handling */
1858 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1859 "LttvTracefileStateType", &info
, 0);
1865 static void module_init()
1867 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1868 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1869 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1870 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1871 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1872 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1873 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1874 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1875 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1876 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1877 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1878 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1879 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1880 LTTV_STATE_RUN
= g_quark_from_string("running");
1881 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1882 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1883 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1884 LTTV_STATE_EVENT
= g_quark_from_string("event");
1885 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1886 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1887 LTTV_STATE_TIME
= g_quark_from_string("time");
1888 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1889 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1890 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1891 g_quark_from_string("trace_state_use_count");
1894 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1895 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1898 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1899 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1900 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1901 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1902 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1903 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1904 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1905 LTT_EVENT_FORK
= g_quark_from_string("fork");
1906 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1907 LTT_EVENT_FREE
= g_quark_from_string("free");
1910 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1911 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1912 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1913 LTT_FIELD_OUT
= g_quark_from_string("out");
1914 LTT_FIELD_IN
= g_quark_from_string("in");
1915 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1916 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1917 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1918 LTT_FIELD_PID
= g_quark_from_string("pid");
1922 static void module_destroy()
1927 LTTV_MODULE("state", "State computation", \
1928 "Update the system state, possibly saving it at intervals", \
1929 module_init
, module_destroy
)