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
;
471 g_info("State save");
473 nb_tracefile
= self
->parent
.tracefiles
->len
;
475 for(i
= 0 ; i
< nb_tracefile
; i
++) {
477 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
478 LttvTracefileContext
*, i
));
479 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
480 value
= lttv_attribute_add(tracefiles_tree
, i
,
482 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
484 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
486 *(value
.v_uint
) = tfcs
->process
->pid
;
488 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
490 /* Only save the position if the tfs has not infinite time. */
491 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
492 // && current_tfcs != tfcs) {
493 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
494 *(value
.v_pointer
) = NULL
;
496 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
497 ep
= ltt_event_position_new();
498 ltt_event_position(e
, ep
);
499 *(value
.v_pointer
) = ep
;
501 guint nb_block
, offset
;
504 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
505 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
507 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
513 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
515 guint i
, nb_tracefile
, pid
, nb_cpus
;
517 LttvTracefileState
*tfcs
;
519 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
521 guint
*running_process
;
523 LttvAttributeType type
;
525 LttvAttributeValue value
;
527 LttvAttributeName name
;
529 LttEventPosition
*ep
;
531 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
533 tracefiles_tree
= lttv_attribute_find_subdir(container
,
534 LTTV_STATE_TRACEFILES
);
536 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
538 g_assert(type
== LTTV_POINTER
);
539 lttv_state_free_process_table(self
->processes
);
540 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
542 /* Add the currently running processes array */
543 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
544 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
546 g_assert(type
== LTTV_POINTER
);
547 running_process
= *(value
.v_pointer
);
548 for(i
=0;i
<nb_cpus
;i
++) {
549 pid
= running_process
[i
];
550 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
551 g_assert(self
->running_process
[i
] != NULL
);
555 nb_tracefile
= self
->parent
.tracefiles
->len
;
557 g_tree_destroy(tsc
->pqueue
);
558 tsc
->pqueue
= g_tree_new(compare_tracefile
);
560 for(i
= 0 ; i
< nb_tracefile
; i
++) {
562 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
563 LttvTracefileContext
*, i
));
564 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
565 g_assert(type
== LTTV_GOBJECT
);
566 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
568 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
570 g_assert(type
== LTTV_UINT
);
571 pid
= *(value
.v_uint
);
572 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
574 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
576 g_assert(type
== LTTV_POINTER
);
577 //g_assert(*(value.v_pointer) != NULL);
578 ep
= *(value
.v_pointer
);
579 g_assert(tfcs
->parent
.t_context
!= NULL
);
581 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
584 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
585 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
586 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
587 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
588 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
590 tfc
->timestamp
= ltt_time_infinite
;
596 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
598 guint i
, nb_tracefile
, nb_cpus
;
600 LttvTracefileState
*tfcs
;
602 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
604 guint
*running_process
;
606 LttvAttributeType type
;
608 LttvAttributeValue value
;
610 LttvAttributeName name
;
612 LttEventPosition
*ep
;
614 tracefiles_tree
= lttv_attribute_find_subdir(container
,
615 LTTV_STATE_TRACEFILES
);
616 g_object_ref(G_OBJECT(tracefiles_tree
));
617 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
619 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
621 g_assert(type
== LTTV_POINTER
);
622 lttv_state_free_process_table(*(value
.v_pointer
));
623 *(value
.v_pointer
) = NULL
;
624 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
626 /* Free running processes array */
627 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
628 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
630 g_assert(type
== LTTV_POINTER
);
631 running_process
= *(value
.v_pointer
);
632 g_free(running_process
);
634 nb_tracefile
= self
->parent
.tracefiles
->len
;
636 for(i
= 0 ; i
< nb_tracefile
; i
++) {
638 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
639 LttvTracefileContext
*, i
));
640 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
641 g_assert(type
== LTTV_GOBJECT
);
642 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
644 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
646 g_assert(type
== LTTV_POINTER
);
647 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
649 g_object_unref(G_OBJECT(tracefiles_tree
));
653 static void free_saved_state(LttvTraceState
*self
)
657 LttvAttributeType type
;
659 LttvAttributeValue value
;
661 LttvAttributeName name
;
663 LttvAttribute
*saved_states
;
665 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
666 LTTV_STATE_SAVED_STATES
);
668 nb
= lttv_attribute_get_number(saved_states
);
669 for(i
= 0 ; i
< nb
; i
++) {
670 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
671 g_assert(type
== LTTV_GOBJECT
);
672 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
675 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
680 create_max_time(LttvTraceState
*tcs
)
682 LttvAttributeValue v
;
684 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
686 g_assert(*(v
.v_pointer
) == NULL
);
687 *(v
.v_pointer
) = g_new(LttTime
,1);
688 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
693 get_max_time(LttvTraceState
*tcs
)
695 LttvAttributeValue v
;
697 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
699 g_assert(*(v
.v_pointer
) != NULL
);
700 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
705 free_max_time(LttvTraceState
*tcs
)
707 LttvAttributeValue v
;
709 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
711 g_free(*(v
.v_pointer
));
712 *(v
.v_pointer
) = NULL
;
716 typedef struct _LttvNameTables
{
717 // FIXME GQuark *eventtype_names;
718 GQuark
*syscall_names
;
725 create_name_tables(LttvTraceState
*tcs
)
729 GQuark f_name
, e_name
;
733 LttvTraceHookByFacility
*thf
;
739 GString
*fe_name
= g_string_new("");
741 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
743 LttvAttributeValue v
;
745 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
747 g_assert(*(v
.v_pointer
) == NULL
);
748 *(v
.v_pointer
) = name_tables
;
749 #if 0 // Use iteration over the facilities_by_name and then list all event
750 // types of each facility
751 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
752 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
753 for(i
= 0 ; i
< nb
; i
++) {
754 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
755 e_name
= ltt_eventtype_name(et
);
756 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
757 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
758 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
761 if(lttv_trace_find_hook(tcs
->parent
.t
,
762 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
763 LTT_FIELD_SYSCALL_ID
, 0, 0,
767 thf
= lttv_trace_hook_get_first(&h
);
769 t
= ltt_field_type(thf
->f1
);
770 nb
= ltt_type_element_number(t
);
772 lttv_trace_hook_destroy(&h
);
774 /* CHECK syscalls should be an enum but currently are not!
775 name_tables->syscall_names = g_new(GQuark, nb);
777 for(i = 0 ; i < nb ; i++) {
778 name_tables->syscall_names[i] = g_quark_from_string(
779 ltt_enum_string_get(t, i));
783 name_tables
->syscall_names
= g_new(GQuark
, 256);
784 for(i
= 0 ; i
< 256 ; i
++) {
785 g_string_printf(fe_name
, "syscall %d", i
);
786 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
789 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
790 LTT_EVENT_TRAP_ENTRY
,
791 LTT_FIELD_TRAP_ID
, 0, 0,
795 thf
= lttv_trace_hook_get_first(&h
);
797 t
= ltt_field_type(thf
->f1
);
798 nb
= ltt_type_element_number(t
);
800 lttv_trace_hook_destroy(&h
);
803 name_tables->trap_names = g_new(GQuark, nb);
804 for(i = 0 ; i < nb ; i++) {
805 name_tables->trap_names[i] = g_quark_from_string(
806 ltt_enum_string_get(t, i));
810 name_tables
->trap_names
= g_new(GQuark
, 256);
811 for(i
= 0 ; i
< 256 ; i
++) {
812 g_string_printf(fe_name
, "trap %d", i
);
813 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
816 if(lttv_trace_find_hook(tcs
->parent
.t
,
817 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
818 LTT_FIELD_IRQ_ID
, 0, 0,
822 thf
= lttv_trace_hook_get_first(&h
);
824 t
= ltt_field_type(thf
->f1
);
825 nb
= ltt_type_element_number(t
);
827 lttv_trace_hook_destroy(&h
);
830 name_tables->irq_names = g_new(GQuark, nb);
831 for(i = 0 ; i < nb ; i++) {
832 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
836 name_tables
->irq_names
= g_new(GQuark
, 256);
837 for(i
= 0 ; i
< 256 ; i
++) {
838 g_string_printf(fe_name
, "irq %d", i
);
839 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
842 g_string_free(fe_name
, TRUE
);
847 get_name_tables(LttvTraceState
*tcs
)
849 LttvNameTables
*name_tables
;
851 LttvAttributeValue v
;
853 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
855 g_assert(*(v
.v_pointer
) != NULL
);
856 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
857 //tcs->eventtype_names = name_tables->eventtype_names;
858 tcs
->syscall_names
= name_tables
->syscall_names
;
859 tcs
->trap_names
= name_tables
->trap_names
;
860 tcs
->irq_names
= name_tables
->irq_names
;
865 free_name_tables(LttvTraceState
*tcs
)
867 LttvNameTables
*name_tables
;
869 LttvAttributeValue v
;
871 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
873 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
874 *(v
.v_pointer
) = NULL
;
876 // g_free(name_tables->eventtype_names);
877 g_free(name_tables
->syscall_names
);
878 g_free(name_tables
->trap_names
);
879 g_free(name_tables
->irq_names
);
883 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
886 LttvExecutionState
*es
;
888 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
889 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
890 LttvProcessState
*process
= ts
->running_process
[cpu
];
892 guint depth
= process
->execution_stack
->len
;
894 process
->execution_stack
=
895 g_array_set_size(process
->execution_stack
, depth
+ 1);
898 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
900 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
903 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
904 es
->s
= process
->state
->s
;
909 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
911 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
912 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
913 LttvProcessState
*process
= ts
->running_process
[cpu
];
915 guint depth
= process
->execution_stack
->len
;
917 if(process
->state
->t
!= t
){
918 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
919 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
920 g_info("process state has %s when pop_int is %s\n",
921 g_quark_to_string(process
->state
->t
),
922 g_quark_to_string(t
));
923 g_info("{ %u, %u, %s, %s }\n",
926 g_quark_to_string(process
->name
),
927 g_quark_to_string(process
->state
->s
));
932 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
933 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
937 process
->execution_stack
=
938 g_array_set_size(process
->execution_stack
, depth
- 1);
939 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
941 process
->state
->change
= tfs
->parent
.timestamp
;
946 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
947 guint cpu
, guint pid
, const LttTime
*timestamp
)
949 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
951 LttvExecutionState
*es
;
953 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
959 //process->last_cpu = tfs->cpu_name;
960 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
961 g_info("Process %u, core %p", process
->pid
, process
);
962 g_hash_table_insert(tcs
->processes
, process
, process
);
965 process
->ppid
= parent
->pid
;
966 process
->name
= parent
->name
;
967 process
->creation_time
= *timestamp
;
970 /* No parent. This process exists but we are missing all information about
971 its creation. The birth time is set to zero but we remember the time of
976 process
->name
= LTTV_STATE_UNNAMED
;
977 process
->creation_time
= ltt_time_zero
;
980 process
->insertion_time
= *timestamp
;
981 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
982 process
->creation_time
.tv_nsec
);
983 process
->pid_time
= g_quark_from_string(buffer
);
985 //process->last_cpu = tfs->cpu_name;
986 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
987 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
988 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
989 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
990 es
= process
->state
= &g_array_index(process
->execution_stack
,
991 LttvExecutionState
, 0);
992 es
->t
= LTTV_STATE_USER_MODE
;
993 es
->n
= LTTV_STATE_SUBMODE_NONE
;
994 es
->entry
= *timestamp
;
995 //g_assert(timestamp->tv_sec != 0);
996 es
->change
= *timestamp
;
997 es
->s
= LTTV_STATE_WAIT_FORK
;
1002 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1005 LttvProcessState key
;
1006 LttvProcessState
*process
;
1010 process
= g_hash_table_lookup(ts
->processes
, &key
);
1015 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1018 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1020 /* Put ltt_time_zero creation time for unexisting processes */
1021 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1022 NULL
, cpu
, pid
, timestamp
);
1026 /* FIXME : this function should be called when we receive an event telling that
1027 * release_task has been called in the kernel. In happens generally when
1028 * the parent waits for its child terminaison, but may also happen in special
1029 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1030 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1031 * of a killed thread ground, but isn't the leader.
1033 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1035 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1036 LttvProcessState key
;
1038 key
.pid
= process
->pid
;
1039 key
.cpu
= process
->cpu
;
1040 g_hash_table_remove(ts
->processes
, &key
);
1041 g_array_free(process
->execution_stack
, TRUE
);
1046 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1048 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1053 static void lttv_state_free_process_table(GHashTable
*processes
)
1055 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1056 g_hash_table_destroy(processes
);
1060 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1062 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1063 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1064 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1065 LttField
*f
= thf
->f1
;
1067 LttvExecutionSubmode submode
;
1069 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1070 ltt_event_get_unsigned(e
, f
)];
1071 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1076 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1078 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1080 pop_state(s
, LTTV_STATE_SYSCALL
);
1085 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1087 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1088 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1089 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1090 LttField
*f
= thf
->f1
;
1092 LttvExecutionSubmode submode
;
1094 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1095 ltt_event_get_unsigned(e
, f
)];
1096 push_state(s
, LTTV_STATE_TRAP
, submode
);
1101 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1103 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1105 pop_state(s
, LTTV_STATE_TRAP
);
1110 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1112 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1113 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1114 guint8 fac_id
= ltt_event_facility_id(e
);
1115 guint8 ev_id
= ltt_event_eventtype_id(e
);
1116 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1117 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1118 g_assert(thf
->f1
!= NULL
);
1119 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1120 LttField
*f
= thf
->f1
;
1122 LttvExecutionSubmode submode
;
1124 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1125 ltt_event_get_unsigned(e
, f
)];
1127 /* Do something with the info about being in user or system mode when int? */
1128 push_state(s
, LTTV_STATE_IRQ
, submode
);
1133 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1135 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1137 pop_state(s
, LTTV_STATE_IRQ
);
1142 static gboolean
schedchange(void *hook_data
, void *call_data
)
1144 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1145 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1146 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1147 LttvProcessState
*process
= ts
->running_process
[cpu
];
1149 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1150 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1151 guint pid_in
, pid_out
;
1154 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1155 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1156 state_out
= ltt_event_get_int(e
, thf
->f3
);
1158 if(likely(process
!= NULL
)) {
1160 /* We could not know but it was not the idle process executing.
1161 This should only happen at the beginning, before the first schedule
1162 event, and when the initial information (current process for each CPU)
1163 is missing. It is not obvious how we could, after the fact, compensate
1164 the wrongly attributed statistics. */
1166 //This test only makes sense once the state is known and if there is no
1168 //if(unlikely(process->pid != pid_out)) {
1169 // g_assert(process->pid == 0);
1172 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1173 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1175 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1176 else process
->state
->s
= LTTV_STATE_WAIT
;
1177 } /* FIXME : we do not remove process here, because the kernel
1178 * still has them : they may be zombies. We need to know
1179 * exactly when release_task is executed on the PID to
1180 * know when the zombie is destroyed.
1183 // exit_process(s, process);
1185 process
->state
->change
= s
->parent
.timestamp
;
1187 process
= ts
->running_process
[cpu
] =
1188 lttv_state_find_process_or_create(
1189 (LttvTraceState
*)s
->parent
.t_context
,
1191 &s
->parent
.timestamp
);
1192 process
->state
->s
= LTTV_STATE_RUN
;
1194 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1195 process
->state
->change
= s
->parent
.timestamp
;
1199 static gboolean
process_fork(void *hook_data
, void *call_data
)
1201 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1202 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1203 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1207 LttvProcessState
*zombie_process
;
1208 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1209 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1210 LttvProcessState
*process
= ts
->running_process
[cpu
];
1214 parent_pid
= ltt_event_get_unsigned(e
, f
);
1218 child_pid
= ltt_event_get_unsigned(e
, f
);
1220 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1222 if(unlikely(zombie_process
!= NULL
)) {
1223 /* Reutilisation of PID. Only now we are sure that the old PID
1224 * has been released. FIXME : should know when release_task happens instead.
1226 exit_process(s
, zombie_process
);
1228 g_assert(process
->pid
!= child_pid
);
1229 // FIXME : Add this test in the "known state" section
1230 // g_assert(process->pid == parent_pid);
1231 lttv_state_create_process(ts
, process
, cpu
, child_pid
, &s
->parent
.timestamp
);
1237 static gboolean
process_exit(void *hook_data
, void *call_data
)
1239 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1240 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1241 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1244 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1245 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1246 LttvProcessState
*process
= ts
->running_process
[cpu
];
1248 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1250 // FIXME : Add this test in the "known state" section
1251 // g_assert(process->pid == pid);
1253 if(likely(process
!= NULL
)) {
1254 process
->state
->s
= LTTV_STATE_EXIT
;
1259 static gboolean
process_free(void *hook_data
, void *call_data
)
1261 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1262 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1263 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1264 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1266 LttvProcessState
*process
;
1268 /* PID of the process to release */
1269 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1271 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1273 if(likely(process
!= NULL
)) {
1274 /* release_task is happening at kernel level : we can now safely release
1275 * the data structure of the process */
1276 exit_process(s
, process
);
1282 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1284 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1286 lttv_state_add_event_hooks(tss
);
1291 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1293 LttvTraceset
*traceset
= self
->parent
.ts
;
1295 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1299 LttvTracefileState
*tfs
;
1303 LttvTraceHookByFacility
*thf
;
1305 LttvTraceHook
*hook
;
1307 LttvAttributeValue val
;
1311 nb_trace
= lttv_traceset_number(traceset
);
1312 for(i
= 0 ; i
< nb_trace
; i
++) {
1313 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1315 /* Find the eventtype id for the following events and register the
1316 associated by id hooks. */
1318 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 10);
1319 hooks
= g_array_set_size(hooks
, 10);
1321 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1322 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1323 LTT_FIELD_SYSCALL_ID
, 0, 0,
1324 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1327 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1328 LTT_FACILITY_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1330 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1333 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1334 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1335 LTT_FIELD_TRAP_ID
, 0, 0,
1336 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1339 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1340 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1342 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1345 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1346 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1347 LTT_FIELD_IRQ_ID
, 0, 0,
1348 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1351 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1352 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1354 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1357 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1358 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1359 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1360 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1363 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1364 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1365 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1366 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1369 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1370 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1371 LTT_FIELD_PID
, 0, 0,
1372 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1375 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1376 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1377 LTT_FIELD_PID
, 0, 0,
1378 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1382 /* Add these hooks to each event_by_id hooks list */
1384 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1386 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1388 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1389 LttvTracefileContext
*, j
));
1391 for(k
= 0 ; k
< hooks
->len
; k
++) {
1392 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1393 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1394 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1396 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1403 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1404 *(val
.v_pointer
) = hooks
;
1408 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1410 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1412 lttv_state_remove_event_hooks(tss
);
1417 static guint test_event_count
= 0;
1418 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1420 LttvTraceset
*traceset
= self
->parent
.ts
;
1422 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1426 LttvTracefileState
*tfs
;
1430 LttvTraceHook
*hook
;
1432 LttvTraceHookByFacility
*thf
;
1434 LttvAttributeValue val
;
1436 nb_trace
= lttv_traceset_number(traceset
);
1437 for(i
= 0 ; i
< nb_trace
; i
++) {
1438 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1439 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1440 hooks
= *(val
.v_pointer
);
1442 /* Remove these hooks from each event_by_id hooks list */
1444 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1446 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1448 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1449 LttvTracefileContext
*, j
));
1451 for(k
= 0 ; k
< hooks
->len
; k
++) {
1452 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1453 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1454 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1456 lttv_hooks_remove_data(
1457 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1463 for(k
= 0 ; k
< hooks
->len
; k
++)
1464 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1465 g_array_free(hooks
, TRUE
);
1467 g_info("EVENT COUNT TEST : %u", test_event_count
);
1470 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1472 guint
*event_count
= (guint
*)hook_data
;
1475 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1476 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1481 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1483 LttvTracefileState
*tfcs
;
1485 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1487 LttEventPosition
*ep
;
1493 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1495 LttvAttributeValue value
;
1497 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1498 LTTV_STATE_SAVED_STATES
);
1499 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1500 value
= lttv_attribute_add(saved_states_tree
,
1501 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1502 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1503 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1504 *(value
.v_time
) = self
->parent
.timestamp
;
1505 lttv_state_save(tcs
, saved_state_tree
);
1506 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1507 self
->parent
.timestamp
.tv_nsec
);
1509 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1515 static gboolean
block_start(void *hook_data
, void *call_data
)
1517 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1519 LttvTracefileState
*tfcs
;
1521 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1523 LttEventPosition
*ep
;
1525 guint i
, nb_block
, nb_event
, nb_tracefile
;
1529 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1531 LttvAttributeValue value
;
1533 ep
= ltt_event_position_new();
1535 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1537 /* Count the number of events added since the last block end in any
1540 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1542 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1543 LttvTracefileContext
, i
));
1544 ltt_event_position(tfcs
->parent
.e
, ep
);
1545 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1546 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1547 tfcs
->saved_position
= nb_event
;
1551 if(tcs
->nb_event
>= tcs
->save_interval
) {
1552 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1553 LTTV_STATE_SAVED_STATES
);
1554 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1555 value
= lttv_attribute_add(saved_states_tree
,
1556 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1557 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1558 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1559 *(value
.v_time
) = self
->parent
.timestamp
;
1560 lttv_state_save(tcs
, saved_state_tree
);
1562 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1563 self
->parent
.timestamp
.tv_nsec
);
1565 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1571 static gboolean
block_end(void *hook_data
, void *call_data
)
1573 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1575 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1579 LttEventPosition
*ep
;
1581 guint nb_block
, nb_event
;
1583 ep
= ltt_event_position_new();
1584 ltt_event_position(self
->parent
.e
, ep
);
1585 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1586 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1587 self
->saved_position
= 0;
1588 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1595 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1597 LttvTraceset
*traceset
= self
->parent
.ts
;
1599 guint i
, j
, nb_trace
, nb_tracefile
;
1603 LttvTracefileState
*tfs
;
1605 LttvTraceHook hook_start
, hook_end
;
1607 nb_trace
= lttv_traceset_number(traceset
);
1608 for(i
= 0 ; i
< nb_trace
; i
++) {
1609 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1611 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1612 NULL
, NULL
, block_start
, &hook_start
);
1613 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1614 NULL
, NULL
, block_end
, &hook_end
);
1616 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1618 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1620 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1621 LttvTracefileContext
, j
));
1622 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1623 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1624 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1625 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1631 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1633 LttvTraceset
*traceset
= self
->parent
.ts
;
1635 guint i
, j
, nb_trace
, nb_tracefile
;
1639 LttvTracefileState
*tfs
;
1642 nb_trace
= lttv_traceset_number(traceset
);
1643 for(i
= 0 ; i
< nb_trace
; i
++) {
1645 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1646 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1648 guint
*event_count
= g_new(guint
, 1);
1651 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1653 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1654 LttvTracefileContext
*, j
));
1655 lttv_hooks_add(tfs
->parent
.event
,
1656 state_save_event_hook
,
1664 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1666 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1668 lttv_state_save_add_event_hooks(tss
);
1675 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1677 LttvTraceset
*traceset
= self
->parent
.ts
;
1679 guint i
, j
, nb_trace
, nb_tracefile
;
1683 LttvTracefileState
*tfs
;
1685 LttvTraceHook hook_start
, hook_end
;
1687 nb_trace
= lttv_traceset_number(traceset
);
1688 for(i
= 0 ; i
< nb_trace
; i
++) {
1689 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1691 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1692 NULL
, NULL
, block_start
, &hook_start
);
1694 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1695 NULL
, NULL
, block_end
, &hook_end
);
1697 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1699 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1701 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1702 LttvTracefileContext
, j
));
1703 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1704 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1705 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1706 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1712 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1714 LttvTraceset
*traceset
= self
->parent
.ts
;
1716 guint i
, j
, nb_trace
, nb_tracefile
;
1720 LttvTracefileState
*tfs
;
1723 nb_trace
= lttv_traceset_number(traceset
);
1724 for(i
= 0 ; i
< nb_trace
; i
++) {
1726 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1727 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1731 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1733 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1734 LttvTracefileContext
*, j
));
1735 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1736 state_save_event_hook
);
1739 g_free(event_count
);
1743 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1745 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1747 lttv_state_save_remove_event_hooks(tss
);
1752 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1754 LttvTraceset
*traceset
= self
->parent
.ts
;
1758 int min_pos
, mid_pos
, max_pos
;
1760 guint call_rest
= 0;
1762 LttvTraceState
*tcs
;
1764 LttvAttributeValue value
;
1766 LttvAttributeType type
;
1768 LttvAttributeName name
;
1770 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1772 g_tree_destroy(self
->parent
.pqueue
);
1773 self
->parent
.pqueue
= g_tree_new(compare_tracefile
);
1775 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
1777 nb_trace
= lttv_traceset_number(traceset
);
1778 for(i
= 0 ; i
< nb_trace
; i
++) {
1779 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1781 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1782 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1783 LTTV_STATE_SAVED_STATES
);
1786 if(saved_states_tree
) {
1787 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1788 mid_pos
= max_pos
/ 2;
1789 while(min_pos
< max_pos
) {
1790 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1791 g_assert(type
== LTTV_GOBJECT
);
1792 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1793 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1795 g_assert(type
== LTTV_TIME
);
1796 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1798 closest_tree
= saved_state_tree
;
1800 else max_pos
= mid_pos
- 1;
1802 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1806 /* restore the closest earlier saved state */
1808 lttv_state_restore(tcs
, closest_tree
);
1812 /* There is no saved state, yet we want to have it. Restart at T0 */
1814 restore_init_state(tcs
);
1815 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1818 /* We want to seek quickly without restoring/updating the state */
1820 restore_init_state(tcs
);
1821 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1824 if(!call_rest
) g_info("NOT Calling restore");
1829 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1835 traceset_state_finalize (LttvTracesetState
*self
)
1837 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1838 finalize(G_OBJECT(self
));
1843 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1845 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1847 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1848 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1849 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1850 klass
->new_traceset_context
= new_traceset_context
;
1851 klass
->new_trace_context
= new_trace_context
;
1852 klass
->new_tracefile_context
= new_tracefile_context
;
1857 lttv_traceset_state_get_type(void)
1859 static GType type
= 0;
1861 static const GTypeInfo info
= {
1862 sizeof (LttvTracesetStateClass
),
1863 NULL
, /* base_init */
1864 NULL
, /* base_finalize */
1865 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1866 NULL
, /* class_finalize */
1867 NULL
, /* class_data */
1868 sizeof (LttvTracesetState
),
1869 0, /* n_preallocs */
1870 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
1871 NULL
/* value handling */
1874 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1882 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1888 trace_state_finalize (LttvTraceState
*self
)
1890 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1891 finalize(G_OBJECT(self
));
1896 trace_state_class_init (LttvTraceStateClass
*klass
)
1898 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1900 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1901 klass
->state_save
= state_save
;
1902 klass
->state_restore
= state_restore
;
1903 klass
->state_saved_free
= state_saved_free
;
1908 lttv_trace_state_get_type(void)
1910 static GType type
= 0;
1912 static const GTypeInfo info
= {
1913 sizeof (LttvTraceStateClass
),
1914 NULL
, /* base_init */
1915 NULL
, /* base_finalize */
1916 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1917 NULL
, /* class_finalize */
1918 NULL
, /* class_data */
1919 sizeof (LttvTraceState
),
1920 0, /* n_preallocs */
1921 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
1922 NULL
/* value handling */
1925 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1926 "LttvTraceStateType", &info
, 0);
1933 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1939 tracefile_state_finalize (LttvTracefileState
*self
)
1941 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1942 finalize(G_OBJECT(self
));
1947 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1949 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1951 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1956 lttv_tracefile_state_get_type(void)
1958 static GType type
= 0;
1960 static const GTypeInfo info
= {
1961 sizeof (LttvTracefileStateClass
),
1962 NULL
, /* base_init */
1963 NULL
, /* base_finalize */
1964 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1965 NULL
, /* class_finalize */
1966 NULL
, /* class_data */
1967 sizeof (LttvTracefileState
),
1968 0, /* n_preallocs */
1969 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
1970 NULL
/* value handling */
1973 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1974 "LttvTracefileStateType", &info
, 0);
1980 static void module_init()
1982 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1983 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1984 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1985 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1986 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1987 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1988 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1989 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1990 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1991 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1992 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1993 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
1994 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1995 LTTV_STATE_RUN
= g_quark_from_string("running");
1996 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1997 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1998 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1999 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2000 LTTV_STATE_EVENT
= g_quark_from_string("event");
2001 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2002 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2003 LTTV_STATE_TIME
= g_quark_from_string("time");
2004 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2005 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2006 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2007 g_quark_from_string("trace_state_use_count");
2010 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2011 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2014 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2015 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2016 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2017 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2018 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2019 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2020 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2021 LTT_EVENT_FORK
= g_quark_from_string("fork");
2022 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2023 LTT_EVENT_FREE
= g_quark_from_string("free");
2026 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2027 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2028 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2029 LTT_FIELD_OUT
= g_quark_from_string("out");
2030 LTT_FIELD_IN
= g_quark_from_string("in");
2031 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2032 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2033 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2034 LTT_FIELD_PID
= g_quark_from_string("pid");
2038 static void module_destroy()
2043 LTTV_MODULE("state", "State computation", \
2044 "Update the system state, possibly saving it at intervals", \
2045 module_init
, module_destroy
)