1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
33 #define PREALLOCATED_EXECUTION_STACK 10
35 /* Facilities Quarks */
39 LTT_FACILITY_KERNEL_ARCH
,
42 LTT_FACILITY_STATEDUMP
,
43 LTT_FACILITY_USER_GENERIC
;
48 LTT_EVENT_SYSCALL_ENTRY
,
49 LTT_EVENT_SYSCALL_EXIT
,
54 LTT_EVENT_SOFT_IRQ_ENTRY
,
55 LTT_EVENT_SOFT_IRQ_EXIT
,
56 LTT_EVENT_SCHEDCHANGE
,
58 LTT_EVENT_KERNEL_THREAD
,
62 LTT_EVENT_ENUM_PROCESS_STATE
,
63 LTT_EVENT_FUNCTION_ENTRY
,
64 LTT_EVENT_FUNCTION_EXIT
;
72 LTT_FIELD_SOFT_IRQ_ID
,
88 LTTV_STATE_MODE_UNKNOWN
,
96 LTTV_STATE_SUBMODE_UNKNOWN
,
97 LTTV_STATE_SUBMODE_NONE
;
101 LTTV_STATE_WAIT_FORK
,
110 LTTV_STATE_TRACEFILES
,
111 LTTV_STATE_PROCESSES
,
113 LTTV_STATE_RUNNING_PROCESS
,
115 LTTV_STATE_SAVED_STATES
,
116 LTTV_STATE_SAVED_STATES_TIME
,
119 LTTV_STATE_NAME_TABLES
,
120 LTTV_STATE_TRACE_STATE_USE_COUNT
;
122 static void create_max_time(LttvTraceState
*tcs
);
124 static void get_max_time(LttvTraceState
*tcs
);
126 static void free_max_time(LttvTraceState
*tcs
);
128 static void create_name_tables(LttvTraceState
*tcs
);
130 static void get_name_tables(LttvTraceState
*tcs
);
132 static void free_name_tables(LttvTraceState
*tcs
);
134 static void free_saved_state(LttvTraceState
*tcs
);
136 static void lttv_state_free_process_table(GHashTable
*processes
);
139 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
141 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
145 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
147 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
151 void lttv_state_state_saved_free(LttvTraceState
*self
,
152 LttvAttribute
*container
)
154 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
158 guint
process_hash(gconstpointer key
)
160 guint pid
= ((const LttvProcessState
*)key
)->pid
;
161 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
165 /* If the hash table hash function is well distributed,
166 * the process_equal should compare different pid */
167 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
169 const LttvProcessState
*process_a
, *process_b
;
172 process_a
= (const LttvProcessState
*)a
;
173 process_b
= (const LttvProcessState
*)b
;
175 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
176 else if(likely(process_a
->pid
== 0 &&
177 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
182 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
184 g_tree_destroy((GTree
*)value
);
187 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
189 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
190 g_hash_table_destroy(usertraces
);
196 restore_init_state(LttvTraceState
*self
)
200 LttvTracefileState
*tfcs
;
202 /* Free the process tables */
203 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
204 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
205 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
206 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
209 /* Seek time to beginning */
210 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
211 // closest. It's the tracecontext job to seek the trace to the beginning
212 // anyway : the init state might be used at the middle of the trace as well...
213 //g_tree_destroy(self->parent.ts_context->pqueue);
214 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
217 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
219 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
221 /* Put the per cpu running_process to beginning state : process 0. */
222 for(i
=0; i
< nb_cpus
; i
++) {
223 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
224 LTTV_STATE_UNNAMED
, <t_time_zero
);
225 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
226 self
->running_process
[i
]->cpu
= i
;
230 nb_tracefile
= self
->parent
.tracefiles
->len
;
232 for(i
= 0 ; i
< nb_tracefile
; i
++) {
234 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
235 LttvTracefileContext
*, i
));
236 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
237 // tfcs->saved_position = 0;
238 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
239 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
240 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
241 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
246 //static LttTime time_zero = {0,0};
248 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
251 const LttTime
*t1
= (const LttTime
*)a
;
252 const LttTime
*t2
= (const LttTime
*)b
;
254 return ltt_time_compare(*t1
, *t2
);
257 static void free_usertrace_key(gpointer data
)
263 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
265 guint i
, j
, nb_trace
, nb_tracefile
;
267 LttvTraceContext
*tc
;
271 LttvTracefileState
*tfcs
;
273 LttvAttributeValue v
;
275 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
276 init((LttvTracesetContext
*)self
, ts
);
278 nb_trace
= lttv_traceset_number(ts
);
279 for(i
= 0 ; i
< nb_trace
; i
++) {
280 tc
= self
->parent
.traces
[i
];
281 tcs
= LTTV_TRACE_STATE(tc
);
282 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
283 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
287 if(*(v
.v_uint
) == 1) {
288 create_name_tables(tcs
);
289 create_max_time(tcs
);
291 get_name_tables(tcs
);
294 nb_tracefile
= tc
->tracefiles
->len
;
295 tcs
->processes
= NULL
;
296 tcs
->usertraces
= NULL
;
297 tcs
->running_process
= g_new(LttvProcessState
*,
298 ltt_trace_get_num_cpu(tc
->t
));
299 restore_init_state(tcs
);
300 for(j
= 0 ; j
< nb_tracefile
; j
++) {
302 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
303 LttvTracefileContext
*, j
));
304 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
305 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
307 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
308 /* It's a Usertrace */
309 LttvProcessState
*process
;
311 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
312 ltt_tracefile_creation(tfcs
->parent
.tf
));
313 process
= lttv_state_find_process_or_create(
315 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
317 process
->usertrace
= tfcs
;
321 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
322 /* It's a Usertrace */
323 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
324 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
326 if(!usertrace_tree
) {
327 usertrace_tree
= g_tree_new_full(compare_usertraces
,
328 NULL
, free_usertrace_key
, NULL
);
329 g_hash_table_insert(tcs
->usertraces
,
330 (gpointer
)tid
, usertrace_tree
);
332 LttTime
*timestamp
= g_new(LttTime
, 1);
333 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
334 ltt_tracefile_creation(tfcs
->parent
.tf
));
335 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
343 fini(LttvTracesetState
*self
)
349 LttvTracefileState
*tfcs
;
351 LttvAttributeValue v
;
353 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
354 for(i
= 0 ; i
< nb_trace
; i
++) {
355 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
356 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
359 g_assert(*(v
.v_uint
) != 0);
362 if(*(v
.v_uint
) == 0) {
363 free_name_tables(tcs
);
365 free_saved_state(tcs
);
367 g_free(tcs
->running_process
);
368 tcs
->running_process
= NULL
;
369 lttv_state_free_process_table(tcs
->processes
);
370 lttv_state_free_usertraces(tcs
->usertraces
);
371 tcs
->processes
= NULL
;
372 tcs
->usertraces
= NULL
;
374 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
375 fini((LttvTracesetContext
*)self
);
379 static LttvTracesetContext
*
380 new_traceset_context(LttvTracesetContext
*self
)
382 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
386 static LttvTraceContext
*
387 new_trace_context(LttvTracesetContext
*self
)
389 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
393 static LttvTracefileContext
*
394 new_tracefile_context(LttvTracesetContext
*self
)
396 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
400 /* Write the process state of the trace */
402 static void write_process_state(gpointer key
, gpointer value
,
405 LttvProcessState
*process
;
407 LttvExecutionState
*es
;
409 FILE *fp
= (FILE *)user_data
;
413 process
= (LttvProcessState
*)value
;
415 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
416 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
417 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
420 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
421 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
422 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
423 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
424 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
425 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
426 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
428 fprintf(fp
, " </PROCESS>\n");
432 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
434 guint i
, nb_tracefile
, nb_block
, offset
;
437 LttvTracefileState
*tfcs
;
441 LttEventPosition
*ep
;
445 ep
= ltt_event_position_new();
447 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
449 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
451 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
452 for(i
=0;i
<nb_cpus
;i
++) {
453 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
454 i
, self
->running_process
[i
]->pid
);
457 nb_tracefile
= self
->parent
.tracefiles
->len
;
459 for(i
= 0 ; i
< nb_tracefile
; i
++) {
461 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
462 LttvTracefileContext
*, i
));
463 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
464 tfcs
->parent
.timestamp
.tv_sec
,
465 tfcs
->parent
.timestamp
.tv_nsec
);
466 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
467 if(e
== NULL
) fprintf(fp
,"/>\n");
469 ltt_event_position(e
, ep
);
470 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
471 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
476 fprintf(fp
,"</PROCESS_STATE>");
480 /* Copy each process from an existing hash table to a new one */
482 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
484 LttvProcessState
*process
, *new_process
;
486 GHashTable
*new_processes
= (GHashTable
*)user_data
;
490 process
= (LttvProcessState
*)value
;
491 new_process
= g_new(LttvProcessState
, 1);
492 *new_process
= *process
;
493 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
494 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
495 new_process
->execution_stack
=
496 g_array_set_size(new_process
->execution_stack
,
497 process
->execution_stack
->len
);
498 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
499 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
500 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
502 new_process
->state
= &g_array_index(new_process
->execution_stack
,
503 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
504 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
506 new_process
->user_stack
=
507 g_array_set_size(new_process
->user_stack
,
508 process
->user_stack
->len
);
509 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
510 g_array_index(new_process
->user_stack
, guint64
, i
) =
511 g_array_index(process
->user_stack
, guint64
, i
);
513 new_process
->current_function
= process
->current_function
;
514 g_hash_table_insert(new_processes
, new_process
, new_process
);
518 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
520 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
522 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
523 return new_processes
;
527 /* The saved state for each trace contains a member "processes", which
528 stores a copy of the process table, and a member "tracefiles" with
529 one entry per tracefile. Each tracefile has a "process" member pointing
530 to the current process and a "position" member storing the tracefile
531 position (needed to seek to the current "next" event. */
533 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
535 guint i
, nb_tracefile
, nb_cpus
;
537 LttvTracefileState
*tfcs
;
539 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
541 guint
*running_process
;
543 LttvAttributeType type
;
545 LttvAttributeValue value
;
547 LttvAttributeName name
;
549 LttEventPosition
*ep
;
551 tracefiles_tree
= lttv_attribute_find_subdir(container
,
552 LTTV_STATE_TRACEFILES
);
554 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
556 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
558 /* Add the currently running processes array */
559 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
560 running_process
= g_new(guint
, nb_cpus
);
561 for(i
=0;i
<nb_cpus
;i
++) {
562 running_process
[i
] = self
->running_process
[i
]->pid
;
564 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
566 *(value
.v_pointer
) = running_process
;
568 g_info("State save");
570 nb_tracefile
= self
->parent
.tracefiles
->len
;
572 for(i
= 0 ; i
< nb_tracefile
; i
++) {
574 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
575 LttvTracefileContext
*, i
));
576 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
577 value
= lttv_attribute_add(tracefiles_tree
, i
,
579 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
581 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
583 *(value
.v_uint
) = tfcs
->process
->pid
;
585 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
587 /* Only save the position if the tfs has not infinite time. */
588 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
589 // && current_tfcs != tfcs) {
590 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
591 *(value
.v_pointer
) = NULL
;
593 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
594 ep
= ltt_event_position_new();
595 ltt_event_position(e
, ep
);
596 *(value
.v_pointer
) = ep
;
598 guint nb_block
, offset
;
601 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
602 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
604 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
610 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
612 guint i
, nb_tracefile
, pid
, nb_cpus
;
614 LttvTracefileState
*tfcs
;
616 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
618 guint
*running_process
;
620 LttvAttributeType type
;
622 LttvAttributeValue value
;
624 LttvAttributeName name
;
628 LttEventPosition
*ep
;
630 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
632 tracefiles_tree
= lttv_attribute_find_subdir(container
,
633 LTTV_STATE_TRACEFILES
);
635 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
637 g_assert(type
== LTTV_POINTER
);
638 lttv_state_free_process_table(self
->processes
);
639 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
641 /* Add the currently running processes array */
642 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
643 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
645 g_assert(type
== LTTV_POINTER
);
646 running_process
= *(value
.v_pointer
);
647 for(i
=0;i
<nb_cpus
;i
++) {
648 pid
= running_process
[i
];
649 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
650 g_assert(self
->running_process
[i
] != NULL
);
654 nb_tracefile
= self
->parent
.tracefiles
->len
;
656 //g_tree_destroy(tsc->pqueue);
657 //tsc->pqueue = g_tree_new(compare_tracefile);
659 for(i
= 0 ; i
< nb_tracefile
; i
++) {
661 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
662 LttvTracefileContext
*, i
));
663 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
664 g_assert(type
== LTTV_GOBJECT
);
665 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
667 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
669 g_assert(type
== LTTV_UINT
);
670 pid
= *(value
.v_uint
);
671 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
673 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
675 g_assert(type
== LTTV_POINTER
);
676 //g_assert(*(value.v_pointer) != NULL);
677 ep
= *(value
.v_pointer
);
678 g_assert(tfcs
->parent
.t_context
!= NULL
);
680 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
681 g_tree_remove(tsc
->pqueue
, tfc
);
684 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
685 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
686 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
687 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
688 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
690 tfc
->timestamp
= ltt_time_infinite
;
696 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
698 guint i
, nb_tracefile
, nb_cpus
;
700 LttvTracefileState
*tfcs
;
702 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
704 guint
*running_process
;
706 LttvAttributeType type
;
708 LttvAttributeValue value
;
710 LttvAttributeName name
;
714 LttEventPosition
*ep
;
716 tracefiles_tree
= lttv_attribute_find_subdir(container
,
717 LTTV_STATE_TRACEFILES
);
718 g_object_ref(G_OBJECT(tracefiles_tree
));
719 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
721 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
723 g_assert(type
== LTTV_POINTER
);
724 lttv_state_free_process_table(*(value
.v_pointer
));
725 *(value
.v_pointer
) = NULL
;
726 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
728 /* Free running processes array */
729 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
732 g_assert(type
== LTTV_POINTER
);
733 running_process
= *(value
.v_pointer
);
734 g_free(running_process
);
736 nb_tracefile
= self
->parent
.tracefiles
->len
;
738 for(i
= 0 ; i
< nb_tracefile
; i
++) {
740 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
741 LttvTracefileContext
*, i
));
742 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
743 g_assert(type
== LTTV_GOBJECT
);
744 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
746 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
748 g_assert(type
== LTTV_POINTER
);
749 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
751 g_object_unref(G_OBJECT(tracefiles_tree
));
755 static void free_saved_state(LttvTraceState
*self
)
759 LttvAttributeType type
;
761 LttvAttributeValue value
;
763 LttvAttributeName name
;
767 LttvAttribute
*saved_states
;
769 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
770 LTTV_STATE_SAVED_STATES
);
772 nb
= lttv_attribute_get_number(saved_states
);
773 for(i
= 0 ; i
< nb
; i
++) {
774 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
775 g_assert(type
== LTTV_GOBJECT
);
776 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
779 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
784 create_max_time(LttvTraceState
*tcs
)
786 LttvAttributeValue v
;
788 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
790 g_assert(*(v
.v_pointer
) == NULL
);
791 *(v
.v_pointer
) = g_new(LttTime
,1);
792 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
797 get_max_time(LttvTraceState
*tcs
)
799 LttvAttributeValue v
;
801 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
803 g_assert(*(v
.v_pointer
) != NULL
);
804 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
809 free_max_time(LttvTraceState
*tcs
)
811 LttvAttributeValue v
;
813 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
815 g_free(*(v
.v_pointer
));
816 *(v
.v_pointer
) = NULL
;
820 typedef struct _LttvNameTables
{
821 // FIXME GQuark *eventtype_names;
822 GQuark
*syscall_names
;
826 GQuark
*soft_irq_names
;
831 create_name_tables(LttvTraceState
*tcs
)
835 GQuark f_name
, e_name
;
839 LttvTraceHookByFacility
*thf
;
845 GString
*fe_name
= g_string_new("");
847 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
849 LttvAttributeValue v
;
851 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
853 g_assert(*(v
.v_pointer
) == NULL
);
854 *(v
.v_pointer
) = name_tables
;
855 #if 0 // Use iteration over the facilities_by_name and then list all event
856 // types of each facility
857 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
858 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
859 for(i
= 0 ; i
< nb
; i
++) {
860 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
861 e_name
= ltt_eventtype_name(et
);
862 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
863 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
864 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
867 if(!lttv_trace_find_hook(tcs
->parent
.t
,
868 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
869 LTT_FIELD_SYSCALL_ID
, 0, 0,
872 thf
= lttv_trace_hook_get_first(&h
);
874 t
= ltt_field_type(thf
->f1
);
875 nb
= ltt_type_element_number(t
);
877 lttv_trace_hook_destroy(&h
);
879 name_tables
->syscall_names
= g_new(GQuark
, nb
);
880 name_tables
->nb_syscalls
= nb
;
882 for(i
= 0 ; i
< nb
; i
++) {
883 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
886 //name_tables->syscall_names = g_new(GQuark, 256);
887 //for(i = 0 ; i < 256 ; i++) {
888 // g_string_printf(fe_name, "syscall %d", i);
889 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
892 name_tables
->syscall_names
= NULL
;
893 name_tables
->nb_syscalls
= 0;
896 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
897 LTT_EVENT_TRAP_ENTRY
,
898 LTT_FIELD_TRAP_ID
, 0, 0,
901 thf
= lttv_trace_hook_get_first(&h
);
903 t
= ltt_field_type(thf
->f1
);
904 //nb = ltt_type_element_number(t);
906 lttv_trace_hook_destroy(&h
);
909 name_tables->trap_names = g_new(GQuark, nb);
910 for(i = 0 ; i < nb ; i++) {
911 name_tables->trap_names[i] = g_quark_from_string(
912 ltt_enum_string_get(t, i));
916 name_tables
->trap_names
= g_new(GQuark
, 256);
917 for(i
= 0 ; i
< 256 ; i
++) {
918 g_string_printf(fe_name
, "trap %d", i
);
919 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
922 name_tables
->trap_names
= NULL
;
925 if(!lttv_trace_find_hook(tcs
->parent
.t
,
926 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
927 LTT_FIELD_IRQ_ID
, 0, 0,
930 thf
= lttv_trace_hook_get_first(&h
);
932 t
= ltt_field_type(thf
->f1
);
933 //nb = ltt_type_element_number(t);
935 lttv_trace_hook_destroy(&h
);
938 name_tables->irq_names = g_new(GQuark, nb);
939 for(i = 0 ; i < nb ; i++) {
940 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
944 name_tables
->irq_names
= g_new(GQuark
, 256);
945 for(i
= 0 ; i
< 256 ; i
++) {
946 g_string_printf(fe_name
, "irq %d", i
);
947 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
950 name_tables
->irq_names
= NULL
;
953 name_tables->soft_irq_names = g_new(GQuark, nb);
954 for(i = 0 ; i < nb ; i++) {
955 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
959 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
960 for(i
= 0 ; i
< 256 ; i
++) {
961 g_string_printf(fe_name
, "softirq %d", i
);
962 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
966 g_string_free(fe_name
, TRUE
);
971 get_name_tables(LttvTraceState
*tcs
)
973 LttvNameTables
*name_tables
;
975 LttvAttributeValue v
;
977 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
979 g_assert(*(v
.v_pointer
) != NULL
);
980 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
981 //tcs->eventtype_names = name_tables->eventtype_names;
982 tcs
->syscall_names
= name_tables
->syscall_names
;
983 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
984 tcs
->trap_names
= name_tables
->trap_names
;
985 tcs
->irq_names
= name_tables
->irq_names
;
986 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
991 free_name_tables(LttvTraceState
*tcs
)
993 LttvNameTables
*name_tables
;
995 LttvAttributeValue v
;
997 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
999 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1000 *(v
.v_pointer
) = NULL
;
1002 // g_free(name_tables->eventtype_names);
1003 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1004 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1005 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1006 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1007 if(name_tables
) g_free(name_tables
);
1010 #ifdef HASH_TABLE_DEBUG
1012 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1014 LttvProcessState
*process
= (LttvProcessState
*)value
;
1016 /* Test for process corruption */
1017 guint stack_len
= process
->execution_stack
->len
;
1020 static void hash_table_check(GHashTable
*table
)
1022 g_hash_table_foreach(table
, test_process
, NULL
);
1029 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1032 LttvExecutionState
*es
;
1034 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1035 guint cpu
= tfs
->cpu
;
1037 #ifdef HASH_TABLE_DEBUG
1038 hash_table_check(ts
->processes
);
1040 LttvProcessState
*process
= ts
->running_process
[cpu
];
1042 guint depth
= process
->execution_stack
->len
;
1044 process
->execution_stack
=
1045 g_array_set_size(process
->execution_stack
, depth
+ 1);
1048 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1050 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1053 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1054 es
->cum_cpu_time
= ltt_time_zero
;
1055 es
->s
= process
->state
->s
;
1056 process
->state
= es
;
1060 * return 1 when empty, else 0 */
1061 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1062 LttvTracefileState
*tfs
)
1064 guint cpu
= tfs
->cpu
;
1065 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1067 guint depth
= process
->execution_stack
->len
;
1073 process
->execution_stack
=
1074 g_array_set_size(process
->execution_stack
, depth
- 1);
1075 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1077 process
->state
->change
= tfs
->parent
.timestamp
;
1082 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1084 guint cpu
= tfs
->cpu
;
1085 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1086 LttvProcessState
*process
= ts
->running_process
[cpu
];
1088 guint depth
= process
->execution_stack
->len
;
1090 if(process
->state
->t
!= t
){
1091 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1092 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1093 g_info("process state has %s when pop_int is %s\n",
1094 g_quark_to_string(process
->state
->t
),
1095 g_quark_to_string(t
));
1096 g_info("{ %u, %u, %s, %s }\n",
1099 g_quark_to_string(process
->name
),
1100 g_quark_to_string(process
->state
->s
));
1105 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1106 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1110 process
->execution_stack
=
1111 g_array_set_size(process
->execution_stack
, depth
- 1);
1112 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1114 process
->state
->change
= tfs
->parent
.timestamp
;
1117 struct search_result
{
1118 const LttTime
*time
; /* Requested time */
1119 LttTime
*best
; /* Best result */
1122 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1124 const LttTime
*elem_time
= (const LttTime
*)a
;
1125 /* Explicit non const cast */
1126 struct search_result
*res
= (struct search_result
*)b
;
1128 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1129 /* The usertrace was created before the schedchange */
1130 /* Get larger keys */
1132 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1133 /* The usertrace was created after the schedchange time */
1134 /* Get smaller keys */
1136 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1137 res
->best
= elem_time
;
1140 res
->best
= elem_time
;
1147 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1148 guint pid
, const LttTime
*timestamp
)
1150 LttvTracefileState
*tfs
= NULL
;
1151 struct search_result res
;
1152 /* Find the usertrace associated with a pid and time interval.
1153 * Search in the usertraces by PID (within a hash) and then, for each
1154 * corresponding element of the array, find the first one with creation
1155 * timestamp the lowest, but higher or equal to "timestamp". */
1156 res
.time
= timestamp
;
1158 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1159 if(usertrace_tree
) {
1160 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1162 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1170 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1171 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1173 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1175 LttvExecutionState
*es
;
1177 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1183 process
->name
= name
;
1184 //process->last_cpu = tfs->cpu_name;
1185 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1186 process
->kernel_thread
= 0;
1187 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1188 process
->current_function
= 0; //function 0x0 by default.
1190 g_info("Process %u, core %p", process
->pid
, process
);
1191 g_hash_table_insert(tcs
->processes
, process
, process
);
1194 process
->ppid
= parent
->pid
;
1195 process
->creation_time
= *timestamp
;
1198 /* No parent. This process exists but we are missing all information about
1199 its creation. The birth time is set to zero but we remember the time of
1204 process
->creation_time
= ltt_time_zero
;
1207 process
->insertion_time
= *timestamp
;
1208 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1209 process
->creation_time
.tv_nsec
);
1210 process
->pid_time
= g_quark_from_string(buffer
);
1212 //process->last_cpu = tfs->cpu_name;
1213 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1214 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1215 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1216 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1217 es
= process
->state
= &g_array_index(process
->execution_stack
,
1218 LttvExecutionState
, 0);
1219 es
->t
= LTTV_STATE_USER_MODE
;
1220 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1221 es
->entry
= *timestamp
;
1222 //g_assert(timestamp->tv_sec != 0);
1223 es
->change
= *timestamp
;
1224 es
->cum_cpu_time
= ltt_time_zero
;
1225 es
->s
= LTTV_STATE_RUN
;
1227 es
= process
->state
= &g_array_index(process
->execution_stack
,
1228 LttvExecutionState
, 1);
1229 es
->t
= LTTV_STATE_SYSCALL
;
1230 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1231 es
->entry
= *timestamp
;
1232 //g_assert(timestamp->tv_sec != 0);
1233 es
->change
= *timestamp
;
1234 es
->cum_cpu_time
= ltt_time_zero
;
1235 es
->s
= LTTV_STATE_WAIT_FORK
;
1237 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1238 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1239 sizeof(guint64
), 0);
1244 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1247 LttvProcessState key
;
1248 LttvProcessState
*process
;
1252 process
= g_hash_table_lookup(ts
->processes
, &key
);
1257 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1260 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1261 LttvExecutionState
*es
;
1263 /* Put ltt_time_zero creation time for unexisting processes */
1264 if(unlikely(process
== NULL
)) {
1265 process
= lttv_state_create_process(ts
,
1266 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1267 /* We are not sure is it's a kernel thread or normal thread, put the
1268 * bottom stack state to unknown */
1269 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1270 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1275 /* FIXME : this function should be called when we receive an event telling that
1276 * release_task has been called in the kernel. In happens generally when
1277 * the parent waits for its child terminaison, but may also happen in special
1278 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1279 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1280 * of a killed thread ground, but isn't the leader.
1282 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1284 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1285 LttvProcessState key
;
1287 key
.pid
= process
->pid
;
1288 key
.cpu
= process
->cpu
;
1289 g_hash_table_remove(ts
->processes
, &key
);
1290 g_array_free(process
->execution_stack
, TRUE
);
1291 g_array_free(process
->user_stack
, TRUE
);
1296 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1298 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1299 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1304 static void lttv_state_free_process_table(GHashTable
*processes
)
1306 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1307 g_hash_table_destroy(processes
);
1311 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1313 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1314 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1315 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1316 LttField
*f
= thf
->f1
;
1318 LttvExecutionSubmode submode
;
1320 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1321 guint syscall
= ltt_event_get_unsigned(e
, f
);
1323 if(syscall
< nb_syscalls
) {
1324 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1327 /* Fixup an incomplete syscall table */
1328 GString
*string
= g_string_new("");
1329 g_string_printf(string
, "syscall %u", syscall
);
1330 submode
= g_quark_from_string(string
->str
);
1331 g_string_free(string
, TRUE
);
1333 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1338 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1340 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1342 pop_state(s
, LTTV_STATE_SYSCALL
);
1347 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1349 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1350 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1351 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1352 LttField
*f
= thf
->f1
;
1354 LttvExecutionSubmode submode
;
1356 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1357 ltt_event_get_unsigned(e
, f
)];
1358 push_state(s
, LTTV_STATE_TRAP
, submode
);
1363 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1365 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1367 pop_state(s
, LTTV_STATE_TRAP
);
1372 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1374 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1375 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1376 guint8 fac_id
= ltt_event_facility_id(e
);
1377 guint8 ev_id
= ltt_event_eventtype_id(e
);
1378 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1379 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1380 g_assert(thf
->f1
!= NULL
);
1381 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1382 LttField
*f
= thf
->f1
;
1384 LttvExecutionSubmode submode
;
1386 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1387 ltt_event_get_unsigned(e
, f
)];
1389 /* Do something with the info about being in user or system mode when int? */
1390 push_state(s
, LTTV_STATE_IRQ
, submode
);
1394 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1396 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1398 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1404 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1406 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1408 pop_state(s
, LTTV_STATE_IRQ
);
1412 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1414 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1415 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1416 guint8 fac_id
= ltt_event_facility_id(e
);
1417 guint8 ev_id
= ltt_event_eventtype_id(e
);
1418 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1419 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1420 g_assert(thf
->f1
!= NULL
);
1421 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1422 LttField
*f
= thf
->f1
;
1424 LttvExecutionSubmode submode
;
1426 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1427 ltt_event_get_unsigned(e
, f
)];
1429 /* Do something with the info about being in user or system mode when int? */
1430 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1434 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1438 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1439 guint cpu
= tfs
->cpu
;
1440 LttvProcessState
*process
= ts
->running_process
[cpu
];
1442 guint depth
= process
->user_stack
->len
;
1444 process
->user_stack
=
1445 g_array_set_size(process
->user_stack
, depth
+ 1);
1447 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1448 *new_func
= funcptr
;
1449 process
->current_function
= funcptr
;
1452 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1454 guint cpu
= tfs
->cpu
;
1455 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1456 LttvProcessState
*process
= ts
->running_process
[cpu
];
1458 if(process
->current_function
!= funcptr
){
1459 g_info("Different functions (%lu.%09lu): ignore it\n",
1460 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1461 g_info("process state has %llu when pop_function is %llu\n",
1462 process
->current_function
, funcptr
);
1463 g_info("{ %u, %u, %s, %s }\n",
1466 g_quark_to_string(process
->name
),
1467 g_quark_to_string(process
->state
->s
));
1470 guint depth
= process
->user_stack
->len
;
1473 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1474 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1478 process
->user_stack
=
1479 g_array_set_size(process
->user_stack
, depth
- 1);
1480 process
->current_function
=
1481 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1485 static gboolean
function_entry(void *hook_data
, void *call_data
)
1487 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1488 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1489 guint8 fac_id
= ltt_event_facility_id(e
);
1490 guint8 ev_id
= ltt_event_eventtype_id(e
);
1491 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1492 g_assert(thf
->f1
!= NULL
);
1493 LttField
*f
= thf
->f1
;
1494 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1496 push_function(s
, funcptr
);
1500 static gboolean
function_exit(void *hook_data
, void *call_data
)
1502 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1503 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1504 guint8 fac_id
= ltt_event_facility_id(e
);
1505 guint8 ev_id
= ltt_event_eventtype_id(e
);
1506 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1507 g_assert(thf
->f1
!= NULL
);
1508 LttField
*f
= thf
->f1
;
1509 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1511 LttvExecutionSubmode submode
;
1513 pop_function(s
, funcptr
);
1517 static gboolean
schedchange(void *hook_data
, void *call_data
)
1519 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1521 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1522 LttvProcessState
*process
= ts
->running_process
[cpu
];
1523 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1525 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1526 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1527 guint pid_in
, pid_out
;
1530 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1531 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1532 state_out
= ltt_event_get_int(e
, thf
->f3
);
1534 if(likely(process
!= NULL
)) {
1536 /* We could not know but it was not the idle process executing.
1537 This should only happen at the beginning, before the first schedule
1538 event, and when the initial information (current process for each CPU)
1539 is missing. It is not obvious how we could, after the fact, compensate
1540 the wrongly attributed statistics. */
1542 //This test only makes sense once the state is known and if there is no
1543 //missing events. We need to silently ignore schedchange coming after a
1544 //process_free, or it causes glitches. (FIXME)
1545 //if(unlikely(process->pid != pid_out)) {
1546 // g_assert(process->pid == 0);
1549 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1550 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1551 process
->state
->change
= s
->parent
.timestamp
;
1553 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1554 else process
->state
->s
= LTTV_STATE_WAIT
;
1555 process
->state
->change
= s
->parent
.timestamp
;
1559 exit_process(s
, process
); /* EXIT_DEAD */
1560 /* see sched.h for states */
1562 process
= ts
->running_process
[cpu
] =
1563 lttv_state_find_process_or_create(
1564 (LttvTraceState
*)s
->parent
.t_context
,
1566 &s
->parent
.timestamp
);
1567 process
->state
->s
= LTTV_STATE_RUN
;
1569 if(process
->usertrace
)
1570 process
->usertrace
->cpu
= cpu
;
1571 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1572 process
->state
->change
= s
->parent
.timestamp
;
1576 static gboolean
process_fork(void *hook_data
, void *call_data
)
1578 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1579 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1580 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1583 LttvProcessState
*zombie_process
;
1585 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1586 LttvProcessState
*process
= ts
->running_process
[cpu
];
1587 LttvProcessState
*child_process
;
1590 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1593 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1595 /* Mathieu : it seems like the process might have been scheduled in before the
1596 * fork, and, in a rare case, might be the current process. This might happen
1597 * in a SMP case where we don't have enough precision on the clocks.
1599 * Test reenabled after precision fixes on time. (Mathieu) */
1601 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1603 if(unlikely(zombie_process
!= NULL
)) {
1604 /* Reutilisation of PID. Only now we are sure that the old PID
1605 * has been released. FIXME : should know when release_task happens instead.
1607 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1609 for(i
=0; i
< num_cpus
; i
++) {
1610 g_assert(zombie_process
!= ts
->running_process
[i
]);
1613 exit_process(s
, zombie_process
);
1616 g_assert(process
->pid
!= child_pid
);
1617 // FIXME : Add this test in the "known state" section
1618 // g_assert(process->pid == parent_pid);
1619 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1620 if(child_process
== NULL
) {
1621 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1622 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1624 /* The process has already been created : due to time imprecision between
1625 * multiple CPUs : it has been scheduled in before creation. Note that we
1626 * shouldn't have this kind of imprecision.
1628 * Simply put a correct parent.
1630 g_assert(0); /* This is a problematic case : the process has been created
1631 before the fork event */
1632 child_process
->ppid
= process
->pid
;
1634 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1635 child_process
->name
= process
->name
;
1640 /* We stamp a newly created process as kernel_thread */
1641 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1643 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1644 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1645 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1648 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1649 LttvProcessState
*process
;
1650 LttvExecutionState
*es
;
1653 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1655 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1656 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1657 es
->t
= LTTV_STATE_SYSCALL
;
1658 process
->kernel_thread
= 1;
1663 static gboolean
process_exit(void *hook_data
, void *call_data
)
1665 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1666 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1667 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1671 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1672 LttvProcessState
*process
= ts
->running_process
[cpu
];
1674 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1676 // FIXME : Add this test in the "known state" section
1677 // g_assert(process->pid == pid);
1679 if(likely(process
!= NULL
)) {
1680 process
->state
->s
= LTTV_STATE_EXIT
;
1685 static gboolean
process_free(void *hook_data
, void *call_data
)
1687 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1688 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1689 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1690 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1692 LttvProcessState
*process
;
1694 /* PID of the process to release */
1695 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1697 g_assert(release_pid
!= 0);
1699 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1701 if(likely(process
!= NULL
)) {
1702 /* release_task is happening at kernel level : we can now safely release
1703 * the data structure of the process */
1704 //This test is fun, though, as it may happen that
1705 //at time t : CPU 0 : process_free
1706 //at time t+150ns : CPU 1 : schedule out
1707 //Clearly due to time imprecision, we disable it. (Mathieu)
1708 //If this weird case happen, we have no choice but to put the
1709 //Currently running process on the cpu to 0.
1710 //I re-enable it following time precision fixes. (Mathieu)
1711 //Well, in the case where an process is freed by a process on another CPU
1712 //and still scheduled, it happens that this is the schedchange that will
1713 //drop the last reference count. Do not free it here!
1714 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1716 for(i
=0; i
< num_cpus
; i
++) {
1717 //g_assert(process != ts->running_process[i]);
1718 if(process
== ts
->running_process
[i
]) {
1719 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1723 //if(i == num_cpus) /* process is not scheduled */
1724 //exit_process(s, process); // do nothing : wait for the schedchange to
1725 //delete the process.
1732 static gboolean
process_exec(void *hook_data
, void *call_data
)
1734 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1735 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1736 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1737 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1740 LttvProcessState
*process
= ts
->running_process
[cpu
];
1742 /* PID of the process to release */
1743 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1744 //name = ltt_event_get_string(e, thf->f1);
1745 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1747 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1748 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1749 memcpy(null_term_name
, name_begin
, name_len
);
1750 null_term_name
[name_len
] = '\0';
1752 process
->name
= g_quark_from_string(null_term_name
);
1753 g_free(null_term_name
);
1757 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1759 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1760 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1761 //It's slow : optimise later by doing this before reading trace.
1762 LttEventType
*et
= ltt_event_eventtype(e
);
1764 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1769 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1770 LttvProcessState
*process
= ts
->running_process
[cpu
];
1771 LttvProcessState
*parent_process
;
1772 LttField
*f4
, *f5
, *f6
;
1773 GQuark mode
, submode
, status
;
1776 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1779 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1782 command
= ltt_event_get_string(e
, thf
->f3
);
1785 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1786 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1787 ltt_event_get_unsigned(e
, f4
));
1790 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1791 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1792 ltt_event_get_unsigned(e
, f5
));
1795 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1796 status
= ltt_enum_string_get(ltt_field_type(f6
),
1797 ltt_event_get_unsigned(e
, f6
));
1799 /* The process might exist if a process was forked while performing the sate dump. */
1800 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1801 if(process
== NULL
) {
1802 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1803 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1804 pid
, g_quark_from_string(command
),
1805 &s
->parent
.timestamp
);
1807 /* Keep the stack bottom : a running user mode */
1809 /* Disabled because of inconsistencies in the current statedump states. */
1810 if(mode
== LTTV_STATE_USER_MODE
) {
1811 /* Only keep the bottom */
1812 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1814 /* On top of it : */
1815 LttvExecutionState
*es
;
1816 es
= process
->state
= &g_array_index(process
->execution_stack
,
1817 LttvExecutionState
, 1);
1826 LttvExecutionState
*es
;
1827 es
= process
->state
= &g_array_index(process
->execution_stack
,
1828 LttvExecutionState
, 1);
1829 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1830 es
->s
= LTTV_STATE_UNNAMED
;
1831 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1834 /* The process has already been created :
1835 * Probably was forked while dumping the process state or
1836 * was simply scheduled in prior to get the state dump event.
1838 process
->ppid
= parent_pid
;
1839 process
->name
= g_quark_from_string(command
);
1840 /* Don't mess around with the stack, it will eventually become
1841 * ok after the end of state dump. */
1847 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1849 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1851 lttv_state_add_event_hooks(tss
);
1856 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1858 LttvTraceset
*traceset
= self
->parent
.ts
;
1860 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1864 LttvTracefileState
*tfs
;
1868 LttvTraceHookByFacility
*thf
;
1870 LttvTraceHook
*hook
;
1872 LttvAttributeValue val
;
1877 nb_trace
= lttv_traceset_number(traceset
);
1878 for(i
= 0 ; i
< nb_trace
; i
++) {
1879 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1881 /* Find the eventtype id for the following events and register the
1882 associated by id hooks. */
1884 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1885 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1888 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1889 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1890 LTT_FIELD_SYSCALL_ID
, 0, 0,
1891 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1894 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1895 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1897 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1900 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1901 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1902 LTT_FIELD_TRAP_ID
, 0, 0,
1903 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1906 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1907 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1909 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1912 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1913 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1914 LTT_FIELD_IRQ_ID
, 0, 0,
1915 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1918 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1919 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1921 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1924 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1925 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1926 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1927 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1930 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1931 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1933 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1936 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1937 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1938 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1939 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1942 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1943 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1944 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1945 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1948 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1949 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1950 LTT_FIELD_PID
, 0, 0,
1951 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1955 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1956 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1957 LTT_FIELD_PID
, 0, 0,
1958 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1961 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1962 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1963 LTT_FIELD_PID
, 0, 0,
1964 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1967 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1968 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1969 LTT_FIELD_FILENAME
, 0, 0,
1970 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1973 /* statedump-related hooks */
1974 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1975 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1976 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1977 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1980 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1981 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1982 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1983 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1986 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1987 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1988 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1989 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1992 hooks
= g_array_set_size(hooks
, hn
);
1994 /* Add these hooks to each event_by_id hooks list */
1996 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1998 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2000 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2001 LttvTracefileContext
*, j
));
2003 for(k
= 0 ; k
< hooks
->len
; k
++) {
2004 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2005 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2006 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2008 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2015 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2016 *(val
.v_pointer
) = hooks
;
2020 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2022 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2024 lttv_state_remove_event_hooks(tss
);
2029 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2031 LttvTraceset
*traceset
= self
->parent
.ts
;
2033 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2037 LttvTracefileState
*tfs
;
2041 LttvTraceHook
*hook
;
2043 LttvTraceHookByFacility
*thf
;
2045 LttvAttributeValue val
;
2047 nb_trace
= lttv_traceset_number(traceset
);
2048 for(i
= 0 ; i
< nb_trace
; i
++) {
2049 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2050 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2051 hooks
= *(val
.v_pointer
);
2053 /* Remove these hooks from each event_by_id hooks list */
2055 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2057 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2059 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2060 LttvTracefileContext
*, j
));
2062 for(k
= 0 ; k
< hooks
->len
; k
++) {
2063 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2064 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2065 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2067 lttv_hooks_remove_data(
2068 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2074 for(k
= 0 ; k
< hooks
->len
; k
++)
2075 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2076 g_array_free(hooks
, TRUE
);
2080 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2082 guint
*event_count
= (guint
*)hook_data
;
2084 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2085 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2090 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2092 LttvTracefileState
*tfcs
;
2094 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2096 LttEventPosition
*ep
;
2102 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2104 LttvAttributeValue value
;
2106 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2107 LTTV_STATE_SAVED_STATES
);
2108 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2109 value
= lttv_attribute_add(saved_states_tree
,
2110 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2111 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2112 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2113 *(value
.v_time
) = self
->parent
.timestamp
;
2114 lttv_state_save(tcs
, saved_state_tree
);
2115 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2116 self
->parent
.timestamp
.tv_nsec
);
2118 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2123 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2125 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2127 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2132 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2140 static gboolean
block_start(void *hook_data
, void *call_data
)
2142 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2144 LttvTracefileState
*tfcs
;
2146 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2148 LttEventPosition
*ep
;
2150 guint i
, nb_block
, nb_event
, nb_tracefile
;
2154 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2156 LttvAttributeValue value
;
2158 ep
= ltt_event_position_new();
2160 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2162 /* Count the number of events added since the last block end in any
2165 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2167 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2168 LttvTracefileContext
, i
));
2169 ltt_event_position(tfcs
->parent
.e
, ep
);
2170 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2171 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2172 tfcs
->saved_position
= nb_event
;
2176 if(tcs
->nb_event
>= tcs
->save_interval
) {
2177 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2178 LTTV_STATE_SAVED_STATES
);
2179 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2180 value
= lttv_attribute_add(saved_states_tree
,
2181 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2182 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2183 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2184 *(value
.v_time
) = self
->parent
.timestamp
;
2185 lttv_state_save(tcs
, saved_state_tree
);
2187 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2188 self
->parent
.timestamp
.tv_nsec
);
2190 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2196 static gboolean
block_end(void *hook_data
, void *call_data
)
2198 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2200 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2204 LttEventPosition
*ep
;
2206 guint nb_block
, nb_event
;
2208 ep
= ltt_event_position_new();
2209 ltt_event_position(self
->parent
.e
, ep
);
2210 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2211 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2212 self
->saved_position
= 0;
2213 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2220 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2222 LttvTraceset
*traceset
= self
->parent
.ts
;
2224 guint i
, j
, nb_trace
, nb_tracefile
;
2228 LttvTracefileState
*tfs
;
2230 LttvTraceHook hook_start
, hook_end
;
2232 nb_trace
= lttv_traceset_number(traceset
);
2233 for(i
= 0 ; i
< nb_trace
; i
++) {
2234 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2236 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2237 NULL
, NULL
, block_start
, &hook_start
);
2238 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2239 NULL
, NULL
, block_end
, &hook_end
);
2241 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2243 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2245 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2246 LttvTracefileContext
, j
));
2247 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2248 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2249 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2250 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2256 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2258 LttvTraceset
*traceset
= self
->parent
.ts
;
2260 guint i
, j
, nb_trace
, nb_tracefile
;
2264 LttvTracefileState
*tfs
;
2267 nb_trace
= lttv_traceset_number(traceset
);
2268 for(i
= 0 ; i
< nb_trace
; i
++) {
2270 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2271 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2273 guint
*event_count
= g_new(guint
, 1);
2276 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2278 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2279 LttvTracefileContext
*, j
));
2280 lttv_hooks_add(tfs
->parent
.event
,
2281 state_save_event_hook
,
2288 lttv_process_traceset_begin(&self
->parent
,
2289 NULL
, NULL
, NULL
, NULL
, NULL
);
2293 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2295 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2297 lttv_state_save_add_event_hooks(tss
);
2304 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2306 LttvTraceset
*traceset
= self
->parent
.ts
;
2308 guint i
, j
, nb_trace
, nb_tracefile
;
2312 LttvTracefileState
*tfs
;
2314 LttvTraceHook hook_start
, hook_end
;
2316 nb_trace
= lttv_traceset_number(traceset
);
2317 for(i
= 0 ; i
< nb_trace
; i
++) {
2318 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2320 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2321 NULL
, NULL
, block_start
, &hook_start
);
2323 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2324 NULL
, NULL
, block_end
, &hook_end
);
2326 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2328 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2330 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2331 LttvTracefileContext
, j
));
2332 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2333 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2334 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2335 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2341 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2343 LttvTraceset
*traceset
= self
->parent
.ts
;
2345 guint i
, j
, nb_trace
, nb_tracefile
;
2349 LttvTracefileState
*tfs
;
2351 LttvHooks
*after_trace
= lttv_hooks_new();
2353 lttv_hooks_add(after_trace
,
2354 state_save_after_trace_hook
,
2359 lttv_process_traceset_end(&self
->parent
,
2360 NULL
, after_trace
, NULL
, NULL
, NULL
);
2362 lttv_hooks_destroy(after_trace
);
2364 nb_trace
= lttv_traceset_number(traceset
);
2365 for(i
= 0 ; i
< nb_trace
; i
++) {
2367 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2368 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2370 guint
*event_count
= NULL
;
2372 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2374 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2375 LttvTracefileContext
*, j
));
2376 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2377 state_save_event_hook
);
2379 if(event_count
) g_free(event_count
);
2383 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2385 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2387 lttv_state_save_remove_event_hooks(tss
);
2392 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2394 LttvTraceset
*traceset
= self
->parent
.ts
;
2398 int min_pos
, mid_pos
, max_pos
;
2400 guint call_rest
= 0;
2402 LttvTraceState
*tcs
;
2404 LttvAttributeValue value
;
2406 LttvAttributeType type
;
2408 LttvAttributeName name
;
2412 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2414 //g_tree_destroy(self->parent.pqueue);
2415 //self->parent.pqueue = g_tree_new(compare_tracefile);
2417 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2419 nb_trace
= lttv_traceset_number(traceset
);
2420 for(i
= 0 ; i
< nb_trace
; i
++) {
2421 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2423 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2424 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2425 LTTV_STATE_SAVED_STATES
);
2428 if(saved_states_tree
) {
2429 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2430 mid_pos
= max_pos
/ 2;
2431 while(min_pos
< max_pos
) {
2432 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2434 g_assert(type
== LTTV_GOBJECT
);
2435 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2436 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2438 g_assert(type
== LTTV_TIME
);
2439 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2441 closest_tree
= saved_state_tree
;
2443 else max_pos
= mid_pos
- 1;
2445 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2449 /* restore the closest earlier saved state */
2451 lttv_state_restore(tcs
, closest_tree
);
2455 /* There is no saved state, yet we want to have it. Restart at T0 */
2457 restore_init_state(tcs
);
2458 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2461 /* We want to seek quickly without restoring/updating the state */
2463 restore_init_state(tcs
);
2464 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2467 if(!call_rest
) g_info("NOT Calling restore");
2472 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2478 traceset_state_finalize (LttvTracesetState
*self
)
2480 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2481 finalize(G_OBJECT(self
));
2486 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2488 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2490 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2491 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2492 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2493 klass
->new_traceset_context
= new_traceset_context
;
2494 klass
->new_trace_context
= new_trace_context
;
2495 klass
->new_tracefile_context
= new_tracefile_context
;
2500 lttv_traceset_state_get_type(void)
2502 static GType type
= 0;
2504 static const GTypeInfo info
= {
2505 sizeof (LttvTracesetStateClass
),
2506 NULL
, /* base_init */
2507 NULL
, /* base_finalize */
2508 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2509 NULL
, /* class_finalize */
2510 NULL
, /* class_data */
2511 sizeof (LttvTracesetState
),
2512 0, /* n_preallocs */
2513 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2514 NULL
/* value handling */
2517 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2525 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2531 trace_state_finalize (LttvTraceState
*self
)
2533 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2534 finalize(G_OBJECT(self
));
2539 trace_state_class_init (LttvTraceStateClass
*klass
)
2541 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2543 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2544 klass
->state_save
= state_save
;
2545 klass
->state_restore
= state_restore
;
2546 klass
->state_saved_free
= state_saved_free
;
2551 lttv_trace_state_get_type(void)
2553 static GType type
= 0;
2555 static const GTypeInfo info
= {
2556 sizeof (LttvTraceStateClass
),
2557 NULL
, /* base_init */
2558 NULL
, /* base_finalize */
2559 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2560 NULL
, /* class_finalize */
2561 NULL
, /* class_data */
2562 sizeof (LttvTraceState
),
2563 0, /* n_preallocs */
2564 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2565 NULL
/* value handling */
2568 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2569 "LttvTraceStateType", &info
, 0);
2576 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2582 tracefile_state_finalize (LttvTracefileState
*self
)
2584 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2585 finalize(G_OBJECT(self
));
2590 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2592 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2594 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2599 lttv_tracefile_state_get_type(void)
2601 static GType type
= 0;
2603 static const GTypeInfo info
= {
2604 sizeof (LttvTracefileStateClass
),
2605 NULL
, /* base_init */
2606 NULL
, /* base_finalize */
2607 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2608 NULL
, /* class_finalize */
2609 NULL
, /* class_data */
2610 sizeof (LttvTracefileState
),
2611 0, /* n_preallocs */
2612 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2613 NULL
/* value handling */
2616 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2617 "LttvTracefileStateType", &info
, 0);
2623 static void module_init()
2625 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2626 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2627 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2628 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2629 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2630 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2631 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2632 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2633 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2634 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2635 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2636 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2637 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2638 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2639 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2640 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2641 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2642 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2643 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2644 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2645 LTTV_STATE_EVENT
= g_quark_from_string("event");
2646 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2647 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2648 LTTV_STATE_TIME
= g_quark_from_string("time");
2649 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2650 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2651 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2652 g_quark_from_string("trace_state_use_count");
2655 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2656 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2657 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2658 LTT_FACILITY_FS
= g_quark_from_string("fs");
2659 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2660 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2663 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2664 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2665 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2666 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2667 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2668 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2669 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2670 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2671 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2672 LTT_EVENT_FORK
= g_quark_from_string("fork");
2673 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2674 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2675 LTT_EVENT_FREE
= g_quark_from_string("free");
2676 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2677 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2678 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2679 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2682 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2683 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2684 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2685 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2686 LTT_FIELD_OUT
= g_quark_from_string("out");
2687 LTT_FIELD_IN
= g_quark_from_string("in");
2688 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2689 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2690 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2691 LTT_FIELD_PID
= g_quark_from_string("pid");
2692 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2693 LTT_FIELD_NAME
= g_quark_from_string("name");
2694 LTT_FIELD_MODE
= g_quark_from_string("mode");
2695 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2696 LTT_FIELD_STATUS
= g_quark_from_string("status");
2697 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2698 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2702 static void module_destroy()
2707 LTTV_MODULE("state", "State computation", \
2708 "Update the system state, possibly saving it at intervals", \
2709 module_init
, module_destroy
)