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
= &g_array_index(new_process
->user_stack
,
514 guint64
, new_process
->user_stack
->len
- 1);
515 g_hash_table_insert(new_processes
, new_process
, new_process
);
519 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
521 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
523 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
524 return new_processes
;
528 /* The saved state for each trace contains a member "processes", which
529 stores a copy of the process table, and a member "tracefiles" with
530 one entry per tracefile. Each tracefile has a "process" member pointing
531 to the current process and a "position" member storing the tracefile
532 position (needed to seek to the current "next" event. */
534 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
536 guint i
, nb_tracefile
, nb_cpus
;
538 LttvTracefileState
*tfcs
;
540 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
542 guint
*running_process
;
544 LttvAttributeType type
;
546 LttvAttributeValue value
;
548 LttvAttributeName name
;
550 LttEventPosition
*ep
;
552 tracefiles_tree
= lttv_attribute_find_subdir(container
,
553 LTTV_STATE_TRACEFILES
);
555 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
557 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
559 /* Add the currently running processes array */
560 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
561 running_process
= g_new(guint
, nb_cpus
);
562 for(i
=0;i
<nb_cpus
;i
++) {
563 running_process
[i
] = self
->running_process
[i
]->pid
;
565 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
567 *(value
.v_pointer
) = running_process
;
569 g_info("State save");
571 nb_tracefile
= self
->parent
.tracefiles
->len
;
573 for(i
= 0 ; i
< nb_tracefile
; i
++) {
575 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
576 LttvTracefileContext
*, i
));
577 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
578 value
= lttv_attribute_add(tracefiles_tree
, i
,
580 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
582 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
584 *(value
.v_uint
) = tfcs
->process
->pid
;
586 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
588 /* Only save the position if the tfs has not infinite time. */
589 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
590 // && current_tfcs != tfcs) {
591 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
592 *(value
.v_pointer
) = NULL
;
594 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
595 ep
= ltt_event_position_new();
596 ltt_event_position(e
, ep
);
597 *(value
.v_pointer
) = ep
;
599 guint nb_block
, offset
;
602 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
603 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
605 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
611 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
613 guint i
, nb_tracefile
, pid
, nb_cpus
;
615 LttvTracefileState
*tfcs
;
617 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
619 guint
*running_process
;
621 LttvAttributeType type
;
623 LttvAttributeValue value
;
625 LttvAttributeName name
;
627 LttEventPosition
*ep
;
629 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
631 tracefiles_tree
= lttv_attribute_find_subdir(container
,
632 LTTV_STATE_TRACEFILES
);
634 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
636 g_assert(type
== LTTV_POINTER
);
637 lttv_state_free_process_table(self
->processes
);
638 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
640 /* Add the currently 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 for(i
=0;i
<nb_cpus
;i
++) {
647 pid
= running_process
[i
];
648 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
649 g_assert(self
->running_process
[i
] != NULL
);
653 nb_tracefile
= self
->parent
.tracefiles
->len
;
655 //g_tree_destroy(tsc->pqueue);
656 //tsc->pqueue = g_tree_new(compare_tracefile);
658 for(i
= 0 ; i
< nb_tracefile
; i
++) {
660 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
661 LttvTracefileContext
*, i
));
662 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
663 g_assert(type
== LTTV_GOBJECT
);
664 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
666 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
668 g_assert(type
== LTTV_UINT
);
669 pid
= *(value
.v_uint
);
670 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
672 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
674 g_assert(type
== LTTV_POINTER
);
675 //g_assert(*(value.v_pointer) != NULL);
676 ep
= *(value
.v_pointer
);
677 g_assert(tfcs
->parent
.t_context
!= NULL
);
679 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
680 g_tree_remove(tsc
->pqueue
, tfc
);
683 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
684 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
685 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
686 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
687 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
689 tfc
->timestamp
= ltt_time_infinite
;
695 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
697 guint i
, nb_tracefile
, nb_cpus
;
699 LttvTracefileState
*tfcs
;
701 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
703 guint
*running_process
;
705 LttvAttributeType type
;
707 LttvAttributeValue value
;
709 LttvAttributeName name
;
711 LttEventPosition
*ep
;
713 tracefiles_tree
= lttv_attribute_find_subdir(container
,
714 LTTV_STATE_TRACEFILES
);
715 g_object_ref(G_OBJECT(tracefiles_tree
));
716 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
718 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
720 g_assert(type
== LTTV_POINTER
);
721 lttv_state_free_process_table(*(value
.v_pointer
));
722 *(value
.v_pointer
) = NULL
;
723 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
725 /* Free running processes array */
726 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
727 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
729 g_assert(type
== LTTV_POINTER
);
730 running_process
= *(value
.v_pointer
);
731 g_free(running_process
);
733 nb_tracefile
= self
->parent
.tracefiles
->len
;
735 for(i
= 0 ; i
< nb_tracefile
; i
++) {
737 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
738 LttvTracefileContext
*, i
));
739 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
740 g_assert(type
== LTTV_GOBJECT
);
741 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
743 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
745 g_assert(type
== LTTV_POINTER
);
746 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
748 g_object_unref(G_OBJECT(tracefiles_tree
));
752 static void free_saved_state(LttvTraceState
*self
)
756 LttvAttributeType type
;
758 LttvAttributeValue value
;
760 LttvAttributeName name
;
762 LttvAttribute
*saved_states
;
764 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
765 LTTV_STATE_SAVED_STATES
);
767 nb
= lttv_attribute_get_number(saved_states
);
768 for(i
= 0 ; i
< nb
; i
++) {
769 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
770 g_assert(type
== LTTV_GOBJECT
);
771 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
774 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
779 create_max_time(LttvTraceState
*tcs
)
781 LttvAttributeValue v
;
783 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
785 g_assert(*(v
.v_pointer
) == NULL
);
786 *(v
.v_pointer
) = g_new(LttTime
,1);
787 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
792 get_max_time(LttvTraceState
*tcs
)
794 LttvAttributeValue v
;
796 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
798 g_assert(*(v
.v_pointer
) != NULL
);
799 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
804 free_max_time(LttvTraceState
*tcs
)
806 LttvAttributeValue v
;
808 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
810 g_free(*(v
.v_pointer
));
811 *(v
.v_pointer
) = NULL
;
815 typedef struct _LttvNameTables
{
816 // FIXME GQuark *eventtype_names;
817 GQuark
*syscall_names
;
821 GQuark
*soft_irq_names
;
826 create_name_tables(LttvTraceState
*tcs
)
830 GQuark f_name
, e_name
;
834 LttvTraceHookByFacility
*thf
;
840 GString
*fe_name
= g_string_new("");
842 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
844 LttvAttributeValue v
;
846 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
848 g_assert(*(v
.v_pointer
) == NULL
);
849 *(v
.v_pointer
) = name_tables
;
850 #if 0 // Use iteration over the facilities_by_name and then list all event
851 // types of each facility
852 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
853 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
854 for(i
= 0 ; i
< nb
; i
++) {
855 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
856 e_name
= ltt_eventtype_name(et
);
857 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
858 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
859 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
862 if(lttv_trace_find_hook(tcs
->parent
.t
,
863 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
864 LTT_FIELD_SYSCALL_ID
, 0, 0,
868 thf
= lttv_trace_hook_get_first(&h
);
870 t
= ltt_field_type(thf
->f1
);
871 nb
= ltt_type_element_number(t
);
873 lttv_trace_hook_destroy(&h
);
875 name_tables
->syscall_names
= g_new(GQuark
, nb
);
876 name_tables
->nb_syscalls
= nb
;
878 for(i
= 0 ; i
< nb
; i
++) {
879 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
882 //name_tables->syscall_names = g_new(GQuark, 256);
883 //for(i = 0 ; i < 256 ; i++) {
884 // g_string_printf(fe_name, "syscall %d", i);
885 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
888 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
889 LTT_EVENT_TRAP_ENTRY
,
890 LTT_FIELD_TRAP_ID
, 0, 0,
894 thf
= lttv_trace_hook_get_first(&h
);
896 t
= ltt_field_type(thf
->f1
);
897 //nb = ltt_type_element_number(t);
899 lttv_trace_hook_destroy(&h
);
902 name_tables->trap_names = g_new(GQuark, nb);
903 for(i = 0 ; i < nb ; i++) {
904 name_tables->trap_names[i] = g_quark_from_string(
905 ltt_enum_string_get(t, i));
909 name_tables
->trap_names
= g_new(GQuark
, 256);
910 for(i
= 0 ; i
< 256 ; i
++) {
911 g_string_printf(fe_name
, "trap %d", i
);
912 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
915 if(lttv_trace_find_hook(tcs
->parent
.t
,
916 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
917 LTT_FIELD_IRQ_ID
, 0, 0,
921 thf
= lttv_trace_hook_get_first(&h
);
923 t
= ltt_field_type(thf
->f1
);
924 //nb = ltt_type_element_number(t);
926 lttv_trace_hook_destroy(&h
);
929 name_tables->irq_names = g_new(GQuark, nb);
930 for(i = 0 ; i < nb ; i++) {
931 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
935 name_tables
->irq_names
= g_new(GQuark
, 256);
936 for(i
= 0 ; i
< 256 ; i
++) {
937 g_string_printf(fe_name
, "irq %d", i
);
938 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
942 name_tables->soft_irq_names = g_new(GQuark, nb);
943 for(i = 0 ; i < nb ; i++) {
944 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
948 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
949 for(i
= 0 ; i
< 256 ; i
++) {
950 g_string_printf(fe_name
, "softirq %d", i
);
951 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
955 g_string_free(fe_name
, TRUE
);
960 get_name_tables(LttvTraceState
*tcs
)
962 LttvNameTables
*name_tables
;
964 LttvAttributeValue v
;
966 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
968 g_assert(*(v
.v_pointer
) != NULL
);
969 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
970 //tcs->eventtype_names = name_tables->eventtype_names;
971 tcs
->syscall_names
= name_tables
->syscall_names
;
972 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
973 tcs
->trap_names
= name_tables
->trap_names
;
974 tcs
->irq_names
= name_tables
->irq_names
;
975 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
980 free_name_tables(LttvTraceState
*tcs
)
982 LttvNameTables
*name_tables
;
984 LttvAttributeValue v
;
986 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
988 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
989 *(v
.v_pointer
) = NULL
;
991 // g_free(name_tables->eventtype_names);
992 g_free(name_tables
->syscall_names
);
993 g_free(name_tables
->trap_names
);
994 g_free(name_tables
->irq_names
);
995 g_free(name_tables
->soft_irq_names
);
999 #ifdef HASH_TABLE_DEBUG
1001 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1003 LttvProcessState
*process
= (LttvProcessState
*)value
;
1005 /* Test for process corruption */
1006 guint stack_len
= process
->execution_stack
->len
;
1009 static void hash_table_check(GHashTable
*table
)
1011 g_hash_table_foreach(table
, test_process
, NULL
);
1018 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1021 LttvExecutionState
*es
;
1023 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1024 guint cpu
= tfs
->cpu
;
1026 #ifdef HASH_TABLE_DEBUG
1027 hash_table_check(ts
->processes
);
1029 LttvProcessState
*process
= ts
->running_process
[cpu
];
1031 guint depth
= process
->execution_stack
->len
;
1033 process
->execution_stack
=
1034 g_array_set_size(process
->execution_stack
, depth
+ 1);
1037 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1039 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1042 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1043 es
->s
= process
->state
->s
;
1044 process
->state
= es
;
1048 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1050 guint cpu
= tfs
->cpu
;
1051 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1052 LttvProcessState
*process
= ts
->running_process
[cpu
];
1054 guint depth
= process
->execution_stack
->len
;
1056 if(process
->state
->t
!= t
){
1057 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1058 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1059 g_info("process state has %s when pop_int is %s\n",
1060 g_quark_to_string(process
->state
->t
),
1061 g_quark_to_string(t
));
1062 g_info("{ %u, %u, %s, %s }\n",
1065 g_quark_to_string(process
->name
),
1066 g_quark_to_string(process
->state
->s
));
1071 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1072 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1076 process
->execution_stack
=
1077 g_array_set_size(process
->execution_stack
, depth
- 1);
1078 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1080 process
->state
->change
= tfs
->parent
.timestamp
;
1083 struct search_result
{
1084 const LttTime
*time
; /* Requested time */
1085 LttTime
*best
; /* Best result */
1088 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1090 const LttTime
*elem_time
= (const LttTime
*)a
;
1091 /* Explicit non const cast */
1092 struct search_result
*res
= (struct search_result
*)b
;
1094 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1095 /* The usertrace was created before the schedchange */
1096 /* Get larger keys */
1098 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1099 /* The usertrace was created after the schedchange time */
1100 /* Get smaller keys */
1102 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1103 res
->best
= elem_time
;
1106 res
->best
= elem_time
;
1113 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1114 guint pid
, const LttTime
*timestamp
)
1116 LttvTracefileState
*tfs
= NULL
;
1117 struct search_result res
;
1118 /* Find the usertrace associated with a pid and time interval.
1119 * Search in the usertraces by PID (within a hash) and then, for each
1120 * corresponding element of the array, find the first one with creation
1121 * timestamp the lowest, but higher or equal to "timestamp". */
1122 res
.time
= timestamp
;
1124 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1125 if(usertrace_tree
) {
1126 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1128 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1136 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1137 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1139 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1141 LttvExecutionState
*es
;
1143 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1149 process
->name
= name
;
1150 //process->last_cpu = tfs->cpu_name;
1151 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1152 process
->kernel_thread
= 0;
1153 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1154 process
->current_function
= 0; //function 0x0 by default.
1156 g_info("Process %u, core %p", process
->pid
, process
);
1157 g_hash_table_insert(tcs
->processes
, process
, process
);
1160 process
->ppid
= parent
->pid
;
1161 process
->creation_time
= *timestamp
;
1164 /* No parent. This process exists but we are missing all information about
1165 its creation. The birth time is set to zero but we remember the time of
1170 process
->creation_time
= ltt_time_zero
;
1173 process
->insertion_time
= *timestamp
;
1174 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1175 process
->creation_time
.tv_nsec
);
1176 process
->pid_time
= g_quark_from_string(buffer
);
1178 //process->last_cpu = tfs->cpu_name;
1179 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1180 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1181 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1182 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1183 es
= process
->state
= &g_array_index(process
->execution_stack
,
1184 LttvExecutionState
, 0);
1185 es
->t
= LTTV_STATE_USER_MODE
;
1186 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1187 es
->entry
= *timestamp
;
1188 //g_assert(timestamp->tv_sec != 0);
1189 es
->change
= *timestamp
;
1190 es
->s
= LTTV_STATE_RUN
;
1192 es
= process
->state
= &g_array_index(process
->execution_stack
,
1193 LttvExecutionState
, 1);
1194 es
->t
= LTTV_STATE_SYSCALL
;
1195 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1196 es
->entry
= *timestamp
;
1197 //g_assert(timestamp->tv_sec != 0);
1198 es
->change
= *timestamp
;
1199 es
->s
= LTTV_STATE_WAIT_FORK
;
1201 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1202 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1203 sizeof(guint64
), 0);
1208 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1211 LttvProcessState key
;
1212 LttvProcessState
*process
;
1216 process
= g_hash_table_lookup(ts
->processes
, &key
);
1221 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1224 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1225 LttvExecutionState
*es
;
1227 /* Put ltt_time_zero creation time for unexisting processes */
1228 if(unlikely(process
== NULL
)) {
1229 process
= lttv_state_create_process(ts
,
1230 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1231 /* We are not sure is it's a kernel thread or normal thread, put the
1232 * bottom stack state to unknown */
1233 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1234 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1239 /* FIXME : this function should be called when we receive an event telling that
1240 * release_task has been called in the kernel. In happens generally when
1241 * the parent waits for its child terminaison, but may also happen in special
1242 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1243 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1244 * of a killed thread ground, but isn't the leader.
1246 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1248 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1249 LttvProcessState key
;
1251 key
.pid
= process
->pid
;
1252 key
.cpu
= process
->cpu
;
1253 g_hash_table_remove(ts
->processes
, &key
);
1254 g_array_free(process
->execution_stack
, TRUE
);
1255 g_array_free(process
->user_stack
, TRUE
);
1260 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1262 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1263 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1268 static void lttv_state_free_process_table(GHashTable
*processes
)
1270 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1271 g_hash_table_destroy(processes
);
1275 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1277 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1278 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1279 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1280 LttField
*f
= thf
->f1
;
1282 LttvExecutionSubmode submode
;
1284 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1285 guint syscall
= ltt_event_get_unsigned(e
, f
);
1287 if(syscall
< nb_syscalls
) {
1288 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1291 /* Fixup an incomplete syscall table */
1292 GString
*string
= g_string_new("");
1293 g_string_printf(string
, "syscall %u", syscall
);
1294 submode
= g_quark_from_string(string
->str
);
1295 g_string_free(string
, TRUE
);
1297 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1302 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1304 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1306 pop_state(s
, LTTV_STATE_SYSCALL
);
1311 static gboolean
trap_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 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1321 ltt_event_get_unsigned(e
, f
)];
1322 push_state(s
, LTTV_STATE_TRAP
, submode
);
1327 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1329 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1331 pop_state(s
, LTTV_STATE_TRAP
);
1336 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1338 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1339 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1340 guint8 fac_id
= ltt_event_facility_id(e
);
1341 guint8 ev_id
= ltt_event_eventtype_id(e
);
1342 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1343 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1344 g_assert(thf
->f1
!= NULL
);
1345 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1346 LttField
*f
= thf
->f1
;
1348 LttvExecutionSubmode submode
;
1350 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1351 ltt_event_get_unsigned(e
, f
)];
1353 /* Do something with the info about being in user or system mode when int? */
1354 push_state(s
, LTTV_STATE_IRQ
, submode
);
1358 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1360 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1362 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1368 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1370 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1372 pop_state(s
, LTTV_STATE_IRQ
);
1376 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1378 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1379 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1380 guint8 fac_id
= ltt_event_facility_id(e
);
1381 guint8 ev_id
= ltt_event_eventtype_id(e
);
1382 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1383 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1384 g_assert(thf
->f1
!= NULL
);
1385 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1386 LttField
*f
= thf
->f1
;
1388 LttvExecutionSubmode submode
;
1390 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1391 ltt_event_get_unsigned(e
, f
)];
1393 /* Do something with the info about being in user or system mode when int? */
1394 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1398 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1402 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1403 guint cpu
= tfs
->cpu
;
1404 LttvProcessState
*process
= ts
->running_process
[cpu
];
1406 guint depth
= process
->user_stack
->len
;
1408 process
->user_stack
=
1409 g_array_set_size(process
->user_stack
, depth
+ 1);
1411 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1412 *new_func
= funcptr
;
1413 process
->current_function
=
1414 g_array_index(process
->user_stack
, guint64
, depth
- 1);
1417 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1419 guint cpu
= tfs
->cpu
;
1420 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1421 LttvProcessState
*process
= ts
->running_process
[cpu
];
1423 guint depth
= process
->user_stack
->len
;
1424 if(process
->current_function
!= funcptr
){
1425 g_info("Different functions (%lu.%09lu): ignore it\n",
1426 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1427 g_info("process state has %llu when pop_function is %llu\n",
1428 process
->current_function
, funcptr
);
1429 g_info("{ %u, %u, %s, %s }\n",
1432 g_quark_to_string(process
->name
),
1433 g_quark_to_string(process
->state
->s
));
1438 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1439 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1443 process
->user_stack
=
1444 g_array_set_size(process
->user_stack
, depth
- 1);
1445 process
->current_function
=
1446 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1450 static gboolean
function_entry(void *hook_data
, void *call_data
)
1452 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1453 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1454 guint8 fac_id
= ltt_event_facility_id(e
);
1455 guint8 ev_id
= ltt_event_eventtype_id(e
);
1456 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1457 g_assert(thf
->f1
!= NULL
);
1458 LttField
*f
= thf
->f1
;
1459 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1461 push_function(s
, funcptr
);
1465 static gboolean
function_exit(void *hook_data
, void *call_data
)
1467 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1468 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1469 guint8 fac_id
= ltt_event_facility_id(e
);
1470 guint8 ev_id
= ltt_event_eventtype_id(e
);
1471 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1472 g_assert(thf
->f1
!= NULL
);
1473 LttField
*f
= thf
->f1
;
1474 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1476 LttvExecutionSubmode submode
;
1478 pop_function(s
, funcptr
);
1482 static gboolean
schedchange(void *hook_data
, void *call_data
)
1484 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1486 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1487 LttvProcessState
*process
= ts
->running_process
[cpu
];
1488 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1490 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1491 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1492 guint pid_in
, pid_out
;
1495 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1496 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1497 state_out
= ltt_event_get_int(e
, thf
->f3
);
1499 if(likely(process
!= NULL
)) {
1501 /* We could not know but it was not the idle process executing.
1502 This should only happen at the beginning, before the first schedule
1503 event, and when the initial information (current process for each CPU)
1504 is missing. It is not obvious how we could, after the fact, compensate
1505 the wrongly attributed statistics. */
1507 //This test only makes sense once the state is known and if there is no
1508 //missing events. We need to silently ignore schedchange coming after a
1509 //process_free, or it causes glitches. (FIXME)
1510 //if(unlikely(process->pid != pid_out)) {
1511 // g_assert(process->pid == 0);
1514 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1515 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1516 process
->state
->change
= s
->parent
.timestamp
;
1518 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1519 else process
->state
->s
= LTTV_STATE_WAIT
;
1520 process
->state
->change
= s
->parent
.timestamp
;
1524 exit_process(s
, process
); /* EXIT_DEAD */
1525 /* see sched.h for states */
1527 process
= ts
->running_process
[cpu
] =
1528 lttv_state_find_process_or_create(
1529 (LttvTraceState
*)s
->parent
.t_context
,
1531 &s
->parent
.timestamp
);
1532 process
->state
->s
= LTTV_STATE_RUN
;
1534 if(process
->usertrace
)
1535 process
->usertrace
->cpu
= cpu
;
1536 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1537 process
->state
->change
= s
->parent
.timestamp
;
1541 static gboolean
process_fork(void *hook_data
, void *call_data
)
1543 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1544 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1545 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1548 LttvProcessState
*zombie_process
;
1550 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1551 LttvProcessState
*process
= ts
->running_process
[cpu
];
1552 LttvProcessState
*child_process
;
1555 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1558 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1560 /* Mathieu : it seems like the process might have been scheduled in before the
1561 * fork, and, in a rare case, might be the current process. This might happen
1562 * in a SMP case where we don't have enough precision on the clocks.
1564 * Test reenabled after precision fixes on time. (Mathieu) */
1566 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1568 if(unlikely(zombie_process
!= NULL
)) {
1569 /* Reutilisation of PID. Only now we are sure that the old PID
1570 * has been released. FIXME : should know when release_task happens instead.
1572 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1574 for(i
=0; i
< num_cpus
; i
++) {
1575 g_assert(zombie_process
!= ts
->running_process
[i
]);
1578 exit_process(s
, zombie_process
);
1581 g_assert(process
->pid
!= child_pid
);
1582 // FIXME : Add this test in the "known state" section
1583 // g_assert(process->pid == parent_pid);
1584 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1585 if(child_process
== NULL
) {
1586 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1587 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1589 /* The process has already been created : due to time imprecision between
1590 * multiple CPUs : it has been scheduled in before creation. Note that we
1591 * shouldn't have this kind of imprecision.
1593 * Simply put a correct parent.
1595 g_assert(0); /* This is a problematic case : the process has been created
1596 before the fork event */
1597 child_process
->ppid
= process
->pid
;
1599 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1600 child_process
->name
= process
->name
;
1605 /* We stamp a newly created process as kernel_thread */
1606 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1608 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1609 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1610 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1613 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1614 LttvProcessState
*process
;
1615 LttvExecutionState
*es
;
1618 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1620 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1621 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1622 es
->t
= LTTV_STATE_SYSCALL
;
1623 process
->kernel_thread
= 1;
1628 static gboolean
process_exit(void *hook_data
, void *call_data
)
1630 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1631 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1632 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1636 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1637 LttvProcessState
*process
= ts
->running_process
[cpu
];
1639 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1641 // FIXME : Add this test in the "known state" section
1642 // g_assert(process->pid == pid);
1644 if(likely(process
!= NULL
)) {
1645 process
->state
->s
= LTTV_STATE_EXIT
;
1650 static gboolean
process_free(void *hook_data
, void *call_data
)
1652 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1653 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1654 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1655 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1657 LttvProcessState
*process
;
1659 /* PID of the process to release */
1660 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1662 g_assert(release_pid
!= 0);
1664 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1666 if(likely(process
!= NULL
)) {
1667 /* release_task is happening at kernel level : we can now safely release
1668 * the data structure of the process */
1669 //This test is fun, though, as it may happen that
1670 //at time t : CPU 0 : process_free
1671 //at time t+150ns : CPU 1 : schedule out
1672 //Clearly due to time imprecision, we disable it. (Mathieu)
1673 //If this weird case happen, we have no choice but to put the
1674 //Currently running process on the cpu to 0.
1675 //I re-enable it following time precision fixes. (Mathieu)
1676 //Well, in the case where an process is freed by a process on another CPU
1677 //and still scheduled, it happens that this is the schedchange that will
1678 //drop the last reference count. Do not free it here!
1679 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1681 for(i
=0; i
< num_cpus
; i
++) {
1682 //g_assert(process != ts->running_process[i]);
1683 if(process
== ts
->running_process
[i
]) {
1684 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1688 //if(i == num_cpus) /* process is not scheduled */
1689 //exit_process(s, process); // do nothing : wait for the schedchange to
1690 //delete the process.
1697 static gboolean
process_exec(void *hook_data
, void *call_data
)
1699 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1700 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1701 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1702 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1705 LttvProcessState
*process
= ts
->running_process
[cpu
];
1707 /* PID of the process to release */
1708 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1709 //name = ltt_event_get_string(e, thf->f1);
1710 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1712 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1713 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1714 memcpy(null_term_name
, name_begin
, name_len
);
1715 null_term_name
[name_len
] = '\0';
1717 process
->name
= g_quark_from_string(null_term_name
);
1718 g_free(null_term_name
);
1722 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1724 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1725 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1726 //It's slow : optimise later by doing this before reading trace.
1727 LttEventType
*et
= ltt_event_eventtype(e
);
1729 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1734 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1735 LttvProcessState
*process
= ts
->running_process
[cpu
];
1736 LttvProcessState
*parent_process
;
1737 LttField
*f4
, *f5
, *f6
;
1738 GQuark mode
, submode
, status
;
1741 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1744 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1747 command
= ltt_event_get_string(e
, thf
->f3
);
1750 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1751 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1752 ltt_event_get_unsigned(e
, f4
));
1755 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1756 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1757 ltt_event_get_unsigned(e
, f5
));
1760 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1761 status
= ltt_enum_string_get(ltt_field_type(f6
),
1762 ltt_event_get_unsigned(e
, f6
));
1764 /* The process might exist if a process was forked while performing the sate dump. */
1765 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1766 if(process
== NULL
) {
1767 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1768 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1769 pid
, g_quark_from_string(command
),
1770 &s
->parent
.timestamp
);
1772 /* Keep the stack bottom : a running user mode */
1774 /* Disabled because of inconsistencies in the current statedump states. */
1775 if(mode
== LTTV_STATE_USER_MODE
) {
1776 /* Only keep the bottom */
1777 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1779 /* On top of it : */
1780 LttvExecutionState
*es
;
1781 es
= process
->state
= &g_array_index(process
->execution_stack
,
1782 LttvExecutionState
, 1);
1791 LttvExecutionState
*es
;
1792 es
= process
->state
= &g_array_index(process
->execution_stack
,
1793 LttvExecutionState
, 1);
1794 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1795 es
->s
= LTTV_STATE_UNNAMED
;
1796 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1799 /* The process has already been created :
1800 * Probably was forked while dumping the process state or
1801 * was simply scheduled in prior to get the state dump event.
1803 process
->ppid
= parent_pid
;
1804 process
->name
= g_quark_from_string(command
);
1805 /* Don't mess around with the stack, it will eventually become
1806 * ok after the end of state dump. */
1812 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1814 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1816 lttv_state_add_event_hooks(tss
);
1821 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1823 LttvTraceset
*traceset
= self
->parent
.ts
;
1825 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1829 LttvTracefileState
*tfs
;
1833 LttvTraceHookByFacility
*thf
;
1835 LttvTraceHook
*hook
;
1837 LttvAttributeValue val
;
1842 nb_trace
= lttv_traceset_number(traceset
);
1843 for(i
= 0 ; i
< nb_trace
; i
++) {
1844 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1846 /* Find the eventtype id for the following events and register the
1847 associated by id hooks. */
1849 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1850 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1853 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1854 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1855 LTT_FIELD_SYSCALL_ID
, 0, 0,
1856 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1859 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1860 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1862 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1865 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1866 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1867 LTT_FIELD_TRAP_ID
, 0, 0,
1868 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1871 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1872 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1874 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1877 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1878 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1879 LTT_FIELD_IRQ_ID
, 0, 0,
1880 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1883 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1884 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1886 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1889 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1890 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1891 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1892 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1895 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1896 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1898 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1901 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1902 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1903 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1904 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1907 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1908 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1909 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1910 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1913 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1914 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1915 LTT_FIELD_PID
, 0, 0,
1916 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1920 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1921 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1922 LTT_FIELD_PID
, 0, 0,
1923 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1926 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1927 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1928 LTT_FIELD_PID
, 0, 0,
1929 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1932 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1933 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1934 LTT_FIELD_FILENAME
, 0, 0,
1935 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1938 /* statedump-related hooks */
1939 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1940 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1941 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1942 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1945 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1946 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
1947 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1948 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1951 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1952 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
1953 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
1954 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1957 hooks
= g_array_set_size(hooks
, hn
);
1959 /* Add these hooks to each event_by_id hooks list */
1961 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1963 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1965 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1966 LttvTracefileContext
*, j
));
1968 for(k
= 0 ; k
< hooks
->len
; k
++) {
1969 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1970 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1971 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1973 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1980 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1981 *(val
.v_pointer
) = hooks
;
1985 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1987 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1989 lttv_state_remove_event_hooks(tss
);
1994 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1996 LttvTraceset
*traceset
= self
->parent
.ts
;
1998 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2002 LttvTracefileState
*tfs
;
2006 LttvTraceHook
*hook
;
2008 LttvTraceHookByFacility
*thf
;
2010 LttvAttributeValue val
;
2012 nb_trace
= lttv_traceset_number(traceset
);
2013 for(i
= 0 ; i
< nb_trace
; i
++) {
2014 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2015 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2016 hooks
= *(val
.v_pointer
);
2018 /* Remove these hooks from each event_by_id hooks list */
2020 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2022 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2024 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2025 LttvTracefileContext
*, j
));
2027 for(k
= 0 ; k
< hooks
->len
; k
++) {
2028 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2029 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2030 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2032 lttv_hooks_remove_data(
2033 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2039 for(k
= 0 ; k
< hooks
->len
; k
++)
2040 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2041 g_array_free(hooks
, TRUE
);
2045 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2047 guint
*event_count
= (guint
*)hook_data
;
2049 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2050 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2055 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2057 LttvTracefileState
*tfcs
;
2059 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2061 LttEventPosition
*ep
;
2067 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2069 LttvAttributeValue value
;
2071 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2072 LTTV_STATE_SAVED_STATES
);
2073 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2074 value
= lttv_attribute_add(saved_states_tree
,
2075 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2076 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2077 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2078 *(value
.v_time
) = self
->parent
.timestamp
;
2079 lttv_state_save(tcs
, saved_state_tree
);
2080 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2081 self
->parent
.timestamp
.tv_nsec
);
2083 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2088 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2090 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2092 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2097 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2105 static gboolean
block_start(void *hook_data
, void *call_data
)
2107 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2109 LttvTracefileState
*tfcs
;
2111 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2113 LttEventPosition
*ep
;
2115 guint i
, nb_block
, nb_event
, nb_tracefile
;
2119 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2121 LttvAttributeValue value
;
2123 ep
= ltt_event_position_new();
2125 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2127 /* Count the number of events added since the last block end in any
2130 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2132 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2133 LttvTracefileContext
, i
));
2134 ltt_event_position(tfcs
->parent
.e
, ep
);
2135 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2136 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2137 tfcs
->saved_position
= nb_event
;
2141 if(tcs
->nb_event
>= tcs
->save_interval
) {
2142 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2143 LTTV_STATE_SAVED_STATES
);
2144 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2145 value
= lttv_attribute_add(saved_states_tree
,
2146 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2147 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2148 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2149 *(value
.v_time
) = self
->parent
.timestamp
;
2150 lttv_state_save(tcs
, saved_state_tree
);
2152 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2153 self
->parent
.timestamp
.tv_nsec
);
2155 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2161 static gboolean
block_end(void *hook_data
, void *call_data
)
2163 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2165 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2169 LttEventPosition
*ep
;
2171 guint nb_block
, nb_event
;
2173 ep
= ltt_event_position_new();
2174 ltt_event_position(self
->parent
.e
, ep
);
2175 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2176 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2177 self
->saved_position
= 0;
2178 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2185 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2187 LttvTraceset
*traceset
= self
->parent
.ts
;
2189 guint i
, j
, nb_trace
, nb_tracefile
;
2193 LttvTracefileState
*tfs
;
2195 LttvTraceHook hook_start
, hook_end
;
2197 nb_trace
= lttv_traceset_number(traceset
);
2198 for(i
= 0 ; i
< nb_trace
; i
++) {
2199 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2201 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2202 NULL
, NULL
, block_start
, &hook_start
);
2203 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2204 NULL
, NULL
, block_end
, &hook_end
);
2206 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2208 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2210 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2211 LttvTracefileContext
, j
));
2212 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2213 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2214 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2215 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2221 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2223 LttvTraceset
*traceset
= self
->parent
.ts
;
2225 guint i
, j
, nb_trace
, nb_tracefile
;
2229 LttvTracefileState
*tfs
;
2232 nb_trace
= lttv_traceset_number(traceset
);
2233 for(i
= 0 ; i
< nb_trace
; i
++) {
2235 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2236 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2238 guint
*event_count
= g_new(guint
, 1);
2241 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2243 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2244 LttvTracefileContext
*, j
));
2245 lttv_hooks_add(tfs
->parent
.event
,
2246 state_save_event_hook
,
2253 lttv_process_traceset_begin(&self
->parent
,
2254 NULL
, NULL
, NULL
, NULL
, NULL
);
2258 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2260 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2262 lttv_state_save_add_event_hooks(tss
);
2269 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2271 LttvTraceset
*traceset
= self
->parent
.ts
;
2273 guint i
, j
, nb_trace
, nb_tracefile
;
2277 LttvTracefileState
*tfs
;
2279 LttvTraceHook hook_start
, hook_end
;
2281 nb_trace
= lttv_traceset_number(traceset
);
2282 for(i
= 0 ; i
< nb_trace
; i
++) {
2283 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2285 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2286 NULL
, NULL
, block_start
, &hook_start
);
2288 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2289 NULL
, NULL
, block_end
, &hook_end
);
2291 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2293 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2295 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2296 LttvTracefileContext
, j
));
2297 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2298 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2299 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2300 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2306 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2308 LttvTraceset
*traceset
= self
->parent
.ts
;
2310 guint i
, j
, nb_trace
, nb_tracefile
;
2314 LttvTracefileState
*tfs
;
2316 LttvHooks
*after_trace
= lttv_hooks_new();
2318 lttv_hooks_add(after_trace
,
2319 state_save_after_trace_hook
,
2324 lttv_process_traceset_end(&self
->parent
,
2325 NULL
, after_trace
, NULL
, NULL
, NULL
);
2327 lttv_hooks_destroy(after_trace
);
2329 nb_trace
= lttv_traceset_number(traceset
);
2330 for(i
= 0 ; i
< nb_trace
; i
++) {
2332 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2333 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2335 guint
*event_count
= NULL
;
2337 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2339 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2340 LttvTracefileContext
*, j
));
2341 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2342 state_save_event_hook
);
2344 if(event_count
) g_free(event_count
);
2348 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2350 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2352 lttv_state_save_remove_event_hooks(tss
);
2357 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2359 LttvTraceset
*traceset
= self
->parent
.ts
;
2363 int min_pos
, mid_pos
, max_pos
;
2365 guint call_rest
= 0;
2367 LttvTraceState
*tcs
;
2369 LttvAttributeValue value
;
2371 LttvAttributeType type
;
2373 LttvAttributeName name
;
2375 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2377 //g_tree_destroy(self->parent.pqueue);
2378 //self->parent.pqueue = g_tree_new(compare_tracefile);
2380 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2382 nb_trace
= lttv_traceset_number(traceset
);
2383 for(i
= 0 ; i
< nb_trace
; i
++) {
2384 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2386 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2387 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2388 LTTV_STATE_SAVED_STATES
);
2391 if(saved_states_tree
) {
2392 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2393 mid_pos
= max_pos
/ 2;
2394 while(min_pos
< max_pos
) {
2395 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2396 g_assert(type
== LTTV_GOBJECT
);
2397 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2398 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2400 g_assert(type
== LTTV_TIME
);
2401 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2403 closest_tree
= saved_state_tree
;
2405 else max_pos
= mid_pos
- 1;
2407 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2411 /* restore the closest earlier saved state */
2413 lttv_state_restore(tcs
, closest_tree
);
2417 /* There is no saved state, yet we want to have it. Restart at T0 */
2419 restore_init_state(tcs
);
2420 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2423 /* We want to seek quickly without restoring/updating the state */
2425 restore_init_state(tcs
);
2426 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2429 if(!call_rest
) g_info("NOT Calling restore");
2434 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2440 traceset_state_finalize (LttvTracesetState
*self
)
2442 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2443 finalize(G_OBJECT(self
));
2448 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2450 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2452 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2453 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2454 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2455 klass
->new_traceset_context
= new_traceset_context
;
2456 klass
->new_trace_context
= new_trace_context
;
2457 klass
->new_tracefile_context
= new_tracefile_context
;
2462 lttv_traceset_state_get_type(void)
2464 static GType type
= 0;
2466 static const GTypeInfo info
= {
2467 sizeof (LttvTracesetStateClass
),
2468 NULL
, /* base_init */
2469 NULL
, /* base_finalize */
2470 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2471 NULL
, /* class_finalize */
2472 NULL
, /* class_data */
2473 sizeof (LttvTracesetState
),
2474 0, /* n_preallocs */
2475 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2476 NULL
/* value handling */
2479 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2487 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2493 trace_state_finalize (LttvTraceState
*self
)
2495 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2496 finalize(G_OBJECT(self
));
2501 trace_state_class_init (LttvTraceStateClass
*klass
)
2503 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2505 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2506 klass
->state_save
= state_save
;
2507 klass
->state_restore
= state_restore
;
2508 klass
->state_saved_free
= state_saved_free
;
2513 lttv_trace_state_get_type(void)
2515 static GType type
= 0;
2517 static const GTypeInfo info
= {
2518 sizeof (LttvTraceStateClass
),
2519 NULL
, /* base_init */
2520 NULL
, /* base_finalize */
2521 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2522 NULL
, /* class_finalize */
2523 NULL
, /* class_data */
2524 sizeof (LttvTraceState
),
2525 0, /* n_preallocs */
2526 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2527 NULL
/* value handling */
2530 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2531 "LttvTraceStateType", &info
, 0);
2538 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2544 tracefile_state_finalize (LttvTracefileState
*self
)
2546 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2547 finalize(G_OBJECT(self
));
2552 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2554 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2556 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2561 lttv_tracefile_state_get_type(void)
2563 static GType type
= 0;
2565 static const GTypeInfo info
= {
2566 sizeof (LttvTracefileStateClass
),
2567 NULL
, /* base_init */
2568 NULL
, /* base_finalize */
2569 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2570 NULL
, /* class_finalize */
2571 NULL
, /* class_data */
2572 sizeof (LttvTracefileState
),
2573 0, /* n_preallocs */
2574 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2575 NULL
/* value handling */
2578 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2579 "LttvTracefileStateType", &info
, 0);
2585 static void module_init()
2587 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2588 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2589 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2590 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2591 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2592 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2593 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2594 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2595 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2596 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2597 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2598 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2599 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2600 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2601 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2602 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2603 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2604 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2605 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2606 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2607 LTTV_STATE_EVENT
= g_quark_from_string("event");
2608 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2609 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2610 LTTV_STATE_TIME
= g_quark_from_string("time");
2611 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2612 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2613 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2614 g_quark_from_string("trace_state_use_count");
2617 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2618 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2619 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2620 LTT_FACILITY_FS
= g_quark_from_string("fs");
2621 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2622 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2625 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2626 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2627 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2628 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2629 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2630 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2631 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2632 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2633 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2634 LTT_EVENT_FORK
= g_quark_from_string("fork");
2635 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2636 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2637 LTT_EVENT_FREE
= g_quark_from_string("free");
2638 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2639 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2640 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2641 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2644 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2645 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2646 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2647 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2648 LTT_FIELD_OUT
= g_quark_from_string("out");
2649 LTT_FIELD_IN
= g_quark_from_string("in");
2650 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2651 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2652 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2653 LTT_FIELD_PID
= g_quark_from_string("pid");
2654 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2655 LTT_FIELD_NAME
= g_quark_from_string("name");
2656 LTT_FIELD_MODE
= g_quark_from_string("mode");
2657 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2658 LTT_FIELD_STATUS
= g_quark_from_string("status");
2659 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2660 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2664 static void module_destroy()
2669 LTTV_MODULE("state", "State computation", \
2670 "Update the system state, possibly saving it at intervals", \
2671 module_init
, module_destroy
)