1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
32 #define PREALLOCATED_EXECUTION_STACK 10
34 /* Facilities Quarks */
38 LTT_FACILITY_ASM_I386_KERNEL
,
45 LTT_EVENT_SYSCALL_ENTRY
,
46 LTT_EVENT_SYSCALL_EXIT
,
51 LTT_EVENT_SCHEDCHANGE
,
72 LTTV_STATE_MODE_UNKNOWN
,
79 LTTV_STATE_SUBMODE_UNKNOWN
,
80 LTTV_STATE_SUBMODE_NONE
;
93 LTTV_STATE_TRACEFILES
,
96 LTTV_STATE_RUNNING_PROCESS
,
98 LTTV_STATE_SAVED_STATES
,
99 LTTV_STATE_SAVED_STATES_TIME
,
102 LTTV_STATE_NAME_TABLES
,
103 LTTV_STATE_TRACE_STATE_USE_COUNT
;
105 static void create_max_time(LttvTraceState
*tcs
);
107 static void get_max_time(LttvTraceState
*tcs
);
109 static void free_max_time(LttvTraceState
*tcs
);
111 static void create_name_tables(LttvTraceState
*tcs
);
113 static void get_name_tables(LttvTraceState
*tcs
);
115 static void free_name_tables(LttvTraceState
*tcs
);
117 static void free_saved_state(LttvTraceState
*tcs
);
119 static void lttv_state_free_process_table(GHashTable
*processes
);
122 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
124 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
128 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
130 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
134 void lttv_state_state_saved_free(LttvTraceState
*self
,
135 LttvAttribute
*container
)
137 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
141 guint
process_hash(gconstpointer key
)
143 guint pid
= ((const LttvProcessState
*)key
)->pid
;
144 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
148 /* If the hash table hash function is well distributed,
149 * the process_equal should compare different pid */
150 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
152 const LttvProcessState
*process_a
, *process_b
;
155 process_a
= (const LttvProcessState
*)a
;
156 process_b
= (const LttvProcessState
*)b
;
158 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
159 else if(likely(process_a
->pid
== 0 &&
160 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
167 restore_init_state(LttvTraceState
*self
)
171 LttvTracefileState
*tfcs
;
173 /* Free the process tables */
174 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
175 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
178 /* Seek time to beginning */
179 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
180 // closest. It's the tracecontext job to seek the trace to the beginning
181 // anyway : the init state might be used at the middle of the trace as well...
182 //g_tree_destroy(self->parent.ts_context->pqueue);
183 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
186 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
188 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
190 /* Put the per cpu running_process to beginning state : process 0. */
191 for(i
=0; i
< nb_cpus
; i
++) {
192 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
194 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
195 self
->running_process
[i
]->cpu
= i
;
199 nb_tracefile
= self
->parent
.tracefiles
->len
;
201 for(i
= 0 ; i
< nb_tracefile
; i
++) {
203 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
204 LttvTracefileContext
*, i
));
205 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
206 // tfcs->saved_position = 0;
207 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
208 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
209 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
210 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
215 //static LttTime time_zero = {0,0};
218 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
220 guint i
, j
, nb_trace
, nb_tracefile
;
222 LttvTraceContext
*tc
;
226 LttvTracefileState
*tfcs
;
228 LttvAttributeValue v
;
230 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
231 init((LttvTracesetContext
*)self
, ts
);
233 nb_trace
= lttv_traceset_number(ts
);
234 for(i
= 0 ; i
< nb_trace
; i
++) {
235 tc
= self
->parent
.traces
[i
];
236 tcs
= LTTV_TRACE_STATE(tc
);
237 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
238 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
242 if(*(v
.v_uint
) == 1) {
243 create_name_tables(tcs
);
244 create_max_time(tcs
);
246 get_name_tables(tcs
);
249 nb_tracefile
= tc
->tracefiles
->len
;
251 for(j
= 0 ; j
< nb_tracefile
; j
++) {
253 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
254 LttvTracefileContext
*, j
));
255 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
258 tcs
->processes
= NULL
;
259 tcs
->running_process
= g_new(LttvProcessState
*,
260 ltt_trace_get_num_cpu(tc
->t
));
261 restore_init_state(tcs
);
267 fini(LttvTracesetState
*self
)
273 LttvTracefileState
*tfcs
;
275 LttvAttributeValue v
;
277 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
278 for(i
= 0 ; i
< nb_trace
; i
++) {
279 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
280 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
283 g_assert(*(v
.v_uint
) != 0);
286 if(*(v
.v_uint
) == 0) {
287 free_name_tables(tcs
);
289 free_saved_state(tcs
);
291 g_free(tcs
->running_process
);
292 tcs
->running_process
= NULL
;
293 lttv_state_free_process_table(tcs
->processes
);
294 tcs
->processes
= NULL
;
296 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
297 fini((LttvTracesetContext
*)self
);
301 static LttvTracesetContext
*
302 new_traceset_context(LttvTracesetContext
*self
)
304 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
308 static LttvTraceContext
*
309 new_trace_context(LttvTracesetContext
*self
)
311 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
315 static LttvTracefileContext
*
316 new_tracefile_context(LttvTracesetContext
*self
)
318 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
322 /* Write the process state of the trace */
324 static void write_process_state(gpointer key
, gpointer value
,
327 LttvProcessState
*process
;
329 LttvExecutionState
*es
;
331 FILE *fp
= (FILE *)user_data
;
335 process
= (LttvProcessState
*)value
;
337 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
338 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
339 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
342 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
343 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
344 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
345 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
346 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
347 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
348 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
350 fprintf(fp
, " </PROCESS>\n");
354 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
356 guint i
, nb_tracefile
, nb_block
, offset
;
359 LttvTracefileState
*tfcs
;
363 LttEventPosition
*ep
;
367 ep
= ltt_event_position_new();
369 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
371 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
373 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
374 for(i
=0;i
<nb_cpus
;i
++) {
375 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
376 i
, self
->running_process
[i
]->pid
);
379 nb_tracefile
= self
->parent
.tracefiles
->len
;
381 for(i
= 0 ; i
< nb_tracefile
; i
++) {
383 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
384 LttvTracefileContext
*, i
));
385 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
386 tfcs
->parent
.timestamp
.tv_sec
,
387 tfcs
->parent
.timestamp
.tv_nsec
);
388 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
389 if(e
== NULL
) fprintf(fp
,"/>\n");
391 ltt_event_position(e
, ep
);
392 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
393 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
398 fprintf(fp
,"</PROCESS_STATE>");
402 /* Copy each process from an existing hash table to a new one */
404 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
406 LttvProcessState
*process
, *new_process
;
408 GHashTable
*new_processes
= (GHashTable
*)user_data
;
412 process
= (LttvProcessState
*)value
;
413 new_process
= g_new(LttvProcessState
, 1);
414 *new_process
= *process
;
415 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
416 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
417 new_process
->execution_stack
=
418 g_array_set_size(new_process
->execution_stack
,
419 process
->execution_stack
->len
);
420 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
421 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
422 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
424 new_process
->state
= &g_array_index(new_process
->execution_stack
,
425 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
426 g_hash_table_insert(new_processes
, new_process
, new_process
);
430 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
432 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
434 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
435 return new_processes
;
439 /* The saved state for each trace contains a member "processes", which
440 stores a copy of the process table, and a member "tracefiles" with
441 one entry per tracefile. Each tracefile has a "process" member pointing
442 to the current process and a "position" member storing the tracefile
443 position (needed to seek to the current "next" event. */
445 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
447 guint i
, nb_tracefile
, nb_cpus
;
449 LttvTracefileState
*tfcs
;
451 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
453 guint
*running_process
;
455 LttvAttributeType type
;
457 LttvAttributeValue value
;
459 LttvAttributeName name
;
461 LttEventPosition
*ep
;
463 tracefiles_tree
= lttv_attribute_find_subdir(container
,
464 LTTV_STATE_TRACEFILES
);
466 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
468 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
470 /* Add the currently running processes array */
471 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
472 running_process
= g_new(guint
, nb_cpus
);
473 for(i
=0;i
<nb_cpus
;i
++) {
474 running_process
[i
] = self
->running_process
[i
]->pid
;
476 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
478 *(value
.v_pointer
) = running_process
;
480 g_info("State save");
482 nb_tracefile
= self
->parent
.tracefiles
->len
;
484 for(i
= 0 ; i
< nb_tracefile
; i
++) {
486 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
487 LttvTracefileContext
*, i
));
488 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
489 value
= lttv_attribute_add(tracefiles_tree
, i
,
491 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
493 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
495 *(value
.v_uint
) = tfcs
->process
->pid
;
497 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
499 /* Only save the position if the tfs has not infinite time. */
500 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
501 // && current_tfcs != tfcs) {
502 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
503 *(value
.v_pointer
) = NULL
;
505 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
506 ep
= ltt_event_position_new();
507 ltt_event_position(e
, ep
);
508 *(value
.v_pointer
) = ep
;
510 guint nb_block
, offset
;
513 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
514 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
516 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
522 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
524 guint i
, nb_tracefile
, pid
, nb_cpus
;
526 LttvTracefileState
*tfcs
;
528 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
530 guint
*running_process
;
532 LttvAttributeType type
;
534 LttvAttributeValue value
;
536 LttvAttributeName name
;
538 LttEventPosition
*ep
;
540 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
542 tracefiles_tree
= lttv_attribute_find_subdir(container
,
543 LTTV_STATE_TRACEFILES
);
545 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
547 g_assert(type
== LTTV_POINTER
);
548 lttv_state_free_process_table(self
->processes
);
549 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
551 /* Add the currently running processes array */
552 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
553 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
555 g_assert(type
== LTTV_POINTER
);
556 running_process
= *(value
.v_pointer
);
557 for(i
=0;i
<nb_cpus
;i
++) {
558 pid
= running_process
[i
];
559 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
560 g_assert(self
->running_process
[i
] != NULL
);
564 nb_tracefile
= self
->parent
.tracefiles
->len
;
566 //g_tree_destroy(tsc->pqueue);
567 //tsc->pqueue = g_tree_new(compare_tracefile);
569 for(i
= 0 ; i
< nb_tracefile
; i
++) {
571 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
572 LttvTracefileContext
*, i
));
573 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
574 g_assert(type
== LTTV_GOBJECT
);
575 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
577 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
579 g_assert(type
== LTTV_UINT
);
580 pid
= *(value
.v_uint
);
581 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
583 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
585 g_assert(type
== LTTV_POINTER
);
586 //g_assert(*(value.v_pointer) != NULL);
587 ep
= *(value
.v_pointer
);
588 g_assert(tfcs
->parent
.t_context
!= NULL
);
590 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
591 g_tree_remove(tsc
->pqueue
, tfc
);
594 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
595 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
596 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
597 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
598 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
600 tfc
->timestamp
= ltt_time_infinite
;
606 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
608 guint i
, nb_tracefile
, nb_cpus
;
610 LttvTracefileState
*tfcs
;
612 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
614 guint
*running_process
;
616 LttvAttributeType type
;
618 LttvAttributeValue value
;
620 LttvAttributeName name
;
622 LttEventPosition
*ep
;
624 tracefiles_tree
= lttv_attribute_find_subdir(container
,
625 LTTV_STATE_TRACEFILES
);
626 g_object_ref(G_OBJECT(tracefiles_tree
));
627 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
629 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
631 g_assert(type
== LTTV_POINTER
);
632 lttv_state_free_process_table(*(value
.v_pointer
));
633 *(value
.v_pointer
) = NULL
;
634 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
636 /* Free running processes array */
637 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
638 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
640 g_assert(type
== LTTV_POINTER
);
641 running_process
= *(value
.v_pointer
);
642 g_free(running_process
);
644 nb_tracefile
= self
->parent
.tracefiles
->len
;
646 for(i
= 0 ; i
< nb_tracefile
; i
++) {
648 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
649 LttvTracefileContext
*, i
));
650 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
651 g_assert(type
== LTTV_GOBJECT
);
652 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
654 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
656 g_assert(type
== LTTV_POINTER
);
657 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
659 g_object_unref(G_OBJECT(tracefiles_tree
));
663 static void free_saved_state(LttvTraceState
*self
)
667 LttvAttributeType type
;
669 LttvAttributeValue value
;
671 LttvAttributeName name
;
673 LttvAttribute
*saved_states
;
675 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
676 LTTV_STATE_SAVED_STATES
);
678 nb
= lttv_attribute_get_number(saved_states
);
679 for(i
= 0 ; i
< nb
; i
++) {
680 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
681 g_assert(type
== LTTV_GOBJECT
);
682 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
685 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
690 create_max_time(LttvTraceState
*tcs
)
692 LttvAttributeValue v
;
694 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
696 g_assert(*(v
.v_pointer
) == NULL
);
697 *(v
.v_pointer
) = g_new(LttTime
,1);
698 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
703 get_max_time(LttvTraceState
*tcs
)
705 LttvAttributeValue v
;
707 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
709 g_assert(*(v
.v_pointer
) != NULL
);
710 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
715 free_max_time(LttvTraceState
*tcs
)
717 LttvAttributeValue v
;
719 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
721 g_free(*(v
.v_pointer
));
722 *(v
.v_pointer
) = NULL
;
726 typedef struct _LttvNameTables
{
727 // FIXME GQuark *eventtype_names;
728 GQuark
*syscall_names
;
735 create_name_tables(LttvTraceState
*tcs
)
739 GQuark f_name
, e_name
;
743 LttvTraceHookByFacility
*thf
;
749 GString
*fe_name
= g_string_new("");
751 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
753 LttvAttributeValue v
;
755 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
757 g_assert(*(v
.v_pointer
) == NULL
);
758 *(v
.v_pointer
) = name_tables
;
759 #if 0 // Use iteration over the facilities_by_name and then list all event
760 // types of each facility
761 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
762 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
763 for(i
= 0 ; i
< nb
; i
++) {
764 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
765 e_name
= ltt_eventtype_name(et
);
766 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
767 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
768 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
771 if(lttv_trace_find_hook(tcs
->parent
.t
,
772 LTT_FACILITY_ASM_I386_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
773 LTT_FIELD_SYSCALL_ID
, 0, 0,
777 thf
= lttv_trace_hook_get_first(&h
);
779 t
= ltt_field_type(thf
->f1
);
780 //nb = ltt_type_element_number(t);
782 lttv_trace_hook_destroy(&h
);
784 /* CHECK syscalls should be an enum but currently are not!
785 name_tables->syscall_names = g_new(GQuark, nb);
787 for(i = 0 ; i < nb ; i++) {
788 name_tables->syscall_names[i] = g_quark_from_string(
789 ltt_enum_string_get(t, i));
793 name_tables
->syscall_names
= g_new(GQuark
, 256);
794 for(i
= 0 ; i
< 256 ; i
++) {
795 g_string_printf(fe_name
, "syscall %d", i
);
796 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
799 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
800 LTT_EVENT_TRAP_ENTRY
,
801 LTT_FIELD_TRAP_ID
, 0, 0,
805 thf
= lttv_trace_hook_get_first(&h
);
807 t
= ltt_field_type(thf
->f1
);
808 //nb = ltt_type_element_number(t);
810 lttv_trace_hook_destroy(&h
);
813 name_tables->trap_names = g_new(GQuark, nb);
814 for(i = 0 ; i < nb ; i++) {
815 name_tables->trap_names[i] = g_quark_from_string(
816 ltt_enum_string_get(t, i));
820 name_tables
->trap_names
= g_new(GQuark
, 256);
821 for(i
= 0 ; i
< 256 ; i
++) {
822 g_string_printf(fe_name
, "trap %d", i
);
823 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
826 if(lttv_trace_find_hook(tcs
->parent
.t
,
827 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
828 LTT_FIELD_IRQ_ID
, 0, 0,
832 thf
= lttv_trace_hook_get_first(&h
);
834 t
= ltt_field_type(thf
->f1
);
835 //nb = ltt_type_element_number(t);
837 lttv_trace_hook_destroy(&h
);
840 name_tables->irq_names = g_new(GQuark, nb);
841 for(i = 0 ; i < nb ; i++) {
842 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
846 name_tables
->irq_names
= g_new(GQuark
, 256);
847 for(i
= 0 ; i
< 256 ; i
++) {
848 g_string_printf(fe_name
, "irq %d", i
);
849 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
852 g_string_free(fe_name
, TRUE
);
857 get_name_tables(LttvTraceState
*tcs
)
859 LttvNameTables
*name_tables
;
861 LttvAttributeValue v
;
863 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
865 g_assert(*(v
.v_pointer
) != NULL
);
866 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
867 //tcs->eventtype_names = name_tables->eventtype_names;
868 tcs
->syscall_names
= name_tables
->syscall_names
;
869 tcs
->trap_names
= name_tables
->trap_names
;
870 tcs
->irq_names
= name_tables
->irq_names
;
875 free_name_tables(LttvTraceState
*tcs
)
877 LttvNameTables
*name_tables
;
879 LttvAttributeValue v
;
881 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
883 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
884 *(v
.v_pointer
) = NULL
;
886 // g_free(name_tables->eventtype_names);
887 g_free(name_tables
->syscall_names
);
888 g_free(name_tables
->trap_names
);
889 g_free(name_tables
->irq_names
);
893 #ifdef HASH_TABLE_DEBUG
895 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
897 LttvProcessState
*process
= (LttvProcessState
*)value
;
899 /* Test for process corruption */
900 guint stack_len
= process
->execution_stack
->len
;
903 static void hash_table_check(GHashTable
*table
)
905 g_hash_table_foreach(table
, test_process
, NULL
);
912 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
915 LttvExecutionState
*es
;
917 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
918 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
920 #ifdef HASH_TABLE_DEBUG
921 hash_table_check(ts
->processes
);
923 LttvProcessState
*process
= ts
->running_process
[cpu
];
925 guint depth
= process
->execution_stack
->len
;
927 process
->execution_stack
=
928 g_array_set_size(process
->execution_stack
, depth
+ 1);
931 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
933 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
936 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
937 es
->s
= process
->state
->s
;
942 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
944 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
945 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
946 LttvProcessState
*process
= ts
->running_process
[cpu
];
948 guint depth
= process
->execution_stack
->len
;
950 if(process
->state
->t
!= t
){
951 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
952 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
953 g_info("process state has %s when pop_int is %s\n",
954 g_quark_to_string(process
->state
->t
),
955 g_quark_to_string(t
));
956 g_info("{ %u, %u, %s, %s }\n",
959 g_quark_to_string(process
->name
),
960 g_quark_to_string(process
->state
->s
));
965 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
966 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
970 process
->execution_stack
=
971 g_array_set_size(process
->execution_stack
, depth
- 1);
972 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
974 process
->state
->change
= tfs
->parent
.timestamp
;
979 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
980 guint cpu
, guint pid
, const LttTime
*timestamp
)
982 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
984 LttvExecutionState
*es
;
986 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
992 //process->last_cpu = tfs->cpu_name;
993 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
994 g_info("Process %u, core %p", process
->pid
, process
);
995 g_hash_table_insert(tcs
->processes
, process
, process
);
998 process
->ppid
= parent
->pid
;
999 process
->name
= parent
->name
;
1000 process
->creation_time
= *timestamp
;
1003 /* No parent. This process exists but we are missing all information about
1004 its creation. The birth time is set to zero but we remember the time of
1009 process
->name
= LTTV_STATE_UNNAMED
;
1010 process
->creation_time
= ltt_time_zero
;
1013 process
->insertion_time
= *timestamp
;
1014 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1015 process
->creation_time
.tv_nsec
);
1016 process
->pid_time
= g_quark_from_string(buffer
);
1018 //process->last_cpu = tfs->cpu_name;
1019 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1020 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1021 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1022 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1023 es
= process
->state
= &g_array_index(process
->execution_stack
,
1024 LttvExecutionState
, 0);
1025 es
->t
= LTTV_STATE_USER_MODE
;
1026 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1027 es
->entry
= *timestamp
;
1028 //g_assert(timestamp->tv_sec != 0);
1029 es
->change
= *timestamp
;
1030 es
->s
= LTTV_STATE_RUN
;
1032 es
= process
->state
= &g_array_index(process
->execution_stack
,
1033 LttvExecutionState
, 1);
1034 es
->t
= LTTV_STATE_SYSCALL
;
1035 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1036 es
->entry
= *timestamp
;
1037 //g_assert(timestamp->tv_sec != 0);
1038 es
->change
= *timestamp
;
1039 es
->s
= LTTV_STATE_WAIT_FORK
;
1044 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1047 LttvProcessState key
;
1048 LttvProcessState
*process
;
1052 process
= g_hash_table_lookup(ts
->processes
, &key
);
1057 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1060 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1062 /* Put ltt_time_zero creation time for unexisting processes */
1063 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1064 NULL
, cpu
, pid
, timestamp
);
1068 /* FIXME : this function should be called when we receive an event telling that
1069 * release_task has been called in the kernel. In happens generally when
1070 * the parent waits for its child terminaison, but may also happen in special
1071 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1072 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1073 * of a killed thread ground, but isn't the leader.
1075 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1077 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1078 LttvProcessState key
;
1080 key
.pid
= process
->pid
;
1081 key
.cpu
= process
->cpu
;
1082 g_hash_table_remove(ts
->processes
, &key
);
1083 g_array_free(process
->execution_stack
, TRUE
);
1088 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1090 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1095 static void lttv_state_free_process_table(GHashTable
*processes
)
1097 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1098 g_hash_table_destroy(processes
);
1102 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1104 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1105 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1106 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1107 LttField
*f
= thf
->f1
;
1109 LttvExecutionSubmode submode
;
1111 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1112 ltt_event_get_unsigned(e
, f
)];
1113 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1118 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1120 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1122 pop_state(s
, LTTV_STATE_SYSCALL
);
1127 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1129 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1130 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1131 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1132 LttField
*f
= thf
->f1
;
1134 LttvExecutionSubmode submode
;
1136 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1137 ltt_event_get_unsigned(e
, f
)];
1138 push_state(s
, LTTV_STATE_TRAP
, submode
);
1143 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1145 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1147 pop_state(s
, LTTV_STATE_TRAP
);
1152 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1154 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1155 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1156 guint8 fac_id
= ltt_event_facility_id(e
);
1157 guint8 ev_id
= ltt_event_eventtype_id(e
);
1158 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1159 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1160 g_assert(thf
->f1
!= NULL
);
1161 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1162 LttField
*f
= thf
->f1
;
1164 LttvExecutionSubmode submode
;
1166 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1167 ltt_event_get_unsigned(e
, f
)];
1169 /* Do something with the info about being in user or system mode when int? */
1170 push_state(s
, LTTV_STATE_IRQ
, submode
);
1175 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1177 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1179 pop_state(s
, LTTV_STATE_IRQ
);
1184 static gboolean
schedchange(void *hook_data
, void *call_data
)
1186 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1187 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1188 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1189 LttvProcessState
*process
= ts
->running_process
[cpu
];
1191 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1192 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1193 guint pid_in
, pid_out
;
1196 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1197 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1198 state_out
= ltt_event_get_int(e
, thf
->f3
);
1200 if(likely(process
!= NULL
)) {
1202 /* We could not know but it was not the idle process executing.
1203 This should only happen at the beginning, before the first schedule
1204 event, and when the initial information (current process for each CPU)
1205 is missing. It is not obvious how we could, after the fact, compensate
1206 the wrongly attributed statistics. */
1208 //This test only makes sense once the state is known and if there is no
1210 //if(unlikely(process->pid != pid_out)) {
1211 // g_assert(process->pid == 0);
1214 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1215 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1216 process
->state
->change
= s
->parent
.timestamp
;
1218 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1219 else process
->state
->s
= LTTV_STATE_WAIT
;
1220 process
->state
->change
= s
->parent
.timestamp
;
1224 exit_process(s
, process
); /* EXIT_DEAD */
1225 /* see sched.h for states */
1227 process
= ts
->running_process
[cpu
] =
1228 lttv_state_find_process_or_create(
1229 (LttvTraceState
*)s
->parent
.t_context
,
1231 &s
->parent
.timestamp
);
1232 process
->state
->s
= LTTV_STATE_RUN
;
1234 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1235 process
->state
->change
= s
->parent
.timestamp
;
1239 static gboolean
process_fork(void *hook_data
, void *call_data
)
1241 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1242 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1243 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1247 LttvProcessState
*zombie_process
;
1248 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1249 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1250 LttvProcessState
*process
= ts
->running_process
[cpu
];
1251 LttvProcessState
*child_process
;
1255 parent_pid
= ltt_event_get_unsigned(e
, f
);
1259 child_pid
= ltt_event_get_unsigned(e
, f
);
1261 /* Mathieu : it seems like the process might have been scheduled in before the
1262 * fork, and, in a rare case, might be the current process. This might happen
1263 * in a SMP case where we don't have enough precision on the clocks.
1265 * Test reenabled after precision fixes on time. (Mathieu) */
1267 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1269 if(unlikely(zombie_process
!= NULL
)) {
1270 /* Reutilisation of PID. Only now we are sure that the old PID
1271 * has been released. FIXME : should know when release_task happens instead.
1273 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1275 for(i
=0; i
< num_cpus
; i
++) {
1276 g_assert(zombie_process
!= ts
->running_process
[i
]);
1279 exit_process(s
, zombie_process
);
1282 g_assert(process
->pid
!= child_pid
);
1283 // FIXME : Add this test in the "known state" section
1284 // g_assert(process->pid == parent_pid);
1285 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1286 if(child_process
== NULL
) {
1287 lttv_state_create_process(ts
, process
, cpu
,
1288 child_pid
, &s
->parent
.timestamp
);
1290 /* The process has already been created : due to time imprecision between
1291 * multiple CPUs : it has been scheduled in before creation. Note that we
1292 * shouldn't have this kind of imprecision.
1294 * Simply put a correct parent.
1296 g_assert(0); /* This is a problematic case : the process has been created
1297 before the fork event */
1298 child_process
->ppid
= process
->pid
;
1305 static gboolean
process_exit(void *hook_data
, void *call_data
)
1307 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1308 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1309 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1312 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1313 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1314 LttvProcessState
*process
= ts
->running_process
[cpu
];
1316 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1318 // FIXME : Add this test in the "known state" section
1319 // g_assert(process->pid == pid);
1321 if(likely(process
!= NULL
)) {
1322 process
->state
->s
= LTTV_STATE_EXIT
;
1327 static gboolean
process_free(void *hook_data
, void *call_data
)
1329 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1330 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1331 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1332 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1334 LttvProcessState
*process
;
1336 /* PID of the process to release */
1337 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1339 g_assert(release_pid
!= 0);
1341 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1343 if(likely(process
!= NULL
)) {
1344 /* release_task is happening at kernel level : we can now safely release
1345 * the data structure of the process */
1346 //This test is fun, though, as it may happen that
1347 //at time t : CPU 0 : process_free
1348 //at time t+150ns : CPU 1 : schedule out
1349 //Clearly due to time imprecision, we disable it. (Mathieu)
1350 //If this weird case happen, we have no choice but to put the
1351 //Currently running process on the cpu to 0.
1352 //I re-enable it following time precision fixes. (Mathieu)
1353 //Well, in the case where an process is freed by a process on another CPU
1354 //and still scheduled, it happens that this is the schedchange that will
1355 //drop the last reference count. Do not free it here!
1356 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1358 for(i
=0; i
< num_cpus
; i
++) {
1359 //g_assert(process != ts->running_process[i]);
1360 if(process
== ts
->running_process
[i
]) {
1361 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1365 if(i
== num_cpus
) /* process is not scheduled */
1366 exit_process(s
, process
);
1373 static gboolean
process_exec(void *hook_data
, void *call_data
)
1375 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1376 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1377 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1378 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1380 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1381 LttvProcessState
*process
= ts
->running_process
[cpu
];
1383 /* PID of the process to release */
1384 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1385 //name = ltt_event_get_string(e, thf->f1);
1386 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1388 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1389 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1390 memcpy(null_term_name
, name_begin
, name_len
);
1391 null_term_name
[name_len
] = '\0';
1393 process
->name
= g_quark_from_string(null_term_name
);
1394 g_free(null_term_name
);
1401 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1403 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1405 lttv_state_add_event_hooks(tss
);
1410 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1412 LttvTraceset
*traceset
= self
->parent
.ts
;
1414 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1418 LttvTracefileState
*tfs
;
1422 LttvTraceHookByFacility
*thf
;
1424 LttvTraceHook
*hook
;
1426 LttvAttributeValue val
;
1430 nb_trace
= lttv_traceset_number(traceset
);
1431 for(i
= 0 ; i
< nb_trace
; i
++) {
1432 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1434 /* Find the eventtype id for the following events and register the
1435 associated by id hooks. */
1437 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 11);
1438 hooks
= g_array_set_size(hooks
, 11);
1440 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1441 LTT_FACILITY_ASM_I386_KERNEL
, LTT_EVENT_SYSCALL_ENTRY
,
1442 LTT_FIELD_SYSCALL_ID
, 0, 0,
1443 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1446 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1447 LTT_FACILITY_ASM_I386_KERNEL
, LTT_EVENT_SYSCALL_EXIT
,
1449 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1452 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1453 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1454 LTT_FIELD_TRAP_ID
, 0, 0,
1455 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1458 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1459 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1461 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1464 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1465 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1466 LTT_FIELD_IRQ_ID
, 0, 0,
1467 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1470 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1471 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1473 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1476 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1477 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1478 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1479 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1482 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1483 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1484 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1485 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1488 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1489 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1490 LTT_FIELD_PID
, 0, 0,
1491 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1494 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1495 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1496 LTT_FIELD_PID
, 0, 0,
1497 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1500 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1501 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1502 LTT_FIELD_FILENAME
, 0, 0,
1503 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1508 /* Add these hooks to each event_by_id hooks list */
1510 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1512 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1514 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1515 LttvTracefileContext
*, j
));
1517 for(k
= 0 ; k
< hooks
->len
; k
++) {
1518 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1519 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1520 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1522 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1529 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1530 *(val
.v_pointer
) = hooks
;
1534 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1536 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1538 lttv_state_remove_event_hooks(tss
);
1543 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1545 LttvTraceset
*traceset
= self
->parent
.ts
;
1547 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1551 LttvTracefileState
*tfs
;
1555 LttvTraceHook
*hook
;
1557 LttvTraceHookByFacility
*thf
;
1559 LttvAttributeValue val
;
1561 nb_trace
= lttv_traceset_number(traceset
);
1562 for(i
= 0 ; i
< nb_trace
; i
++) {
1563 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1564 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1565 hooks
= *(val
.v_pointer
);
1567 /* Remove these hooks from each event_by_id hooks list */
1569 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1571 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1573 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1574 LttvTracefileContext
*, j
));
1576 for(k
= 0 ; k
< hooks
->len
; k
++) {
1577 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1578 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1579 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1581 lttv_hooks_remove_data(
1582 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1588 for(k
= 0 ; k
< hooks
->len
; k
++)
1589 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1590 g_array_free(hooks
, TRUE
);
1594 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1596 guint
*event_count
= (guint
*)hook_data
;
1598 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1599 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1604 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1606 LttvTracefileState
*tfcs
;
1608 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1610 LttEventPosition
*ep
;
1616 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1618 LttvAttributeValue value
;
1620 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1621 LTTV_STATE_SAVED_STATES
);
1622 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1623 value
= lttv_attribute_add(saved_states_tree
,
1624 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1625 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1626 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1627 *(value
.v_time
) = self
->parent
.timestamp
;
1628 lttv_state_save(tcs
, saved_state_tree
);
1629 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1630 self
->parent
.timestamp
.tv_nsec
);
1632 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1637 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1639 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1641 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1647 static gboolean
block_start(void *hook_data
, void *call_data
)
1649 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1651 LttvTracefileState
*tfcs
;
1653 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1655 LttEventPosition
*ep
;
1657 guint i
, nb_block
, nb_event
, nb_tracefile
;
1661 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1663 LttvAttributeValue value
;
1665 ep
= ltt_event_position_new();
1667 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1669 /* Count the number of events added since the last block end in any
1672 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1674 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1675 LttvTracefileContext
, i
));
1676 ltt_event_position(tfcs
->parent
.e
, ep
);
1677 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1678 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1679 tfcs
->saved_position
= nb_event
;
1683 if(tcs
->nb_event
>= tcs
->save_interval
) {
1684 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1685 LTTV_STATE_SAVED_STATES
);
1686 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1687 value
= lttv_attribute_add(saved_states_tree
,
1688 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1689 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1690 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1691 *(value
.v_time
) = self
->parent
.timestamp
;
1692 lttv_state_save(tcs
, saved_state_tree
);
1694 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1695 self
->parent
.timestamp
.tv_nsec
);
1697 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1703 static gboolean
block_end(void *hook_data
, void *call_data
)
1705 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1707 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1711 LttEventPosition
*ep
;
1713 guint nb_block
, nb_event
;
1715 ep
= ltt_event_position_new();
1716 ltt_event_position(self
->parent
.e
, ep
);
1717 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1718 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1719 self
->saved_position
= 0;
1720 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1727 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1729 LttvTraceset
*traceset
= self
->parent
.ts
;
1731 guint i
, j
, nb_trace
, nb_tracefile
;
1735 LttvTracefileState
*tfs
;
1737 LttvTraceHook hook_start
, hook_end
;
1739 nb_trace
= lttv_traceset_number(traceset
);
1740 for(i
= 0 ; i
< nb_trace
; i
++) {
1741 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1743 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1744 NULL
, NULL
, block_start
, &hook_start
);
1745 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1746 NULL
, NULL
, block_end
, &hook_end
);
1748 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1750 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1752 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1753 LttvTracefileContext
, j
));
1754 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1755 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1756 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1757 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1763 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1765 LttvTraceset
*traceset
= self
->parent
.ts
;
1767 guint i
, j
, nb_trace
, nb_tracefile
;
1771 LttvTracefileState
*tfs
;
1774 nb_trace
= lttv_traceset_number(traceset
);
1775 for(i
= 0 ; i
< nb_trace
; i
++) {
1777 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1778 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1780 guint
*event_count
= g_new(guint
, 1);
1783 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1785 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1786 LttvTracefileContext
*, j
));
1787 lttv_hooks_add(tfs
->parent
.event
,
1788 state_save_event_hook
,
1795 lttv_process_traceset_begin(&self
->parent
,
1796 NULL
, NULL
, NULL
, NULL
, NULL
);
1800 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1802 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1804 lttv_state_save_add_event_hooks(tss
);
1811 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1813 LttvTraceset
*traceset
= self
->parent
.ts
;
1815 guint i
, j
, nb_trace
, nb_tracefile
;
1819 LttvTracefileState
*tfs
;
1821 LttvTraceHook hook_start
, hook_end
;
1823 nb_trace
= lttv_traceset_number(traceset
);
1824 for(i
= 0 ; i
< nb_trace
; i
++) {
1825 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1827 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1828 NULL
, NULL
, block_start
, &hook_start
);
1830 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1831 NULL
, NULL
, block_end
, &hook_end
);
1833 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1835 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1837 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1838 LttvTracefileContext
, j
));
1839 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1840 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1841 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1842 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1848 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1850 LttvTraceset
*traceset
= self
->parent
.ts
;
1852 guint i
, j
, nb_trace
, nb_tracefile
;
1856 LttvTracefileState
*tfs
;
1858 LttvHooks
*after_trace
= lttv_hooks_new();
1860 lttv_hooks_add(after_trace
,
1861 state_save_after_trace_hook
,
1866 lttv_process_traceset_end(&self
->parent
,
1867 NULL
, after_trace
, NULL
, NULL
, NULL
);
1869 lttv_hooks_destroy(after_trace
);
1871 nb_trace
= lttv_traceset_number(traceset
);
1872 for(i
= 0 ; i
< nb_trace
; i
++) {
1874 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1875 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1877 guint
*event_count
= NULL
;
1879 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1881 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1882 LttvTracefileContext
*, j
));
1883 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1884 state_save_event_hook
);
1886 if(event_count
) g_free(event_count
);
1890 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1892 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1894 lttv_state_save_remove_event_hooks(tss
);
1899 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1901 LttvTraceset
*traceset
= self
->parent
.ts
;
1905 int min_pos
, mid_pos
, max_pos
;
1907 guint call_rest
= 0;
1909 LttvTraceState
*tcs
;
1911 LttvAttributeValue value
;
1913 LttvAttributeType type
;
1915 LttvAttributeName name
;
1917 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1919 //g_tree_destroy(self->parent.pqueue);
1920 //self->parent.pqueue = g_tree_new(compare_tracefile);
1922 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
1924 nb_trace
= lttv_traceset_number(traceset
);
1925 for(i
= 0 ; i
< nb_trace
; i
++) {
1926 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1928 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1929 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1930 LTTV_STATE_SAVED_STATES
);
1933 if(saved_states_tree
) {
1934 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1935 mid_pos
= max_pos
/ 2;
1936 while(min_pos
< max_pos
) {
1937 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1938 g_assert(type
== LTTV_GOBJECT
);
1939 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1940 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
1942 g_assert(type
== LTTV_TIME
);
1943 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
1945 closest_tree
= saved_state_tree
;
1947 else max_pos
= mid_pos
- 1;
1949 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
1953 /* restore the closest earlier saved state */
1955 lttv_state_restore(tcs
, closest_tree
);
1959 /* There is no saved state, yet we want to have it. Restart at T0 */
1961 restore_init_state(tcs
);
1962 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
1965 /* We want to seek quickly without restoring/updating the state */
1967 restore_init_state(tcs
);
1968 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
1971 if(!call_rest
) g_info("NOT Calling restore");
1976 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
1982 traceset_state_finalize (LttvTracesetState
*self
)
1984 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
1985 finalize(G_OBJECT(self
));
1990 traceset_state_class_init (LttvTracesetContextClass
*klass
)
1992 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
1994 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
1995 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
1996 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
1997 klass
->new_traceset_context
= new_traceset_context
;
1998 klass
->new_trace_context
= new_trace_context
;
1999 klass
->new_tracefile_context
= new_tracefile_context
;
2004 lttv_traceset_state_get_type(void)
2006 static GType type
= 0;
2008 static const GTypeInfo info
= {
2009 sizeof (LttvTracesetStateClass
),
2010 NULL
, /* base_init */
2011 NULL
, /* base_finalize */
2012 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2013 NULL
, /* class_finalize */
2014 NULL
, /* class_data */
2015 sizeof (LttvTracesetState
),
2016 0, /* n_preallocs */
2017 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2018 NULL
/* value handling */
2021 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2029 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2035 trace_state_finalize (LttvTraceState
*self
)
2037 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2038 finalize(G_OBJECT(self
));
2043 trace_state_class_init (LttvTraceStateClass
*klass
)
2045 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2047 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2048 klass
->state_save
= state_save
;
2049 klass
->state_restore
= state_restore
;
2050 klass
->state_saved_free
= state_saved_free
;
2055 lttv_trace_state_get_type(void)
2057 static GType type
= 0;
2059 static const GTypeInfo info
= {
2060 sizeof (LttvTraceStateClass
),
2061 NULL
, /* base_init */
2062 NULL
, /* base_finalize */
2063 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2064 NULL
, /* class_finalize */
2065 NULL
, /* class_data */
2066 sizeof (LttvTraceState
),
2067 0, /* n_preallocs */
2068 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2069 NULL
/* value handling */
2072 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2073 "LttvTraceStateType", &info
, 0);
2080 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2086 tracefile_state_finalize (LttvTracefileState
*self
)
2088 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2089 finalize(G_OBJECT(self
));
2094 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2096 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2098 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2103 lttv_tracefile_state_get_type(void)
2105 static GType type
= 0;
2107 static const GTypeInfo info
= {
2108 sizeof (LttvTracefileStateClass
),
2109 NULL
, /* base_init */
2110 NULL
, /* base_finalize */
2111 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2112 NULL
, /* class_finalize */
2113 NULL
, /* class_data */
2114 sizeof (LttvTracefileState
),
2115 0, /* n_preallocs */
2116 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2117 NULL
/* value handling */
2120 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2121 "LttvTracefileStateType", &info
, 0);
2127 static void module_init()
2129 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2130 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
2131 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
2132 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
2133 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
2134 LTTV_STATE_TRAP
= g_quark_from_string("trap");
2135 LTTV_STATE_IRQ
= g_quark_from_string("irq");
2136 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
2137 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
2138 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
2139 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
2140 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
2141 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
2142 LTTV_STATE_RUN
= g_quark_from_string("running");
2143 LTTV_STATE_DEAD
= g_quark_from_string("dead");
2144 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2145 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2146 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2147 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2148 LTTV_STATE_EVENT
= g_quark_from_string("event");
2149 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2150 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2151 LTTV_STATE_TIME
= g_quark_from_string("time");
2152 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2153 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2154 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2155 g_quark_from_string("trace_state_use_count");
2158 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2159 LTT_FACILITY_ASM_I386_KERNEL
= g_quark_from_string("asm_i386_kernel");
2160 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2161 LTT_FACILITY_FS
= g_quark_from_string("fs");
2164 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2165 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2166 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2167 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2168 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2169 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2170 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2171 LTT_EVENT_FORK
= g_quark_from_string("fork");
2172 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2173 LTT_EVENT_FREE
= g_quark_from_string("free");
2174 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2177 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2178 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2179 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2180 LTT_FIELD_OUT
= g_quark_from_string("out");
2181 LTT_FIELD_IN
= g_quark_from_string("in");
2182 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2183 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2184 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2185 LTT_FIELD_PID
= g_quark_from_string("pid");
2186 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2190 static void module_destroy()
2195 LTTV_MODULE("state", "State computation", \
2196 "Update the system state, possibly saving it at intervals", \
2197 module_init
, module_destroy
)