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
;
263 for(j
= 0 ; j
< nb_tracefile
; j
++) {
265 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
266 LttvTracefileContext
*, j
));
267 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
270 tcs
->processes
= NULL
;
271 tcs
->running_process
= g_new(LttvProcessState
*,
272 ltt_trace_get_num_cpu(tc
->t
));
273 restore_init_state(tcs
);
279 fini(LttvTracesetState
*self
)
285 LttvTracefileState
*tfcs
;
287 LttvAttributeValue v
;
289 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
290 for(i
= 0 ; i
< nb_trace
; i
++) {
291 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
292 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
295 g_assert(*(v
.v_uint
) != 0);
298 if(*(v
.v_uint
) == 0) {
299 free_name_tables(tcs
);
301 free_saved_state(tcs
);
303 g_free(tcs
->running_process
);
304 tcs
->running_process
= NULL
;
305 lttv_state_free_process_table(tcs
->processes
);
306 tcs
->processes
= NULL
;
308 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
309 fini((LttvTracesetContext
*)self
);
313 static LttvTracesetContext
*
314 new_traceset_context(LttvTracesetContext
*self
)
316 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
320 static LttvTraceContext
*
321 new_trace_context(LttvTracesetContext
*self
)
323 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
327 static LttvTracefileContext
*
328 new_tracefile_context(LttvTracesetContext
*self
)
330 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
334 /* Write the process state of the trace */
336 static void write_process_state(gpointer key
, gpointer value
,
339 LttvProcessState
*process
;
341 LttvExecutionState
*es
;
343 FILE *fp
= (FILE *)user_data
;
347 process
= (LttvProcessState
*)value
;
349 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
350 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
351 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
354 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
355 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
356 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
357 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
358 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
359 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
360 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
362 fprintf(fp
, " </PROCESS>\n");
366 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
368 guint i
, nb_tracefile
, nb_block
, offset
;
371 LttvTracefileState
*tfcs
;
375 LttEventPosition
*ep
;
379 ep
= ltt_event_position_new();
381 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
383 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
385 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
386 for(i
=0;i
<nb_cpus
;i
++) {
387 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
388 i
, self
->running_process
[i
]->pid
);
391 nb_tracefile
= self
->parent
.tracefiles
->len
;
393 for(i
= 0 ; i
< nb_tracefile
; i
++) {
395 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
396 LttvTracefileContext
*, i
));
397 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
398 tfcs
->parent
.timestamp
.tv_sec
,
399 tfcs
->parent
.timestamp
.tv_nsec
);
400 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
401 if(e
== NULL
) fprintf(fp
,"/>\n");
403 ltt_event_position(e
, ep
);
404 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
405 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
410 fprintf(fp
,"</PROCESS_STATE>");
414 /* Copy each process from an existing hash table to a new one */
416 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
418 LttvProcessState
*process
, *new_process
;
420 GHashTable
*new_processes
= (GHashTable
*)user_data
;
424 process
= (LttvProcessState
*)value
;
425 new_process
= g_new(LttvProcessState
, 1);
426 *new_process
= *process
;
427 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
428 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
429 new_process
->execution_stack
=
430 g_array_set_size(new_process
->execution_stack
,
431 process
->execution_stack
->len
);
432 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
433 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
434 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
436 new_process
->state
= &g_array_index(new_process
->execution_stack
,
437 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
438 g_hash_table_insert(new_processes
, new_process
, new_process
);
442 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
444 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
446 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
447 return new_processes
;
451 /* The saved state for each trace contains a member "processes", which
452 stores a copy of the process table, and a member "tracefiles" with
453 one entry per tracefile. Each tracefile has a "process" member pointing
454 to the current process and a "position" member storing the tracefile
455 position (needed to seek to the current "next" event. */
457 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
459 guint i
, nb_tracefile
, nb_cpus
;
461 LttvTracefileState
*tfcs
;
463 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
465 guint
*running_process
;
467 LttvAttributeType type
;
469 LttvAttributeValue value
;
471 LttvAttributeName name
;
473 LttEventPosition
*ep
;
475 tracefiles_tree
= lttv_attribute_find_subdir(container
,
476 LTTV_STATE_TRACEFILES
);
478 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
480 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
482 /* Add the currently running processes array */
483 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
484 running_process
= g_new(guint
, nb_cpus
);
485 for(i
=0;i
<nb_cpus
;i
++) {
486 running_process
[i
] = self
->running_process
[i
]->pid
;
488 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
490 *(value
.v_pointer
) = running_process
;
492 g_info("State save");
494 nb_tracefile
= self
->parent
.tracefiles
->len
;
496 for(i
= 0 ; i
< nb_tracefile
; i
++) {
498 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
499 LttvTracefileContext
*, i
));
500 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
501 value
= lttv_attribute_add(tracefiles_tree
, i
,
503 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
505 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
507 *(value
.v_uint
) = tfcs
->process
->pid
;
509 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
511 /* Only save the position if the tfs has not infinite time. */
512 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
513 // && current_tfcs != tfcs) {
514 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
515 *(value
.v_pointer
) = NULL
;
517 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
518 ep
= ltt_event_position_new();
519 ltt_event_position(e
, ep
);
520 *(value
.v_pointer
) = ep
;
522 guint nb_block
, offset
;
525 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
526 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
528 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
534 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
536 guint i
, nb_tracefile
, pid
, nb_cpus
;
538 LttvTracefileState
*tfcs
;
540 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
542 guint
*running_process
;
544 LttvAttributeType type
;
546 LttvAttributeValue value
;
548 LttvAttributeName name
;
550 LttEventPosition
*ep
;
552 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
554 tracefiles_tree
= lttv_attribute_find_subdir(container
,
555 LTTV_STATE_TRACEFILES
);
557 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
559 g_assert(type
== LTTV_POINTER
);
560 lttv_state_free_process_table(self
->processes
);
561 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
563 /* Add the currently running processes array */
564 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
565 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
567 g_assert(type
== LTTV_POINTER
);
568 running_process
= *(value
.v_pointer
);
569 for(i
=0;i
<nb_cpus
;i
++) {
570 pid
= running_process
[i
];
571 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
572 g_assert(self
->running_process
[i
] != NULL
);
576 nb_tracefile
= self
->parent
.tracefiles
->len
;
578 //g_tree_destroy(tsc->pqueue);
579 //tsc->pqueue = g_tree_new(compare_tracefile);
581 for(i
= 0 ; i
< nb_tracefile
; i
++) {
583 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
584 LttvTracefileContext
*, i
));
585 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
586 g_assert(type
== LTTV_GOBJECT
);
587 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
589 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
591 g_assert(type
== LTTV_UINT
);
592 pid
= *(value
.v_uint
);
593 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
595 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
597 g_assert(type
== LTTV_POINTER
);
598 //g_assert(*(value.v_pointer) != NULL);
599 ep
= *(value
.v_pointer
);
600 g_assert(tfcs
->parent
.t_context
!= NULL
);
602 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
603 g_tree_remove(tsc
->pqueue
, tfc
);
606 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
607 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
608 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
609 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
610 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
612 tfc
->timestamp
= ltt_time_infinite
;
618 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
620 guint i
, nb_tracefile
, nb_cpus
;
622 LttvTracefileState
*tfcs
;
624 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
626 guint
*running_process
;
628 LttvAttributeType type
;
630 LttvAttributeValue value
;
632 LttvAttributeName name
;
634 LttEventPosition
*ep
;
636 tracefiles_tree
= lttv_attribute_find_subdir(container
,
637 LTTV_STATE_TRACEFILES
);
638 g_object_ref(G_OBJECT(tracefiles_tree
));
639 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
641 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
643 g_assert(type
== LTTV_POINTER
);
644 lttv_state_free_process_table(*(value
.v_pointer
));
645 *(value
.v_pointer
) = NULL
;
646 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
648 /* Free running processes array */
649 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
650 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
652 g_assert(type
== LTTV_POINTER
);
653 running_process
= *(value
.v_pointer
);
654 g_free(running_process
);
656 nb_tracefile
= self
->parent
.tracefiles
->len
;
658 for(i
= 0 ; i
< nb_tracefile
; i
++) {
660 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
661 LttvTracefileContext
*, i
));
662 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
663 g_assert(type
== LTTV_GOBJECT
);
664 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
666 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
668 g_assert(type
== LTTV_POINTER
);
669 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
671 g_object_unref(G_OBJECT(tracefiles_tree
));
675 static void free_saved_state(LttvTraceState
*self
)
679 LttvAttributeType type
;
681 LttvAttributeValue value
;
683 LttvAttributeName name
;
685 LttvAttribute
*saved_states
;
687 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
688 LTTV_STATE_SAVED_STATES
);
690 nb
= lttv_attribute_get_number(saved_states
);
691 for(i
= 0 ; i
< nb
; i
++) {
692 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
693 g_assert(type
== LTTV_GOBJECT
);
694 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
697 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
702 create_max_time(LttvTraceState
*tcs
)
704 LttvAttributeValue v
;
706 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
708 g_assert(*(v
.v_pointer
) == NULL
);
709 *(v
.v_pointer
) = g_new(LttTime
,1);
710 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
715 get_max_time(LttvTraceState
*tcs
)
717 LttvAttributeValue v
;
719 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
721 g_assert(*(v
.v_pointer
) != NULL
);
722 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
727 free_max_time(LttvTraceState
*tcs
)
729 LttvAttributeValue v
;
731 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
733 g_free(*(v
.v_pointer
));
734 *(v
.v_pointer
) = NULL
;
738 typedef struct _LttvNameTables
{
739 // FIXME GQuark *eventtype_names;
740 GQuark
*syscall_names
;
743 GQuark
*soft_irq_names
;
748 create_name_tables(LttvTraceState
*tcs
)
752 GQuark f_name
, e_name
;
756 LttvTraceHookByFacility
*thf
;
762 GString
*fe_name
= g_string_new("");
764 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
766 LttvAttributeValue v
;
768 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
770 g_assert(*(v
.v_pointer
) == NULL
);
771 *(v
.v_pointer
) = name_tables
;
772 #if 0 // Use iteration over the facilities_by_name and then list all event
773 // types of each facility
774 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
775 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
776 for(i
= 0 ; i
< nb
; i
++) {
777 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
778 e_name
= ltt_eventtype_name(et
);
779 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
780 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
781 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
784 if(lttv_trace_find_hook(tcs
->parent
.t
,
785 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
786 LTT_FIELD_SYSCALL_ID
, 0, 0,
790 thf
= lttv_trace_hook_get_first(&h
);
792 t
= ltt_field_type(thf
->f1
);
793 nb
= ltt_type_element_number(t
);
795 lttv_trace_hook_destroy(&h
);
797 name_tables
->syscall_names
= g_new(GQuark
, nb
);
799 for(i
= 0 ; i
< nb
; i
++) {
800 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
803 //name_tables->syscall_names = g_new(GQuark, 256);
804 //for(i = 0 ; i < 256 ; i++) {
805 // g_string_printf(fe_name, "syscall %d", i);
806 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
809 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
810 LTT_EVENT_TRAP_ENTRY
,
811 LTT_FIELD_TRAP_ID
, 0, 0,
815 thf
= lttv_trace_hook_get_first(&h
);
817 t
= ltt_field_type(thf
->f1
);
818 //nb = ltt_type_element_number(t);
820 lttv_trace_hook_destroy(&h
);
823 name_tables->trap_names = g_new(GQuark, nb);
824 for(i = 0 ; i < nb ; i++) {
825 name_tables->trap_names[i] = g_quark_from_string(
826 ltt_enum_string_get(t, i));
830 name_tables
->trap_names
= g_new(GQuark
, 256);
831 for(i
= 0 ; i
< 256 ; i
++) {
832 g_string_printf(fe_name
, "trap %d", i
);
833 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
836 if(lttv_trace_find_hook(tcs
->parent
.t
,
837 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
838 LTT_FIELD_IRQ_ID
, 0, 0,
842 thf
= lttv_trace_hook_get_first(&h
);
844 t
= ltt_field_type(thf
->f1
);
845 //nb = ltt_type_element_number(t);
847 lttv_trace_hook_destroy(&h
);
850 name_tables->irq_names = g_new(GQuark, nb);
851 for(i = 0 ; i < nb ; i++) {
852 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
856 name_tables
->irq_names
= g_new(GQuark
, 256);
857 for(i
= 0 ; i
< 256 ; i
++) {
858 g_string_printf(fe_name
, "irq %d", i
);
859 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
863 name_tables->soft_irq_names = g_new(GQuark, nb);
864 for(i = 0 ; i < nb ; i++) {
865 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
869 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
870 for(i
= 0 ; i
< 256 ; i
++) {
871 g_string_printf(fe_name
, "softirq %d", i
);
872 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
876 g_string_free(fe_name
, TRUE
);
881 get_name_tables(LttvTraceState
*tcs
)
883 LttvNameTables
*name_tables
;
885 LttvAttributeValue v
;
887 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
889 g_assert(*(v
.v_pointer
) != NULL
);
890 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
891 //tcs->eventtype_names = name_tables->eventtype_names;
892 tcs
->syscall_names
= name_tables
->syscall_names
;
893 tcs
->trap_names
= name_tables
->trap_names
;
894 tcs
->irq_names
= name_tables
->irq_names
;
895 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
900 free_name_tables(LttvTraceState
*tcs
)
902 LttvNameTables
*name_tables
;
904 LttvAttributeValue v
;
906 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
908 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
909 *(v
.v_pointer
) = NULL
;
911 // g_free(name_tables->eventtype_names);
912 g_free(name_tables
->syscall_names
);
913 g_free(name_tables
->trap_names
);
914 g_free(name_tables
->irq_names
);
915 g_free(name_tables
->soft_irq_names
);
919 #ifdef HASH_TABLE_DEBUG
921 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
923 LttvProcessState
*process
= (LttvProcessState
*)value
;
925 /* Test for process corruption */
926 guint stack_len
= process
->execution_stack
->len
;
929 static void hash_table_check(GHashTable
*table
)
931 g_hash_table_foreach(table
, test_process
, NULL
);
938 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
941 LttvExecutionState
*es
;
943 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
944 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
946 #ifdef HASH_TABLE_DEBUG
947 hash_table_check(ts
->processes
);
949 LttvProcessState
*process
= ts
->running_process
[cpu
];
951 guint depth
= process
->execution_stack
->len
;
953 process
->execution_stack
=
954 g_array_set_size(process
->execution_stack
, depth
+ 1);
957 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
959 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
962 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
963 es
->s
= process
->state
->s
;
968 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
970 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
971 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
972 LttvProcessState
*process
= ts
->running_process
[cpu
];
974 guint depth
= process
->execution_stack
->len
;
976 if(process
->state
->t
!= t
){
977 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
978 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
979 g_info("process state has %s when pop_int is %s\n",
980 g_quark_to_string(process
->state
->t
),
981 g_quark_to_string(t
));
982 g_info("{ %u, %u, %s, %s }\n",
985 g_quark_to_string(process
->name
),
986 g_quark_to_string(process
->state
->s
));
991 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
992 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
996 process
->execution_stack
=
997 g_array_set_size(process
->execution_stack
, depth
- 1);
998 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1000 process
->state
->change
= tfs
->parent
.timestamp
;
1005 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1006 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1008 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1010 LttvExecutionState
*es
;
1012 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1018 process
->name
= name
;
1019 //process->last_cpu = tfs->cpu_name;
1020 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1021 process
->kernel_thread
= 0;
1023 g_info("Process %u, core %p", process
->pid
, process
);
1024 g_hash_table_insert(tcs
->processes
, process
, process
);
1027 process
->ppid
= parent
->pid
;
1028 process
->creation_time
= *timestamp
;
1031 /* No parent. This process exists but we are missing all information about
1032 its creation. The birth time is set to zero but we remember the time of
1037 process
->creation_time
= ltt_time_zero
;
1040 process
->insertion_time
= *timestamp
;
1041 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1042 process
->creation_time
.tv_nsec
);
1043 process
->pid_time
= g_quark_from_string(buffer
);
1045 //process->last_cpu = tfs->cpu_name;
1046 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1047 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1048 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1049 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1050 es
= process
->state
= &g_array_index(process
->execution_stack
,
1051 LttvExecutionState
, 0);
1052 es
->t
= LTTV_STATE_USER_MODE
;
1053 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1054 es
->entry
= *timestamp
;
1055 //g_assert(timestamp->tv_sec != 0);
1056 es
->change
= *timestamp
;
1057 es
->s
= LTTV_STATE_RUN
;
1059 es
= process
->state
= &g_array_index(process
->execution_stack
,
1060 LttvExecutionState
, 1);
1061 es
->t
= LTTV_STATE_SYSCALL
;
1062 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1063 es
->entry
= *timestamp
;
1064 //g_assert(timestamp->tv_sec != 0);
1065 es
->change
= *timestamp
;
1066 es
->s
= LTTV_STATE_WAIT_FORK
;
1071 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1074 LttvProcessState key
;
1075 LttvProcessState
*process
;
1079 process
= g_hash_table_lookup(ts
->processes
, &key
);
1084 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1087 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1088 LttvExecutionState
*es
;
1090 /* Put ltt_time_zero creation time for unexisting processes */
1091 if(unlikely(process
== NULL
)) {
1092 process
= lttv_state_create_process(ts
,
1093 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1094 /* We are not sure is it's a kernel thread or normal thread, put the
1095 * bottom stack state to unknown */
1096 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1097 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1102 /* FIXME : this function should be called when we receive an event telling that
1103 * release_task has been called in the kernel. In happens generally when
1104 * the parent waits for its child terminaison, but may also happen in special
1105 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1106 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1107 * of a killed thread ground, but isn't the leader.
1109 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1111 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1112 LttvProcessState key
;
1114 key
.pid
= process
->pid
;
1115 key
.cpu
= process
->cpu
;
1116 g_hash_table_remove(ts
->processes
, &key
);
1117 g_array_free(process
->execution_stack
, TRUE
);
1122 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1124 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1129 static void lttv_state_free_process_table(GHashTable
*processes
)
1131 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1132 g_hash_table_destroy(processes
);
1136 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1138 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1139 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1140 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1141 LttField
*f
= thf
->f1
;
1143 LttvExecutionSubmode submode
;
1145 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1146 ltt_event_get_unsigned(e
, f
)];
1147 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1152 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1154 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1156 pop_state(s
, LTTV_STATE_SYSCALL
);
1161 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1163 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1164 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1165 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1166 LttField
*f
= thf
->f1
;
1168 LttvExecutionSubmode submode
;
1170 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1171 ltt_event_get_unsigned(e
, f
)];
1172 push_state(s
, LTTV_STATE_TRAP
, submode
);
1177 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1179 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1181 pop_state(s
, LTTV_STATE_TRAP
);
1186 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1188 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1189 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1190 guint8 fac_id
= ltt_event_facility_id(e
);
1191 guint8 ev_id
= ltt_event_eventtype_id(e
);
1192 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1193 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1194 g_assert(thf
->f1
!= NULL
);
1195 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1196 LttField
*f
= thf
->f1
;
1198 LttvExecutionSubmode submode
;
1200 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1201 ltt_event_get_unsigned(e
, f
)];
1203 /* Do something with the info about being in user or system mode when int? */
1204 push_state(s
, LTTV_STATE_IRQ
, submode
);
1209 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1211 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1213 pop_state(s
, LTTV_STATE_IRQ
);
1217 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1219 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1220 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1221 guint8 fac_id
= ltt_event_facility_id(e
);
1222 guint8 ev_id
= ltt_event_eventtype_id(e
);
1223 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1224 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1225 g_assert(thf
->f1
!= NULL
);
1226 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1227 LttField
*f
= thf
->f1
;
1229 LttvExecutionSubmode submode
;
1231 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1232 ltt_event_get_unsigned(e
, f
)];
1234 /* Do something with the info about being in user or system mode when int? */
1235 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1240 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1242 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1244 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1249 static gboolean
schedchange(void *hook_data
, void *call_data
)
1251 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1252 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1253 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1254 LttvProcessState
*process
= ts
->running_process
[cpu
];
1255 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1257 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1258 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1259 guint pid_in
, pid_out
;
1262 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1263 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1264 state_out
= ltt_event_get_int(e
, thf
->f3
);
1266 if(likely(process
!= NULL
)) {
1268 /* We could not know but it was not the idle process executing.
1269 This should only happen at the beginning, before the first schedule
1270 event, and when the initial information (current process for each CPU)
1271 is missing. It is not obvious how we could, after the fact, compensate
1272 the wrongly attributed statistics. */
1274 //This test only makes sense once the state is known and if there is no
1275 //missing events. We need to silently ignore schedchange coming after a
1276 //process_free, or it causes glitches. (FIXME)
1277 //if(unlikely(process->pid != pid_out)) {
1278 // g_assert(process->pid == 0);
1281 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1282 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1283 process
->state
->change
= s
->parent
.timestamp
;
1285 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1286 else process
->state
->s
= LTTV_STATE_WAIT
;
1287 process
->state
->change
= s
->parent
.timestamp
;
1291 exit_process(s
, process
); /* EXIT_DEAD */
1292 /* see sched.h for states */
1294 process
= ts
->running_process
[cpu
] =
1295 lttv_state_find_process_or_create(
1296 (LttvTraceState
*)s
->parent
.t_context
,
1298 &s
->parent
.timestamp
);
1299 process
->state
->s
= LTTV_STATE_RUN
;
1301 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1302 process
->state
->change
= s
->parent
.timestamp
;
1306 static gboolean
process_fork(void *hook_data
, void *call_data
)
1308 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1309 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1310 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1313 LttvProcessState
*zombie_process
;
1314 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1315 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1316 LttvProcessState
*process
= ts
->running_process
[cpu
];
1317 LttvProcessState
*child_process
;
1320 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1323 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1325 /* Mathieu : it seems like the process might have been scheduled in before the
1326 * fork, and, in a rare case, might be the current process. This might happen
1327 * in a SMP case where we don't have enough precision on the clocks.
1329 * Test reenabled after precision fixes on time. (Mathieu) */
1331 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1333 if(unlikely(zombie_process
!= NULL
)) {
1334 /* Reutilisation of PID. Only now we are sure that the old PID
1335 * has been released. FIXME : should know when release_task happens instead.
1337 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1339 for(i
=0; i
< num_cpus
; i
++) {
1340 g_assert(zombie_process
!= ts
->running_process
[i
]);
1343 exit_process(s
, zombie_process
);
1346 g_assert(process
->pid
!= child_pid
);
1347 // FIXME : Add this test in the "known state" section
1348 // g_assert(process->pid == parent_pid);
1349 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1350 if(child_process
== NULL
) {
1351 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1352 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1354 /* The process has already been created : due to time imprecision between
1355 * multiple CPUs : it has been scheduled in before creation. Note that we
1356 * shouldn't have this kind of imprecision.
1358 * Simply put a correct parent.
1360 g_assert(0); /* This is a problematic case : the process has been created
1361 before the fork event */
1362 child_process
->ppid
= process
->pid
;
1364 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1365 child_process
->name
= process
->name
;
1370 /* We stamp a newly created process as kernel_thread */
1371 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1373 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1374 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1375 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1377 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1378 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1379 LttvProcessState
*process
;
1380 LttvExecutionState
*es
;
1383 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1385 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1386 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1387 es
->t
= LTTV_STATE_SYSCALL
;
1388 process
->kernel_thread
= 1;
1393 static gboolean
process_exit(void *hook_data
, void *call_data
)
1395 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1396 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1397 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1400 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1401 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1402 LttvProcessState
*process
= ts
->running_process
[cpu
];
1404 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1406 // FIXME : Add this test in the "known state" section
1407 // g_assert(process->pid == pid);
1409 if(likely(process
!= NULL
)) {
1410 process
->state
->s
= LTTV_STATE_EXIT
;
1415 static gboolean
process_free(void *hook_data
, void *call_data
)
1417 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1418 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1419 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1420 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1422 LttvProcessState
*process
;
1424 /* PID of the process to release */
1425 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1427 g_assert(release_pid
!= 0);
1429 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1431 if(likely(process
!= NULL
)) {
1432 /* release_task is happening at kernel level : we can now safely release
1433 * the data structure of the process */
1434 //This test is fun, though, as it may happen that
1435 //at time t : CPU 0 : process_free
1436 //at time t+150ns : CPU 1 : schedule out
1437 //Clearly due to time imprecision, we disable it. (Mathieu)
1438 //If this weird case happen, we have no choice but to put the
1439 //Currently running process on the cpu to 0.
1440 //I re-enable it following time precision fixes. (Mathieu)
1441 //Well, in the case where an process is freed by a process on another CPU
1442 //and still scheduled, it happens that this is the schedchange that will
1443 //drop the last reference count. Do not free it here!
1444 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1446 for(i
=0; i
< num_cpus
; i
++) {
1447 //g_assert(process != ts->running_process[i]);
1448 if(process
== ts
->running_process
[i
]) {
1449 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1453 //if(i == num_cpus) /* process is not scheduled */
1454 //exit_process(s, process); // do nothing : wait for the schedchange to
1455 //delete the process.
1462 static gboolean
process_exec(void *hook_data
, void *call_data
)
1464 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1465 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1466 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1467 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1469 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1470 LttvProcessState
*process
= ts
->running_process
[cpu
];
1472 /* PID of the process to release */
1473 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1474 //name = ltt_event_get_string(e, thf->f1);
1475 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1477 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1478 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1479 memcpy(null_term_name
, name_begin
, name_len
);
1480 null_term_name
[name_len
] = '\0';
1482 process
->name
= g_quark_from_string(null_term_name
);
1483 g_free(null_term_name
);
1487 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1489 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1490 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1491 //It's slow : optimise later by doing this before reading trace.
1492 LttEventType
*et
= ltt_event_eventtype(e
);
1494 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1498 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1499 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1500 LttvProcessState
*process
= ts
->running_process
[cpu
];
1501 LttvProcessState
*parent_process
;
1502 LttField
*f4
, *f5
, *f6
;
1503 GQuark mode
, submode
, status
;
1506 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1509 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1512 command
= ltt_event_get_string(e
, thf
->f3
);
1515 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1516 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1517 ltt_event_get_unsigned(e
, f4
));
1520 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1521 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1522 ltt_event_get_unsigned(e
, f5
));
1525 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1526 status
= ltt_enum_string_get(ltt_field_type(f6
),
1527 ltt_event_get_unsigned(e
, f6
));
1529 /* The process might exist if a process was forked while performing the sate dump. */
1530 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1531 if(process
== NULL
) {
1532 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1533 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1534 pid
, g_quark_from_string(command
),
1535 &s
->parent
.timestamp
);
1537 /* Keep the stack bottom : a running user mode */
1539 /* Disabled because of inconsistencies in the current statedump states. */
1540 if(mode
== LTTV_STATE_USER_MODE
) {
1541 /* Only keep the bottom */
1542 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1544 /* On top of it : */
1545 LttvExecutionState
*es
;
1546 es
= process
->state
= &g_array_index(process
->execution_stack
,
1547 LttvExecutionState
, 1);
1556 LttvExecutionState
*es
;
1557 es
= process
->state
= &g_array_index(process
->execution_stack
,
1558 LttvExecutionState
, 1);
1559 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1560 es
->s
= LTTV_STATE_UNNAMED
;
1561 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1564 /* The process has already been created :
1565 * Probably was forked while dumping the process state or
1566 * was simply scheduled in prior to get the state dump event.
1568 process
->ppid
= parent_pid
;
1569 process
->name
= g_quark_from_string(command
);
1570 /* Don't mess around with the stack, it will eventually become
1571 * ok after the end of state dump. */
1577 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1579 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1581 lttv_state_add_event_hooks(tss
);
1586 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1588 LttvTraceset
*traceset
= self
->parent
.ts
;
1590 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1594 LttvTracefileState
*tfs
;
1598 LttvTraceHookByFacility
*thf
;
1600 LttvTraceHook
*hook
;
1602 LttvAttributeValue val
;
1606 nb_trace
= lttv_traceset_number(traceset
);
1607 for(i
= 0 ; i
< nb_trace
; i
++) {
1608 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1610 /* Find the eventtype id for the following events and register the
1611 associated by id hooks. */
1613 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 15);
1614 hooks
= g_array_set_size(hooks
, 15);
1616 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1617 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1618 LTT_FIELD_SYSCALL_ID
, 0, 0,
1619 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1622 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1623 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1625 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1628 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1629 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1630 LTT_FIELD_TRAP_ID
, 0, 0,
1631 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1634 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1635 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1637 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1640 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1641 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1642 LTT_FIELD_IRQ_ID
, 0, 0,
1643 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1646 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1647 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1649 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1652 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1653 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1654 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1655 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1658 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1659 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1661 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1664 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1665 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1666 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1667 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1670 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1671 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1672 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1673 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1676 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1677 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1678 LTT_FIELD_PID
, 0, 0,
1679 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1682 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1683 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1684 LTT_FIELD_PID
, 0, 0,
1685 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1688 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1689 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1690 LTT_FIELD_PID
, 0, 0,
1691 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1694 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1695 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1696 LTT_FIELD_FILENAME
, 0, 0,
1697 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1700 /* statedump-related hooks */
1701 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1702 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1703 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1704 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 14));
1708 /* Add these hooks to each event_by_id hooks list */
1710 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1712 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1714 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1715 LttvTracefileContext
*, j
));
1717 for(k
= 0 ; k
< hooks
->len
; k
++) {
1718 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1719 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1720 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1722 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1729 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1730 *(val
.v_pointer
) = hooks
;
1734 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1736 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1738 lttv_state_remove_event_hooks(tss
);
1743 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1745 LttvTraceset
*traceset
= self
->parent
.ts
;
1747 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1751 LttvTracefileState
*tfs
;
1755 LttvTraceHook
*hook
;
1757 LttvTraceHookByFacility
*thf
;
1759 LttvAttributeValue val
;
1761 nb_trace
= lttv_traceset_number(traceset
);
1762 for(i
= 0 ; i
< nb_trace
; i
++) {
1763 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1764 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1765 hooks
= *(val
.v_pointer
);
1767 /* Remove these hooks from each event_by_id hooks list */
1769 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1771 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1773 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1774 LttvTracefileContext
*, j
));
1776 for(k
= 0 ; k
< hooks
->len
; k
++) {
1777 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1778 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1779 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1781 lttv_hooks_remove_data(
1782 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1788 for(k
= 0 ; k
< hooks
->len
; k
++)
1789 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1790 g_array_free(hooks
, TRUE
);
1794 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1796 guint
*event_count
= (guint
*)hook_data
;
1798 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1799 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1804 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1806 LttvTracefileState
*tfcs
;
1808 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1810 LttEventPosition
*ep
;
1816 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1818 LttvAttributeValue value
;
1820 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1821 LTTV_STATE_SAVED_STATES
);
1822 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1823 value
= lttv_attribute_add(saved_states_tree
,
1824 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1825 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1826 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1827 *(value
.v_time
) = self
->parent
.timestamp
;
1828 lttv_state_save(tcs
, saved_state_tree
);
1829 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1830 self
->parent
.timestamp
.tv_nsec
);
1832 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1837 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1839 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1841 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1847 static gboolean
block_start(void *hook_data
, void *call_data
)
1849 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1851 LttvTracefileState
*tfcs
;
1853 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1855 LttEventPosition
*ep
;
1857 guint i
, nb_block
, nb_event
, nb_tracefile
;
1861 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1863 LttvAttributeValue value
;
1865 ep
= ltt_event_position_new();
1867 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1869 /* Count the number of events added since the last block end in any
1872 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1874 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1875 LttvTracefileContext
, i
));
1876 ltt_event_position(tfcs
->parent
.e
, ep
);
1877 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1878 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1879 tfcs
->saved_position
= nb_event
;
1883 if(tcs
->nb_event
>= tcs
->save_interval
) {
1884 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1885 LTTV_STATE_SAVED_STATES
);
1886 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1887 value
= lttv_attribute_add(saved_states_tree
,
1888 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1889 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1890 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1891 *(value
.v_time
) = self
->parent
.timestamp
;
1892 lttv_state_save(tcs
, saved_state_tree
);
1894 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1895 self
->parent
.timestamp
.tv_nsec
);
1897 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1903 static gboolean
block_end(void *hook_data
, void *call_data
)
1905 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1907 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1911 LttEventPosition
*ep
;
1913 guint nb_block
, nb_event
;
1915 ep
= ltt_event_position_new();
1916 ltt_event_position(self
->parent
.e
, ep
);
1917 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1918 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1919 self
->saved_position
= 0;
1920 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1927 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1929 LttvTraceset
*traceset
= self
->parent
.ts
;
1931 guint i
, j
, nb_trace
, nb_tracefile
;
1935 LttvTracefileState
*tfs
;
1937 LttvTraceHook hook_start
, hook_end
;
1939 nb_trace
= lttv_traceset_number(traceset
);
1940 for(i
= 0 ; i
< nb_trace
; i
++) {
1941 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1943 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1944 NULL
, NULL
, block_start
, &hook_start
);
1945 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1946 NULL
, NULL
, block_end
, &hook_end
);
1948 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1950 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1952 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1953 LttvTracefileContext
, j
));
1954 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1955 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1956 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1957 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1963 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1965 LttvTraceset
*traceset
= self
->parent
.ts
;
1967 guint i
, j
, nb_trace
, nb_tracefile
;
1971 LttvTracefileState
*tfs
;
1974 nb_trace
= lttv_traceset_number(traceset
);
1975 for(i
= 0 ; i
< nb_trace
; i
++) {
1977 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1978 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1980 guint
*event_count
= g_new(guint
, 1);
1983 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1985 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1986 LttvTracefileContext
*, j
));
1987 lttv_hooks_add(tfs
->parent
.event
,
1988 state_save_event_hook
,
1995 lttv_process_traceset_begin(&self
->parent
,
1996 NULL
, NULL
, NULL
, NULL
, NULL
);
2000 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2002 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2004 lttv_state_save_add_event_hooks(tss
);
2011 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2013 LttvTraceset
*traceset
= self
->parent
.ts
;
2015 guint i
, j
, nb_trace
, nb_tracefile
;
2019 LttvTracefileState
*tfs
;
2021 LttvTraceHook hook_start
, hook_end
;
2023 nb_trace
= lttv_traceset_number(traceset
);
2024 for(i
= 0 ; i
< nb_trace
; i
++) {
2025 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2027 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2028 NULL
, NULL
, block_start
, &hook_start
);
2030 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2031 NULL
, NULL
, block_end
, &hook_end
);
2033 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2035 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2037 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2038 LttvTracefileContext
, j
));
2039 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2040 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2041 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2042 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2048 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2050 LttvTraceset
*traceset
= self
->parent
.ts
;
2052 guint i
, j
, nb_trace
, nb_tracefile
;
2056 LttvTracefileState
*tfs
;
2058 LttvHooks
*after_trace
= lttv_hooks_new();
2060 lttv_hooks_add(after_trace
,
2061 state_save_after_trace_hook
,
2066 lttv_process_traceset_end(&self
->parent
,
2067 NULL
, after_trace
, NULL
, NULL
, NULL
);
2069 lttv_hooks_destroy(after_trace
);
2071 nb_trace
= lttv_traceset_number(traceset
);
2072 for(i
= 0 ; i
< nb_trace
; i
++) {
2074 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2075 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2077 guint
*event_count
= NULL
;
2079 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2081 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2082 LttvTracefileContext
*, j
));
2083 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2084 state_save_event_hook
);
2086 if(event_count
) g_free(event_count
);
2090 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2092 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2094 lttv_state_save_remove_event_hooks(tss
);
2099 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2101 LttvTraceset
*traceset
= self
->parent
.ts
;
2105 int min_pos
, mid_pos
, max_pos
;
2107 guint call_rest
= 0;
2109 LttvTraceState
*tcs
;
2111 LttvAttributeValue value
;
2113 LttvAttributeType type
;
2115 LttvAttributeName name
;
2117 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2119 //g_tree_destroy(self->parent.pqueue);
2120 //self->parent.pqueue = g_tree_new(compare_tracefile);
2122 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2124 nb_trace
= lttv_traceset_number(traceset
);
2125 for(i
= 0 ; i
< nb_trace
; i
++) {
2126 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2128 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2129 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2130 LTTV_STATE_SAVED_STATES
);
2133 if(saved_states_tree
) {
2134 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2135 mid_pos
= max_pos
/ 2;
2136 while(min_pos
< max_pos
) {
2137 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2138 g_assert(type
== LTTV_GOBJECT
);
2139 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2140 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2142 g_assert(type
== LTTV_TIME
);
2143 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2145 closest_tree
= saved_state_tree
;
2147 else max_pos
= mid_pos
- 1;
2149 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2153 /* restore the closest earlier saved state */
2155 lttv_state_restore(tcs
, closest_tree
);
2159 /* There is no saved state, yet we want to have it. Restart at T0 */
2161 restore_init_state(tcs
);
2162 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2165 /* We want to seek quickly without restoring/updating the state */
2167 restore_init_state(tcs
);
2168 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2171 if(!call_rest
) g_info("NOT Calling restore");
2176 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2182 traceset_state_finalize (LttvTracesetState
*self
)
2184 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2185 finalize(G_OBJECT(self
));
2190 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2192 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2194 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2195 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2196 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2197 klass
->new_traceset_context
= new_traceset_context
;
2198 klass
->new_trace_context
= new_trace_context
;
2199 klass
->new_tracefile_context
= new_tracefile_context
;
2204 lttv_traceset_state_get_type(void)
2206 static GType type
= 0;
2208 static const GTypeInfo info
= {
2209 sizeof (LttvTracesetStateClass
),
2210 NULL
, /* base_init */
2211 NULL
, /* base_finalize */
2212 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2213 NULL
, /* class_finalize */
2214 NULL
, /* class_data */
2215 sizeof (LttvTracesetState
),
2216 0, /* n_preallocs */
2217 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2218 NULL
/* value handling */
2221 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2229 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2235 trace_state_finalize (LttvTraceState
*self
)
2237 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2238 finalize(G_OBJECT(self
));
2243 trace_state_class_init (LttvTraceStateClass
*klass
)
2245 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2247 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2248 klass
->state_save
= state_save
;
2249 klass
->state_restore
= state_restore
;
2250 klass
->state_saved_free
= state_saved_free
;
2255 lttv_trace_state_get_type(void)
2257 static GType type
= 0;
2259 static const GTypeInfo info
= {
2260 sizeof (LttvTraceStateClass
),
2261 NULL
, /* base_init */
2262 NULL
, /* base_finalize */
2263 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2264 NULL
, /* class_finalize */
2265 NULL
, /* class_data */
2266 sizeof (LttvTraceState
),
2267 0, /* n_preallocs */
2268 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2269 NULL
/* value handling */
2272 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2273 "LttvTraceStateType", &info
, 0);
2280 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2286 tracefile_state_finalize (LttvTracefileState
*self
)
2288 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2289 finalize(G_OBJECT(self
));
2294 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2296 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2298 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2303 lttv_tracefile_state_get_type(void)
2305 static GType type
= 0;
2307 static const GTypeInfo info
= {
2308 sizeof (LttvTracefileStateClass
),
2309 NULL
, /* base_init */
2310 NULL
, /* base_finalize */
2311 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2312 NULL
, /* class_finalize */
2313 NULL
, /* class_data */
2314 sizeof (LttvTracefileState
),
2315 0, /* n_preallocs */
2316 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2317 NULL
/* value handling */
2320 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2321 "LttvTracefileStateType", &info
, 0);
2327 static void module_init()
2329 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2330 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2331 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2332 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2333 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2334 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2335 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2336 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2337 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2338 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2339 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2340 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2341 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2342 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2343 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2344 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2345 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2346 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2347 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2348 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2349 LTTV_STATE_EVENT
= g_quark_from_string("event");
2350 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2351 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2352 LTTV_STATE_TIME
= g_quark_from_string("time");
2353 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2354 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2355 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2356 g_quark_from_string("trace_state_use_count");
2359 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2360 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2361 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2362 LTT_FACILITY_FS
= g_quark_from_string("fs");
2363 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2366 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2367 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2368 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2369 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2370 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2371 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2372 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2373 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2374 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2375 LTT_EVENT_FORK
= g_quark_from_string("fork");
2376 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2377 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2378 LTT_EVENT_FREE
= g_quark_from_string("free");
2379 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2380 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2383 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2384 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2385 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2386 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2387 LTT_FIELD_OUT
= g_quark_from_string("out");
2388 LTT_FIELD_IN
= g_quark_from_string("in");
2389 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2390 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2391 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2392 LTT_FIELD_PID
= g_quark_from_string("pid");
2393 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2394 LTT_FIELD_NAME
= g_quark_from_string("name");
2395 LTT_FIELD_MODE
= g_quark_from_string("mode");
2396 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2397 LTT_FIELD_STATUS
= g_quark_from_string("status");
2401 static void module_destroy()
2406 LTTV_MODULE("state", "State computation", \
2407 "Update the system state, possibly saving it at intervals", \
2408 module_init
, module_destroy
)