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_KERNEL_ARCH
,
45 LTT_EVENT_SYSCALL_ENTRY
,
46 LTT_EVENT_SYSCALL_EXIT
,
51 LTT_EVENT_SOFT_IRQ_ENTRY
,
52 LTT_EVENT_SOFT_IRQ_EXIT
,
53 LTT_EVENT_SCHEDCHANGE
,
65 LTT_FIELD_SOFT_IRQ_ID
,
75 LTTV_STATE_MODE_UNKNOWN
,
83 LTTV_STATE_SUBMODE_UNKNOWN
,
84 LTTV_STATE_SUBMODE_NONE
;
97 LTTV_STATE_TRACEFILES
,
100 LTTV_STATE_RUNNING_PROCESS
,
102 LTTV_STATE_SAVED_STATES
,
103 LTTV_STATE_SAVED_STATES_TIME
,
106 LTTV_STATE_NAME_TABLES
,
107 LTTV_STATE_TRACE_STATE_USE_COUNT
;
109 static void create_max_time(LttvTraceState
*tcs
);
111 static void get_max_time(LttvTraceState
*tcs
);
113 static void free_max_time(LttvTraceState
*tcs
);
115 static void create_name_tables(LttvTraceState
*tcs
);
117 static void get_name_tables(LttvTraceState
*tcs
);
119 static void free_name_tables(LttvTraceState
*tcs
);
121 static void free_saved_state(LttvTraceState
*tcs
);
123 static void lttv_state_free_process_table(GHashTable
*processes
);
126 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
128 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
132 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
134 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
138 void lttv_state_state_saved_free(LttvTraceState
*self
,
139 LttvAttribute
*container
)
141 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
145 guint
process_hash(gconstpointer key
)
147 guint pid
= ((const LttvProcessState
*)key
)->pid
;
148 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
152 /* If the hash table hash function is well distributed,
153 * the process_equal should compare different pid */
154 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
156 const LttvProcessState
*process_a
, *process_b
;
159 process_a
= (const LttvProcessState
*)a
;
160 process_b
= (const LttvProcessState
*)b
;
162 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
163 else if(likely(process_a
->pid
== 0 &&
164 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
171 restore_init_state(LttvTraceState
*self
)
175 LttvTracefileState
*tfcs
;
177 /* Free the process tables */
178 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
179 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
182 /* Seek time to beginning */
183 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
184 // closest. It's the tracecontext job to seek the trace to the beginning
185 // anyway : the init state might be used at the middle of the trace as well...
186 //g_tree_destroy(self->parent.ts_context->pqueue);
187 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
190 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
192 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
194 /* Put the per cpu running_process to beginning state : process 0. */
195 for(i
=0; i
< nb_cpus
; i
++) {
196 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
198 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
199 self
->running_process
[i
]->cpu
= i
;
203 nb_tracefile
= self
->parent
.tracefiles
->len
;
205 for(i
= 0 ; i
< nb_tracefile
; i
++) {
207 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
208 LttvTracefileContext
*, i
));
209 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
210 // tfcs->saved_position = 0;
211 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
212 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
213 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
214 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
219 //static LttTime time_zero = {0,0};
222 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
224 guint i
, j
, nb_trace
, nb_tracefile
;
226 LttvTraceContext
*tc
;
230 LttvTracefileState
*tfcs
;
232 LttvAttributeValue v
;
234 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
235 init((LttvTracesetContext
*)self
, ts
);
237 nb_trace
= lttv_traceset_number(ts
);
238 for(i
= 0 ; i
< nb_trace
; i
++) {
239 tc
= self
->parent
.traces
[i
];
240 tcs
= LTTV_TRACE_STATE(tc
);
241 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
242 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
246 if(*(v
.v_uint
) == 1) {
247 create_name_tables(tcs
);
248 create_max_time(tcs
);
250 get_name_tables(tcs
);
253 nb_tracefile
= tc
->tracefiles
->len
;
255 for(j
= 0 ; j
< nb_tracefile
; j
++) {
257 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
258 LttvTracefileContext
*, j
));
259 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
262 tcs
->processes
= NULL
;
263 tcs
->running_process
= g_new(LttvProcessState
*,
264 ltt_trace_get_num_cpu(tc
->t
));
265 restore_init_state(tcs
);
271 fini(LttvTracesetState
*self
)
277 LttvTracefileState
*tfcs
;
279 LttvAttributeValue v
;
281 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
282 for(i
= 0 ; i
< nb_trace
; i
++) {
283 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
284 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
287 g_assert(*(v
.v_uint
) != 0);
290 if(*(v
.v_uint
) == 0) {
291 free_name_tables(tcs
);
293 free_saved_state(tcs
);
295 g_free(tcs
->running_process
);
296 tcs
->running_process
= NULL
;
297 lttv_state_free_process_table(tcs
->processes
);
298 tcs
->processes
= NULL
;
300 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
301 fini((LttvTracesetContext
*)self
);
305 static LttvTracesetContext
*
306 new_traceset_context(LttvTracesetContext
*self
)
308 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
312 static LttvTraceContext
*
313 new_trace_context(LttvTracesetContext
*self
)
315 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
319 static LttvTracefileContext
*
320 new_tracefile_context(LttvTracesetContext
*self
)
322 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
326 /* Write the process state of the trace */
328 static void write_process_state(gpointer key
, gpointer value
,
331 LttvProcessState
*process
;
333 LttvExecutionState
*es
;
335 FILE *fp
= (FILE *)user_data
;
339 process
= (LttvProcessState
*)value
;
341 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
342 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
343 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
346 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
347 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
348 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
349 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
350 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
351 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
352 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
354 fprintf(fp
, " </PROCESS>\n");
358 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
360 guint i
, nb_tracefile
, nb_block
, offset
;
363 LttvTracefileState
*tfcs
;
367 LttEventPosition
*ep
;
371 ep
= ltt_event_position_new();
373 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
375 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
377 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
378 for(i
=0;i
<nb_cpus
;i
++) {
379 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
380 i
, self
->running_process
[i
]->pid
);
383 nb_tracefile
= self
->parent
.tracefiles
->len
;
385 for(i
= 0 ; i
< nb_tracefile
; i
++) {
387 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
388 LttvTracefileContext
*, i
));
389 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
390 tfcs
->parent
.timestamp
.tv_sec
,
391 tfcs
->parent
.timestamp
.tv_nsec
);
392 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
393 if(e
== NULL
) fprintf(fp
,"/>\n");
395 ltt_event_position(e
, ep
);
396 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
397 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
402 fprintf(fp
,"</PROCESS_STATE>");
406 /* Copy each process from an existing hash table to a new one */
408 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
410 LttvProcessState
*process
, *new_process
;
412 GHashTable
*new_processes
= (GHashTable
*)user_data
;
416 process
= (LttvProcessState
*)value
;
417 new_process
= g_new(LttvProcessState
, 1);
418 *new_process
= *process
;
419 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
420 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
421 new_process
->execution_stack
=
422 g_array_set_size(new_process
->execution_stack
,
423 process
->execution_stack
->len
);
424 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
425 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
426 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
428 new_process
->state
= &g_array_index(new_process
->execution_stack
,
429 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
430 g_hash_table_insert(new_processes
, new_process
, new_process
);
434 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
436 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
438 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
439 return new_processes
;
443 /* The saved state for each trace contains a member "processes", which
444 stores a copy of the process table, and a member "tracefiles" with
445 one entry per tracefile. Each tracefile has a "process" member pointing
446 to the current process and a "position" member storing the tracefile
447 position (needed to seek to the current "next" event. */
449 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
451 guint i
, nb_tracefile
, nb_cpus
;
453 LttvTracefileState
*tfcs
;
455 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
457 guint
*running_process
;
459 LttvAttributeType type
;
461 LttvAttributeValue value
;
463 LttvAttributeName name
;
465 LttEventPosition
*ep
;
467 tracefiles_tree
= lttv_attribute_find_subdir(container
,
468 LTTV_STATE_TRACEFILES
);
470 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
472 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
474 /* Add the currently running processes array */
475 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
476 running_process
= g_new(guint
, nb_cpus
);
477 for(i
=0;i
<nb_cpus
;i
++) {
478 running_process
[i
] = self
->running_process
[i
]->pid
;
480 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
482 *(value
.v_pointer
) = running_process
;
484 g_info("State save");
486 nb_tracefile
= self
->parent
.tracefiles
->len
;
488 for(i
= 0 ; i
< nb_tracefile
; i
++) {
490 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
491 LttvTracefileContext
*, i
));
492 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
493 value
= lttv_attribute_add(tracefiles_tree
, i
,
495 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
497 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
499 *(value
.v_uint
) = tfcs
->process
->pid
;
501 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
503 /* Only save the position if the tfs has not infinite time. */
504 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
505 // && current_tfcs != tfcs) {
506 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
507 *(value
.v_pointer
) = NULL
;
509 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
510 ep
= ltt_event_position_new();
511 ltt_event_position(e
, ep
);
512 *(value
.v_pointer
) = ep
;
514 guint nb_block
, offset
;
517 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
518 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
520 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
526 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
528 guint i
, nb_tracefile
, pid
, nb_cpus
;
530 LttvTracefileState
*tfcs
;
532 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
534 guint
*running_process
;
536 LttvAttributeType type
;
538 LttvAttributeValue value
;
540 LttvAttributeName name
;
542 LttEventPosition
*ep
;
544 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
546 tracefiles_tree
= lttv_attribute_find_subdir(container
,
547 LTTV_STATE_TRACEFILES
);
549 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
551 g_assert(type
== LTTV_POINTER
);
552 lttv_state_free_process_table(self
->processes
);
553 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
555 /* Add the currently running processes array */
556 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
557 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
559 g_assert(type
== LTTV_POINTER
);
560 running_process
= *(value
.v_pointer
);
561 for(i
=0;i
<nb_cpus
;i
++) {
562 pid
= running_process
[i
];
563 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
564 g_assert(self
->running_process
[i
] != NULL
);
568 nb_tracefile
= self
->parent
.tracefiles
->len
;
570 //g_tree_destroy(tsc->pqueue);
571 //tsc->pqueue = g_tree_new(compare_tracefile);
573 for(i
= 0 ; i
< nb_tracefile
; i
++) {
575 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
576 LttvTracefileContext
*, i
));
577 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
578 g_assert(type
== LTTV_GOBJECT
);
579 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
581 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
583 g_assert(type
== LTTV_UINT
);
584 pid
= *(value
.v_uint
);
585 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
587 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
589 g_assert(type
== LTTV_POINTER
);
590 //g_assert(*(value.v_pointer) != NULL);
591 ep
= *(value
.v_pointer
);
592 g_assert(tfcs
->parent
.t_context
!= NULL
);
594 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
595 g_tree_remove(tsc
->pqueue
, tfc
);
598 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
599 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
600 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
601 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
602 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
604 tfc
->timestamp
= ltt_time_infinite
;
610 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
612 guint i
, nb_tracefile
, nb_cpus
;
614 LttvTracefileState
*tfcs
;
616 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
618 guint
*running_process
;
620 LttvAttributeType type
;
622 LttvAttributeValue value
;
624 LttvAttributeName name
;
626 LttEventPosition
*ep
;
628 tracefiles_tree
= lttv_attribute_find_subdir(container
,
629 LTTV_STATE_TRACEFILES
);
630 g_object_ref(G_OBJECT(tracefiles_tree
));
631 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
633 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
635 g_assert(type
== LTTV_POINTER
);
636 lttv_state_free_process_table(*(value
.v_pointer
));
637 *(value
.v_pointer
) = NULL
;
638 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
640 /* Free running processes array */
641 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
642 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
644 g_assert(type
== LTTV_POINTER
);
645 running_process
= *(value
.v_pointer
);
646 g_free(running_process
);
648 nb_tracefile
= self
->parent
.tracefiles
->len
;
650 for(i
= 0 ; i
< nb_tracefile
; i
++) {
652 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
653 LttvTracefileContext
*, i
));
654 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
655 g_assert(type
== LTTV_GOBJECT
);
656 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
658 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
660 g_assert(type
== LTTV_POINTER
);
661 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
663 g_object_unref(G_OBJECT(tracefiles_tree
));
667 static void free_saved_state(LttvTraceState
*self
)
671 LttvAttributeType type
;
673 LttvAttributeValue value
;
675 LttvAttributeName name
;
677 LttvAttribute
*saved_states
;
679 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
680 LTTV_STATE_SAVED_STATES
);
682 nb
= lttv_attribute_get_number(saved_states
);
683 for(i
= 0 ; i
< nb
; i
++) {
684 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
685 g_assert(type
== LTTV_GOBJECT
);
686 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
689 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
694 create_max_time(LttvTraceState
*tcs
)
696 LttvAttributeValue v
;
698 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
700 g_assert(*(v
.v_pointer
) == NULL
);
701 *(v
.v_pointer
) = g_new(LttTime
,1);
702 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
707 get_max_time(LttvTraceState
*tcs
)
709 LttvAttributeValue v
;
711 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
713 g_assert(*(v
.v_pointer
) != NULL
);
714 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
719 free_max_time(LttvTraceState
*tcs
)
721 LttvAttributeValue v
;
723 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
725 g_free(*(v
.v_pointer
));
726 *(v
.v_pointer
) = NULL
;
730 typedef struct _LttvNameTables
{
731 // FIXME GQuark *eventtype_names;
732 GQuark
*syscall_names
;
735 GQuark
*soft_irq_names
;
740 create_name_tables(LttvTraceState
*tcs
)
744 GQuark f_name
, e_name
;
748 LttvTraceHookByFacility
*thf
;
754 GString
*fe_name
= g_string_new("");
756 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
758 LttvAttributeValue v
;
760 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
762 g_assert(*(v
.v_pointer
) == NULL
);
763 *(v
.v_pointer
) = name_tables
;
764 #if 0 // Use iteration over the facilities_by_name and then list all event
765 // types of each facility
766 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
767 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
768 for(i
= 0 ; i
< nb
; i
++) {
769 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
770 e_name
= ltt_eventtype_name(et
);
771 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
772 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
773 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
776 if(lttv_trace_find_hook(tcs
->parent
.t
,
777 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
778 LTT_FIELD_SYSCALL_ID
, 0, 0,
782 thf
= lttv_trace_hook_get_first(&h
);
784 t
= ltt_field_type(thf
->f1
);
785 nb
= ltt_type_element_number(t
);
787 lttv_trace_hook_destroy(&h
);
789 name_tables
->syscall_names
= g_new(GQuark
, nb
);
791 for(i
= 0 ; i
< nb
; i
++) {
792 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
795 //name_tables->syscall_names = g_new(GQuark, 256);
796 //for(i = 0 ; i < 256 ; i++) {
797 // g_string_printf(fe_name, "syscall %d", i);
798 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
801 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
802 LTT_EVENT_TRAP_ENTRY
,
803 LTT_FIELD_TRAP_ID
, 0, 0,
807 thf
= lttv_trace_hook_get_first(&h
);
809 t
= ltt_field_type(thf
->f1
);
810 //nb = ltt_type_element_number(t);
812 lttv_trace_hook_destroy(&h
);
815 name_tables->trap_names = g_new(GQuark, nb);
816 for(i = 0 ; i < nb ; i++) {
817 name_tables->trap_names[i] = g_quark_from_string(
818 ltt_enum_string_get(t, i));
822 name_tables
->trap_names
= g_new(GQuark
, 256);
823 for(i
= 0 ; i
< 256 ; i
++) {
824 g_string_printf(fe_name
, "trap %d", i
);
825 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
828 if(lttv_trace_find_hook(tcs
->parent
.t
,
829 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
830 LTT_FIELD_IRQ_ID
, 0, 0,
834 thf
= lttv_trace_hook_get_first(&h
);
836 t
= ltt_field_type(thf
->f1
);
837 //nb = ltt_type_element_number(t);
839 lttv_trace_hook_destroy(&h
);
842 name_tables->irq_names = g_new(GQuark, nb);
843 for(i = 0 ; i < nb ; i++) {
844 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
848 name_tables
->irq_names
= g_new(GQuark
, 256);
849 for(i
= 0 ; i
< 256 ; i
++) {
850 g_string_printf(fe_name
, "irq %d", i
);
851 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
855 name_tables->soft_irq_names = g_new(GQuark, nb);
856 for(i = 0 ; i < nb ; i++) {
857 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
861 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
862 for(i
= 0 ; i
< 256 ; i
++) {
863 g_string_printf(fe_name
, "softirq %d", i
);
864 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
868 g_string_free(fe_name
, TRUE
);
873 get_name_tables(LttvTraceState
*tcs
)
875 LttvNameTables
*name_tables
;
877 LttvAttributeValue v
;
879 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
881 g_assert(*(v
.v_pointer
) != NULL
);
882 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
883 //tcs->eventtype_names = name_tables->eventtype_names;
884 tcs
->syscall_names
= name_tables
->syscall_names
;
885 tcs
->trap_names
= name_tables
->trap_names
;
886 tcs
->irq_names
= name_tables
->irq_names
;
887 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
892 free_name_tables(LttvTraceState
*tcs
)
894 LttvNameTables
*name_tables
;
896 LttvAttributeValue v
;
898 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
900 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
901 *(v
.v_pointer
) = NULL
;
903 // g_free(name_tables->eventtype_names);
904 g_free(name_tables
->syscall_names
);
905 g_free(name_tables
->trap_names
);
906 g_free(name_tables
->irq_names
);
907 g_free(name_tables
->soft_irq_names
);
911 #ifdef HASH_TABLE_DEBUG
913 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
915 LttvProcessState
*process
= (LttvProcessState
*)value
;
917 /* Test for process corruption */
918 guint stack_len
= process
->execution_stack
->len
;
921 static void hash_table_check(GHashTable
*table
)
923 g_hash_table_foreach(table
, test_process
, NULL
);
930 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
933 LttvExecutionState
*es
;
935 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
936 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
938 #ifdef HASH_TABLE_DEBUG
939 hash_table_check(ts
->processes
);
941 LttvProcessState
*process
= ts
->running_process
[cpu
];
943 guint depth
= process
->execution_stack
->len
;
945 process
->execution_stack
=
946 g_array_set_size(process
->execution_stack
, depth
+ 1);
949 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
951 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
954 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
955 es
->s
= process
->state
->s
;
960 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
962 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
963 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
964 LttvProcessState
*process
= ts
->running_process
[cpu
];
966 guint depth
= process
->execution_stack
->len
;
968 if(process
->state
->t
!= t
){
969 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
970 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
971 g_info("process state has %s when pop_int is %s\n",
972 g_quark_to_string(process
->state
->t
),
973 g_quark_to_string(t
));
974 g_info("{ %u, %u, %s, %s }\n",
977 g_quark_to_string(process
->name
),
978 g_quark_to_string(process
->state
->s
));
983 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
984 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
988 process
->execution_stack
=
989 g_array_set_size(process
->execution_stack
, depth
- 1);
990 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
992 process
->state
->change
= tfs
->parent
.timestamp
;
997 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
998 guint cpu
, guint pid
, const LttTime
*timestamp
)
1000 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1002 LttvExecutionState
*es
;
1004 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1010 //process->last_cpu = tfs->cpu_name;
1011 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1012 g_info("Process %u, core %p", process
->pid
, process
);
1013 g_hash_table_insert(tcs
->processes
, process
, process
);
1016 process
->ppid
= parent
->pid
;
1017 process
->name
= parent
->name
;
1018 process
->creation_time
= *timestamp
;
1021 /* No parent. This process exists but we are missing all information about
1022 its creation. The birth time is set to zero but we remember the time of
1027 process
->name
= LTTV_STATE_UNNAMED
;
1028 process
->creation_time
= ltt_time_zero
;
1031 process
->insertion_time
= *timestamp
;
1032 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1033 process
->creation_time
.tv_nsec
);
1034 process
->pid_time
= g_quark_from_string(buffer
);
1036 //process->last_cpu = tfs->cpu_name;
1037 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1038 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1039 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1040 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1041 es
= process
->state
= &g_array_index(process
->execution_stack
,
1042 LttvExecutionState
, 0);
1043 es
->t
= LTTV_STATE_USER_MODE
;
1044 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1045 es
->entry
= *timestamp
;
1046 //g_assert(timestamp->tv_sec != 0);
1047 es
->change
= *timestamp
;
1048 es
->s
= LTTV_STATE_RUN
;
1050 es
= process
->state
= &g_array_index(process
->execution_stack
,
1051 LttvExecutionState
, 1);
1052 es
->t
= LTTV_STATE_SYSCALL
;
1053 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1054 es
->entry
= *timestamp
;
1055 //g_assert(timestamp->tv_sec != 0);
1056 es
->change
= *timestamp
;
1057 es
->s
= LTTV_STATE_WAIT_FORK
;
1062 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1065 LttvProcessState key
;
1066 LttvProcessState
*process
;
1070 process
= g_hash_table_lookup(ts
->processes
, &key
);
1075 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1078 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1080 /* Put ltt_time_zero creation time for unexisting processes */
1081 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1082 NULL
, cpu
, pid
, timestamp
);
1086 /* FIXME : this function should be called when we receive an event telling that
1087 * release_task has been called in the kernel. In happens generally when
1088 * the parent waits for its child terminaison, but may also happen in special
1089 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1090 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1091 * of a killed thread ground, but isn't the leader.
1093 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1095 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1096 LttvProcessState key
;
1098 key
.pid
= process
->pid
;
1099 key
.cpu
= process
->cpu
;
1100 g_hash_table_remove(ts
->processes
, &key
);
1101 g_array_free(process
->execution_stack
, TRUE
);
1106 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1108 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1113 static void lttv_state_free_process_table(GHashTable
*processes
)
1115 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1116 g_hash_table_destroy(processes
);
1120 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1122 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1123 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1124 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1125 LttField
*f
= thf
->f1
;
1127 LttvExecutionSubmode submode
;
1129 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1130 ltt_event_get_unsigned(e
, f
)];
1131 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1136 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1138 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1140 pop_state(s
, LTTV_STATE_SYSCALL
);
1145 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1147 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1148 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1149 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1150 LttField
*f
= thf
->f1
;
1152 LttvExecutionSubmode submode
;
1154 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1155 ltt_event_get_unsigned(e
, f
)];
1156 push_state(s
, LTTV_STATE_TRAP
, submode
);
1161 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1163 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1165 pop_state(s
, LTTV_STATE_TRAP
);
1170 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1172 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1173 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1174 guint8 fac_id
= ltt_event_facility_id(e
);
1175 guint8 ev_id
= ltt_event_eventtype_id(e
);
1176 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1177 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1178 g_assert(thf
->f1
!= NULL
);
1179 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1180 LttField
*f
= thf
->f1
;
1182 LttvExecutionSubmode submode
;
1184 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1185 ltt_event_get_unsigned(e
, f
)];
1187 /* Do something with the info about being in user or system mode when int? */
1188 push_state(s
, LTTV_STATE_IRQ
, submode
);
1193 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1195 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1197 pop_state(s
, LTTV_STATE_IRQ
);
1201 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1203 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1204 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1205 guint8 fac_id
= ltt_event_facility_id(e
);
1206 guint8 ev_id
= ltt_event_eventtype_id(e
);
1207 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1208 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1209 g_assert(thf
->f1
!= NULL
);
1210 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1211 LttField
*f
= thf
->f1
;
1213 LttvExecutionSubmode submode
;
1215 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1216 ltt_event_get_unsigned(e
, f
)];
1218 /* Do something with the info about being in user or system mode when int? */
1219 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1224 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1226 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1228 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1233 static gboolean
schedchange(void *hook_data
, void *call_data
)
1235 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1236 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1237 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1238 LttvProcessState
*process
= ts
->running_process
[cpu
];
1240 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1241 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1242 guint pid_in
, pid_out
;
1245 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1246 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1247 state_out
= ltt_event_get_int(e
, thf
->f3
);
1249 if(likely(process
!= NULL
)) {
1251 /* We could not know but it was not the idle process executing.
1252 This should only happen at the beginning, before the first schedule
1253 event, and when the initial information (current process for each CPU)
1254 is missing. It is not obvious how we could, after the fact, compensate
1255 the wrongly attributed statistics. */
1257 //This test only makes sense once the state is known and if there is no
1259 //if(unlikely(process->pid != pid_out)) {
1260 // g_assert(process->pid == 0);
1263 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1264 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1265 process
->state
->change
= s
->parent
.timestamp
;
1267 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1268 else process
->state
->s
= LTTV_STATE_WAIT
;
1269 process
->state
->change
= s
->parent
.timestamp
;
1273 exit_process(s
, process
); /* EXIT_DEAD */
1274 /* see sched.h for states */
1276 process
= ts
->running_process
[cpu
] =
1277 lttv_state_find_process_or_create(
1278 (LttvTraceState
*)s
->parent
.t_context
,
1280 &s
->parent
.timestamp
);
1281 process
->state
->s
= LTTV_STATE_RUN
;
1283 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1284 process
->state
->change
= s
->parent
.timestamp
;
1288 static gboolean
process_fork(void *hook_data
, void *call_data
)
1290 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1291 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1292 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1296 LttvProcessState
*zombie_process
;
1297 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1298 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1299 LttvProcessState
*process
= ts
->running_process
[cpu
];
1300 LttvProcessState
*child_process
;
1304 parent_pid
= ltt_event_get_unsigned(e
, f
);
1308 child_pid
= ltt_event_get_unsigned(e
, f
);
1310 /* Mathieu : it seems like the process might have been scheduled in before the
1311 * fork, and, in a rare case, might be the current process. This might happen
1312 * in a SMP case where we don't have enough precision on the clocks.
1314 * Test reenabled after precision fixes on time. (Mathieu) */
1316 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1318 if(unlikely(zombie_process
!= NULL
)) {
1319 /* Reutilisation of PID. Only now we are sure that the old PID
1320 * has been released. FIXME : should know when release_task happens instead.
1322 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1324 for(i
=0; i
< num_cpus
; i
++) {
1325 g_assert(zombie_process
!= ts
->running_process
[i
]);
1328 exit_process(s
, zombie_process
);
1331 g_assert(process
->pid
!= child_pid
);
1332 // FIXME : Add this test in the "known state" section
1333 // g_assert(process->pid == parent_pid);
1334 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1335 if(child_process
== NULL
) {
1336 lttv_state_create_process(ts
, process
, cpu
,
1337 child_pid
, &s
->parent
.timestamp
);
1339 /* The process has already been created : due to time imprecision between
1340 * multiple CPUs : it has been scheduled in before creation. Note that we
1341 * shouldn't have this kind of imprecision.
1343 * Simply put a correct parent.
1345 g_assert(0); /* This is a problematic case : the process has been created
1346 before the fork event */
1347 child_process
->ppid
= process
->pid
;
1354 static gboolean
process_exit(void *hook_data
, void *call_data
)
1356 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1357 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1358 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1361 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1362 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1363 LttvProcessState
*process
= ts
->running_process
[cpu
];
1365 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1367 // FIXME : Add this test in the "known state" section
1368 // g_assert(process->pid == pid);
1370 if(likely(process
!= NULL
)) {
1371 process
->state
->s
= LTTV_STATE_EXIT
;
1376 static gboolean
process_free(void *hook_data
, void *call_data
)
1378 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1379 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1380 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1381 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1383 LttvProcessState
*process
;
1385 /* PID of the process to release */
1386 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1388 g_assert(release_pid
!= 0);
1390 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1392 if(likely(process
!= NULL
)) {
1393 /* release_task is happening at kernel level : we can now safely release
1394 * the data structure of the process */
1395 //This test is fun, though, as it may happen that
1396 //at time t : CPU 0 : process_free
1397 //at time t+150ns : CPU 1 : schedule out
1398 //Clearly due to time imprecision, we disable it. (Mathieu)
1399 //If this weird case happen, we have no choice but to put the
1400 //Currently running process on the cpu to 0.
1401 //I re-enable it following time precision fixes. (Mathieu)
1402 //Well, in the case where an process is freed by a process on another CPU
1403 //and still scheduled, it happens that this is the schedchange that will
1404 //drop the last reference count. Do not free it here!
1405 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1407 for(i
=0; i
< num_cpus
; i
++) {
1408 //g_assert(process != ts->running_process[i]);
1409 if(process
== ts
->running_process
[i
]) {
1410 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1414 if(i
== num_cpus
) /* process is not scheduled */
1415 exit_process(s
, process
);
1422 static gboolean
process_exec(void *hook_data
, void *call_data
)
1424 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1425 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1426 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1427 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1429 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1430 LttvProcessState
*process
= ts
->running_process
[cpu
];
1432 /* PID of the process to release */
1433 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1434 //name = ltt_event_get_string(e, thf->f1);
1435 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1437 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1438 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1439 memcpy(null_term_name
, name_begin
, name_len
);
1440 null_term_name
[name_len
] = '\0';
1442 process
->name
= g_quark_from_string(null_term_name
);
1443 g_free(null_term_name
);
1450 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1452 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1454 lttv_state_add_event_hooks(tss
);
1459 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1461 LttvTraceset
*traceset
= self
->parent
.ts
;
1463 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1467 LttvTracefileState
*tfs
;
1471 LttvTraceHookByFacility
*thf
;
1473 LttvTraceHook
*hook
;
1475 LttvAttributeValue val
;
1479 nb_trace
= lttv_traceset_number(traceset
);
1480 for(i
= 0 ; i
< nb_trace
; i
++) {
1481 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1483 /* Find the eventtype id for the following events and register the
1484 associated by id hooks. */
1486 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 13);
1487 hooks
= g_array_set_size(hooks
, 13);
1489 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1490 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1491 LTT_FIELD_SYSCALL_ID
, 0, 0,
1492 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1495 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1496 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1498 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1501 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1502 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1503 LTT_FIELD_TRAP_ID
, 0, 0,
1504 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1507 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1508 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1510 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1513 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1514 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1515 LTT_FIELD_IRQ_ID
, 0, 0,
1516 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1519 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1520 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1522 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1525 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1526 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1527 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1528 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1531 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1532 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1534 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1537 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1538 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1539 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1540 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1543 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1544 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1545 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1546 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1549 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1550 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1551 LTT_FIELD_PID
, 0, 0,
1552 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1555 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1556 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1557 LTT_FIELD_PID
, 0, 0,
1558 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1561 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1562 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1563 LTT_FIELD_FILENAME
, 0, 0,
1564 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1569 /* Add these hooks to each event_by_id hooks list */
1571 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1573 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1575 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1576 LttvTracefileContext
*, j
));
1578 for(k
= 0 ; k
< hooks
->len
; k
++) {
1579 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1580 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1581 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1583 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1590 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1591 *(val
.v_pointer
) = hooks
;
1595 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1597 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1599 lttv_state_remove_event_hooks(tss
);
1604 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1606 LttvTraceset
*traceset
= self
->parent
.ts
;
1608 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1612 LttvTracefileState
*tfs
;
1616 LttvTraceHook
*hook
;
1618 LttvTraceHookByFacility
*thf
;
1620 LttvAttributeValue val
;
1622 nb_trace
= lttv_traceset_number(traceset
);
1623 for(i
= 0 ; i
< nb_trace
; i
++) {
1624 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1625 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1626 hooks
= *(val
.v_pointer
);
1628 /* Remove these hooks from each event_by_id hooks list */
1630 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1632 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1634 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1635 LttvTracefileContext
*, j
));
1637 for(k
= 0 ; k
< hooks
->len
; k
++) {
1638 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1639 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1640 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1642 lttv_hooks_remove_data(
1643 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1649 for(k
= 0 ; k
< hooks
->len
; k
++)
1650 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1651 g_array_free(hooks
, TRUE
);
1655 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1657 guint
*event_count
= (guint
*)hook_data
;
1659 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1660 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1665 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1667 LttvTracefileState
*tfcs
;
1669 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1671 LttEventPosition
*ep
;
1677 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1679 LttvAttributeValue value
;
1681 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1682 LTTV_STATE_SAVED_STATES
);
1683 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1684 value
= lttv_attribute_add(saved_states_tree
,
1685 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1686 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1687 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1688 *(value
.v_time
) = self
->parent
.timestamp
;
1689 lttv_state_save(tcs
, saved_state_tree
);
1690 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1691 self
->parent
.timestamp
.tv_nsec
);
1693 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1698 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1700 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1702 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1708 static gboolean
block_start(void *hook_data
, void *call_data
)
1710 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1712 LttvTracefileState
*tfcs
;
1714 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1716 LttEventPosition
*ep
;
1718 guint i
, nb_block
, nb_event
, nb_tracefile
;
1722 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1724 LttvAttributeValue value
;
1726 ep
= ltt_event_position_new();
1728 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1730 /* Count the number of events added since the last block end in any
1733 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1735 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1736 LttvTracefileContext
, i
));
1737 ltt_event_position(tfcs
->parent
.e
, ep
);
1738 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1739 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1740 tfcs
->saved_position
= nb_event
;
1744 if(tcs
->nb_event
>= tcs
->save_interval
) {
1745 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1746 LTTV_STATE_SAVED_STATES
);
1747 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1748 value
= lttv_attribute_add(saved_states_tree
,
1749 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1750 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1751 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1752 *(value
.v_time
) = self
->parent
.timestamp
;
1753 lttv_state_save(tcs
, saved_state_tree
);
1755 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1756 self
->parent
.timestamp
.tv_nsec
);
1758 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1764 static gboolean
block_end(void *hook_data
, void *call_data
)
1766 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1768 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1772 LttEventPosition
*ep
;
1774 guint nb_block
, nb_event
;
1776 ep
= ltt_event_position_new();
1777 ltt_event_position(self
->parent
.e
, ep
);
1778 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1779 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1780 self
->saved_position
= 0;
1781 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1788 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1790 LttvTraceset
*traceset
= self
->parent
.ts
;
1792 guint i
, j
, nb_trace
, nb_tracefile
;
1796 LttvTracefileState
*tfs
;
1798 LttvTraceHook hook_start
, hook_end
;
1800 nb_trace
= lttv_traceset_number(traceset
);
1801 for(i
= 0 ; i
< nb_trace
; i
++) {
1802 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1804 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1805 NULL
, NULL
, block_start
, &hook_start
);
1806 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1807 NULL
, NULL
, block_end
, &hook_end
);
1809 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1811 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1813 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1814 LttvTracefileContext
, j
));
1815 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1816 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1817 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1818 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1824 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1826 LttvTraceset
*traceset
= self
->parent
.ts
;
1828 guint i
, j
, nb_trace
, nb_tracefile
;
1832 LttvTracefileState
*tfs
;
1835 nb_trace
= lttv_traceset_number(traceset
);
1836 for(i
= 0 ; i
< nb_trace
; i
++) {
1838 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1839 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1841 guint
*event_count
= g_new(guint
, 1);
1844 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1846 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1847 LttvTracefileContext
*, j
));
1848 lttv_hooks_add(tfs
->parent
.event
,
1849 state_save_event_hook
,
1856 lttv_process_traceset_begin(&self
->parent
,
1857 NULL
, NULL
, NULL
, NULL
, NULL
);
1861 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1863 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1865 lttv_state_save_add_event_hooks(tss
);
1872 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1874 LttvTraceset
*traceset
= self
->parent
.ts
;
1876 guint i
, j
, nb_trace
, nb_tracefile
;
1880 LttvTracefileState
*tfs
;
1882 LttvTraceHook hook_start
, hook_end
;
1884 nb_trace
= lttv_traceset_number(traceset
);
1885 for(i
= 0 ; i
< nb_trace
; i
++) {
1886 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1888 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1889 NULL
, NULL
, block_start
, &hook_start
);
1891 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1892 NULL
, NULL
, block_end
, &hook_end
);
1894 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1896 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1898 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1899 LttvTracefileContext
, j
));
1900 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1901 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1902 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1903 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1909 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1911 LttvTraceset
*traceset
= self
->parent
.ts
;
1913 guint i
, j
, nb_trace
, nb_tracefile
;
1917 LttvTracefileState
*tfs
;
1919 LttvHooks
*after_trace
= lttv_hooks_new();
1921 lttv_hooks_add(after_trace
,
1922 state_save_after_trace_hook
,
1927 lttv_process_traceset_end(&self
->parent
,
1928 NULL
, after_trace
, NULL
, NULL
, NULL
);
1930 lttv_hooks_destroy(after_trace
);
1932 nb_trace
= lttv_traceset_number(traceset
);
1933 for(i
= 0 ; i
< nb_trace
; i
++) {
1935 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1936 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1938 guint
*event_count
= NULL
;
1940 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1942 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1943 LttvTracefileContext
*, j
));
1944 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
1945 state_save_event_hook
);
1947 if(event_count
) g_free(event_count
);
1951 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1953 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1955 lttv_state_save_remove_event_hooks(tss
);
1960 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
1962 LttvTraceset
*traceset
= self
->parent
.ts
;
1966 int min_pos
, mid_pos
, max_pos
;
1968 guint call_rest
= 0;
1970 LttvTraceState
*tcs
;
1972 LttvAttributeValue value
;
1974 LttvAttributeType type
;
1976 LttvAttributeName name
;
1978 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
1980 //g_tree_destroy(self->parent.pqueue);
1981 //self->parent.pqueue = g_tree_new(compare_tracefile);
1983 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
1985 nb_trace
= lttv_traceset_number(traceset
);
1986 for(i
= 0 ; i
< nb_trace
; i
++) {
1987 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
1989 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
1990 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1991 LTTV_STATE_SAVED_STATES
);
1994 if(saved_states_tree
) {
1995 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
1996 mid_pos
= max_pos
/ 2;
1997 while(min_pos
< max_pos
) {
1998 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
1999 g_assert(type
== LTTV_GOBJECT
);
2000 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2001 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2003 g_assert(type
== LTTV_TIME
);
2004 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2006 closest_tree
= saved_state_tree
;
2008 else max_pos
= mid_pos
- 1;
2010 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2014 /* restore the closest earlier saved state */
2016 lttv_state_restore(tcs
, closest_tree
);
2020 /* There is no saved state, yet we want to have it. Restart at T0 */
2022 restore_init_state(tcs
);
2023 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2026 /* We want to seek quickly without restoring/updating the state */
2028 restore_init_state(tcs
);
2029 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2032 if(!call_rest
) g_info("NOT Calling restore");
2037 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2043 traceset_state_finalize (LttvTracesetState
*self
)
2045 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2046 finalize(G_OBJECT(self
));
2051 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2053 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2055 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2056 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2057 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2058 klass
->new_traceset_context
= new_traceset_context
;
2059 klass
->new_trace_context
= new_trace_context
;
2060 klass
->new_tracefile_context
= new_tracefile_context
;
2065 lttv_traceset_state_get_type(void)
2067 static GType type
= 0;
2069 static const GTypeInfo info
= {
2070 sizeof (LttvTracesetStateClass
),
2071 NULL
, /* base_init */
2072 NULL
, /* base_finalize */
2073 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2074 NULL
, /* class_finalize */
2075 NULL
, /* class_data */
2076 sizeof (LttvTracesetState
),
2077 0, /* n_preallocs */
2078 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2079 NULL
/* value handling */
2082 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2090 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2096 trace_state_finalize (LttvTraceState
*self
)
2098 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2099 finalize(G_OBJECT(self
));
2104 trace_state_class_init (LttvTraceStateClass
*klass
)
2106 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2108 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2109 klass
->state_save
= state_save
;
2110 klass
->state_restore
= state_restore
;
2111 klass
->state_saved_free
= state_saved_free
;
2116 lttv_trace_state_get_type(void)
2118 static GType type
= 0;
2120 static const GTypeInfo info
= {
2121 sizeof (LttvTraceStateClass
),
2122 NULL
, /* base_init */
2123 NULL
, /* base_finalize */
2124 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2125 NULL
, /* class_finalize */
2126 NULL
, /* class_data */
2127 sizeof (LttvTraceState
),
2128 0, /* n_preallocs */
2129 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2130 NULL
/* value handling */
2133 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2134 "LttvTraceStateType", &info
, 0);
2141 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2147 tracefile_state_finalize (LttvTracefileState
*self
)
2149 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2150 finalize(G_OBJECT(self
));
2155 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2157 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2159 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2164 lttv_tracefile_state_get_type(void)
2166 static GType type
= 0;
2168 static const GTypeInfo info
= {
2169 sizeof (LttvTracefileStateClass
),
2170 NULL
, /* base_init */
2171 NULL
, /* base_finalize */
2172 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2173 NULL
, /* class_finalize */
2174 NULL
, /* class_data */
2175 sizeof (LttvTracefileState
),
2176 0, /* n_preallocs */
2177 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2178 NULL
/* value handling */
2181 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2182 "LttvTracefileStateType", &info
, 0);
2188 static void module_init()
2190 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2191 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("unknown execution mode");
2192 LTTV_STATE_USER_MODE
= g_quark_from_string("user mode");
2193 LTTV_STATE_WAIT_FORK
= g_quark_from_string("wait fork");
2194 LTTV_STATE_SYSCALL
= g_quark_from_string("system call");
2195 LTTV_STATE_TRAP
= g_quark_from_string("trap");
2196 LTTV_STATE_IRQ
= g_quark_from_string("irq");
2197 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("softirq");
2198 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("unknown submode");
2199 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("(no submode)");
2200 LTTV_STATE_WAIT_CPU
= g_quark_from_string("wait for cpu");
2201 LTTV_STATE_EXIT
= g_quark_from_string("exiting");
2202 LTTV_STATE_ZOMBIE
= g_quark_from_string("zombie");
2203 LTTV_STATE_WAIT
= g_quark_from_string("wait for I/O");
2204 LTTV_STATE_RUN
= g_quark_from_string("running");
2205 LTTV_STATE_DEAD
= g_quark_from_string("dead");
2206 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2207 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2208 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2209 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2210 LTTV_STATE_EVENT
= g_quark_from_string("event");
2211 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2212 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2213 LTTV_STATE_TIME
= g_quark_from_string("time");
2214 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2215 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2216 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2217 g_quark_from_string("trace_state_use_count");
2220 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2221 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2222 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2223 LTT_FACILITY_FS
= g_quark_from_string("fs");
2226 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2227 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2228 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2229 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2230 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2231 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2232 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2233 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2234 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2235 LTT_EVENT_FORK
= g_quark_from_string("fork");
2236 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2237 LTT_EVENT_FREE
= g_quark_from_string("free");
2238 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2241 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2242 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2243 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2244 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2245 LTT_FIELD_OUT
= g_quark_from_string("out");
2246 LTT_FIELD_IN
= g_quark_from_string("in");
2247 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2248 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2249 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2250 LTT_FIELD_PID
= g_quark_from_string("pid");
2251 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2255 static void module_destroy()
2260 LTTV_MODULE("state", "State computation", \
2261 "Update the system state, possibly saving it at intervals", \
2262 module_init
, module_destroy
)