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
,
91 LTTV_STATE_RUNNING_PROCESS
,
93 LTTV_STATE_SAVED_STATES
,
94 LTTV_STATE_SAVED_STATES_TIME
,
97 LTTV_STATE_NAME_TABLES
,
98 LTTV_STATE_TRACE_STATE_USE_COUNT
;
100 static void create_max_time(LttvTraceState
*tcs
);
102 static void get_max_time(LttvTraceState
*tcs
);
104 static void free_max_time(LttvTraceState
*tcs
);
106 static void create_name_tables(LttvTraceState
*tcs
);
108 static void get_name_tables(LttvTraceState
*tcs
);
110 static void free_name_tables(LttvTraceState
*tcs
);
112 static void free_saved_state(LttvTraceState
*tcs
);
114 static void lttv_state_free_process_table(GHashTable
*processes
);
117 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
119 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
123 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
125 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
129 void lttv_state_state_saved_free(LttvTraceState
*self
,
130 LttvAttribute
*container
)
132 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
136 guint
process_hash(gconstpointer key
)
138 guint pid
= ((const LttvProcessState
*)key
)->pid
;
139 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
143 /* If the hash table hash function is well distributed,
144 * the process_equal should compare different pid */
145 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
147 const LttvProcessState
*process_a
, *process_b
;
150 process_a
= (const LttvProcessState
*)a
;
151 process_b
= (const LttvProcessState
*)b
;
153 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
154 else if(likely(process_a
->pid
== 0 &&
155 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
162 restore_init_state(LttvTraceState
*self
)
166 LttvTracefileState
*tfcs
;
168 /* Free the process tables */
169 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
170 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
173 /* Seek time to beginning */
174 g_tree_destroy(self
->parent
.ts_context
->pqueue
);
175 self
->parent
.ts_context
->pqueue
= g_tree_new(compare_tracefile
);
177 lttv_process_trace_seek_time(&self
->parent
, ltt_time_zero
);
179 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
181 /* Put the per cpu running_process to beginning state : process 0. */
182 for(i
=0; i
< nb_cpus
; i
++) {
183 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
185 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
186 self
->running_process
[i
]->cpu
= i
;
190 nb_tracefile
= self
->parent
.tracefiles
->len
;
192 for(i
= 0 ; i
< nb_tracefile
; i
++) {
194 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
195 LttvTracefileContext
*, i
));
196 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
197 // tfcs->saved_position = 0;
198 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
199 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
200 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
201 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
206 //static LttTime time_zero = {0,0};
209 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
211 guint i
, j
, nb_trace
, nb_tracefile
;
213 LttvTraceContext
*tc
;
217 LttvTracefileState
*tfcs
;
219 LttvAttributeValue v
;
221 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
222 init((LttvTracesetContext
*)self
, ts
);
224 nb_trace
= lttv_traceset_number(ts
);
225 for(i
= 0 ; i
< nb_trace
; i
++) {
226 tc
= self
->parent
.traces
[i
];
227 tcs
= LTTV_TRACE_STATE(tc
);
228 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
229 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
233 if(*(v
.v_uint
) == 1) {
234 create_name_tables(tcs
);
235 create_max_time(tcs
);
237 get_name_tables(tcs
);
240 nb_tracefile
= tc
->tracefiles
->len
;
242 for(j
= 0 ; j
< nb_tracefile
; j
++) {
244 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
245 LttvTracefileContext
*, j
));
246 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
249 tcs
->processes
= NULL
;
250 tcs
->running_process
= g_new(LttvProcessState
*,
251 ltt_trace_get_num_cpu(tc
->t
));
252 restore_init_state(tcs
);
258 fini(LttvTracesetState
*self
)
264 LttvTracefileState
*tfcs
;
266 LttvAttributeValue v
;
268 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
269 for(i
= 0 ; i
< nb_trace
; i
++) {
270 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
271 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
274 g_assert(*(v
.v_uint
) != 0);
277 if(*(v
.v_uint
) == 0) {
278 free_name_tables(tcs
);
280 free_saved_state(tcs
);
282 g_free(tcs
->running_process
);
283 tcs
->running_process
= NULL
;
284 lttv_state_free_process_table(tcs
->processes
);
285 tcs
->processes
= NULL
;
287 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
288 fini((LttvTracesetContext
*)self
);
292 static LttvTracesetContext
*
293 new_traceset_context(LttvTracesetContext
*self
)
295 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
299 static LttvTraceContext
*
300 new_trace_context(LttvTracesetContext
*self
)
302 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
306 static LttvTracefileContext
*
307 new_tracefile_context(LttvTracesetContext
*self
)
309 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
313 /* Write the process state of the trace */
315 static void write_process_state(gpointer key
, gpointer value
,
318 LttvProcessState
*process
;
320 LttvExecutionState
*es
;
322 FILE *fp
= (FILE *)user_data
;
326 process
= (LttvProcessState
*)value
;
328 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
329 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
330 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
333 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
334 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
335 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
336 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
337 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
338 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
339 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
341 fprintf(fp
, " </PROCESS>\n");
345 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
347 guint i
, nb_tracefile
, nb_block
, offset
;
350 LttvTracefileState
*tfcs
;
354 LttEventPosition
*ep
;
358 ep
= ltt_event_position_new();
360 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
362 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
364 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
365 for(i
=0;i
<nb_cpus
;i
++) {
366 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
367 i
, self
->running_process
[i
]->pid
);
370 nb_tracefile
= self
->parent
.tracefiles
->len
;
372 for(i
= 0 ; i
< nb_tracefile
; i
++) {
374 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
375 LttvTracefileContext
*, i
));
376 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
377 tfcs
->parent
.timestamp
.tv_sec
,
378 tfcs
->parent
.timestamp
.tv_nsec
);
379 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
380 if(e
== NULL
) fprintf(fp
,"/>\n");
382 ltt_event_position(e
, ep
);
383 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
384 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
389 fprintf(fp
,"</PROCESS_STATE>");
393 /* Copy each process from an existing hash table to a new one */
395 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
397 LttvProcessState
*process
, *new_process
;
399 GHashTable
*new_processes
= (GHashTable
*)user_data
;
403 process
= (LttvProcessState
*)value
;
404 new_process
= g_new(LttvProcessState
, 1);
405 *new_process
= *process
;
406 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
407 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
408 new_process
->execution_stack
=
409 g_array_set_size(new_process
->execution_stack
,
410 process
->execution_stack
->len
);
411 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
412 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
413 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
415 new_process
->state
= &g_array_index(new_process
->execution_stack
,
416 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
417 g_hash_table_insert(new_processes
, new_process
, new_process
);
421 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
423 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
425 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
426 return new_processes
;
430 /* The saved state for each trace contains a member "processes", which
431 stores a copy of the process table, and a member "tracefiles" with
432 one entry per tracefile. Each tracefile has a "process" member pointing
433 to the current process and a "position" member storing the tracefile
434 position (needed to seek to the current "next" event. */
436 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
438 guint i
, nb_tracefile
, nb_cpus
;
440 LttvTracefileState
*tfcs
;
442 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
444 guint
*running_process
;
446 LttvAttributeType type
;
448 LttvAttributeValue value
;
450 LttvAttributeName name
;
452 LttEventPosition
*ep
;
454 tracefiles_tree
= lttv_attribute_find_subdir(container
,
455 LTTV_STATE_TRACEFILES
);
457 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
459 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
461 /* Add the currently running processes array */
462 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
463 running_process
= g_new(guint
, nb_cpus
);
464 for(i
=0;i
<nb_cpus
;i
++) {
465 running_process
[i
] = self
->running_process
[i
]->pid
;
467 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
469 *(value
.v_pointer
) = running_process
;
472 nb_tracefile
= self
->parent
.tracefiles
->len
;
474 for(i
= 0 ; i
< nb_tracefile
; i
++) {
476 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
477 LttvTracefileContext
*, i
));
478 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
479 value
= lttv_attribute_add(tracefiles_tree
, i
,
481 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
483 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
485 *(value
.v_uint
) = tfcs
->process
->pid
;
487 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
489 /* Only save the position if the tfs has not infinite time. */
490 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
491 // && current_tfcs != tfcs) {
492 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
493 *(value
.v_pointer
) = NULL
;
495 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
496 ep
= ltt_event_position_new();
497 ltt_event_position(e
, ep
);
498 *(value
.v_pointer
) = ep
;
500 guint nb_block
, offset
;
503 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
504 g_debug("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
506 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
512 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
514 guint i
, nb_tracefile
, pid
, nb_cpus
;
516 LttvTracefileState
*tfcs
;
518 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
520 guint
*running_process
;
522 LttvAttributeType type
;
524 LttvAttributeValue value
;
526 LttvAttributeName name
;
528 LttEventPosition
*ep
;
530 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
532 tracefiles_tree
= lttv_attribute_find_subdir(container
,
533 LTTV_STATE_TRACEFILES
);
535 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
537 g_assert(type
== LTTV_POINTER
);
538 lttv_state_free_process_table(self
->processes
);
539 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
541 /* Add the currently running processes array */
542 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
543 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
545 g_assert(type
== LTTV_POINTER
);
546 running_process
= *(value
.v_pointer
);
547 for(i
=0;i
<nb_cpus
;i
++) {
548 pid
= running_process
[i
];
549 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
550 g_assert(self
->running_process
[i
] != NULL
);
554 nb_tracefile
= self
->parent
.tracefiles
->len
;
556 g_tree_destroy(tsc
->pqueue
);
557 tsc
->pqueue
= g_tree_new(compare_tracefile
);
559 for(i
= 0 ; i
< nb_tracefile
; i
++) {
561 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
562 LttvTracefileContext
*, i
));
563 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
564 g_assert(type
== LTTV_GOBJECT
);
565 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
567 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
569 g_assert(type
== LTTV_UINT
);
570 pid
= *(value
.v_uint
);
571 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
573 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
575 g_assert(type
== LTTV_POINTER
);
576 //g_assert(*(value.v_pointer) != NULL);
577 ep
= *(value
.v_pointer
);
578 g_assert(tfcs
->parent
.t_context
!= NULL
);
580 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
583 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
584 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
585 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
586 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
588 tfc
->timestamp
= ltt_time_infinite
;
594 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
596 guint i
, nb_tracefile
, nb_cpus
;
598 LttvTracefileState
*tfcs
;
600 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
602 guint
*running_process
;
604 LttvAttributeType type
;
606 LttvAttributeValue value
;
608 LttvAttributeName name
;
610 LttEventPosition
*ep
;
612 tracefiles_tree
= lttv_attribute_find_subdir(container
,
613 LTTV_STATE_TRACEFILES
);
614 g_object_ref(G_OBJECT(tracefiles_tree
));
615 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
617 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
619 g_assert(type
== LTTV_POINTER
);
620 lttv_state_free_process_table(*(value
.v_pointer
));
621 *(value
.v_pointer
) = NULL
;
622 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
624 /* Free running processes array */
625 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
626 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_RUNNING_PROCESS
,
628 g_assert(type
== LTTV_POINTER
);
629 running_process
= *(value
.v_pointer
);
630 g_free(running_process
);
632 nb_tracefile
= self
->parent
.tracefiles
->len
;
634 for(i
= 0 ; i
< nb_tracefile
; i
++) {
636 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
637 LttvTracefileContext
*, i
));
638 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
639 g_assert(type
== LTTV_GOBJECT
);
640 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
642 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
644 g_assert(type
== LTTV_POINTER
);
645 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
647 g_object_unref(G_OBJECT(tracefiles_tree
));
651 static void free_saved_state(LttvTraceState
*self
)
655 LttvAttributeType type
;
657 LttvAttributeValue value
;
659 LttvAttributeName name
;
661 LttvAttribute
*saved_states
;
663 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
664 LTTV_STATE_SAVED_STATES
);
666 nb
= lttv_attribute_get_number(saved_states
);
667 for(i
= 0 ; i
< nb
; i
++) {
668 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
669 g_assert(type
== LTTV_GOBJECT
);
670 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
673 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
678 create_max_time(LttvTraceState
*tcs
)
680 LttvAttributeValue v
;
682 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
684 g_assert(*(v
.v_pointer
) == NULL
);
685 *(v
.v_pointer
) = g_new(LttTime
,1);
686 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
691 get_max_time(LttvTraceState
*tcs
)
693 LttvAttributeValue v
;
695 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
697 g_assert(*(v
.v_pointer
) != NULL
);
698 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
703 free_max_time(LttvTraceState
*tcs
)
705 LttvAttributeValue v
;
707 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
709 g_free(*(v
.v_pointer
));
710 *(v
.v_pointer
) = NULL
;
714 typedef struct _LttvNameTables
{
715 // FIXME GQuark *eventtype_names;
716 GQuark
*syscall_names
;
723 create_name_tables(LttvTraceState
*tcs
)
727 GQuark f_name
, e_name
;
731 LttvTraceHookByFacility
*thf
;
737 GString
*fe_name
= g_string_new("");
739 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
741 LttvAttributeValue v
;
743 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
745 g_assert(*(v
.v_pointer
) == NULL
);
746 *(v
.v_pointer
) = name_tables
;
747 #if 0 // Use iteration over the facilities_by_name and then list all event
748 // types of each facility
749 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
750 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
751 for(i
= 0 ; i
< nb
; i
++) {
752 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
753 e_name
= ltt_eventtype_name(et
);
754 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
755 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
756 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
759 if(lttv_trace_find_hook(tcs
->parent
.t
,
760 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
761 LTT_FIELD_SYSCALL_ID
, 0, 0,
765 thf
= lttv_trace_hook_get_first(&h
);
767 t
= ltt_field_type(thf
->f1
);
768 nb
= ltt_type_element_number(t
);
770 lttv_trace_hook_destroy(&h
);
772 /* CHECK syscalls should be an enum but currently are not!
773 name_tables->syscall_names = g_new(GQuark, nb);
775 for(i = 0 ; i < nb ; i++) {
776 name_tables->syscall_names[i] = g_quark_from_string(
777 ltt_enum_string_get(t, i));
781 name_tables
->syscall_names
= g_new(GQuark
, 256);
782 for(i
= 0 ; i
< 256 ; i
++) {
783 g_string_printf(fe_name
, "syscall %d", i
);
784 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
787 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
788 LTT_EVENT_TRAP_ENTRY
,
789 LTT_FIELD_TRAP_ID
, 0, 0,
793 thf
= lttv_trace_hook_get_first(&h
);
795 t
= ltt_field_type(thf
->f1
);
796 nb
= ltt_type_element_number(t
);
798 lttv_trace_hook_destroy(&h
);
801 name_tables->trap_names = g_new(GQuark, nb);
802 for(i = 0 ; i < nb ; i++) {
803 name_tables->trap_names[i] = g_quark_from_string(
804 ltt_enum_string_get(t, i));
808 name_tables
->trap_names
= g_new(GQuark
, 256);
809 for(i
= 0 ; i
< 256 ; i
++) {
810 g_string_printf(fe_name
, "trap %d", i
);
811 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
814 if(lttv_trace_find_hook(tcs
->parent
.t
,
815 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
816 LTT_FIELD_IRQ_ID
, 0, 0,
820 thf
= lttv_trace_hook_get_first(&h
);
822 t
= ltt_field_type(thf
->f1
);
823 nb
= ltt_type_element_number(t
);
825 lttv_trace_hook_destroy(&h
);
828 name_tables->irq_names = g_new(GQuark, nb);
829 for(i = 0 ; i < nb ; i++) {
830 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
834 name_tables
->irq_names
= g_new(GQuark
, 256);
835 for(i
= 0 ; i
< 256 ; i
++) {
836 g_string_printf(fe_name
, "irq %d", i
);
837 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
840 g_string_free(fe_name
, TRUE
);
845 get_name_tables(LttvTraceState
*tcs
)
847 LttvNameTables
*name_tables
;
849 LttvAttributeValue v
;
851 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
853 g_assert(*(v
.v_pointer
) != NULL
);
854 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
855 //tcs->eventtype_names = name_tables->eventtype_names;
856 tcs
->syscall_names
= name_tables
->syscall_names
;
857 tcs
->trap_names
= name_tables
->trap_names
;
858 tcs
->irq_names
= name_tables
->irq_names
;
863 free_name_tables(LttvTraceState
*tcs
)
865 LttvNameTables
*name_tables
;
867 LttvAttributeValue v
;
869 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
871 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
872 *(v
.v_pointer
) = NULL
;
874 // g_free(name_tables->eventtype_names);
875 g_free(name_tables
->syscall_names
);
876 g_free(name_tables
->trap_names
);
877 g_free(name_tables
->irq_names
);
881 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
884 LttvExecutionState
*es
;
886 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
887 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
888 LttvProcessState
*process
= ts
->running_process
[cpu
];
890 guint depth
= process
->execution_stack
->len
;
892 process
->execution_stack
=
893 g_array_set_size(process
->execution_stack
, depth
+ 1);
896 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
898 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
901 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
902 es
->s
= process
->state
->s
;
907 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
909 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
910 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
911 LttvProcessState
*process
= ts
->running_process
[cpu
];
913 guint depth
= process
->execution_stack
->len
;
915 if(process
->state
->t
!= t
){
916 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
917 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
918 g_info("process state has %s when pop_int is %s\n",
919 g_quark_to_string(process
->state
->t
),
920 g_quark_to_string(t
));
921 g_info("{ %u, %u, %s, %s }\n",
924 g_quark_to_string(process
->name
),
925 g_quark_to_string(process
->state
->s
));
930 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
931 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
935 process
->execution_stack
=
936 g_array_set_size(process
->execution_stack
, depth
- 1);
937 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
939 process
->state
->change
= tfs
->parent
.timestamp
;
944 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
945 guint cpu
, guint pid
, const LttTime
*timestamp
)
947 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
949 LttvExecutionState
*es
;
951 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
957 //process->last_cpu = tfs->cpu_name;
958 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
959 g_info("Process %u, core %p", process
->pid
, process
);
960 g_hash_table_insert(tcs
->processes
, process
, process
);
963 process
->ppid
= parent
->pid
;
964 process
->name
= parent
->name
;
965 process
->creation_time
= *timestamp
;
968 /* No parent. This process exists but we are missing all information about
969 its creation. The birth time is set to zero but we remember the time of
974 process
->name
= LTTV_STATE_UNNAMED
;
975 process
->creation_time
= ltt_time_zero
;
978 process
->insertion_time
= *timestamp
;
979 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
980 process
->creation_time
.tv_nsec
);
981 process
->pid_time
= g_quark_from_string(buffer
);
983 //process->last_cpu = tfs->cpu_name;
984 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
985 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
986 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
987 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
988 es
= process
->state
= &g_array_index(process
->execution_stack
,
989 LttvExecutionState
, 0);
990 es
->t
= LTTV_STATE_USER_MODE
;
991 es
->n
= LTTV_STATE_SUBMODE_NONE
;
992 es
->entry
= *timestamp
;
993 //g_assert(timestamp->tv_sec != 0);
994 es
->change
= *timestamp
;
995 es
->s
= LTTV_STATE_WAIT_FORK
;
1000 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1003 LttvProcessState key
;
1004 LttvProcessState
*process
;
1008 process
= g_hash_table_lookup(ts
->processes
, &key
);
1013 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1016 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1018 /* Put ltt_time_zero creation time for unexisting processes */
1019 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1020 NULL
, cpu
, pid
, timestamp
);
1024 /* FIXME : this function should be called when we receive an event telling that
1025 * release_task has been called in the kernel. In happens generally when
1026 * the parent waits for its child terminaison, but may also happen in special
1027 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1028 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1029 * of a killed thread ground, but isn't the leader.
1031 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1033 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1034 LttvProcessState key
;
1036 key
.pid
= process
->pid
;
1037 key
.cpu
= process
->cpu
;
1038 g_hash_table_remove(ts
->processes
, &key
);
1039 g_array_free(process
->execution_stack
, TRUE
);
1044 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1046 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1051 static void lttv_state_free_process_table(GHashTable
*processes
)
1053 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1054 g_hash_table_destroy(processes
);
1058 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1060 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1061 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1062 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1063 LttField
*f
= thf
->f1
;
1065 LttvExecutionSubmode submode
;
1067 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1068 ltt_event_get_unsigned(e
, f
)];
1069 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1074 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1076 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1078 pop_state(s
, LTTV_STATE_SYSCALL
);
1083 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1085 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1086 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1087 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1088 LttField
*f
= thf
->f1
;
1090 LttvExecutionSubmode submode
;
1092 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1093 ltt_event_get_unsigned(e
, f
)];
1094 push_state(s
, LTTV_STATE_TRAP
, submode
);
1099 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1101 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1103 pop_state(s
, LTTV_STATE_TRAP
);
1108 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1110 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1111 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1112 guint8 fac_id
= ltt_event_facility_id(e
);
1113 guint8 ev_id
= ltt_event_eventtype_id(e
);
1114 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1115 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1116 g_assert(thf
->f1
!= NULL
);
1117 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1118 LttField
*f
= thf
->f1
;
1120 LttvExecutionSubmode submode
;
1122 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1123 ltt_event_get_unsigned(e
, f
)];
1125 /* Do something with the info about being in user or system mode when int? */
1126 push_state(s
, LTTV_STATE_IRQ
, submode
);
1131 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1133 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1135 pop_state(s
, LTTV_STATE_IRQ
);
1140 static gboolean
schedchange(void *hook_data
, void *call_data
)
1142 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1143 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1144 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1145 LttvProcessState
*process
= ts
->running_process
[cpu
];
1147 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1148 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1149 guint pid_in
, pid_out
;
1152 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1153 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1154 state_out
= ltt_event_get_int(e
, thf
->f3
);
1156 if(likely(process
!= NULL
)) {
1158 /* We could not know but it was not the idle process executing.
1159 This should only happen at the beginning, before the first schedule
1160 event, and when the initial information (current process for each CPU)
1161 is missing. It is not obvious how we could, after the fact, compensate
1162 the wrongly attributed statistics. */
1164 //This test only makes sense once the state is known and if there is no
1166 //if(unlikely(process->pid != pid_out)) {
1167 // g_assert(process->pid == 0);
1170 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1171 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1173 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1174 else process
->state
->s
= LTTV_STATE_WAIT
;
1175 } /* FIXME : we do not remove process here, because the kernel
1176 * still has them : they may be zombies. We need to know
1177 * exactly when release_task is executed on the PID to
1178 * know when the zombie is destroyed.
1181 // exit_process(s, process);
1183 process
->state
->change
= s
->parent
.timestamp
;
1185 process
= ts
->running_process
[cpu
] =
1186 lttv_state_find_process_or_create(
1187 (LttvTraceState
*)s
->parent
.t_context
,
1189 &s
->parent
.timestamp
);
1190 process
->state
->s
= LTTV_STATE_RUN
;
1192 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1193 process
->state
->change
= s
->parent
.timestamp
;
1197 static gboolean
process_fork(void *hook_data
, void *call_data
)
1199 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1200 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1201 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1205 LttvProcessState
*zombie_process
;
1206 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1207 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1208 LttvProcessState
*process
= ts
->running_process
[cpu
];
1212 parent_pid
= ltt_event_get_unsigned(e
, f
);
1216 child_pid
= ltt_event_get_unsigned(e
, f
);
1218 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1220 if(unlikely(zombie_process
!= NULL
)) {
1221 /* Reutilisation of PID. Only now we are sure that the old PID
1222 * has been released. FIXME : should know when release_task happens instead.
1224 exit_process(s
, zombie_process
);
1226 g_assert(process
->pid
!= child_pid
);
1227 // FIXME : Add this test in the "known state" section
1228 // g_assert(process->pid == parent_pid);
1229 lttv_state_create_process(ts
, process
, cpu
, child_pid
, &s
->parent
.timestamp
);
1235 static gboolean
process_exit(void *hook_data
, void *call_data
)
1237 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1238 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1239 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1242 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1243 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1244 LttvProcessState
*process
= ts
->running_process
[cpu
];
1246 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1248 // FIXME : Add this test in the "known state" section
1249 // g_assert(process->pid == pid);
1251 if(likely(process
!= NULL
)) {
1252 process
->state
->s
= LTTV_STATE_EXIT
;
1257 static gboolean
process_free(void *hook_data
, void *call_data
)
1259 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1260 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1261 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1262 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1264 LttvProcessState
*process
;
1266 /* PID of the process to release */
1267 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1269 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1271 if(likely(process
!= NULL
)) {
1272 /* release_task is happening at kernel level : we can now safely release
1273 * the data structure of the process */
1274 exit_process(s
, process
);
1280 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1282 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1284 lttv_state_add_event_hooks(tss
);
1289 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1291 LttvTraceset
*traceset
= self
->parent
.ts
;
1293 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1297 LttvTracefileState
*tfs
;
1301 LttvTraceHookByFacility
*thf
;
1303 LttvTraceHook
*hook
;
1305 LttvAttributeValue val
;
1309 nb_trace
= lttv_traceset_number(traceset
);
1310 for(i
= 0 ; i
< nb_trace
; i
++) {
1311 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1313 /* Find the eventtype id for the following events and register the
1314 associated by id hooks. */
1316 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1317 hooks
= g_array_set_size(hooks
, 10);
1319 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1320 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1321 LTT_FIELD_SYSCALL_ID
, 0, 0,
1322 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1325 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1326 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1328 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1331 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1332 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1333 LTT_FIELD_TRAP_ID
, 0, 0,
1334 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1337 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1338 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1340 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1343 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1344 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1345 LTT_FIELD_IRQ_ID
, 0, 0,
1346 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1349 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1350 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1352 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1355 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1356 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1357 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1358 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1361 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1362 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1363 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1364 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1367 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1368 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1369 LTT_FIELD_PID
, 0, 0,
1370 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1373 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1374 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1375 LTT_FIELD_PID
, 0, 0,
1376 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1380 /* Add these hooks to each event_by_id hooks list */
1382 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1384 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1386 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1387 LttvTracefileContext
*, j
));
1389 for(k
= 0 ; k
< hooks
->len
; k
++) {
1390 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1391 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1392 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1394 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1401 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1402 *(val
.v_pointer
) = hooks
;
1406 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1408 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1410 lttv_state_remove_event_hooks(tss
);
1415 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1417 LttvTraceset
*traceset
= self
->parent
.ts
;
1419 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1423 LttvTracefileState
*tfs
;
1427 LttvTraceHook
*hook
;
1429 LttvTraceHookByFacility
*thf
;
1431 LttvAttributeValue val
;
1433 nb_trace
= lttv_traceset_number(traceset
);
1434 for(i
= 0 ; i
< nb_trace
; i
++) {
1435 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1436 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1437 hooks
= *(val
.v_pointer
);
1439 /* Remove these hooks from each event_by_id hooks list */
1441 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1443 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1445 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1446 LttvTracefileContext
*, j
));
1448 for(k
= 0 ; k
< hooks
->len
; k
++) {
1449 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1450 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1451 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1453 lttv_hooks_remove_data(
1454 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1460 for(k
= 0 ; k
< hooks
->len
; k
++)
1461 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1462 g_array_free(hooks
, TRUE
);
1466 static guint test_event_count
= 0;
1467 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1469 guint
*event_count
= (guint
*)hook_data
;
1472 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1473 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1478 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1480 LttvTracefileState
*tfcs
;
1482 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1484 LttEventPosition
*ep
;
1490 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1492 LttvAttributeValue value
;
1494 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1495 LTTV_STATE_SAVED_STATES
);
1496 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1497 value
= lttv_attribute_add(saved_states_tree
,
1498 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1499 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1500 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1501 *(value
.v_time
) = self
->parent
.timestamp
;
1502 lttv_state_save(tcs
, saved_state_tree
);
1503 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1504 self
->parent
.timestamp
.tv_nsec
);
1506 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1512 static gboolean
block_start(void *hook_data
, void *call_data
)
1514 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1516 LttvTracefileState
*tfcs
;
1518 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1520 LttEventPosition
*ep
;
1522 guint i
, nb_block
, nb_event
, nb_tracefile
;
1526 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1528 LttvAttributeValue value
;
1530 ep
= ltt_event_position_new();
1532 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1534 /* Count the number of events added since the last block end in any
1537 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1539 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1540 LttvTracefileContext
, i
));
1541 ltt_event_position(tfcs
->parent
.e
, ep
);
1542 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1543 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1544 tfcs
->saved_position
= nb_event
;
1548 if(tcs
->nb_event
>= tcs
->save_interval
) {
1549 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1550 LTTV_STATE_SAVED_STATES
);
1551 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1552 value
= lttv_attribute_add(saved_states_tree
,
1553 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1554 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1555 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1556 *(value
.v_time
) = self
->parent
.timestamp
;
1557 lttv_state_save(tcs
, saved_state_tree
);
1559 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1560 self
->parent
.timestamp
.tv_nsec
);
1562 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1568 static gboolean
block_end(void *hook_data
, void *call_data
)
1570 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1572 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1576 LttEventPosition
*ep
;
1578 guint nb_block
, nb_event
;
1580 ep
= ltt_event_position_new();
1581 ltt_event_position(self
->parent
.e
, ep
);
1582 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1583 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1584 self
->saved_position
= 0;
1585 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1592 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1594 LttvTraceset
*traceset
= self
->parent
.ts
;
1596 guint i
, j
, nb_trace
, nb_tracefile
;
1600 LttvTracefileState
*tfs
;
1602 LttvTraceHook hook_start
, hook_end
;
1604 nb_trace
= lttv_traceset_number(traceset
);
1605 for(i
= 0 ; i
< nb_trace
; i
++) {
1606 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1608 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1609 NULL
, NULL
, block_start
, &hook_start
);
1610 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1611 NULL
, NULL
, block_end
, &hook_end
);
1613 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1615 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1617 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1618 LttvTracefileContext
, j
));
1619 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1620 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1621 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1622 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1628 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1630 LttvTraceset
*traceset
= self
->parent
.ts
;
1632 guint i
, j
, nb_trace
, nb_tracefile
;
1636 LttvTracefileState
*tfs
;
1639 nb_trace
= lttv_traceset_number(traceset
);
1640 for(i
= 0 ; i
< nb_trace
; i
++) {
1642 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1643 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1645 guint
*event_count
= g_new(guint
, 1);
1648 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1650 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1651 LttvTracefileContext
*, j
));
1652 lttv_hooks_add(tfs
->parent
.event
,
1653 state_save_event_hook
,
1661 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1663 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1665 lttv_state_save_add_event_hooks(tss
);
1672 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1674 LttvTraceset
*traceset
= self
->parent
.ts
;
1676 guint i
, j
, nb_trace
, nb_tracefile
;
1680 LttvTracefileState
*tfs
;
1682 LttvTraceHook hook_start
, hook_end
;
1684 nb_trace
= lttv_traceset_number(traceset
);
1685 for(i
= 0 ; i
< nb_trace
; i
++) {
1686 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1688 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1689 NULL
, NULL
, block_start
, &hook_start
);
1691 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1692 NULL
, NULL
, block_end
, &hook_end
);
1694 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1696 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1698 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1699 LttvTracefileContext
, j
));
1700 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1701 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1702 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1703 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1709 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1711 LttvTraceset
*traceset
= self
->parent
.ts
;
1713 guint i
, j
, nb_trace
, nb_tracefile
;
1717 LttvTracefileState
*tfs
;
1720 nb_trace
= lttv_traceset_number(traceset
);
1721 for(i
= 0 ; i
< nb_trace
; i
++) {
1723 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1724 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1728 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1730 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1731 LttvTracefileContext
*, j
));
1732 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1733 state_save_event_hook
);
1736 g_free(event_count
);
1738 g_info("EVENT COUNT TEST : %u", test_event_count
);
1741 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1743 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1745 lttv_state_save_remove_event_hooks(tss
);
1750 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1752 LttvTraceset
*traceset
= self
->parent
.ts
;
1756 int min_pos
, mid_pos
, max_pos
;
1758 LttvTraceState
*tcs
;
1760 LttvAttributeValue value
;
1762 LttvAttributeType type
;
1764 LttvAttributeName name
;
1766 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1768 g_tree_destroy(self
->parent
.pqueue
);
1769 self
->parent
.pqueue
= g_tree_new(compare_tracefile
);
1771 nb_trace
= lttv_traceset_number(traceset
);
1772 for(i
= 0 ; i
< nb_trace
; i
++) {
1773 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1775 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1776 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1777 LTTV_STATE_SAVED_STATES
);
1780 if(saved_states_tree
) {
1781 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1782 mid_pos
= max_pos
/ 2;
1783 while(min_pos
< max_pos
) {
1784 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1785 g_assert(type
== LTTV_GOBJECT
);
1786 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1787 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1789 g_assert(type
== LTTV_TIME
);
1790 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1792 closest_tree
= saved_state_tree
;
1794 else max_pos
= mid_pos
- 1;
1796 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1800 /* restore the closest earlier saved state */
1802 lttv_state_restore(tcs
, closest_tree
);
1805 /* There is no saved state, yet we want to have it. Restart at T0 */
1807 restore_init_state(tcs
);
1808 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1811 /* We want to seek quickly without restoring/updating the state */
1813 restore_init_state(tcs
);
1814 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1821 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1827 traceset_state_finalize (LttvTracesetState
*self
)
1829 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1830 finalize(G_OBJECT(self
));
1835 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1837 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1839 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1840 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1841 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1842 klass
->new_traceset_context
= new_traceset_context
;
1843 klass
->new_trace_context
= new_trace_context
;
1844 klass
->new_tracefile_context
= new_tracefile_context
;
1849 lttv_traceset_state_get_type(void)
1851 static GType type
= 0;
1853 static const GTypeInfo info
= {
1854 sizeof (LttvTracesetStateClass
),
1855 NULL
, /* base_init */
1856 NULL
, /* base_finalize */
1857 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1858 NULL
, /* class_finalize */
1859 NULL
, /* class_data */
1860 sizeof (LttvTracesetState
),
1861 0, /* n_preallocs */
1862 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1863 NULL
/* value handling */
1866 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1874 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1880 trace_state_finalize (LttvTraceState
*self
)
1882 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1883 finalize(G_OBJECT(self
));
1888 trace_state_class_init (LttvTraceStateClass
*klass
)
1890 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1892 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1893 klass
->state_save
= state_save
;
1894 klass
->state_restore
= state_restore
;
1895 klass
->state_saved_free
= state_saved_free
;
1900 lttv_trace_state_get_type(void)
1902 static GType type
= 0;
1904 static const GTypeInfo info
= {
1905 sizeof (LttvTraceStateClass
),
1906 NULL
, /* base_init */
1907 NULL
, /* base_finalize */
1908 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1909 NULL
, /* class_finalize */
1910 NULL
, /* class_data */
1911 sizeof (LttvTraceState
),
1912 0, /* n_preallocs */
1913 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1914 NULL
/* value handling */
1917 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1918 "LttvTraceStateType", &info
, 0);
1925 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1931 tracefile_state_finalize (LttvTracefileState
*self
)
1933 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1934 finalize(G_OBJECT(self
));
1939 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1941 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1943 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1948 lttv_tracefile_state_get_type(void)
1950 static GType type
= 0;
1952 static const GTypeInfo info
= {
1953 sizeof (LttvTracefileStateClass
),
1954 NULL
, /* base_init */
1955 NULL
, /* base_finalize */
1956 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1957 NULL
, /* class_finalize */
1958 NULL
, /* class_data */
1959 sizeof (LttvTracefileState
),
1960 0, /* n_preallocs */
1961 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1962 NULL
/* value handling */
1965 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1966 "LttvTracefileStateType", &info
, 0);
1972 static void module_init()
1974 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1975 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1976 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1977 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1978 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1979 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1980 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1981 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1982 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1983 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1984 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1985 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1986 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1987 LTTV_STATE_RUN
= g_quark_from_string("running");
1988 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1989 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1990 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1991 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
1992 LTTV_STATE_EVENT
= g_quark_from_string("event");
1993 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1994 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1995 LTTV_STATE_TIME
= g_quark_from_string("time");
1996 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1997 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
1998 LTTV_STATE_TRACE_STATE_USE_COUNT
=
1999 g_quark_from_string("trace_state_use_count");
2002 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2003 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2006 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2007 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2008 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2009 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2010 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2011 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2012 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2013 LTT_EVENT_FORK
= g_quark_from_string("fork");
2014 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2015 LTT_EVENT_FREE
= g_quark_from_string("free");
2018 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2019 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2020 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2021 LTT_FIELD_OUT
= g_quark_from_string("out");
2022 LTT_FIELD_IN
= g_quark_from_string("in");
2023 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2024 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2025 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2026 LTT_FIELD_PID
= g_quark_from_string("pid");
2030 static void module_destroy()
2035 LTTV_MODULE("state", "State computation", \
2036 "Update the system state, possibly saving it at intervals", \
2037 module_init
, module_destroy
)