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>
33 #define PREALLOCATED_EXECUTION_STACK 10
35 /* Facilities Quarks */
39 LTT_FACILITY_KERNEL_ARCH
,
42 LTT_FACILITY_STATEDUMP
;
47 LTT_EVENT_SYSCALL_ENTRY
,
48 LTT_EVENT_SYSCALL_EXIT
,
53 LTT_EVENT_SOFT_IRQ_ENTRY
,
54 LTT_EVENT_SOFT_IRQ_EXIT
,
55 LTT_EVENT_SCHEDCHANGE
,
57 LTT_EVENT_KERNEL_THREAD
,
61 LTT_EVENT_ENUM_PROCESS_STATE
;
69 LTT_FIELD_SOFT_IRQ_ID
,
83 LTTV_STATE_MODE_UNKNOWN
,
91 LTTV_STATE_SUBMODE_UNKNOWN
,
92 LTTV_STATE_SUBMODE_NONE
;
105 LTTV_STATE_TRACEFILES
,
106 LTTV_STATE_PROCESSES
,
108 LTTV_STATE_RUNNING_PROCESS
,
110 LTTV_STATE_SAVED_STATES
,
111 LTTV_STATE_SAVED_STATES_TIME
,
114 LTTV_STATE_NAME_TABLES
,
115 LTTV_STATE_TRACE_STATE_USE_COUNT
;
117 static void create_max_time(LttvTraceState
*tcs
);
119 static void get_max_time(LttvTraceState
*tcs
);
121 static void free_max_time(LttvTraceState
*tcs
);
123 static void create_name_tables(LttvTraceState
*tcs
);
125 static void get_name_tables(LttvTraceState
*tcs
);
127 static void free_name_tables(LttvTraceState
*tcs
);
129 static void free_saved_state(LttvTraceState
*tcs
);
131 static void lttv_state_free_process_table(GHashTable
*processes
);
134 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
136 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
140 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
142 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
146 void lttv_state_state_saved_free(LttvTraceState
*self
,
147 LttvAttribute
*container
)
149 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
153 guint
process_hash(gconstpointer key
)
155 guint pid
= ((const LttvProcessState
*)key
)->pid
;
156 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
160 /* If the hash table hash function is well distributed,
161 * the process_equal should compare different pid */
162 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
164 const LttvProcessState
*process_a
, *process_b
;
167 process_a
= (const LttvProcessState
*)a
;
168 process_b
= (const LttvProcessState
*)b
;
170 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
171 else if(likely(process_a
->pid
== 0 &&
172 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
179 restore_init_state(LttvTraceState
*self
)
183 LttvTracefileState
*tfcs
;
185 /* Free the process tables */
186 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
187 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
190 /* Seek time to beginning */
191 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
192 // closest. It's the tracecontext job to seek the trace to the beginning
193 // anyway : the init state might be used at the middle of the trace as well...
194 //g_tree_destroy(self->parent.ts_context->pqueue);
195 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
198 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
200 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
202 /* Put the per cpu running_process to beginning state : process 0. */
203 for(i
=0; i
< nb_cpus
; i
++) {
204 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
205 LTTV_STATE_UNNAMED
, <t_time_zero
);
206 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
207 self
->running_process
[i
]->cpu
= i
;
211 nb_tracefile
= self
->parent
.tracefiles
->len
;
213 for(i
= 0 ; i
< nb_tracefile
; i
++) {
215 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
216 LttvTracefileContext
*, i
));
217 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
218 // tfcs->saved_position = 0;
219 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
220 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
221 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
222 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
227 //static LttTime time_zero = {0,0};
230 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
232 guint i
, j
, nb_trace
, nb_tracefile
;
234 LttvTraceContext
*tc
;
238 LttvTracefileState
*tfcs
;
240 LttvAttributeValue v
;
242 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
243 init((LttvTracesetContext
*)self
, ts
);
245 nb_trace
= lttv_traceset_number(ts
);
246 for(i
= 0 ; i
< nb_trace
; i
++) {
247 tc
= self
->parent
.traces
[i
];
248 tcs
= LTTV_TRACE_STATE(tc
);
249 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
250 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
254 if(*(v
.v_uint
) == 1) {
255 create_name_tables(tcs
);
256 create_max_time(tcs
);
258 get_name_tables(tcs
);
261 nb_tracefile
= tc
->tracefiles
->len
;
262 tcs
->processes
= NULL
;
263 tcs
->running_process
= g_new(LttvProcessState
*,
264 ltt_trace_get_num_cpu(tc
->t
));
265 restore_init_state(tcs
);
266 for(j
= 0 ; j
< nb_tracefile
; j
++) {
268 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
269 LttvTracefileContext
*, j
));
270 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
271 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
273 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
274 /* It's a Usertrace */
275 LttvProcessState
*process
;
277 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
278 ltt_tracefile_creation(tfcs
->parent
.tf
));
279 process
= lttv_state_find_process_or_create(
281 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
283 process
->usertrace
= tfcs
;
291 fini(LttvTracesetState
*self
)
297 LttvTracefileState
*tfcs
;
299 LttvAttributeValue v
;
301 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
302 for(i
= 0 ; i
< nb_trace
; i
++) {
303 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
304 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
307 g_assert(*(v
.v_uint
) != 0);
310 if(*(v
.v_uint
) == 0) {
311 free_name_tables(tcs
);
313 free_saved_state(tcs
);
315 g_free(tcs
->running_process
);
316 tcs
->running_process
= NULL
;
317 lttv_state_free_process_table(tcs
->processes
);
318 tcs
->processes
= NULL
;
320 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
321 fini((LttvTracesetContext
*)self
);
325 static LttvTracesetContext
*
326 new_traceset_context(LttvTracesetContext
*self
)
328 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
332 static LttvTraceContext
*
333 new_trace_context(LttvTracesetContext
*self
)
335 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
339 static LttvTracefileContext
*
340 new_tracefile_context(LttvTracesetContext
*self
)
342 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
346 /* Write the process state of the trace */
348 static void write_process_state(gpointer key
, gpointer value
,
351 LttvProcessState
*process
;
353 LttvExecutionState
*es
;
355 FILE *fp
= (FILE *)user_data
;
359 process
= (LttvProcessState
*)value
;
361 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
362 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
363 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
366 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
367 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
368 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
369 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
370 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
371 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
372 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
374 fprintf(fp
, " </PROCESS>\n");
378 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
380 guint i
, nb_tracefile
, nb_block
, offset
;
383 LttvTracefileState
*tfcs
;
387 LttEventPosition
*ep
;
391 ep
= ltt_event_position_new();
393 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
395 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
397 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
398 for(i
=0;i
<nb_cpus
;i
++) {
399 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
400 i
, self
->running_process
[i
]->pid
);
403 nb_tracefile
= self
->parent
.tracefiles
->len
;
405 for(i
= 0 ; i
< nb_tracefile
; i
++) {
407 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
408 LttvTracefileContext
*, i
));
409 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
410 tfcs
->parent
.timestamp
.tv_sec
,
411 tfcs
->parent
.timestamp
.tv_nsec
);
412 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
413 if(e
== NULL
) fprintf(fp
,"/>\n");
415 ltt_event_position(e
, ep
);
416 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
417 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
422 fprintf(fp
,"</PROCESS_STATE>");
426 /* Copy each process from an existing hash table to a new one */
428 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
430 LttvProcessState
*process
, *new_process
;
432 GHashTable
*new_processes
= (GHashTable
*)user_data
;
436 process
= (LttvProcessState
*)value
;
437 new_process
= g_new(LttvProcessState
, 1);
438 *new_process
= *process
;
439 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
440 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
441 new_process
->execution_stack
=
442 g_array_set_size(new_process
->execution_stack
,
443 process
->execution_stack
->len
);
444 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
445 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
446 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
448 new_process
->state
= &g_array_index(new_process
->execution_stack
,
449 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
450 g_hash_table_insert(new_processes
, new_process
, new_process
);
454 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
456 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
458 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
459 return new_processes
;
463 /* The saved state for each trace contains a member "processes", which
464 stores a copy of the process table, and a member "tracefiles" with
465 one entry per tracefile. Each tracefile has a "process" member pointing
466 to the current process and a "position" member storing the tracefile
467 position (needed to seek to the current "next" event. */
469 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
471 guint i
, nb_tracefile
, nb_cpus
;
473 LttvTracefileState
*tfcs
;
475 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
477 guint
*running_process
;
479 LttvAttributeType type
;
481 LttvAttributeValue value
;
483 LttvAttributeName name
;
485 LttEventPosition
*ep
;
487 tracefiles_tree
= lttv_attribute_find_subdir(container
,
488 LTTV_STATE_TRACEFILES
);
490 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
492 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
494 /* Add the currently running processes array */
495 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
496 running_process
= g_new(guint
, nb_cpus
);
497 for(i
=0;i
<nb_cpus
;i
++) {
498 running_process
[i
] = self
->running_process
[i
]->pid
;
500 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
502 *(value
.v_pointer
) = running_process
;
504 g_info("State save");
506 nb_tracefile
= self
->parent
.tracefiles
->len
;
508 for(i
= 0 ; i
< nb_tracefile
; i
++) {
510 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
511 LttvTracefileContext
*, i
));
512 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
513 value
= lttv_attribute_add(tracefiles_tree
, i
,
515 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
517 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
519 *(value
.v_uint
) = tfcs
->process
->pid
;
521 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
523 /* Only save the position if the tfs has not infinite time. */
524 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
525 // && current_tfcs != tfcs) {
526 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
527 *(value
.v_pointer
) = NULL
;
529 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
530 ep
= ltt_event_position_new();
531 ltt_event_position(e
, ep
);
532 *(value
.v_pointer
) = ep
;
534 guint nb_block
, offset
;
537 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
538 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
540 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
546 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
548 guint i
, nb_tracefile
, pid
, nb_cpus
;
550 LttvTracefileState
*tfcs
;
552 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
554 guint
*running_process
;
556 LttvAttributeType type
;
558 LttvAttributeValue value
;
560 LttvAttributeName name
;
562 LttEventPosition
*ep
;
564 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
566 tracefiles_tree
= lttv_attribute_find_subdir(container
,
567 LTTV_STATE_TRACEFILES
);
569 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
571 g_assert(type
== LTTV_POINTER
);
572 lttv_state_free_process_table(self
->processes
);
573 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
575 /* Add the currently running processes array */
576 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
577 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
579 g_assert(type
== LTTV_POINTER
);
580 running_process
= *(value
.v_pointer
);
581 for(i
=0;i
<nb_cpus
;i
++) {
582 pid
= running_process
[i
];
583 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
584 g_assert(self
->running_process
[i
] != NULL
);
588 nb_tracefile
= self
->parent
.tracefiles
->len
;
590 //g_tree_destroy(tsc->pqueue);
591 //tsc->pqueue = g_tree_new(compare_tracefile);
593 for(i
= 0 ; i
< nb_tracefile
; i
++) {
595 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
596 LttvTracefileContext
*, i
));
597 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
598 g_assert(type
== LTTV_GOBJECT
);
599 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
601 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
603 g_assert(type
== LTTV_UINT
);
604 pid
= *(value
.v_uint
);
605 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
607 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
609 g_assert(type
== LTTV_POINTER
);
610 //g_assert(*(value.v_pointer) != NULL);
611 ep
= *(value
.v_pointer
);
612 g_assert(tfcs
->parent
.t_context
!= NULL
);
614 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
615 g_tree_remove(tsc
->pqueue
, tfc
);
618 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
619 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
620 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
621 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
622 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
624 tfc
->timestamp
= ltt_time_infinite
;
630 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
632 guint i
, nb_tracefile
, nb_cpus
;
634 LttvTracefileState
*tfcs
;
636 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
638 guint
*running_process
;
640 LttvAttributeType type
;
642 LttvAttributeValue value
;
644 LttvAttributeName name
;
646 LttEventPosition
*ep
;
648 tracefiles_tree
= lttv_attribute_find_subdir(container
,
649 LTTV_STATE_TRACEFILES
);
650 g_object_ref(G_OBJECT(tracefiles_tree
));
651 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
653 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
655 g_assert(type
== LTTV_POINTER
);
656 lttv_state_free_process_table(*(value
.v_pointer
));
657 *(value
.v_pointer
) = NULL
;
658 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
660 /* Free running processes array */
661 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
662 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
664 g_assert(type
== LTTV_POINTER
);
665 running_process
= *(value
.v_pointer
);
666 g_free(running_process
);
668 nb_tracefile
= self
->parent
.tracefiles
->len
;
670 for(i
= 0 ; i
< nb_tracefile
; i
++) {
672 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
673 LttvTracefileContext
*, i
));
674 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
675 g_assert(type
== LTTV_GOBJECT
);
676 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
678 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
680 g_assert(type
== LTTV_POINTER
);
681 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
683 g_object_unref(G_OBJECT(tracefiles_tree
));
687 static void free_saved_state(LttvTraceState
*self
)
691 LttvAttributeType type
;
693 LttvAttributeValue value
;
695 LttvAttributeName name
;
697 LttvAttribute
*saved_states
;
699 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
700 LTTV_STATE_SAVED_STATES
);
702 nb
= lttv_attribute_get_number(saved_states
);
703 for(i
= 0 ; i
< nb
; i
++) {
704 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
705 g_assert(type
== LTTV_GOBJECT
);
706 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
709 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
714 create_max_time(LttvTraceState
*tcs
)
716 LttvAttributeValue v
;
718 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
720 g_assert(*(v
.v_pointer
) == NULL
);
721 *(v
.v_pointer
) = g_new(LttTime
,1);
722 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
727 get_max_time(LttvTraceState
*tcs
)
729 LttvAttributeValue v
;
731 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
733 g_assert(*(v
.v_pointer
) != NULL
);
734 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
739 free_max_time(LttvTraceState
*tcs
)
741 LttvAttributeValue v
;
743 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
745 g_free(*(v
.v_pointer
));
746 *(v
.v_pointer
) = NULL
;
750 typedef struct _LttvNameTables
{
751 // FIXME GQuark *eventtype_names;
752 GQuark
*syscall_names
;
755 GQuark
*soft_irq_names
;
760 create_name_tables(LttvTraceState
*tcs
)
764 GQuark f_name
, e_name
;
768 LttvTraceHookByFacility
*thf
;
774 GString
*fe_name
= g_string_new("");
776 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
778 LttvAttributeValue v
;
780 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
782 g_assert(*(v
.v_pointer
) == NULL
);
783 *(v
.v_pointer
) = name_tables
;
784 #if 0 // Use iteration over the facilities_by_name and then list all event
785 // types of each facility
786 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
787 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
788 for(i
= 0 ; i
< nb
; i
++) {
789 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
790 e_name
= ltt_eventtype_name(et
);
791 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
792 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
793 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
796 if(lttv_trace_find_hook(tcs
->parent
.t
,
797 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
798 LTT_FIELD_SYSCALL_ID
, 0, 0,
802 thf
= lttv_trace_hook_get_first(&h
);
804 t
= ltt_field_type(thf
->f1
);
805 nb
= ltt_type_element_number(t
);
807 lttv_trace_hook_destroy(&h
);
809 name_tables
->syscall_names
= g_new(GQuark
, nb
);
811 for(i
= 0 ; i
< nb
; i
++) {
812 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
815 //name_tables->syscall_names = g_new(GQuark, 256);
816 //for(i = 0 ; i < 256 ; i++) {
817 // g_string_printf(fe_name, "syscall %d", i);
818 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
821 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
822 LTT_EVENT_TRAP_ENTRY
,
823 LTT_FIELD_TRAP_ID
, 0, 0,
827 thf
= lttv_trace_hook_get_first(&h
);
829 t
= ltt_field_type(thf
->f1
);
830 //nb = ltt_type_element_number(t);
832 lttv_trace_hook_destroy(&h
);
835 name_tables->trap_names = g_new(GQuark, nb);
836 for(i = 0 ; i < nb ; i++) {
837 name_tables->trap_names[i] = g_quark_from_string(
838 ltt_enum_string_get(t, i));
842 name_tables
->trap_names
= g_new(GQuark
, 256);
843 for(i
= 0 ; i
< 256 ; i
++) {
844 g_string_printf(fe_name
, "trap %d", i
);
845 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
848 if(lttv_trace_find_hook(tcs
->parent
.t
,
849 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
850 LTT_FIELD_IRQ_ID
, 0, 0,
854 thf
= lttv_trace_hook_get_first(&h
);
856 t
= ltt_field_type(thf
->f1
);
857 //nb = ltt_type_element_number(t);
859 lttv_trace_hook_destroy(&h
);
862 name_tables->irq_names = g_new(GQuark, nb);
863 for(i = 0 ; i < nb ; i++) {
864 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
868 name_tables
->irq_names
= g_new(GQuark
, 256);
869 for(i
= 0 ; i
< 256 ; i
++) {
870 g_string_printf(fe_name
, "irq %d", i
);
871 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
875 name_tables->soft_irq_names = g_new(GQuark, nb);
876 for(i = 0 ; i < nb ; i++) {
877 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
881 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
882 for(i
= 0 ; i
< 256 ; i
++) {
883 g_string_printf(fe_name
, "softirq %d", i
);
884 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
888 g_string_free(fe_name
, TRUE
);
893 get_name_tables(LttvTraceState
*tcs
)
895 LttvNameTables
*name_tables
;
897 LttvAttributeValue v
;
899 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
901 g_assert(*(v
.v_pointer
) != NULL
);
902 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
903 //tcs->eventtype_names = name_tables->eventtype_names;
904 tcs
->syscall_names
= name_tables
->syscall_names
;
905 tcs
->trap_names
= name_tables
->trap_names
;
906 tcs
->irq_names
= name_tables
->irq_names
;
907 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
912 free_name_tables(LttvTraceState
*tcs
)
914 LttvNameTables
*name_tables
;
916 LttvAttributeValue v
;
918 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
920 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
921 *(v
.v_pointer
) = NULL
;
923 // g_free(name_tables->eventtype_names);
924 g_free(name_tables
->syscall_names
);
925 g_free(name_tables
->trap_names
);
926 g_free(name_tables
->irq_names
);
927 g_free(name_tables
->soft_irq_names
);
931 #ifdef HASH_TABLE_DEBUG
933 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
935 LttvProcessState
*process
= (LttvProcessState
*)value
;
937 /* Test for process corruption */
938 guint stack_len
= process
->execution_stack
->len
;
941 static void hash_table_check(GHashTable
*table
)
943 g_hash_table_foreach(table
, test_process
, NULL
);
950 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
953 LttvExecutionState
*es
;
955 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
956 guint cpu
= tfs
->cpu
;
958 #ifdef HASH_TABLE_DEBUG
959 hash_table_check(ts
->processes
);
961 LttvProcessState
*process
= ts
->running_process
[cpu
];
963 guint depth
= process
->execution_stack
->len
;
965 process
->execution_stack
=
966 g_array_set_size(process
->execution_stack
, depth
+ 1);
969 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
971 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
974 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
975 es
->s
= process
->state
->s
;
980 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
982 guint cpu
= tfs
->cpu
;
983 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
984 LttvProcessState
*process
= ts
->running_process
[cpu
];
986 guint depth
= process
->execution_stack
->len
;
988 if(process
->state
->t
!= t
){
989 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
990 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
991 g_info("process state has %s when pop_int is %s\n",
992 g_quark_to_string(process
->state
->t
),
993 g_quark_to_string(t
));
994 g_info("{ %u, %u, %s, %s }\n",
997 g_quark_to_string(process
->name
),
998 g_quark_to_string(process
->state
->s
));
1003 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1004 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1008 process
->execution_stack
=
1009 g_array_set_size(process
->execution_stack
, depth
- 1);
1010 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1012 process
->state
->change
= tfs
->parent
.timestamp
;
1017 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1018 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1020 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1022 LttvExecutionState
*es
;
1024 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1030 process
->name
= name
;
1031 //process->last_cpu = tfs->cpu_name;
1032 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1033 process
->kernel_thread
= 0;
1034 process
->usertrace
= NULL
;
1036 g_info("Process %u, core %p", process
->pid
, process
);
1037 g_hash_table_insert(tcs
->processes
, process
, process
);
1040 process
->ppid
= parent
->pid
;
1041 process
->creation_time
= *timestamp
;
1044 /* No parent. This process exists but we are missing all information about
1045 its creation. The birth time is set to zero but we remember the time of
1050 process
->creation_time
= ltt_time_zero
;
1053 process
->insertion_time
= *timestamp
;
1054 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1055 process
->creation_time
.tv_nsec
);
1056 process
->pid_time
= g_quark_from_string(buffer
);
1058 //process->last_cpu = tfs->cpu_name;
1059 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1060 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1061 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1062 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1063 es
= process
->state
= &g_array_index(process
->execution_stack
,
1064 LttvExecutionState
, 0);
1065 es
->t
= LTTV_STATE_USER_MODE
;
1066 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1067 es
->entry
= *timestamp
;
1068 //g_assert(timestamp->tv_sec != 0);
1069 es
->change
= *timestamp
;
1070 es
->s
= LTTV_STATE_RUN
;
1072 es
= process
->state
= &g_array_index(process
->execution_stack
,
1073 LttvExecutionState
, 1);
1074 es
->t
= LTTV_STATE_SYSCALL
;
1075 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1076 es
->entry
= *timestamp
;
1077 //g_assert(timestamp->tv_sec != 0);
1078 es
->change
= *timestamp
;
1079 es
->s
= LTTV_STATE_WAIT_FORK
;
1084 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1087 LttvProcessState key
;
1088 LttvProcessState
*process
;
1092 process
= g_hash_table_lookup(ts
->processes
, &key
);
1097 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1100 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1101 LttvExecutionState
*es
;
1103 /* Put ltt_time_zero creation time for unexisting processes */
1104 if(unlikely(process
== NULL
)) {
1105 process
= lttv_state_create_process(ts
,
1106 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1107 /* We are not sure is it's a kernel thread or normal thread, put the
1108 * bottom stack state to unknown */
1109 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1110 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1115 /* FIXME : this function should be called when we receive an event telling that
1116 * release_task has been called in the kernel. In happens generally when
1117 * the parent waits for its child terminaison, but may also happen in special
1118 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1119 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1120 * of a killed thread ground, but isn't the leader.
1122 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1124 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1125 LttvProcessState key
;
1127 key
.pid
= process
->pid
;
1128 key
.cpu
= process
->cpu
;
1129 g_hash_table_remove(ts
->processes
, &key
);
1130 g_array_free(process
->execution_stack
, TRUE
);
1135 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1137 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1142 static void lttv_state_free_process_table(GHashTable
*processes
)
1144 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1145 g_hash_table_destroy(processes
);
1149 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1151 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1152 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1153 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1154 LttField
*f
= thf
->f1
;
1156 LttvExecutionSubmode submode
;
1158 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1159 ltt_event_get_unsigned(e
, f
)];
1160 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1165 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1167 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1169 pop_state(s
, LTTV_STATE_SYSCALL
);
1174 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1176 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1177 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1178 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1179 LttField
*f
= thf
->f1
;
1181 LttvExecutionSubmode submode
;
1183 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1184 ltt_event_get_unsigned(e
, f
)];
1185 push_state(s
, LTTV_STATE_TRAP
, submode
);
1190 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1192 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1194 pop_state(s
, LTTV_STATE_TRAP
);
1199 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1201 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1202 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1203 guint8 fac_id
= ltt_event_facility_id(e
);
1204 guint8 ev_id
= ltt_event_eventtype_id(e
);
1205 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1206 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1207 g_assert(thf
->f1
!= NULL
);
1208 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1209 LttField
*f
= thf
->f1
;
1211 LttvExecutionSubmode submode
;
1213 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1214 ltt_event_get_unsigned(e
, f
)];
1216 /* Do something with the info about being in user or system mode when int? */
1217 push_state(s
, LTTV_STATE_IRQ
, submode
);
1222 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1226 pop_state(s
, LTTV_STATE_IRQ
);
1230 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1232 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1233 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1234 guint8 fac_id
= ltt_event_facility_id(e
);
1235 guint8 ev_id
= ltt_event_eventtype_id(e
);
1236 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1237 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1238 g_assert(thf
->f1
!= NULL
);
1239 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1240 LttField
*f
= thf
->f1
;
1242 LttvExecutionSubmode submode
;
1244 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1245 ltt_event_get_unsigned(e
, f
)];
1247 /* Do something with the info about being in user or system mode when int? */
1248 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1253 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1255 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1257 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1262 static gboolean
schedchange(void *hook_data
, void *call_data
)
1264 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1266 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1267 LttvProcessState
*process
= ts
->running_process
[cpu
];
1268 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1270 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1271 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1272 guint pid_in
, pid_out
;
1275 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1276 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1277 state_out
= ltt_event_get_int(e
, thf
->f3
);
1279 if(likely(process
!= NULL
)) {
1281 /* We could not know but it was not the idle process executing.
1282 This should only happen at the beginning, before the first schedule
1283 event, and when the initial information (current process for each CPU)
1284 is missing. It is not obvious how we could, after the fact, compensate
1285 the wrongly attributed statistics. */
1287 //This test only makes sense once the state is known and if there is no
1288 //missing events. We need to silently ignore schedchange coming after a
1289 //process_free, or it causes glitches. (FIXME)
1290 //if(unlikely(process->pid != pid_out)) {
1291 // g_assert(process->pid == 0);
1294 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1295 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1296 process
->state
->change
= s
->parent
.timestamp
;
1298 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1299 else process
->state
->s
= LTTV_STATE_WAIT
;
1300 process
->state
->change
= s
->parent
.timestamp
;
1304 exit_process(s
, process
); /* EXIT_DEAD */
1305 /* see sched.h for states */
1307 process
= ts
->running_process
[cpu
] =
1308 lttv_state_find_process_or_create(
1309 (LttvTraceState
*)s
->parent
.t_context
,
1311 &s
->parent
.timestamp
);
1312 process
->state
->s
= LTTV_STATE_RUN
;
1314 if(process
->usertrace
)
1315 process
->usertrace
->cpu
= cpu
;
1316 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1317 process
->state
->change
= s
->parent
.timestamp
;
1321 static gboolean
process_fork(void *hook_data
, void *call_data
)
1323 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1324 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1325 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1328 LttvProcessState
*zombie_process
;
1330 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1331 LttvProcessState
*process
= ts
->running_process
[cpu
];
1332 LttvProcessState
*child_process
;
1335 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1338 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1340 /* Mathieu : it seems like the process might have been scheduled in before the
1341 * fork, and, in a rare case, might be the current process. This might happen
1342 * in a SMP case where we don't have enough precision on the clocks.
1344 * Test reenabled after precision fixes on time. (Mathieu) */
1346 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1348 if(unlikely(zombie_process
!= NULL
)) {
1349 /* Reutilisation of PID. Only now we are sure that the old PID
1350 * has been released. FIXME : should know when release_task happens instead.
1352 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1354 for(i
=0; i
< num_cpus
; i
++) {
1355 g_assert(zombie_process
!= ts
->running_process
[i
]);
1358 exit_process(s
, zombie_process
);
1361 g_assert(process
->pid
!= child_pid
);
1362 // FIXME : Add this test in the "known state" section
1363 // g_assert(process->pid == parent_pid);
1364 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1365 if(child_process
== NULL
) {
1366 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1367 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1369 /* The process has already been created : due to time imprecision between
1370 * multiple CPUs : it has been scheduled in before creation. Note that we
1371 * shouldn't have this kind of imprecision.
1373 * Simply put a correct parent.
1375 //It can also happen when created by a usertrace. In that case, it's
1377 //g_assert(0); /* This is a problematic case : the process has been created
1378 // before the fork event */
1379 child_process
->ppid
= process
->pid
;
1381 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1382 child_process
->name
= process
->name
;
1387 /* We stamp a newly created process as kernel_thread */
1388 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1390 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1391 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1392 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1395 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1396 LttvProcessState
*process
;
1397 LttvExecutionState
*es
;
1400 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1402 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1403 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1404 es
->t
= LTTV_STATE_SYSCALL
;
1405 process
->kernel_thread
= 1;
1410 static gboolean
process_exit(void *hook_data
, void *call_data
)
1412 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1413 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1414 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1418 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1419 LttvProcessState
*process
= ts
->running_process
[cpu
];
1421 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1423 // FIXME : Add this test in the "known state" section
1424 // g_assert(process->pid == pid);
1426 if(likely(process
!= NULL
)) {
1427 process
->state
->s
= LTTV_STATE_EXIT
;
1432 static gboolean
process_free(void *hook_data
, void *call_data
)
1434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1435 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1436 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1437 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1439 LttvProcessState
*process
;
1441 /* PID of the process to release */
1442 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1444 g_assert(release_pid
!= 0);
1446 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1448 if(likely(process
!= NULL
)) {
1449 /* release_task is happening at kernel level : we can now safely release
1450 * the data structure of the process */
1451 //This test is fun, though, as it may happen that
1452 //at time t : CPU 0 : process_free
1453 //at time t+150ns : CPU 1 : schedule out
1454 //Clearly due to time imprecision, we disable it. (Mathieu)
1455 //If this weird case happen, we have no choice but to put the
1456 //Currently running process on the cpu to 0.
1457 //I re-enable it following time precision fixes. (Mathieu)
1458 //Well, in the case where an process is freed by a process on another CPU
1459 //and still scheduled, it happens that this is the schedchange that will
1460 //drop the last reference count. Do not free it here!
1461 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1463 for(i
=0; i
< num_cpus
; i
++) {
1464 //g_assert(process != ts->running_process[i]);
1465 if(process
== ts
->running_process
[i
]) {
1466 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1470 //if(i == num_cpus) /* process is not scheduled */
1471 //exit_process(s, process); // do nothing : wait for the schedchange to
1472 //delete the process.
1479 static gboolean
process_exec(void *hook_data
, void *call_data
)
1481 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1482 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1483 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1484 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1487 LttvProcessState
*process
= ts
->running_process
[cpu
];
1489 /* PID of the process to release */
1490 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1491 //name = ltt_event_get_string(e, thf->f1);
1492 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1494 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1495 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1496 memcpy(null_term_name
, name_begin
, name_len
);
1497 null_term_name
[name_len
] = '\0';
1499 process
->name
= g_quark_from_string(null_term_name
);
1500 g_free(null_term_name
);
1504 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1506 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1507 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1508 //It's slow : optimise later by doing this before reading trace.
1509 LttEventType
*et
= ltt_event_eventtype(e
);
1511 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1516 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1517 LttvProcessState
*process
= ts
->running_process
[cpu
];
1518 LttvProcessState
*parent_process
;
1519 LttField
*f4
, *f5
, *f6
;
1520 GQuark mode
, submode
, status
;
1523 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1526 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1529 command
= ltt_event_get_string(e
, thf
->f3
);
1532 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1533 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1534 ltt_event_get_unsigned(e
, f4
));
1537 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1538 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1539 ltt_event_get_unsigned(e
, f5
));
1542 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1543 status
= ltt_enum_string_get(ltt_field_type(f6
),
1544 ltt_event_get_unsigned(e
, f6
));
1546 /* The process might exist if a process was forked while performing the sate dump. */
1547 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1548 if(process
== NULL
) {
1549 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1550 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1551 pid
, g_quark_from_string(command
),
1552 &s
->parent
.timestamp
);
1554 /* Keep the stack bottom : a running user mode */
1556 /* Disabled because of inconsistencies in the current statedump states. */
1557 if(mode
== LTTV_STATE_USER_MODE
) {
1558 /* Only keep the bottom */
1559 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1561 /* On top of it : */
1562 LttvExecutionState
*es
;
1563 es
= process
->state
= &g_array_index(process
->execution_stack
,
1564 LttvExecutionState
, 1);
1573 LttvExecutionState
*es
;
1574 es
= process
->state
= &g_array_index(process
->execution_stack
,
1575 LttvExecutionState
, 1);
1576 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1577 es
->s
= LTTV_STATE_UNNAMED
;
1578 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1581 /* The process has already been created :
1582 * Probably was forked while dumping the process state or
1583 * was simply scheduled in prior to get the state dump event.
1585 process
->ppid
= parent_pid
;
1586 process
->name
= g_quark_from_string(command
);
1587 /* Don't mess around with the stack, it will eventually become
1588 * ok after the end of state dump. */
1594 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1596 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1598 lttv_state_add_event_hooks(tss
);
1603 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1605 LttvTraceset
*traceset
= self
->parent
.ts
;
1607 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1611 LttvTracefileState
*tfs
;
1615 LttvTraceHookByFacility
*thf
;
1617 LttvTraceHook
*hook
;
1619 LttvAttributeValue val
;
1623 nb_trace
= lttv_traceset_number(traceset
);
1624 for(i
= 0 ; i
< nb_trace
; i
++) {
1625 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1627 /* Find the eventtype id for the following events and register the
1628 associated by id hooks. */
1630 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 15);
1631 hooks
= g_array_set_size(hooks
, 15);
1633 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1634 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1635 LTT_FIELD_SYSCALL_ID
, 0, 0,
1636 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1639 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1640 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1642 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1645 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1646 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1647 LTT_FIELD_TRAP_ID
, 0, 0,
1648 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1651 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1652 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1654 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1657 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1658 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1659 LTT_FIELD_IRQ_ID
, 0, 0,
1660 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1663 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1664 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1666 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1669 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1670 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1671 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1672 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1675 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1676 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1678 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1681 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1682 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1683 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1684 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1687 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1688 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1689 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1690 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1693 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1694 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1695 LTT_FIELD_PID
, 0, 0,
1696 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1699 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1700 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1701 LTT_FIELD_PID
, 0, 0,
1702 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1705 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1706 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1707 LTT_FIELD_PID
, 0, 0,
1708 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1711 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1712 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1713 LTT_FIELD_FILENAME
, 0, 0,
1714 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1717 /* statedump-related hooks */
1718 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1719 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1720 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1721 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 14));
1725 /* Add these hooks to each event_by_id hooks list */
1727 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1729 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1731 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1732 LttvTracefileContext
*, j
));
1734 for(k
= 0 ; k
< hooks
->len
; k
++) {
1735 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1736 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1737 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1739 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1746 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1747 *(val
.v_pointer
) = hooks
;
1751 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1753 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1755 lttv_state_remove_event_hooks(tss
);
1760 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1762 LttvTraceset
*traceset
= self
->parent
.ts
;
1764 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1768 LttvTracefileState
*tfs
;
1772 LttvTraceHook
*hook
;
1774 LttvTraceHookByFacility
*thf
;
1776 LttvAttributeValue val
;
1778 nb_trace
= lttv_traceset_number(traceset
);
1779 for(i
= 0 ; i
< nb_trace
; i
++) {
1780 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1781 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1782 hooks
= *(val
.v_pointer
);
1784 /* Remove these hooks from each event_by_id hooks list */
1786 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1788 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1790 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1791 LttvTracefileContext
*, j
));
1793 for(k
= 0 ; k
< hooks
->len
; k
++) {
1794 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1795 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1796 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1798 lttv_hooks_remove_data(
1799 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1805 for(k
= 0 ; k
< hooks
->len
; k
++)
1806 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1807 g_array_free(hooks
, TRUE
);
1811 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1813 guint
*event_count
= (guint
*)hook_data
;
1815 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1816 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1821 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1823 LttvTracefileState
*tfcs
;
1825 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1827 LttEventPosition
*ep
;
1833 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1835 LttvAttributeValue value
;
1837 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1838 LTTV_STATE_SAVED_STATES
);
1839 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1840 value
= lttv_attribute_add(saved_states_tree
,
1841 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1842 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1843 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1844 *(value
.v_time
) = self
->parent
.timestamp
;
1845 lttv_state_save(tcs
, saved_state_tree
);
1846 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1847 self
->parent
.timestamp
.tv_nsec
);
1849 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1854 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1856 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1858 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1863 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
1871 static gboolean
block_start(void *hook_data
, void *call_data
)
1873 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1875 LttvTracefileState
*tfcs
;
1877 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1879 LttEventPosition
*ep
;
1881 guint i
, nb_block
, nb_event
, nb_tracefile
;
1885 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1887 LttvAttributeValue value
;
1889 ep
= ltt_event_position_new();
1891 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1893 /* Count the number of events added since the last block end in any
1896 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1898 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1899 LttvTracefileContext
, i
));
1900 ltt_event_position(tfcs
->parent
.e
, ep
);
1901 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1902 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1903 tfcs
->saved_position
= nb_event
;
1907 if(tcs
->nb_event
>= tcs
->save_interval
) {
1908 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1909 LTTV_STATE_SAVED_STATES
);
1910 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1911 value
= lttv_attribute_add(saved_states_tree
,
1912 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1913 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1914 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1915 *(value
.v_time
) = self
->parent
.timestamp
;
1916 lttv_state_save(tcs
, saved_state_tree
);
1918 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1919 self
->parent
.timestamp
.tv_nsec
);
1921 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1927 static gboolean
block_end(void *hook_data
, void *call_data
)
1929 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1931 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1935 LttEventPosition
*ep
;
1937 guint nb_block
, nb_event
;
1939 ep
= ltt_event_position_new();
1940 ltt_event_position(self
->parent
.e
, ep
);
1941 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1942 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1943 self
->saved_position
= 0;
1944 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1951 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1953 LttvTraceset
*traceset
= self
->parent
.ts
;
1955 guint i
, j
, nb_trace
, nb_tracefile
;
1959 LttvTracefileState
*tfs
;
1961 LttvTraceHook hook_start
, hook_end
;
1963 nb_trace
= lttv_traceset_number(traceset
);
1964 for(i
= 0 ; i
< nb_trace
; i
++) {
1965 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1967 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1968 NULL
, NULL
, block_start
, &hook_start
);
1969 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1970 NULL
, NULL
, block_end
, &hook_end
);
1972 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1974 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1976 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1977 LttvTracefileContext
, j
));
1978 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1979 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1980 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1981 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1987 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1989 LttvTraceset
*traceset
= self
->parent
.ts
;
1991 guint i
, j
, nb_trace
, nb_tracefile
;
1995 LttvTracefileState
*tfs
;
1998 nb_trace
= lttv_traceset_number(traceset
);
1999 for(i
= 0 ; i
< nb_trace
; i
++) {
2001 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2002 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2004 guint
*event_count
= g_new(guint
, 1);
2007 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2009 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2010 LttvTracefileContext
*, j
));
2011 lttv_hooks_add(tfs
->parent
.event
,
2012 state_save_event_hook
,
2019 lttv_process_traceset_begin(&self
->parent
,
2020 NULL
, NULL
, NULL
, NULL
, NULL
);
2024 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2026 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2028 lttv_state_save_add_event_hooks(tss
);
2035 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2037 LttvTraceset
*traceset
= self
->parent
.ts
;
2039 guint i
, j
, nb_trace
, nb_tracefile
;
2043 LttvTracefileState
*tfs
;
2045 LttvTraceHook hook_start
, hook_end
;
2047 nb_trace
= lttv_traceset_number(traceset
);
2048 for(i
= 0 ; i
< nb_trace
; i
++) {
2049 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2051 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2052 NULL
, NULL
, block_start
, &hook_start
);
2054 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2055 NULL
, NULL
, block_end
, &hook_end
);
2057 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2059 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2061 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2062 LttvTracefileContext
, j
));
2063 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2064 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2065 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2066 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2072 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2074 LttvTraceset
*traceset
= self
->parent
.ts
;
2076 guint i
, j
, nb_trace
, nb_tracefile
;
2080 LttvTracefileState
*tfs
;
2082 LttvHooks
*after_trace
= lttv_hooks_new();
2084 lttv_hooks_add(after_trace
,
2085 state_save_after_trace_hook
,
2090 lttv_process_traceset_end(&self
->parent
,
2091 NULL
, after_trace
, NULL
, NULL
, NULL
);
2093 lttv_hooks_destroy(after_trace
);
2095 nb_trace
= lttv_traceset_number(traceset
);
2096 for(i
= 0 ; i
< nb_trace
; i
++) {
2098 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2099 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2101 guint
*event_count
= NULL
;
2103 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2105 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2106 LttvTracefileContext
*, j
));
2107 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2108 state_save_event_hook
);
2110 if(event_count
) g_free(event_count
);
2114 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2116 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2118 lttv_state_save_remove_event_hooks(tss
);
2123 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2125 LttvTraceset
*traceset
= self
->parent
.ts
;
2129 int min_pos
, mid_pos
, max_pos
;
2131 guint call_rest
= 0;
2133 LttvTraceState
*tcs
;
2135 LttvAttributeValue value
;
2137 LttvAttributeType type
;
2139 LttvAttributeName name
;
2141 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2143 //g_tree_destroy(self->parent.pqueue);
2144 //self->parent.pqueue = g_tree_new(compare_tracefile);
2146 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2148 nb_trace
= lttv_traceset_number(traceset
);
2149 for(i
= 0 ; i
< nb_trace
; i
++) {
2150 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2152 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2153 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2154 LTTV_STATE_SAVED_STATES
);
2157 if(saved_states_tree
) {
2158 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2159 mid_pos
= max_pos
/ 2;
2160 while(min_pos
< max_pos
) {
2161 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2162 g_assert(type
== LTTV_GOBJECT
);
2163 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2164 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2166 g_assert(type
== LTTV_TIME
);
2167 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2169 closest_tree
= saved_state_tree
;
2171 else max_pos
= mid_pos
- 1;
2173 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2177 /* restore the closest earlier saved state */
2179 lttv_state_restore(tcs
, closest_tree
);
2183 /* There is no saved state, yet we want to have it. Restart at T0 */
2185 restore_init_state(tcs
);
2186 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2189 /* We want to seek quickly without restoring/updating the state */
2191 restore_init_state(tcs
);
2192 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2195 if(!call_rest
) g_info("NOT Calling restore");
2200 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2206 traceset_state_finalize (LttvTracesetState
*self
)
2208 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2209 finalize(G_OBJECT(self
));
2214 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2216 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2218 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2219 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2220 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2221 klass
->new_traceset_context
= new_traceset_context
;
2222 klass
->new_trace_context
= new_trace_context
;
2223 klass
->new_tracefile_context
= new_tracefile_context
;
2228 lttv_traceset_state_get_type(void)
2230 static GType type
= 0;
2232 static const GTypeInfo info
= {
2233 sizeof (LttvTracesetStateClass
),
2234 NULL
, /* base_init */
2235 NULL
, /* base_finalize */
2236 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2237 NULL
, /* class_finalize */
2238 NULL
, /* class_data */
2239 sizeof (LttvTracesetState
),
2240 0, /* n_preallocs */
2241 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2242 NULL
/* value handling */
2245 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2253 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2259 trace_state_finalize (LttvTraceState
*self
)
2261 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2262 finalize(G_OBJECT(self
));
2267 trace_state_class_init (LttvTraceStateClass
*klass
)
2269 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2271 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2272 klass
->state_save
= state_save
;
2273 klass
->state_restore
= state_restore
;
2274 klass
->state_saved_free
= state_saved_free
;
2279 lttv_trace_state_get_type(void)
2281 static GType type
= 0;
2283 static const GTypeInfo info
= {
2284 sizeof (LttvTraceStateClass
),
2285 NULL
, /* base_init */
2286 NULL
, /* base_finalize */
2287 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2288 NULL
, /* class_finalize */
2289 NULL
, /* class_data */
2290 sizeof (LttvTraceState
),
2291 0, /* n_preallocs */
2292 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2293 NULL
/* value handling */
2296 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2297 "LttvTraceStateType", &info
, 0);
2304 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2310 tracefile_state_finalize (LttvTracefileState
*self
)
2312 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2313 finalize(G_OBJECT(self
));
2318 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2320 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2322 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2327 lttv_tracefile_state_get_type(void)
2329 static GType type
= 0;
2331 static const GTypeInfo info
= {
2332 sizeof (LttvTracefileStateClass
),
2333 NULL
, /* base_init */
2334 NULL
, /* base_finalize */
2335 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2336 NULL
, /* class_finalize */
2337 NULL
, /* class_data */
2338 sizeof (LttvTracefileState
),
2339 0, /* n_preallocs */
2340 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2341 NULL
/* value handling */
2344 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2345 "LttvTracefileStateType", &info
, 0);
2351 static void module_init()
2353 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2354 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2355 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2356 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2357 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2358 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2359 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2360 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2361 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2362 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2363 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2364 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2365 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2366 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2367 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2368 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2369 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2370 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2371 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2372 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2373 LTTV_STATE_EVENT
= g_quark_from_string("event");
2374 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2375 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2376 LTTV_STATE_TIME
= g_quark_from_string("time");
2377 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2378 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2379 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2380 g_quark_from_string("trace_state_use_count");
2383 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2384 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2385 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2386 LTT_FACILITY_FS
= g_quark_from_string("fs");
2387 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2390 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2391 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2392 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2393 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2394 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2395 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2396 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2397 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2398 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2399 LTT_EVENT_FORK
= g_quark_from_string("fork");
2400 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2401 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2402 LTT_EVENT_FREE
= g_quark_from_string("free");
2403 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2404 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2407 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2408 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2409 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2410 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2411 LTT_FIELD_OUT
= g_quark_from_string("out");
2412 LTT_FIELD_IN
= g_quark_from_string("in");
2413 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2414 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2415 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2416 LTT_FIELD_PID
= g_quark_from_string("pid");
2417 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2418 LTT_FIELD_NAME
= g_quark_from_string("name");
2419 LTT_FIELD_MODE
= g_quark_from_string("mode");
2420 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2421 LTT_FIELD_STATUS
= g_quark_from_string("status");
2425 static void module_destroy()
2430 LTTV_MODULE("state", "State computation", \
2431 "Update the system state, possibly saving it at intervals", \
2432 module_init
, module_destroy
)