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
= (LttvTraceState
*)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 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
440 if(e
== NULL
) *(value
.v_pointer
) = NULL
;
442 ep
= ltt_event_position_new();
443 ltt_event_position(e
, ep
);
444 *(value
.v_pointer
) = ep
;
446 guint nb_block
, offset
;
449 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
450 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
452 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
458 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
460 guint i
, nb_tracefile
, pid
;
462 LttvTracefileState
*tfcs
;
464 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
466 LttvAttributeType type
;
468 LttvAttributeValue value
;
470 LttvAttributeName name
;
472 LttEventPosition
*ep
;
474 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
476 tracefiles_tree
= lttv_attribute_find_subdir(container
,
477 LTTV_STATE_TRACEFILES
);
479 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
481 g_assert(type
== LTTV_POINTER
);
482 lttv_state_free_process_table(self
->processes
);
483 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
485 nb_tracefile
= self
->parent
.tracefiles
->len
;
487 for(i
= 0 ; i
< nb_tracefile
; i
++) {
489 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
490 LttvTracefileContext
*, i
));
491 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
492 g_assert(type
== LTTV_GOBJECT
);
493 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
495 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
497 g_assert(type
== LTTV_UINT
);
498 pid
= *(value
.v_uint
);
499 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
501 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
503 g_assert(type
== LTTV_POINTER
);
504 g_assert(*(value
.v_pointer
) != NULL
);
505 ep
= *(value
.v_pointer
);
506 g_assert(tfcs
->parent
.t_context
!= NULL
);
508 g_tree_destroy(tsc
->pqueue
);
509 tsc
->pqueue
= g_tree_new(compare_tracefile
);
511 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
513 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
514 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
515 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
520 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
522 guint i
, nb_tracefile
;
524 LttvTracefileState
*tfcs
;
526 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
528 LttvAttributeType type
;
530 LttvAttributeValue value
;
532 LttvAttributeName name
;
534 LttEventPosition
*ep
;
536 tracefiles_tree
= lttv_attribute_find_subdir(container
,
537 LTTV_STATE_TRACEFILES
);
538 g_object_ref(G_OBJECT(tracefiles_tree
));
539 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
541 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
543 g_assert(type
== LTTV_POINTER
);
544 lttv_state_free_process_table(*(value
.v_pointer
));
545 *(value
.v_pointer
) = NULL
;
546 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
548 nb_tracefile
= self
->parent
.tracefiles
->len
;
550 for(i
= 0 ; i
< nb_tracefile
; i
++) {
552 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
553 LttvTracefileContext
*, i
));
554 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
555 g_assert(type
== LTTV_GOBJECT
);
556 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
558 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
560 g_assert(type
== LTTV_POINTER
);
561 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
563 g_object_unref(G_OBJECT(tracefiles_tree
));
567 static void free_saved_state(LttvTraceState
*self
)
571 LttvAttributeType type
;
573 LttvAttributeValue value
;
575 LttvAttributeName name
;
577 LttvAttribute
*saved_states
;
579 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
580 LTTV_STATE_SAVED_STATES
);
582 nb
= lttv_attribute_get_number(saved_states
);
583 for(i
= 0 ; i
< nb
; i
++) {
584 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
585 g_assert(type
== LTTV_GOBJECT
);
586 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
589 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
594 create_max_time(LttvTraceState
*tcs
)
596 LttvAttributeValue v
;
598 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
600 g_assert(*(v
.v_pointer
) == NULL
);
601 *(v
.v_pointer
) = g_new(LttTime
,1);
602 *((LttTime
*)*(v
.v_pointer
)) = time_zero
;
607 get_max_time(LttvTraceState
*tcs
)
609 LttvAttributeValue v
;
611 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
613 g_assert(*(v
.v_pointer
) != NULL
);
614 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
619 free_max_time(LttvTraceState
*tcs
)
621 LttvAttributeValue v
;
623 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
625 g_free(*(v
.v_pointer
));
626 *(v
.v_pointer
) = NULL
;
630 typedef struct _LttvNameTables
{
631 // FIXME GQuark *eventtype_names;
632 GQuark
*syscall_names
;
639 create_name_tables(LttvTraceState
*tcs
)
643 GQuark f_name
, e_name
;
647 LttvTraceHookByFacility
*thf
;
653 GString
*fe_name
= g_string_new("");
655 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
657 LttvAttributeValue v
;
659 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
661 g_assert(*(v
.v_pointer
) == NULL
);
662 *(v
.v_pointer
) = name_tables
;
663 #if 0 // Use iteration over the facilities_by_name and then list all event
664 // types of each facility
665 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
666 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
667 for(i
= 0 ; i
< nb
; i
++) {
668 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
669 e_name
= ltt_eventtype_name(et
);
670 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
671 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
672 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
675 if(lttv_trace_find_hook(tcs
->parent
.t
,
676 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
677 LTT_FIELD_SYSCALL_ID
, 0, 0,
681 thf
= lttv_trace_hook_get_first(h
);
683 t
= ltt_field_type(thf
->f1
);
684 nb
= ltt_type_element_number(t
);
686 lttv_trace_hook_destroy(h
);
688 /* CHECK syscalls should be an enum but currently are not!
689 name_tables->syscall_names = g_new(GQuark, nb);
691 for(i = 0 ; i < nb ; i++) {
692 name_tables->syscall_names[i] = g_quark_from_string(
693 ltt_enum_string_get(t, i));
697 name_tables
->syscall_names
= g_new(GQuark
, 256);
698 for(i
= 0 ; i
< 256 ; i
++) {
699 g_string_printf(fe_name
, "syscall %d", i
);
700 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
703 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
704 LTT_EVENT_TRAP_ENTRY
,
705 LTT_FIELD_TRAP_ID
, 0, 0,
709 thf
= lttv_trace_hook_get_first(h
);
711 t
= ltt_field_type(thf
->f1
);
712 nb
= ltt_type_element_number(t
);
714 lttv_trace_hook_destroy(h
);
717 name_tables->trap_names = g_new(GQuark, nb);
718 for(i = 0 ; i < nb ; i++) {
719 name_tables->trap_names[i] = g_quark_from_string(
720 ltt_enum_string_get(t, i));
724 name_tables
->trap_names
= g_new(GQuark
, 256);
725 for(i
= 0 ; i
< 256 ; i
++) {
726 g_string_printf(fe_name
, "trap %d", i
);
727 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
730 if(lttv_trace_find_hook(tcs
->parent
.t
,
731 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
732 LTT_FIELD_IRQ_ID
, 0, 0,
736 thf
= lttv_trace_hook_get_first(h
);
738 t
= ltt_field_type(thf
->f1
);
739 nb
= ltt_type_element_number(t
);
741 lttv_trace_hook_destroy(h
);
744 name_tables->irq_names = g_new(GQuark, nb);
745 for(i = 0 ; i < nb ; i++) {
746 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
750 name_tables
->irq_names
= g_new(GQuark
, 256);
751 for(i
= 0 ; i
< 256 ; i
++) {
752 g_string_printf(fe_name
, "irq %d", i
);
753 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
756 g_string_free(fe_name
, TRUE
);
761 get_name_tables(LttvTraceState
*tcs
)
763 LttvNameTables
*name_tables
;
765 LttvAttributeValue v
;
767 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
769 g_assert(*(v
.v_pointer
) != NULL
);
770 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
771 //tcs->eventtype_names = name_tables->eventtype_names;
772 tcs
->syscall_names
= name_tables
->syscall_names
;
773 tcs
->trap_names
= name_tables
->trap_names
;
774 tcs
->irq_names
= name_tables
->irq_names
;
779 free_name_tables(LttvTraceState
*tcs
)
781 LttvNameTables
*name_tables
;
783 LttvAttributeValue v
;
785 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
787 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
788 *(v
.v_pointer
) = NULL
;
790 // g_free(name_tables->eventtype_names);
791 g_free(name_tables
->syscall_names
);
792 g_free(name_tables
->trap_names
);
793 g_free(name_tables
->irq_names
);
798 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
801 LttvExecutionState
*es
;
803 LttvProcessState
*process
= tfs
->process
;
805 guint depth
= process
->execution_stack
->len
;
807 g_array_set_size(process
->execution_stack
, depth
+ 1);
808 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
811 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
812 es
->s
= process
->state
->s
;
817 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
819 LttvProcessState
*process
= tfs
->process
;
821 guint depth
= process
->execution_stack
->len
;
823 if(process
->state
->t
!= t
){
824 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
825 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
826 g_info("process state has %s when pop_int is %s\n",
827 g_quark_to_string(process
->state
->t
),
828 g_quark_to_string(t
));
829 g_info("{ %u, %u, %s, %s }\n",
832 g_quark_to_string(process
->name
),
833 g_quark_to_string(process
->state
->s
));
838 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
839 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
843 g_array_set_size(process
->execution_stack
, depth
- 1);
844 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
846 process
->state
->change
= tfs
->parent
.timestamp
;
851 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
854 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
856 LttvExecutionState
*es
;
858 LttvTraceContext
*tc
;
864 tc
= tfs
->parent
.t_context
;
865 tcs
= (LttvTraceState
*)tc
;
868 process
->last_cpu
= tfs
->cpu_name
;
869 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
870 g_info("Process %u, core %p", process
->pid
, process
);
871 g_hash_table_insert(tcs
->processes
, process
, process
);
874 process
->ppid
= parent
->pid
;
875 process
->name
= parent
->name
;
876 process
->creation_time
= tfs
->parent
.timestamp
;
879 /* No parent. This process exists but we are missing all information about
880 its creation. The birth time is set to zero but we remember the time of
885 process
->name
= LTTV_STATE_UNNAMED
;
886 process
->creation_time
= ltt_time_zero
;
889 process
->insertion_time
= tfs
->parent
.timestamp
;
890 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
891 process
->creation_time
.tv_nsec
);
892 process
->pid_time
= g_quark_from_string(buffer
);
893 process
->last_cpu
= tfs
->cpu_name
;
894 process
->last_cpu_index
= ((LttvTracefileContext
*)tfs
)->index
;
895 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
896 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
897 g_array_set_size(process
->execution_stack
, 1);
898 es
= process
->state
= &g_array_index(process
->execution_stack
,
899 LttvExecutionState
, 0);
900 es
->t
= LTTV_STATE_USER_MODE
;
901 es
->n
= LTTV_STATE_SUBMODE_NONE
;
902 es
->entry
= tfs
->parent
.timestamp
;
903 g_assert(tfs
->parent
.timestamp
.tv_sec
!= 0);
904 es
->change
= tfs
->parent
.timestamp
;
905 es
->s
= LTTV_STATE_WAIT_FORK
;
910 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
913 LttvProcessState key
;
914 LttvProcessState
*process
;
916 LttvTraceState
* ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
919 key
.last_cpu
= tfs
->cpu_name
;
920 process
= g_hash_table_lookup(ts
->processes
, &key
);
925 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
927 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
929 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(tfs
, NULL
, pid
);
933 /* FIXME : this function should be called when we receive an event telling that
934 * release_task has been called in the kernel. In happens generally when
935 * the parent waits for its child terminaison, but may also happen in special
936 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
937 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
938 * of a killed thread ground, but isn't the leader.
940 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
942 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
943 LttvProcessState key
;
945 key
.pid
= process
->pid
;
946 key
.last_cpu
= process
->last_cpu
;
947 g_hash_table_remove(ts
->processes
, &key
);
948 g_array_free(process
->execution_stack
, TRUE
);
953 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
955 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
960 static void lttv_state_free_process_table(GHashTable
*processes
)
962 g_hash_table_foreach(processes
, free_process_state
, NULL
);
963 g_hash_table_destroy(processes
);
967 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
969 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
970 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
971 LttvTraceHookByFacility
*thf
=
972 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
973 ltt_event_facility_id(e
));
974 LttField
*f
= thf
->f1
;
976 LttvExecutionSubmode submode
;
978 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
979 ltt_event_get_unsigned(e
, f
)];
980 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
985 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
987 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
989 pop_state(s
, LTTV_STATE_SYSCALL
);
994 static gboolean
trap_entry(void *hook_data
, void *call_data
)
996 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
997 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
998 LttvTraceHookByFacility
*thf
=
999 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1000 ltt_event_facility_id(e
));
1001 LttField
*f
= thf
->f1
;
1003 LttvExecutionSubmode submode
;
1005 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1006 ltt_event_get_unsigned(e
, f
)];
1007 push_state(s
, LTTV_STATE_TRAP
, submode
);
1012 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1014 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1016 pop_state(s
, LTTV_STATE_TRAP
);
1021 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1023 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1024 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1025 guint8 fac_id
= ltt_event_facility_id(e
);
1026 guint8 ev_id
= ltt_event_eventtype_id(e
);
1027 LttvTraceHookByFacility
*thf
=
1028 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1029 ltt_event_facility_id(e
));
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
=
1060 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1061 ltt_event_facility_id(e
));
1062 guint pid_in
, pid_out
, state_out
;
1064 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1065 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1066 state_out
= ltt_event_get_unsigned(e
, thf
->f3
);
1068 if(likely(s
->process
!= NULL
)) {
1070 /* We could not know but it was not the idle process executing.
1071 This should only happen at the beginning, before the first schedule
1072 event, and when the initial information (current process for each CPU)
1073 is missing. It is not obvious how we could, after the fact, compensate
1074 the wrongly attributed statistics. */
1076 if(unlikely(s
->process
->pid
!= pid_out
)) {
1077 g_assert(s
->process
->pid
== 0);
1080 if(unlikely(s
->process
->state
->s
== LTTV_STATE_EXIT
)) {
1081 s
->process
->state
->s
= LTTV_STATE_ZOMBIE
;
1083 if(unlikely(state_out
== 0)) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1084 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
1085 } /* FIXME : we do not remove process here, because the kernel
1086 * still has them : they may be zombies. We need to know
1087 * exactly when release_task is executed on the PID to
1088 * know when the zombie is destroyed.
1091 // exit_process(s, s->process);
1093 s
->process
->state
->change
= s
->parent
.timestamp
;
1095 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
1096 s
->process
->state
->s
= LTTV_STATE_RUN
;
1097 s
->process
->last_cpu
= s
->cpu_name
;
1098 s
->process
->last_cpu_index
= ((LttvTracefileContext
*)s
)->index
;
1099 s
->process
->state
->change
= s
->parent
.timestamp
;
1103 static gboolean
process_fork(void *hook_data
, void *call_data
)
1105 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1106 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1107 LttvTraceHookByFacility
*thf
=
1108 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1109 ltt_event_facility_id(e
));
1113 LttvProcessState
*zombie_process
;
1117 parent_pid
= ltt_event_get_unsigned(e
, f
);
1121 child_pid
= ltt_event_get_unsigned(e
, f
);
1123 zombie_process
= lttv_state_find_process(s
, child_pid
);
1125 if(unlikely(zombie_process
!= NULL
)) {
1126 /* Reutilisation of PID. Only now we are sure that the old PID
1127 * has been released. FIXME : should know when release_task happens instead.
1129 exit_process(s
, zombie_process
);
1131 g_assert(s
->process
->pid
!= child_pid
);
1132 // FIXME : Add this test in the "known state" section
1133 // g_assert(s->process->pid == parent_pid);
1134 lttv_state_create_process(s
, s
->process
, child_pid
);
1140 static gboolean
process_exit(void *hook_data
, void *call_data
)
1142 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1143 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1144 LttvTraceHookByFacility
*thf
=
1145 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1146 ltt_event_facility_id(e
));
1150 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1152 // FIXME : Add this test in the "known state" section
1153 // g_assert(s->process->pid == pid);
1155 if(likely(s
->process
!= NULL
)) {
1156 s
->process
->state
->s
= LTTV_STATE_EXIT
;
1161 static gboolean
process_free(void *hook_data
, void *call_data
)
1163 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1164 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1165 LttvTraceHookByFacility
*thf
=
1166 lttv_trace_hook_get_fac((LttvTraceHook
*)hook_data
,
1167 ltt_event_facility_id(e
));
1169 LttvProcessState
*process
;
1171 /* PID of the process to release */
1172 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1174 process
= lttv_state_find_process(s
, release_pid
);
1176 if(likely(process
!= NULL
)) {
1177 /* release_task is happening at kernel level : we can now safely release
1178 * the data structure of the process */
1179 exit_process(s
, process
);
1185 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1187 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1189 lttv_state_add_event_hooks(tss
);
1194 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1196 LttvTraceset
*traceset
= self
->parent
.ts
;
1198 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1202 LttvTracefileState
*tfs
;
1206 LttvTraceHookByFacility
*thf
;
1208 LttvTraceHook
*hook
;
1210 LttvAttributeValue val
;
1214 nb_trace
= lttv_traceset_number(traceset
);
1215 for(i
= 0 ; i
< nb_trace
; i
++) {
1216 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1218 /* Find the eventtype id for the following events and register the
1219 associated by id hooks. */
1221 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1222 g_array_set_size(hooks
, 10);
1224 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1225 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1226 LTT_FIELD_SYSCALL_ID
, 0, 0,
1227 syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
1230 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1231 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1233 syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
1236 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1237 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1238 LTT_FIELD_TRAP_ID
, 0, 0,
1239 trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
1242 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1243 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1245 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
1248 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1249 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1250 LTT_FIELD_IRQ_ID
, 0, 0,
1251 irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
1254 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1255 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1257 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
1260 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1261 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1262 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1263 schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
1266 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1267 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1268 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1269 process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
1272 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1273 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1274 LTT_FIELD_PID
, 0, 0,
1275 process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
1278 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1279 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1280 LTT_FIELD_PID
, 0, 0,
1281 process_free
, &g_array_index(hooks
, LttvTraceHook
, 9));
1285 /* Add these hooks to each event_by_id hooks list */
1287 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1289 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1291 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1292 LttvTracefileContext
*, j
));
1294 for(k
= 0 ; k
< hooks
->len
; k
++) {
1295 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1296 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1297 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1299 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1306 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1307 *(val
.v_pointer
) = hooks
;
1311 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1313 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1315 lttv_state_remove_event_hooks(tss
);
1320 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1322 LttvTraceset
*traceset
= self
->parent
.ts
;
1324 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1328 LttvTracefileState
*tfs
;
1332 LttvTraceHook
*hook
;
1334 LttvTraceHookByFacility
*thf
;
1336 LttvAttributeValue val
;
1338 nb_trace
= lttv_traceset_number(traceset
);
1339 for(i
= 0 ; i
< nb_trace
; i
++) {
1340 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1341 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1342 hooks
= *(val
.v_pointer
);
1344 /* Remove these hooks from each event_by_id hooks list */
1346 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1348 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1350 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1351 LttvTracefileContext
*, j
));
1353 for(k
= 0 ; k
< hooks
->len
; k
++) {
1354 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1355 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1356 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1358 lttv_hooks_remove_data(
1359 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1361 &g_array_index(hooks
, LttvTraceHook
, k
));
1363 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1366 g_array_free(hooks
, TRUE
);
1371 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1373 guint
*event_count
= (guint
*)hook_data
;
1375 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1376 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1381 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1383 LttvTracefileState
*tfcs
;
1385 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1387 LttEventPosition
*ep
;
1393 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1395 LttvAttributeValue value
;
1397 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1398 LTTV_STATE_SAVED_STATES
);
1399 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1400 value
= lttv_attribute_add(saved_states_tree
,
1401 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1402 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1403 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1404 *(value
.v_time
) = self
->parent
.timestamp
;
1405 lttv_state_save(tcs
, saved_state_tree
);
1406 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1407 self
->parent
.timestamp
.tv_nsec
);
1409 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1415 static gboolean
block_start(void *hook_data
, void *call_data
)
1417 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1419 LttvTracefileState
*tfcs
;
1421 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1423 LttEventPosition
*ep
;
1425 guint i
, nb_block
, nb_event
, nb_tracefile
;
1429 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1431 LttvAttributeValue value
;
1433 ep
= ltt_event_position_new();
1435 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1437 /* Count the number of events added since the last block end in any
1440 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1442 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1443 LttvTracefileContext
, i
));
1444 ltt_event_position(tfcs
->parent
.e
, ep
);
1445 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1446 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1447 tfcs
->saved_position
= nb_event
;
1451 if(tcs
->nb_event
>= tcs
->save_interval
) {
1452 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1453 LTTV_STATE_SAVED_STATES
);
1454 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1455 value
= lttv_attribute_add(saved_states_tree
,
1456 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1457 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1458 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1459 *(value
.v_time
) = self
->parent
.timestamp
;
1460 lttv_state_save(tcs
, saved_state_tree
);
1462 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1463 self
->parent
.timestamp
.tv_nsec
);
1465 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1471 static gboolean
block_end(void *hook_data
, void *call_data
)
1473 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1475 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1479 LttEventPosition
*ep
;
1481 guint nb_block
, nb_event
;
1483 ep
= ltt_event_position_new();
1484 ltt_event_position(self
->parent
.e
, ep
);
1485 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1486 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1487 self
->saved_position
= 0;
1488 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1495 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1497 LttvTraceset
*traceset
= self
->parent
.ts
;
1499 guint i
, j
, nb_trace
, nb_tracefile
;
1503 LttvTracefileState
*tfs
;
1505 LttvTraceHook hook_start
, hook_end
;
1507 nb_trace
= lttv_traceset_number(traceset
);
1508 for(i
= 0 ; i
< nb_trace
; i
++) {
1509 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1511 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1512 NULL
, NULL
, block_start
, &hook_start
);
1513 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1514 NULL
, NULL
, block_end
, &hook_end
);
1516 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1518 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1520 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1521 LttvTracefileContext
, j
));
1522 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1523 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1524 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1525 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1531 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1533 LttvTraceset
*traceset
= self
->parent
.ts
;
1535 guint i
, j
, nb_trace
, nb_tracefile
;
1539 LttvTracefileState
*tfs
;
1542 nb_trace
= lttv_traceset_number(traceset
);
1543 for(i
= 0 ; i
< nb_trace
; i
++) {
1545 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1546 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1548 guint
*event_count
= g_new(guint
, 1);
1551 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1553 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1554 LttvTracefileContext
*, j
));
1555 lttv_hooks_add(tfs
->parent
.event
,
1556 state_save_event_hook
,
1564 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1566 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1568 lttv_state_save_add_event_hooks(tss
);
1575 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1577 LttvTraceset
*traceset
= self
->parent
.ts
;
1579 guint i
, j
, nb_trace
, nb_tracefile
;
1583 LttvTracefileState
*tfs
;
1585 LttvTraceHook hook_start
, hook_end
;
1587 nb_trace
= lttv_traceset_number(traceset
);
1588 for(i
= 0 ; i
< nb_trace
; i
++) {
1589 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1591 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1592 NULL
, NULL
, block_start
, &hook_start
);
1594 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1595 NULL
, NULL
, block_end
, &hook_end
);
1597 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1599 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1601 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1602 LttvTracefileContext
, j
));
1603 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1604 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1605 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1606 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1612 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1614 LttvTraceset
*traceset
= self
->parent
.ts
;
1616 guint i
, j
, nb_trace
, nb_tracefile
;
1620 LttvTracefileState
*tfs
;
1623 nb_trace
= lttv_traceset_number(traceset
);
1624 for(i
= 0 ; i
< nb_trace
; i
++) {
1626 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1627 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1631 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1633 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1634 LttvTracefileContext
*, j
));
1635 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1636 state_save_event_hook
);
1637 g_free(event_count
);
1643 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1645 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1647 lttv_state_save_remove_event_hooks(tss
);
1652 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1654 LttvTraceset
*traceset
= self
->parent
.ts
;
1658 int min_pos
, mid_pos
, max_pos
;
1660 LttvTraceState
*tcs
;
1662 LttvAttributeValue value
;
1664 LttvAttributeType type
;
1666 LttvAttributeName name
;
1668 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1670 nb_trace
= lttv_traceset_number(traceset
);
1671 for(i
= 0 ; i
< nb_trace
; i
++) {
1672 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1674 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1675 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1676 LTTV_STATE_SAVED_STATES
);
1679 if(saved_states_tree
) {
1680 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1681 mid_pos
= max_pos
/ 2;
1682 while(min_pos
< max_pos
) {
1683 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1684 g_assert(type
== LTTV_GOBJECT
);
1685 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1686 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1688 g_assert(type
== LTTV_TIME
);
1689 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1691 closest_tree
= saved_state_tree
;
1693 else max_pos
= mid_pos
- 1;
1695 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1699 /* restore the closest earlier saved state */
1701 lttv_state_restore(tcs
, closest_tree
);
1704 /* There is no saved state, yet we want to have it. Restart at T0 */
1706 restore_init_state(tcs
);
1707 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1710 /* We want to seek quickly without restoring/updating the state */
1712 restore_init_state(tcs
);
1713 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1720 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1726 traceset_state_finalize (LttvTracesetState
*self
)
1728 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1729 finalize(G_OBJECT(self
));
1734 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1736 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1738 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1739 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1740 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1741 klass
->new_traceset_context
= new_traceset_context
;
1742 klass
->new_trace_context
= new_trace_context
;
1743 klass
->new_tracefile_context
= new_tracefile_context
;
1748 lttv_traceset_state_get_type(void)
1750 static GType type
= 0;
1752 static const GTypeInfo info
= {
1753 sizeof (LttvTracesetStateClass
),
1754 NULL
, /* base_init */
1755 NULL
, /* base_finalize */
1756 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1757 NULL
, /* class_finalize */
1758 NULL
, /* class_data */
1759 sizeof (LttvTracesetState
),
1760 0, /* n_preallocs */
1761 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1762 NULL
/* value handling */
1765 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1773 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1779 trace_state_finalize (LttvTraceState
*self
)
1781 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1782 finalize(G_OBJECT(self
));
1787 trace_state_class_init (LttvTraceStateClass
*klass
)
1789 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1791 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1792 klass
->state_save
= state_save
;
1793 klass
->state_restore
= state_restore
;
1794 klass
->state_saved_free
= state_saved_free
;
1799 lttv_trace_state_get_type(void)
1801 static GType type
= 0;
1803 static const GTypeInfo info
= {
1804 sizeof (LttvTraceStateClass
),
1805 NULL
, /* base_init */
1806 NULL
, /* base_finalize */
1807 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1808 NULL
, /* class_finalize */
1809 NULL
, /* class_data */
1810 sizeof (LttvTraceState
),
1811 0, /* n_preallocs */
1812 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1813 NULL
/* value handling */
1816 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1817 "LttvTraceStateType", &info
, 0);
1824 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1830 tracefile_state_finalize (LttvTracefileState
*self
)
1832 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1833 finalize(G_OBJECT(self
));
1838 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1840 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1842 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1847 lttv_tracefile_state_get_type(void)
1849 static GType type
= 0;
1851 static const GTypeInfo info
= {
1852 sizeof (LttvTracefileStateClass
),
1853 NULL
, /* base_init */
1854 NULL
, /* base_finalize */
1855 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1856 NULL
, /* class_finalize */
1857 NULL
, /* class_data */
1858 sizeof (LttvTracefileState
),
1859 0, /* n_preallocs */
1860 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1861 NULL
/* value handling */
1864 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1865 "LttvTracefileStateType", &info
, 0);
1871 static void module_init()
1873 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1874 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1875 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1876 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1877 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1878 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1879 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1880 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1881 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1882 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1883 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1884 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1885 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1886 LTTV_STATE_RUN
= g_quark_from_string("running");
1887 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1888 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1889 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1890 LTTV_STATE_EVENT
= g_quark_from_string("event");
1891 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1892 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1893 LTTV_STATE_TIME
= g_quark_from_string("time");
1894 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1895 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1896 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1897 g_quark_from_string("trace_state_use_count");
1900 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
1901 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
1904 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
1905 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
1906 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
1907 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
1908 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
1909 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
1910 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
1911 LTT_EVENT_FORK
= g_quark_from_string("fork");
1912 LTT_EVENT_EXIT
= g_quark_from_string("exit");
1913 LTT_EVENT_FREE
= g_quark_from_string("free");
1916 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
1917 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
1918 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
1919 LTT_FIELD_OUT
= g_quark_from_string("out");
1920 LTT_FIELD_IN
= g_quark_from_string("in");
1921 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
1922 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
1923 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
1924 LTT_FIELD_PID
= g_quark_from_string("pid");
1928 static void module_destroy()
1933 LTTV_MODULE("state", "State computation", \
1934 "Update the system state, possibly saving it at intervals", \
1935 module_init
, module_destroy
)