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,
20 #include <lttv/state.h>
21 #include <ltt/facility.h>
22 #include <ltt/trace.h>
23 #include <ltt/event.h>
27 LTTV_STATE_MODE_UNKNOWN
,
34 LTTV_STATE_SUBMODE_UNKNOWN
,
35 LTTV_STATE_SUBMODE_NONE
;
46 LTTV_STATE_TRACEFILES
,
50 LTTV_STATE_SAVED_STATES
,
51 LTTV_STATE_SAVED_STATES_TIME
,
56 static void fill_name_tables(LttvTraceState
*tcs
);
58 static void free_name_tables(LttvTraceState
*tcs
);
60 static void lttv_state_free_process_table(GHashTable
*processes
);
63 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
65 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
69 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
71 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
75 void lttv_state_saved_state_free(LttvTraceState
*self
,
76 LttvAttribute
*container
)
78 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
82 guint
process_hash(gconstpointer key
)
84 return ((LttvProcessState
*)key
)->pid
;
88 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
90 LttvProcessState
*process_a
, *process_b
;
92 process_a
= (LttvProcessState
*)a
;
93 process_b
= (LttvProcessState
*)b
;
95 if(process_a
->pid
!= process_b
->pid
) return FALSE
;
96 if(process_a
->pid
== 0 &&
97 process_a
->last_cpu
!= process_b
->last_cpu
) return FALSE
;
103 restore_init_state(LttvTraceState
*self
)
105 guint i
, nb_tracefile
;
107 LttvTracefileState
*tfcs
;
109 LttTime null_time
= {0,0};
111 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
112 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
115 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
116 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
118 for(i
= 0 ; i
< nb_tracefile
; i
++) {
119 tfcs
= LTTV_TRACEFILE_STATE(self
->parent
.tracefiles
[i
]);
120 tfcs
->parent
.timestamp
= null_time
;
121 tfcs
->saved_position
= 0;
122 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
123 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
124 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
128 static LttTime time_zero
= {0,0};
131 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
133 guint i
, j
, nb_trace
, nb_tracefile
;
135 LttvTraceContext
*tc
;
139 LttvTracefileState
*tfcs
;
141 LttvAttributeValue v
;
143 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
144 init((LttvTracesetContext
*)self
, ts
);
146 nb_trace
= lttv_traceset_number(ts
);
147 for(i
= 0 ; i
< nb_trace
; i
++) {
148 tc
= self
->parent
.traces
[i
];
149 tcs
= (LttvTraceState
*)tc
;
150 tcs
->save_interval
= 50000;
151 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
153 if(*(v
.v_pointer
) == NULL
) *(v
.v_pointer
) = g_new(LttTime
,1);
154 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
156 fill_name_tables(tcs
);
158 nb_tracefile
= ltt_trace_control_tracefile_number(tc
->t
) +
159 ltt_trace_per_cpu_tracefile_number(tc
->t
);
161 for(j
= 0 ; j
< nb_tracefile
; j
++) {
162 tfcs
= LTTV_TRACEFILE_STATE(tc
->tracefiles
[j
]);
163 tfcs
->cpu_name
= g_quark_from_string(ltt_tracefile_name(tfcs
->parent
.tf
));
165 tcs
->processes
= NULL
;
166 restore_init_state(tcs
);
172 fini(LttvTracesetState
*self
)
174 guint i
, j
, nb_trace
;
178 LttvTracefileState
*tfcs
;
180 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
181 for(i
= 0 ; i
< nb_trace
; i
++) {
182 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
183 lttv_state_free_process_table(tcs
->processes
);
184 tcs
->processes
= NULL
;
185 free_name_tables(tcs
);
187 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
188 fini((LttvTracesetContext
*)self
);
192 static LttvTracesetContext
*
193 new_traceset_context(LttvTracesetContext
*self
)
195 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
199 static LttvTraceContext
*
200 new_trace_context(LttvTracesetContext
*self
)
202 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
206 static LttvTracefileContext
*
207 new_tracefile_context(LttvTracesetContext
*self
)
209 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
213 /* Write the process state of the trace */
215 static void write_process_state(gpointer key
, gpointer value
,
218 LttvProcessState
*process
;
220 LttvExecutionState
*es
;
222 FILE *fp
= (FILE *)user_data
;
226 process
= (LttvProcessState
*)value
;
228 " <PROCESS PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
229 process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
230 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
231 g_quark_to_string(process
->last_cpu
));
233 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
234 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
235 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
236 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
237 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
238 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
239 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
241 fprintf(fp
, " </PROCESS>\n");
245 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
247 guint i
, nb_tracefile
, nb_block
, nb_event
;
249 LttvTracefileState
*tfcs
;
253 LttEventPosition
*ep
;
255 ep
= ltt_event_position_new();
257 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
259 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
261 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
262 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
264 for(i
= 0 ; i
< nb_tracefile
; i
++) {
265 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
266 fprintf(fp
, " <TRACEFILE PID=%u", tfcs
->process
->pid
);
267 if(tfcs
->parent
.e
== NULL
) fprintf(fp
,"/>\n");
269 ltt_event_position(tfcs
->parent
.e
, ep
);
270 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
271 fprintf(fp
, " BLOCK=%u EVENT=%u/>\n", nb_block
, nb_event
);
275 fprintf(fp
,"</PROCESS_STATE>");
279 /* Copy each process from an existing hash table to a new one */
281 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
283 LttvProcessState
*process
, *new_process
;
285 GHashTable
*new_processes
= (GHashTable
*)user_data
;
289 process
= (LttvProcessState
*)value
;
290 new_process
= g_new(LttvProcessState
, 1);
291 *new_process
= *process
;
292 new_process
->execution_stack
= g_array_new(FALSE
, FALSE
,
293 sizeof(LttvExecutionState
));
294 g_array_set_size(new_process
->execution_stack
,process
->execution_stack
->len
);
295 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
296 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
297 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
299 new_process
->state
= &g_array_index(new_process
->execution_stack
,
300 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
301 g_hash_table_insert(new_processes
, new_process
, new_process
);
305 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
307 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
309 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
310 return new_processes
;
314 /* The saved state for each trace contains a member "processes", which
315 stores a copy of the process table, and a member "tracefiles" with
316 one entry per tracefile. Each tracefile has a "process" member pointing
317 to the current process and a "position" member storing the tracefile
318 position (needed to seek to the current "next" event. */
320 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
322 guint i
, nb_tracefile
;
324 LttvTracefileState
*tfcs
;
326 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
328 LttvAttributeType type
;
330 LttvAttributeValue value
;
332 LttvAttributeName name
;
334 LttEventPosition
*ep
;
336 tracefiles_tree
= lttv_attribute_find_subdir(container
,
337 LTTV_STATE_TRACEFILES
);
339 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
341 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
343 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
344 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
346 for(i
= 0 ; i
< nb_tracefile
; i
++) {
347 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
348 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
349 value
= lttv_attribute_add(tracefiles_tree
, i
,
351 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
352 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
354 *(value
.v_uint
) = tfcs
->process
->pid
;
355 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
357 if(tfcs
->parent
.e
== NULL
) *(value
.v_pointer
) = NULL
;
359 ep
= ltt_event_position_new();
360 ltt_event_position(tfcs
->parent
.e
, ep
);
361 *(value
.v_pointer
) = ep
;
367 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
369 guint i
, nb_tracefile
, pid
;
371 LttvTracefileState
*tfcs
;
373 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
375 LttvAttributeType type
;
377 LttvAttributeValue value
;
379 LttvAttributeName name
;
381 LttEventPosition
*ep
;
383 tracefiles_tree
= lttv_attribute_find_subdir(container
,
384 LTTV_STATE_TRACEFILES
);
386 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
388 g_assert(type
== LTTV_POINTER
);
389 lttv_state_free_process_table(self
->processes
);
390 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
392 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
393 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
395 for(i
= 0 ; i
< nb_tracefile
; i
++) {
396 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
397 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
398 g_assert(type
== LTTV_GOBJECT
);
399 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
401 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
403 g_assert(type
== LTTV_UINT
);
404 pid
= *(value
.v_uint
);
405 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
407 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
409 g_assert(type
== LTTV_POINTER
);
410 if(*(value
.v_pointer
) == NULL
) tfcs
->parent
.e
= NULL
;
412 ep
= *(value
.v_pointer
);
413 ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
414 tfcs
->parent
.e
= ltt_tracefile_read(tfcs
->parent
.tf
);
415 tfcs
->parent
.timestamp
= ltt_event_time(tfcs
->parent
.e
);
421 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
423 guint i
, nb_tracefile
;
425 LttvTracefileState
*tfcs
;
427 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
429 LttvAttributeType type
;
431 LttvAttributeValue value
;
433 LttvAttributeName name
;
435 LttEventPosition
*ep
;
437 tracefiles_tree
= lttv_attribute_find_subdir(container
,
438 LTTV_STATE_TRACEFILES
);
439 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
441 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
443 g_assert(type
== LTTV_POINTER
);
444 lttv_state_free_process_table(*(value
.v_pointer
));
445 *(value
.v_pointer
) = NULL
;
446 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
448 nb_tracefile
= ltt_trace_control_tracefile_number(self
->parent
.t
) +
449 ltt_trace_per_cpu_tracefile_number(self
->parent
.t
);
451 for(i
= 0 ; i
< nb_tracefile
; i
++) {
452 tfcs
= (LttvTracefileState
*)self
->parent
.tracefiles
[i
];
453 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
454 g_assert(type
== LTTV_GOBJECT
);
455 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
457 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
459 g_assert(type
== LTTV_POINTER
);
460 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
462 lttv_attribute_recursive_free(tracefiles_tree
);
467 fill_name_tables(LttvTraceState
*tcs
)
471 char *f_name
, *e_name
;
479 GString
*fe_name
= g_string_new("");
481 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
482 tcs
->eventtype_names
= g_new(GQuark
, nb
);
483 for(i
= 0 ; i
< nb
; i
++) {
484 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
485 e_name
= ltt_eventtype_name(et
);
486 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
487 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
488 tcs
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
491 lttv_trace_find_hook(tcs
->parent
.t
, "core", "syscall_entry",
492 "syscall_id", NULL
, NULL
, NULL
, &h
);
493 t
= ltt_field_type(h
.f1
);
494 nb
= ltt_type_element_number(t
);
496 /* CHECK syscalls should be an emun but currently are not!
497 tcs->syscall_names = g_new(GQuark, nb);
499 for(i = 0 ; i < nb ; i++) {
500 tcs->syscall_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
504 tcs
->syscall_names
= g_new(GQuark
, 256);
505 for(i
= 0 ; i
< 256 ; i
++) {
506 g_string_printf(fe_name
, "syscall %d", i
);
507 tcs
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
510 lttv_trace_find_hook(tcs
->parent
.t
, "core", "trap_entry",
511 "trap_id", NULL
, NULL
, NULL
, &h
);
512 t
= ltt_field_type(h
.f1
);
513 nb
= ltt_type_element_number(t
);
516 tcs->trap_names = g_new(GQuark, nb);
517 for(i = 0 ; i < nb ; i++) {
518 tcs->trap_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
522 tcs
->trap_names
= g_new(GQuark
, 256);
523 for(i
= 0 ; i
< 256 ; i
++) {
524 g_string_printf(fe_name
, "trap %d", i
);
525 tcs
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
528 lttv_trace_find_hook(tcs
->parent
.t
, "core", "irq_entry",
529 "irq_id", NULL
, NULL
, NULL
, &h
);
530 t
= ltt_field_type(h
.f1
);
531 nb
= ltt_type_element_number(t
);
534 tcs->irq_names = g_new(GQuark, nb);
535 for(i = 0 ; i < nb ; i++) {
536 tcs->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
540 tcs
->irq_names
= g_new(GQuark
, 256);
541 for(i
= 0 ; i
< 256 ; i
++) {
542 g_string_printf(fe_name
, "irq %d", i
);
543 tcs
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
546 g_string_free(fe_name
, TRUE
);
551 free_name_tables(LttvTraceState
*tcs
)
553 g_free(tcs
->eventtype_names
);
554 g_free(tcs
->syscall_names
);
555 g_free(tcs
->trap_names
);
556 g_free(tcs
->irq_names
);
560 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
563 LttvExecutionState
*es
;
565 LttvProcessState
*process
= tfs
->process
;
567 guint depth
= process
->execution_stack
->len
;
569 g_array_set_size(process
->execution_stack
, depth
+ 1);
570 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
573 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
574 es
->s
= process
->state
->s
;
579 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
581 LttvProcessState
*process
= tfs
->process
;
583 guint depth
= process
->execution_stack
->len
- 1;
585 if(process
->state
->t
!= t
){
586 g_warning("Different execution mode type (%d.%09d): ignore it\n",
587 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
588 g_warning("process state has %s when pop_int is %s\n",
589 g_quark_to_string(process
->state
->t
),
590 g_quark_to_string(t
));
591 g_warning("{ %u, %u, %s, %s }\n",
594 g_quark_to_string(process
->name
),
595 g_quark_to_string(process
->state
->s
));
600 g_warning("Trying to pop last state on stack (%d.%09d): ignore it\n",
601 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
605 g_array_remove_index(process
->execution_stack
, depth
);
607 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
609 process
->state
->change
= tfs
->parent
.timestamp
;
614 lttv_state_create_process(LttvTracefileState
*tfs
, LttvProcessState
*parent
,
617 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
619 LttvExecutionState
*es
;
621 LttvTraceContext
*tc
;
627 tcs
= (LttvTraceState
*)tc
= tfs
->parent
.t_context
;
630 process
->last_cpu
= tfs
->cpu_name
;
631 g_hash_table_insert(tcs
->processes
, process
, process
);
634 process
->ppid
= parent
->pid
;
635 process
->name
= parent
->name
;
636 process
->creation_time
= tfs
->parent
.timestamp
;
639 /* No parent. This process exists but we are missing all information about
640 its creation. The birth time is set to zero but we remember the time of
645 process
->name
= LTTV_STATE_UNNAMED
;
646 process
->creation_time
= ltt_time_zero
;
649 process
->insertion_time
= tfs
->parent
.timestamp
;
650 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
651 process
->creation_time
.tv_nsec
);
652 process
->pid_time
= g_quark_from_string(buffer
);
653 process
->last_cpu
= tfs
->cpu_name
;
654 process
->execution_stack
= g_array_new(FALSE
, FALSE
,
655 sizeof(LttvExecutionState
));
656 g_array_set_size(process
->execution_stack
, 1);
657 es
= process
->state
= &g_array_index(process
->execution_stack
,
658 LttvExecutionState
, 0);
659 es
->t
= LTTV_STATE_USER_MODE
;
660 es
->n
= LTTV_STATE_SUBMODE_NONE
;
661 es
->entry
= tfs
->parent
.timestamp
;
662 es
->change
= tfs
->parent
.timestamp
;
663 es
->s
= LTTV_STATE_WAIT_FORK
;
670 lttv_state_find_process_from_trace(LttvTraceState
*ts
, GQuark cpu
, guint pid
)
672 LttvProcessState key
;
673 LttvProcessState
*process
;
677 process
= g_hash_table_lookup(ts
->processes
, &key
);
682 LttvProcessState
*lttv_state_find_process(LttvTracefileState
*tfs
,
685 LttvTraceState
*ts
=(LttvTraceState
*)tfs
->parent
.t_context
;
686 return lttv_state_find_process_from_trace(ts
, tfs
->cpu_name
, pid
);
691 lttv_state_find_process_or_create(LttvTracefileState
*tfs
, guint pid
)
693 LttvProcessState
*process
= lttv_state_find_process(tfs
, pid
);
695 if(process
== NULL
) process
= lttv_state_create_process(tfs
, NULL
, pid
);
700 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
702 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
703 LttvProcessState key
;
705 key
.pid
= process
->pid
;
706 key
.last_cpu
= process
->last_cpu
;
707 g_hash_table_remove(ts
->processes
, &key
);
708 g_array_free(process
->execution_stack
, TRUE
);
713 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
715 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
720 static void lttv_state_free_process_table(GHashTable
*processes
)
722 g_hash_table_foreach(processes
, free_process_state
, NULL
);
723 g_hash_table_destroy(processes
);
727 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
729 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
731 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
733 LttvExecutionSubmode submode
;
735 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
736 ltt_event_get_unsigned(s
->parent
.e
, f
)];
737 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
742 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
744 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
746 pop_state(s
, LTTV_STATE_SYSCALL
);
751 static gboolean
trap_entry(void *hook_data
, void *call_data
)
753 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
755 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
757 LttvExecutionSubmode submode
;
759 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
760 ltt_event_get_unsigned(s
->parent
.e
, f
)];
761 push_state(s
, LTTV_STATE_TRAP
, submode
);
766 static gboolean
trap_exit(void *hook_data
, void *call_data
)
768 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
770 pop_state(s
, LTTV_STATE_TRAP
);
775 static gboolean
irq_entry(void *hook_data
, void *call_data
)
777 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
779 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
781 LttvExecutionSubmode submode
;
783 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
784 ltt_event_get_unsigned(s
->parent
.e
, f
)];
786 /* Do something with the info about being in user or system mode when int? */
787 push_state(s
, LTTV_STATE_IRQ
, submode
);
792 static gboolean
irq_exit(void *hook_data
, void *call_data
)
794 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
796 pop_state(s
, LTTV_STATE_IRQ
);
801 static gboolean
schedchange(void *hook_data
, void *call_data
)
803 LttvTraceHook
*h
= (LttvTraceHook
*)hook_data
;
805 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
807 guint pid_in
, pid_out
, state_out
;
809 pid_in
= ltt_event_get_unsigned(s
->parent
.e
, h
->f1
);
810 pid_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f2
);
811 state_out
= ltt_event_get_unsigned(s
->parent
.e
, h
->f3
);
813 if(s
->process
!= NULL
) {
815 if(state_out
== 0) s
->process
->state
->s
= LTTV_STATE_WAIT_CPU
;
816 else if(s
->process
->state
->s
== LTTV_STATE_EXIT
)
817 exit_process(s
, s
->process
);
818 else s
->process
->state
->s
= LTTV_STATE_WAIT
;
820 if(s
->process
->pid
== 0)
821 s
->process
->pid
= pid_out
;
823 s
->process
->state
->change
= s
->parent
.timestamp
;
825 s
->process
= lttv_state_find_process_or_create(s
, pid_in
);
826 s
->process
->state
->s
= LTTV_STATE_RUN
;
827 s
->process
->last_cpu
= s
->cpu_name
;
828 s
->process
->state
->change
= s
->parent
.timestamp
;
833 static gboolean
process_fork(void *hook_data
, void *call_data
)
835 LttField
*f
= ((LttvTraceHook
*)hook_data
)->f1
;
837 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
841 child_pid
= ltt_event_get_unsigned(s
->parent
.e
, f
);
842 lttv_state_create_process(s
, s
->process
, child_pid
);
847 static gboolean
process_exit(void *hook_data
, void *call_data
)
849 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
851 if(s
->process
!= NULL
) {
852 s
->process
->state
->s
= LTTV_STATE_EXIT
;
858 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
860 LttvTraceset
*traceset
= self
->parent
.ts
;
862 guint i
, j
, k
, nb_trace
, nb_tracefile
;
866 LttvTracefileState
*tfs
;
872 LttvAttributeValue val
;
874 nb_trace
= lttv_traceset_number(traceset
);
875 for(i
= 0 ; i
< nb_trace
; i
++) {
876 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
878 /* Find the eventtype id for the following events and register the
879 associated by id hooks. */
881 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
882 g_array_set_size(hooks
, 9);
884 lttv_trace_find_hook(ts
->parent
.t
, "core","syscall_entry","syscall_id",
885 NULL
, NULL
, syscall_entry
, &g_array_index(hooks
, LttvTraceHook
, 0));
887 lttv_trace_find_hook(ts
->parent
.t
, "core", "syscall_exit", NULL
, NULL
,
888 NULL
, syscall_exit
, &g_array_index(hooks
, LttvTraceHook
, 1));
890 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_entry", "trap_id",
891 NULL
, NULL
, trap_entry
, &g_array_index(hooks
, LttvTraceHook
, 2));
893 lttv_trace_find_hook(ts
->parent
.t
, "core", "trap_exit", NULL
, NULL
, NULL
,
894 trap_exit
, &g_array_index(hooks
, LttvTraceHook
, 3));
896 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_entry", "irq_id", NULL
,
897 NULL
, irq_entry
, &g_array_index(hooks
, LttvTraceHook
, 4));
899 lttv_trace_find_hook(ts
->parent
.t
, "core", "irq_exit", NULL
, NULL
, NULL
,
900 irq_exit
, &g_array_index(hooks
, LttvTraceHook
, 5));
902 lttv_trace_find_hook(ts
->parent
.t
, "core", "schedchange", "in", "out",
903 "out_state", schedchange
, &g_array_index(hooks
, LttvTraceHook
, 6));
905 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_fork", "child_pid",
906 NULL
, NULL
, process_fork
, &g_array_index(hooks
, LttvTraceHook
, 7));
908 lttv_trace_find_hook(ts
->parent
.t
, "core", "process_exit", NULL
, NULL
,
909 NULL
, process_exit
, &g_array_index(hooks
, LttvTraceHook
, 8));
911 /* Add these hooks to each before_event_by_id hooks list */
913 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
914 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
916 for(j
= 0 ; j
< nb_tracefile
; j
++) {
917 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
919 for(k
= 0 ; k
< hooks
->len
; k
++) {
920 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
921 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
922 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
925 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
926 *(val
.v_pointer
) = hooks
;
931 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
933 LttvTraceset
*traceset
= self
->parent
.ts
;
935 guint i
, j
, k
, nb_trace
, nb_tracefile
;
939 LttvTracefileState
*tfs
;
945 LttvAttributeValue val
;
947 nb_trace
= lttv_traceset_number(traceset
);
948 for(i
= 0 ; i
< nb_trace
; i
++) {
949 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
950 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
951 hooks
= *(val
.v_pointer
);
953 /* Add these hooks to each before_event_by_id hooks list */
955 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
956 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
958 for(j
= 0 ; j
< nb_tracefile
; j
++) {
959 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
961 for(k
= 0 ; k
< hooks
->len
; k
++) {
962 hook
= g_array_index(hooks
, LttvTraceHook
, k
);
963 lttv_hooks_remove_data(
964 lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
965 hook
.id
), hook
.h
, &g_array_index(hooks
, LttvTraceHook
, k
));
968 g_array_free(hooks
, TRUE
);
973 static gboolean
block_end(void *hook_data
, void *call_data
)
975 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
977 LttvTracefileState
*tfcs
;
979 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
981 LttEventPosition
*ep
;
983 guint i
, nb_block
, nb_event
, nb_tracefile
;
987 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
989 LttvAttributeValue value
;
991 ep
= ltt_event_position_new();
992 nb_tracefile
= ltt_trace_control_tracefile_number(tcs
->parent
.t
) +
993 ltt_trace_per_cpu_tracefile_number(tcs
->parent
.t
);
995 /* Count the number of events added since the last block end in any
998 for(i
= 0 ; i
< nb_tracefile
; i
++) {
999 tfcs
= (LttvTracefileState
*)tcs
->parent
.tracefiles
[i
];
1000 ltt_event_position(tfcs
->parent
.e
, ep
);
1001 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1002 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1003 tfcs
->saved_position
= nb_event
;
1007 if(tcs
->nb_event
>= tcs
->save_interval
) {
1008 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1009 LTTV_STATE_SAVED_STATES
);
1010 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1011 value
= lttv_attribute_add(saved_states_tree
,
1012 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1013 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1014 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1015 *(value
.v_time
) = self
->parent
.timestamp
;
1016 lttv_state_save(tcs
, saved_state_tree
);
1019 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1024 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1026 LttvTraceset
*traceset
= self
->parent
.ts
;
1028 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1032 LttvTracefileState
*tfs
;
1036 nb_trace
= lttv_traceset_number(traceset
);
1037 for(i
= 0 ; i
< nb_trace
; i
++) {
1038 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1039 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1040 NULL
, NULL
, block_end
, &hook
);
1042 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1043 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1045 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1046 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1047 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.after_event_by_id
,
1048 hook
.id
), hook
.h
, NULL
);
1054 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1056 LttvTraceset
*traceset
= self
->parent
.ts
;
1058 guint i
, j
, k
, nb_trace
, nb_tracefile
;
1062 LttvTracefileState
*tfs
;
1066 nb_trace
= lttv_traceset_number(traceset
);
1067 for(i
= 0 ; i
< nb_trace
; i
++) {
1068 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1069 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1070 NULL
, NULL
, block_end
, &hook
);
1072 nb_tracefile
= ltt_trace_control_tracefile_number(ts
->parent
.t
) +
1073 ltt_trace_per_cpu_tracefile_number(ts
->parent
.t
);
1075 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1076 tfs
= LTTV_TRACEFILE_STATE(ts
->parent
.tracefiles
[j
]);
1077 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1078 tfs
->parent
.after_event_by_id
, hook
.id
), hook
.h
, NULL
);
1084 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1086 LttvTraceset
*traceset
= self
->parent
.ts
;
1088 guint i
, j
, nb_trace
, nb_saved_state
;
1090 int min_pos
, mid_pos
, max_pos
;
1092 LttvTraceState
*tcs
;
1094 LttvAttributeValue value
;
1096 LttvAttributeType type
;
1098 LttvAttributeName name
;
1100 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1102 nb_trace
= lttv_traceset_number(traceset
);
1103 for(i
= 0 ; i
< nb_trace
; i
++) {
1104 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1106 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1107 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1108 LTTV_STATE_SAVED_STATES
);
1111 if(saved_states_tree
) {
1112 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1113 mid_pos
= max_pos
/ 2;
1114 while(min_pos
< max_pos
) {
1115 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1116 g_assert(type
== LTTV_GOBJECT
);
1117 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1118 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1120 g_assert(type
== LTTV_TIME
);
1121 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1123 closest_tree
= saved_state_tree
;
1125 else max_pos
= mid_pos
- 1;
1127 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1131 /* restore the closest earlier saved state */
1132 if(min_pos
!= -1) lttv_state_restore(tcs
, closest_tree
);
1134 /* There is no saved state, yet we want to have it. Restart at T0 */
1136 restore_init_state(tcs
);
1137 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1140 /* We want to seek quickly without restoring/updating the state */
1142 restore_init_state(tcs
);
1143 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1150 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1156 traceset_state_finalize (LttvTracesetState
*self
)
1158 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1159 finalize(G_OBJECT(self
));
1164 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1166 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1168 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1169 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1170 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1171 klass
->new_traceset_context
= new_traceset_context
;
1172 klass
->new_trace_context
= new_trace_context
;
1173 klass
->new_tracefile_context
= new_tracefile_context
;
1178 lttv_traceset_state_get_type(void)
1180 static GType type
= 0;
1182 static const GTypeInfo info
= {
1183 sizeof (LttvTracesetStateClass
),
1184 NULL
, /* base_init */
1185 NULL
, /* base_finalize */
1186 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
1187 NULL
, /* class_finalize */
1188 NULL
, /* class_data */
1189 sizeof (LttvTracesetState
),
1190 0, /* n_preallocs */
1191 (GInstanceInitFunc
) traceset_state_instance_init
/* instance_init */
1194 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
1202 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1208 trace_state_finalize (LttvTraceState
*self
)
1210 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
1211 finalize(G_OBJECT(self
));
1216 trace_state_class_init (LttvTraceStateClass
*klass
)
1218 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1220 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
1221 klass
->state_save
= state_save
;
1222 klass
->state_restore
= state_restore
;
1223 klass
->state_saved_free
= state_saved_free
;
1228 lttv_trace_state_get_type(void)
1230 static GType type
= 0;
1232 static const GTypeInfo info
= {
1233 sizeof (LttvTraceStateClass
),
1234 NULL
, /* base_init */
1235 NULL
, /* base_finalize */
1236 (GClassInitFunc
) trace_state_class_init
, /* class_init */
1237 NULL
, /* class_finalize */
1238 NULL
, /* class_data */
1239 sizeof (LttvTraceState
),
1240 0, /* n_preallocs */
1241 (GInstanceInitFunc
) trace_state_instance_init
/* instance_init */
1244 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
1245 "LttvTraceStateType", &info
, 0);
1252 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1258 tracefile_state_finalize (LttvTracefileState
*self
)
1260 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
1261 finalize(G_OBJECT(self
));
1266 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
1268 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1270 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
1275 lttv_tracefile_state_get_type(void)
1277 static GType type
= 0;
1279 static const GTypeInfo info
= {
1280 sizeof (LttvTracefileStateClass
),
1281 NULL
, /* base_init */
1282 NULL
, /* base_finalize */
1283 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
1284 NULL
, /* class_finalize */
1285 NULL
, /* class_data */
1286 sizeof (LttvTracefileState
),
1287 0, /* n_preallocs */
1288 (GInstanceInitFunc
) tracefile_state_instance_init
/* instance_init */
1291 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
1292 "LttvTracefileStateType", &info
, 0);
1298 void lttv_state_init(int argc
, char **argv
)
1300 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
1301 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
1302 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
1303 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
1304 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
1305 LTTV_STATE_TRAP
= g_quark_from_string("trap");
1306 LTTV_STATE_IRQ
= g_quark_from_string("irq");
1307 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
1308 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
1309 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
1310 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
1311 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
1312 LTTV_STATE_RUN
= g_quark_from_string("running");
1313 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
1314 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
1315 LTTV_STATE_PROCESS
= g_quark_from_string("process");
1316 LTTV_STATE_EVENT
= g_quark_from_string("event");
1317 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
1318 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
1319 LTTV_STATE_TIME
= g_quark_from_string("time");
1320 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
1323 void lttv_state_destroy()