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
,
65 LTT_EVENT_THREAD_BRAND
;
73 LTT_FIELD_SOFT_IRQ_ID
,
90 LTTV_STATE_MODE_UNKNOWN
,
98 LTTV_STATE_SUBMODE_UNKNOWN
,
99 LTTV_STATE_SUBMODE_NONE
;
103 LTTV_STATE_UNBRANDED
,
104 LTTV_STATE_WAIT_FORK
,
113 LTTV_STATE_USER_THREAD
,
114 LTTV_STATE_KERNEL_THREAD
;
117 LTTV_STATE_TRACEFILES
,
118 LTTV_STATE_PROCESSES
,
120 LTTV_STATE_RUNNING_PROCESS
,
122 LTTV_STATE_SAVED_STATES
,
123 LTTV_STATE_SAVED_STATES_TIME
,
126 LTTV_STATE_NAME_TABLES
,
127 LTTV_STATE_TRACE_STATE_USE_COUNT
;
129 static void create_max_time(LttvTraceState
*tcs
);
131 static void get_max_time(LttvTraceState
*tcs
);
133 static void free_max_time(LttvTraceState
*tcs
);
135 static void create_name_tables(LttvTraceState
*tcs
);
137 static void get_name_tables(LttvTraceState
*tcs
);
139 static void free_name_tables(LttvTraceState
*tcs
);
141 static void free_saved_state(LttvTraceState
*tcs
);
143 static void lttv_state_free_process_table(GHashTable
*processes
);
146 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
148 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
152 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
154 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
158 void lttv_state_state_saved_free(LttvTraceState
*self
,
159 LttvAttribute
*container
)
161 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
165 guint
process_hash(gconstpointer key
)
167 guint pid
= ((const LttvProcessState
*)key
)->pid
;
168 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
172 /* If the hash table hash function is well distributed,
173 * the process_equal should compare different pid */
174 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
176 const LttvProcessState
*process_a
, *process_b
;
179 process_a
= (const LttvProcessState
*)a
;
180 process_b
= (const LttvProcessState
*)b
;
182 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
183 else if(likely(process_a
->pid
== 0 &&
184 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
189 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
191 g_tree_destroy((GTree
*)value
);
194 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
196 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
197 g_hash_table_destroy(usertraces
);
203 restore_init_state(LttvTraceState
*self
)
207 LttvTracefileState
*tfcs
;
209 LttTime start_time
, end_time
;
211 /* Free the process tables */
212 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
213 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
214 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
215 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
218 /* Seek time to beginning */
219 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
220 // closest. It's the tracecontext job to seek the trace to the beginning
221 // anyway : the init state might be used at the middle of the trace as well...
222 //g_tree_destroy(self->parent.ts_context->pqueue);
223 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
225 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
227 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
229 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
231 /* Put the per cpu running_process to beginning state : process 0. */
232 for(i
=0; i
< nb_cpus
; i
++) {
233 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
234 LTTV_STATE_UNNAMED
, &start_time
);
235 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
236 self
->running_process
[i
]->cpu
= i
;
240 nb_tracefile
= self
->parent
.tracefiles
->len
;
242 for(i
= 0 ; i
< nb_tracefile
; i
++) {
244 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
245 LttvTracefileContext
*, i
));
246 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
247 // tfcs->saved_position = 0;
248 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
249 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
250 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
251 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
256 //static LttTime time_zero = {0,0};
258 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
261 const LttTime
*t1
= (const LttTime
*)a
;
262 const LttTime
*t2
= (const LttTime
*)b
;
264 return ltt_time_compare(*t1
, *t2
);
267 static void free_usertrace_key(gpointer data
)
273 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
275 guint i
, j
, nb_trace
, nb_tracefile
;
277 LttvTraceContext
*tc
;
281 LttvTracefileState
*tfcs
;
283 LttvAttributeValue v
;
285 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
286 init((LttvTracesetContext
*)self
, ts
);
288 nb_trace
= lttv_traceset_number(ts
);
289 for(i
= 0 ; i
< nb_trace
; i
++) {
290 tc
= self
->parent
.traces
[i
];
291 tcs
= LTTV_TRACE_STATE(tc
);
292 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
293 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
297 if(*(v
.v_uint
) == 1) {
298 create_name_tables(tcs
);
299 create_max_time(tcs
);
301 get_name_tables(tcs
);
304 nb_tracefile
= tc
->tracefiles
->len
;
305 tcs
->processes
= NULL
;
306 tcs
->usertraces
= NULL
;
307 tcs
->running_process
= g_new(LttvProcessState
*,
308 ltt_trace_get_num_cpu(tc
->t
));
309 restore_init_state(tcs
);
310 for(j
= 0 ; j
< nb_tracefile
; j
++) {
312 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
313 LttvTracefileContext
*, j
));
314 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
315 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
317 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
318 /* It's a Usertrace */
319 LttvProcessState
*process
;
321 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
322 ltt_tracefile_creation(tfcs
->parent
.tf
));
323 process
= lttv_state_find_process_or_create(
325 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
327 process
->usertrace
= tfcs
;
331 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
332 /* It's a Usertrace */
333 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
334 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
336 if(!usertrace_tree
) {
337 usertrace_tree
= g_tree_new_full(compare_usertraces
,
338 NULL
, free_usertrace_key
, NULL
);
339 g_hash_table_insert(tcs
->usertraces
,
340 (gpointer
)tid
, usertrace_tree
);
342 LttTime
*timestamp
= g_new(LttTime
, 1);
343 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
344 ltt_tracefile_creation(tfcs
->parent
.tf
));
345 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
353 fini(LttvTracesetState
*self
)
359 LttvTracefileState
*tfcs
;
361 LttvAttributeValue v
;
363 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
364 for(i
= 0 ; i
< nb_trace
; i
++) {
365 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
366 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
369 g_assert(*(v
.v_uint
) != 0);
372 if(*(v
.v_uint
) == 0) {
373 free_name_tables(tcs
);
375 free_saved_state(tcs
);
377 g_free(tcs
->running_process
);
378 tcs
->running_process
= NULL
;
379 lttv_state_free_process_table(tcs
->processes
);
380 lttv_state_free_usertraces(tcs
->usertraces
);
381 tcs
->processes
= NULL
;
382 tcs
->usertraces
= NULL
;
384 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
385 fini((LttvTracesetContext
*)self
);
389 static LttvTracesetContext
*
390 new_traceset_context(LttvTracesetContext
*self
)
392 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
396 static LttvTraceContext
*
397 new_trace_context(LttvTracesetContext
*self
)
399 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
403 static LttvTracefileContext
*
404 new_tracefile_context(LttvTracesetContext
*self
)
406 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
410 /* Write the process state of the trace */
412 static void write_process_state(gpointer key
, gpointer value
,
415 LttvProcessState
*process
;
417 LttvExecutionState
*es
;
419 FILE *fp
= (FILE *)user_data
;
423 process
= (LttvProcessState
*)value
;
425 " <PROCESS CORE=%p PID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
426 process
, process
->pid
, process
->ppid
, g_quark_to_string(process
->type
),
427 process
->creation_time
.tv_sec
,
428 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
429 g_quark_to_string(process
->brand
),
432 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
433 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
434 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
435 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
436 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
437 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
438 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
440 fprintf(fp
, " </PROCESS>\n");
444 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
446 guint i
, nb_tracefile
, nb_block
, offset
;
449 LttvTracefileState
*tfcs
;
453 LttEventPosition
*ep
;
457 ep
= ltt_event_position_new();
459 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
461 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
463 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
464 for(i
=0;i
<nb_cpus
;i
++) {
465 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
466 i
, self
->running_process
[i
]->pid
);
469 nb_tracefile
= self
->parent
.tracefiles
->len
;
471 for(i
= 0 ; i
< nb_tracefile
; i
++) {
473 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
474 LttvTracefileContext
*, i
));
475 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
476 tfcs
->parent
.timestamp
.tv_sec
,
477 tfcs
->parent
.timestamp
.tv_nsec
);
478 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
479 if(e
== NULL
) fprintf(fp
,"/>\n");
481 ltt_event_position(e
, ep
);
482 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
483 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
488 fprintf(fp
,"</PROCESS_STATE>");
492 /* Copy each process from an existing hash table to a new one */
494 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
496 LttvProcessState
*process
, *new_process
;
498 GHashTable
*new_processes
= (GHashTable
*)user_data
;
502 process
= (LttvProcessState
*)value
;
503 new_process
= g_new(LttvProcessState
, 1);
504 *new_process
= *process
;
505 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
506 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
507 new_process
->execution_stack
=
508 g_array_set_size(new_process
->execution_stack
,
509 process
->execution_stack
->len
);
510 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
511 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
512 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
514 new_process
->state
= &g_array_index(new_process
->execution_stack
,
515 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
516 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
518 new_process
->user_stack
=
519 g_array_set_size(new_process
->user_stack
,
520 process
->user_stack
->len
);
521 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
522 g_array_index(new_process
->user_stack
, guint64
, i
) =
523 g_array_index(process
->user_stack
, guint64
, i
);
525 new_process
->current_function
= process
->current_function
;
526 g_hash_table_insert(new_processes
, new_process
, new_process
);
530 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
532 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
534 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
535 return new_processes
;
539 /* The saved state for each trace contains a member "processes", which
540 stores a copy of the process table, and a member "tracefiles" with
541 one entry per tracefile. Each tracefile has a "process" member pointing
542 to the current process and a "position" member storing the tracefile
543 position (needed to seek to the current "next" event. */
545 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
547 guint i
, nb_tracefile
, nb_cpus
;
549 LttvTracefileState
*tfcs
;
551 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
553 guint
*running_process
;
555 LttvAttributeType type
;
557 LttvAttributeValue value
;
559 LttvAttributeName name
;
561 LttEventPosition
*ep
;
563 tracefiles_tree
= lttv_attribute_find_subdir(container
,
564 LTTV_STATE_TRACEFILES
);
566 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
568 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
570 /* Add the currently running processes array */
571 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
572 running_process
= g_new(guint
, nb_cpus
);
573 for(i
=0;i
<nb_cpus
;i
++) {
574 running_process
[i
] = self
->running_process
[i
]->pid
;
576 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
578 *(value
.v_pointer
) = running_process
;
580 g_info("State save");
582 nb_tracefile
= self
->parent
.tracefiles
->len
;
584 for(i
= 0 ; i
< nb_tracefile
; i
++) {
586 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
587 LttvTracefileContext
*, i
));
588 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
589 value
= lttv_attribute_add(tracefiles_tree
, i
,
591 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
593 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
595 *(value
.v_uint
) = tfcs
->process
->pid
;
597 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
599 /* Only save the position if the tfs has not infinite time. */
600 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
601 // && current_tfcs != tfcs) {
602 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
603 *(value
.v_pointer
) = NULL
;
605 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
606 ep
= ltt_event_position_new();
607 ltt_event_position(e
, ep
);
608 *(value
.v_pointer
) = ep
;
610 guint nb_block
, offset
;
613 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
614 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
616 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
622 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
624 guint i
, nb_tracefile
, pid
, nb_cpus
;
626 LttvTracefileState
*tfcs
;
628 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
630 guint
*running_process
;
632 LttvAttributeType type
;
634 LttvAttributeValue value
;
636 LttvAttributeName name
;
640 LttEventPosition
*ep
;
642 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
644 tracefiles_tree
= lttv_attribute_find_subdir(container
,
645 LTTV_STATE_TRACEFILES
);
647 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
649 g_assert(type
== LTTV_POINTER
);
650 lttv_state_free_process_table(self
->processes
);
651 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
653 /* Add the currently running processes array */
654 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
655 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
657 g_assert(type
== LTTV_POINTER
);
658 running_process
= *(value
.v_pointer
);
659 for(i
=0;i
<nb_cpus
;i
++) {
660 pid
= running_process
[i
];
661 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
662 g_assert(self
->running_process
[i
] != NULL
);
666 nb_tracefile
= self
->parent
.tracefiles
->len
;
668 //g_tree_destroy(tsc->pqueue);
669 //tsc->pqueue = g_tree_new(compare_tracefile);
671 for(i
= 0 ; i
< nb_tracefile
; i
++) {
673 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
674 LttvTracefileContext
*, i
));
675 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
676 g_assert(type
== LTTV_GOBJECT
);
677 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
679 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
681 g_assert(type
== LTTV_UINT
);
682 pid
= *(value
.v_uint
);
683 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
685 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
687 g_assert(type
== LTTV_POINTER
);
688 //g_assert(*(value.v_pointer) != NULL);
689 ep
= *(value
.v_pointer
);
690 g_assert(tfcs
->parent
.t_context
!= NULL
);
692 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
693 g_tree_remove(tsc
->pqueue
, tfc
);
696 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
697 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
698 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
699 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
700 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
702 tfc
->timestamp
= ltt_time_infinite
;
708 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
710 guint i
, nb_tracefile
, nb_cpus
;
712 LttvTracefileState
*tfcs
;
714 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
716 guint
*running_process
;
718 LttvAttributeType type
;
720 LttvAttributeValue value
;
722 LttvAttributeName name
;
726 LttEventPosition
*ep
;
728 tracefiles_tree
= lttv_attribute_find_subdir(container
,
729 LTTV_STATE_TRACEFILES
);
730 g_object_ref(G_OBJECT(tracefiles_tree
));
731 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
733 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
735 g_assert(type
== LTTV_POINTER
);
736 lttv_state_free_process_table(*(value
.v_pointer
));
737 *(value
.v_pointer
) = NULL
;
738 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
740 /* Free running processes array */
741 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
742 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
744 g_assert(type
== LTTV_POINTER
);
745 running_process
= *(value
.v_pointer
);
746 g_free(running_process
);
748 nb_tracefile
= self
->parent
.tracefiles
->len
;
750 for(i
= 0 ; i
< nb_tracefile
; i
++) {
752 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
753 LttvTracefileContext
*, i
));
754 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
755 g_assert(type
== LTTV_GOBJECT
);
756 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
758 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
760 g_assert(type
== LTTV_POINTER
);
761 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
763 g_object_unref(G_OBJECT(tracefiles_tree
));
767 static void free_saved_state(LttvTraceState
*self
)
771 LttvAttributeType type
;
773 LttvAttributeValue value
;
775 LttvAttributeName name
;
779 LttvAttribute
*saved_states
;
781 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
782 LTTV_STATE_SAVED_STATES
);
784 nb
= lttv_attribute_get_number(saved_states
);
785 for(i
= 0 ; i
< nb
; i
++) {
786 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
787 g_assert(type
== LTTV_GOBJECT
);
788 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
791 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
796 create_max_time(LttvTraceState
*tcs
)
798 LttvAttributeValue v
;
800 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
802 g_assert(*(v
.v_pointer
) == NULL
);
803 *(v
.v_pointer
) = g_new(LttTime
,1);
804 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
809 get_max_time(LttvTraceState
*tcs
)
811 LttvAttributeValue v
;
813 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
815 g_assert(*(v
.v_pointer
) != NULL
);
816 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
821 free_max_time(LttvTraceState
*tcs
)
823 LttvAttributeValue v
;
825 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
827 g_free(*(v
.v_pointer
));
828 *(v
.v_pointer
) = NULL
;
832 typedef struct _LttvNameTables
{
833 // FIXME GQuark *eventtype_names;
834 GQuark
*syscall_names
;
839 GQuark
*soft_irq_names
;
844 create_name_tables(LttvTraceState
*tcs
)
848 GQuark f_name
, e_name
;
852 LttvTraceHookByFacility
*thf
;
858 GString
*fe_name
= g_string_new("");
860 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
862 LttvAttributeValue v
;
864 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
866 g_assert(*(v
.v_pointer
) == NULL
);
867 *(v
.v_pointer
) = name_tables
;
868 #if 0 // Use iteration over the facilities_by_name and then list all event
869 // types of each facility
870 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
871 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
872 for(i
= 0 ; i
< nb
; i
++) {
873 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
874 e_name
= ltt_eventtype_name(et
);
875 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
876 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
877 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
880 if(!lttv_trace_find_hook(tcs
->parent
.t
,
881 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
882 LTT_FIELD_SYSCALL_ID
, 0, 0,
885 thf
= lttv_trace_hook_get_first(&h
);
887 t
= ltt_field_type(thf
->f1
);
888 nb
= ltt_type_element_number(t
);
890 lttv_trace_hook_destroy(&h
);
892 name_tables
->syscall_names
= g_new(GQuark
, nb
);
893 name_tables
->nb_syscalls
= nb
;
895 for(i
= 0 ; i
< nb
; i
++) {
896 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
899 //name_tables->syscall_names = g_new(GQuark, 256);
900 //for(i = 0 ; i < 256 ; i++) {
901 // g_string_printf(fe_name, "syscall %d", i);
902 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
905 name_tables
->syscall_names
= NULL
;
906 name_tables
->nb_syscalls
= 0;
909 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
910 LTT_EVENT_TRAP_ENTRY
,
911 LTT_FIELD_TRAP_ID
, 0, 0,
914 thf
= lttv_trace_hook_get_first(&h
);
916 t
= ltt_field_type(thf
->f1
);
917 //nb = ltt_type_element_number(t);
919 lttv_trace_hook_destroy(&h
);
922 name_tables->trap_names = g_new(GQuark, nb);
923 for(i = 0 ; i < nb ; i++) {
924 name_tables->trap_names[i] = g_quark_from_string(
925 ltt_enum_string_get(t, i));
928 name_tables
->nb_traps
= 256;
929 name_tables
->trap_names
= g_new(GQuark
, 256);
930 for(i
= 0 ; i
< 256 ; i
++) {
931 g_string_printf(fe_name
, "trap %d", i
);
932 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
935 name_tables
->trap_names
= NULL
;
936 name_tables
->nb_traps
= 0;
939 if(!lttv_trace_find_hook(tcs
->parent
.t
,
940 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
941 LTT_FIELD_IRQ_ID
, 0, 0,
944 thf
= lttv_trace_hook_get_first(&h
);
946 t
= ltt_field_type(thf
->f1
);
947 //nb = ltt_type_element_number(t);
949 lttv_trace_hook_destroy(&h
);
952 name_tables->irq_names = g_new(GQuark, nb);
953 for(i = 0 ; i < nb ; i++) {
954 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
958 name_tables
->irq_names
= g_new(GQuark
, 256);
959 for(i
= 0 ; i
< 256 ; i
++) {
960 g_string_printf(fe_name
, "irq %d", i
);
961 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
964 name_tables
->irq_names
= NULL
;
967 name_tables->soft_irq_names = g_new(GQuark, nb);
968 for(i = 0 ; i < nb ; i++) {
969 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
973 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
974 for(i
= 0 ; i
< 256 ; i
++) {
975 g_string_printf(fe_name
, "softirq %d", i
);
976 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
980 g_string_free(fe_name
, TRUE
);
985 get_name_tables(LttvTraceState
*tcs
)
987 LttvNameTables
*name_tables
;
989 LttvAttributeValue v
;
991 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
993 g_assert(*(v
.v_pointer
) != NULL
);
994 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
995 //tcs->eventtype_names = name_tables->eventtype_names;
996 tcs
->syscall_names
= name_tables
->syscall_names
;
997 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
998 tcs
->trap_names
= name_tables
->trap_names
;
999 tcs
->nb_traps
= name_tables
->nb_traps
;
1000 tcs
->irq_names
= name_tables
->irq_names
;
1001 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1006 free_name_tables(LttvTraceState
*tcs
)
1008 LttvNameTables
*name_tables
;
1010 LttvAttributeValue v
;
1012 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1014 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1015 *(v
.v_pointer
) = NULL
;
1017 // g_free(name_tables->eventtype_names);
1018 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1019 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1020 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1021 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1022 if(name_tables
) g_free(name_tables
);
1025 #ifdef HASH_TABLE_DEBUG
1027 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1029 LttvProcessState
*process
= (LttvProcessState
*)value
;
1031 /* Test for process corruption */
1032 guint stack_len
= process
->execution_stack
->len
;
1035 static void hash_table_check(GHashTable
*table
)
1037 g_hash_table_foreach(table
, test_process
, NULL
);
1044 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1047 LttvExecutionState
*es
;
1049 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1050 guint cpu
= tfs
->cpu
;
1052 #ifdef HASH_TABLE_DEBUG
1053 hash_table_check(ts
->processes
);
1055 LttvProcessState
*process
= ts
->running_process
[cpu
];
1057 guint depth
= process
->execution_stack
->len
;
1059 process
->execution_stack
=
1060 g_array_set_size(process
->execution_stack
, depth
+ 1);
1063 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1065 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1068 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1069 es
->cum_cpu_time
= ltt_time_zero
;
1070 es
->s
= process
->state
->s
;
1071 process
->state
= es
;
1075 * return 1 when empty, else 0 */
1076 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1077 LttvTracefileState
*tfs
)
1079 guint cpu
= tfs
->cpu
;
1080 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1082 guint depth
= process
->execution_stack
->len
;
1088 process
->execution_stack
=
1089 g_array_set_size(process
->execution_stack
, depth
- 1);
1090 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1092 process
->state
->change
= tfs
->parent
.timestamp
;
1097 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1099 guint cpu
= tfs
->cpu
;
1100 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1101 LttvProcessState
*process
= ts
->running_process
[cpu
];
1103 guint depth
= process
->execution_stack
->len
;
1105 if(process
->state
->t
!= t
){
1106 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1107 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1108 g_info("process state has %s when pop_int is %s\n",
1109 g_quark_to_string(process
->state
->t
),
1110 g_quark_to_string(t
));
1111 g_info("{ %u, %u, %s, %s, %s }\n",
1114 g_quark_to_string(process
->name
),
1115 g_quark_to_string(process
->brand
),
1116 g_quark_to_string(process
->state
->s
));
1121 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1122 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1126 process
->execution_stack
=
1127 g_array_set_size(process
->execution_stack
, depth
- 1);
1128 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1130 process
->state
->change
= tfs
->parent
.timestamp
;
1133 struct search_result
{
1134 const LttTime
*time
; /* Requested time */
1135 LttTime
*best
; /* Best result */
1138 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1140 const LttTime
*elem_time
= (const LttTime
*)a
;
1141 /* Explicit non const cast */
1142 struct search_result
*res
= (struct search_result
*)b
;
1144 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1145 /* The usertrace was created before the schedchange */
1146 /* Get larger keys */
1148 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1149 /* The usertrace was created after the schedchange time */
1150 /* Get smaller keys */
1152 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1153 res
->best
= elem_time
;
1156 res
->best
= elem_time
;
1163 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1164 guint pid
, const LttTime
*timestamp
)
1166 LttvTracefileState
*tfs
= NULL
;
1167 struct search_result res
;
1168 /* Find the usertrace associated with a pid and time interval.
1169 * Search in the usertraces by PID (within a hash) and then, for each
1170 * corresponding element of the array, find the first one with creation
1171 * timestamp the lowest, but higher or equal to "timestamp". */
1172 res
.time
= timestamp
;
1174 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1175 if(usertrace_tree
) {
1176 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1178 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1186 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1187 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1189 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1191 LttvExecutionState
*es
;
1193 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1199 process
->name
= name
;
1200 process
->brand
= LTTV_STATE_UNBRANDED
;
1201 //process->last_cpu = tfs->cpu_name;
1202 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1203 process
->type
= LTTV_STATE_USER_THREAD
;
1204 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1205 process
->current_function
= 0; //function 0x0 by default.
1207 g_info("Process %u, core %p", process
->pid
, process
);
1208 g_hash_table_insert(tcs
->processes
, process
, process
);
1211 process
->ppid
= parent
->pid
;
1212 process
->creation_time
= *timestamp
;
1215 /* No parent. This process exists but we are missing all information about
1216 its creation. The birth time is set to zero but we remember the time of
1221 process
->creation_time
= ltt_time_zero
;
1224 process
->insertion_time
= *timestamp
;
1225 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1226 process
->creation_time
.tv_nsec
);
1227 process
->pid_time
= g_quark_from_string(buffer
);
1229 //process->last_cpu = tfs->cpu_name;
1230 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1231 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1232 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1233 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1234 es
= process
->state
= &g_array_index(process
->execution_stack
,
1235 LttvExecutionState
, 0);
1236 es
->t
= LTTV_STATE_USER_MODE
;
1237 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1238 es
->entry
= *timestamp
;
1239 //g_assert(timestamp->tv_sec != 0);
1240 es
->change
= *timestamp
;
1241 es
->cum_cpu_time
= ltt_time_zero
;
1242 es
->s
= LTTV_STATE_RUN
;
1244 es
= process
->state
= &g_array_index(process
->execution_stack
,
1245 LttvExecutionState
, 1);
1246 es
->t
= LTTV_STATE_SYSCALL
;
1247 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1248 es
->entry
= *timestamp
;
1249 //g_assert(timestamp->tv_sec != 0);
1250 es
->change
= *timestamp
;
1251 es
->cum_cpu_time
= ltt_time_zero
;
1252 es
->s
= LTTV_STATE_WAIT_FORK
;
1254 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1255 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1256 sizeof(guint64
), 0);
1261 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1264 LttvProcessState key
;
1265 LttvProcessState
*process
;
1269 process
= g_hash_table_lookup(ts
->processes
, &key
);
1274 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1277 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1278 LttvExecutionState
*es
;
1280 /* Put ltt_time_zero creation time for unexisting processes */
1281 if(unlikely(process
== NULL
)) {
1282 process
= lttv_state_create_process(ts
,
1283 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1284 /* We are not sure is it's a kernel thread or normal thread, put the
1285 * bottom stack state to unknown */
1286 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1287 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1292 /* FIXME : this function should be called when we receive an event telling that
1293 * release_task has been called in the kernel. In happens generally when
1294 * the parent waits for its child terminaison, but may also happen in special
1295 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1296 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1297 * of a killed thread ground, but isn't the leader.
1299 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1301 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1302 LttvProcessState key
;
1304 key
.pid
= process
->pid
;
1305 key
.cpu
= process
->cpu
;
1306 g_hash_table_remove(ts
->processes
, &key
);
1307 g_array_free(process
->execution_stack
, TRUE
);
1308 g_array_free(process
->user_stack
, TRUE
);
1313 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1315 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1316 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1321 static void lttv_state_free_process_table(GHashTable
*processes
)
1323 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1324 g_hash_table_destroy(processes
);
1328 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1330 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1331 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1332 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1333 LttField
*f
= thf
->f1
;
1335 LttvExecutionSubmode submode
;
1337 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1338 guint syscall
= ltt_event_get_unsigned(e
, f
);
1340 if(syscall
< nb_syscalls
) {
1341 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1344 /* Fixup an incomplete syscall table */
1345 GString
*string
= g_string_new("");
1346 g_string_printf(string
, "syscall %u", syscall
);
1347 submode
= g_quark_from_string(string
->str
);
1348 g_string_free(string
, TRUE
);
1350 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1355 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1357 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1359 pop_state(s
, LTTV_STATE_SYSCALL
);
1364 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1366 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1367 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1368 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1369 LttField
*f
= thf
->f1
;
1371 LttvExecutionSubmode submode
;
1373 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1374 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1376 if(trap
< nb_traps
) {
1377 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1379 /* Fixup an incomplete trap table */
1380 GString
*string
= g_string_new("");
1381 g_string_printf(string
, "trap %u", trap
);
1382 submode
= g_quark_from_string(string
->str
);
1383 g_string_free(string
, TRUE
);
1386 push_state(s
, LTTV_STATE_TRAP
, submode
);
1391 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1393 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1395 pop_state(s
, LTTV_STATE_TRAP
);
1400 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1402 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1403 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1404 guint8 fac_id
= ltt_event_facility_id(e
);
1405 guint8 ev_id
= ltt_event_eventtype_id(e
);
1406 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1407 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1408 g_assert(thf
->f1
!= NULL
);
1409 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1410 LttField
*f
= thf
->f1
;
1412 LttvExecutionSubmode submode
;
1414 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1415 ltt_event_get_unsigned(e
, f
)];
1417 /* Do something with the info about being in user or system mode when int? */
1418 push_state(s
, LTTV_STATE_IRQ
, submode
);
1422 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1424 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1426 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1432 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1436 pop_state(s
, LTTV_STATE_IRQ
);
1440 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1442 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1443 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1444 guint8 fac_id
= ltt_event_facility_id(e
);
1445 guint8 ev_id
= ltt_event_eventtype_id(e
);
1446 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1447 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1448 g_assert(thf
->f1
!= NULL
);
1449 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1450 LttField
*f
= thf
->f1
;
1452 LttvExecutionSubmode submode
;
1454 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1455 ltt_event_get_long_unsigned(e
, f
)];
1457 /* Do something with the info about being in user or system mode when int? */
1458 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1462 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1466 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1467 guint cpu
= tfs
->cpu
;
1468 LttvProcessState
*process
= ts
->running_process
[cpu
];
1470 guint depth
= process
->user_stack
->len
;
1472 process
->user_stack
=
1473 g_array_set_size(process
->user_stack
, depth
+ 1);
1475 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1476 *new_func
= funcptr
;
1477 process
->current_function
= funcptr
;
1480 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1482 guint cpu
= tfs
->cpu
;
1483 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1484 LttvProcessState
*process
= ts
->running_process
[cpu
];
1486 if(process
->current_function
!= funcptr
){
1487 g_info("Different functions (%lu.%09lu): ignore it\n",
1488 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1489 g_info("process state has %llu when pop_function is %llu\n",
1490 process
->current_function
, funcptr
);
1491 g_info("{ %u, %u, %s, %s, %s }\n",
1494 g_quark_to_string(process
->name
),
1495 g_quark_to_string(process
->brand
),
1496 g_quark_to_string(process
->state
->s
));
1499 guint depth
= process
->user_stack
->len
;
1502 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1503 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1507 process
->user_stack
=
1508 g_array_set_size(process
->user_stack
, depth
- 1);
1509 process
->current_function
=
1510 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1514 static gboolean
function_entry(void *hook_data
, void *call_data
)
1516 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1517 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1518 guint8 fac_id
= ltt_event_facility_id(e
);
1519 guint8 ev_id
= ltt_event_eventtype_id(e
);
1520 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1521 g_assert(thf
->f1
!= NULL
);
1522 LttField
*f
= thf
->f1
;
1523 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1525 push_function(s
, funcptr
);
1529 static gboolean
function_exit(void *hook_data
, void *call_data
)
1531 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1532 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1533 guint8 fac_id
= ltt_event_facility_id(e
);
1534 guint8 ev_id
= ltt_event_eventtype_id(e
);
1535 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1536 g_assert(thf
->f1
!= NULL
);
1537 LttField
*f
= thf
->f1
;
1538 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1540 LttvExecutionSubmode submode
;
1542 pop_function(s
, funcptr
);
1546 static gboolean
schedchange(void *hook_data
, void *call_data
)
1548 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1550 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1551 LttvProcessState
*process
= ts
->running_process
[cpu
];
1552 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1554 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1555 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1556 guint pid_in
, pid_out
;
1559 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1560 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1561 state_out
= ltt_event_get_int(e
, thf
->f3
);
1563 if(likely(process
!= NULL
)) {
1565 /* We could not know but it was not the idle process executing.
1566 This should only happen at the beginning, before the first schedule
1567 event, and when the initial information (current process for each CPU)
1568 is missing. It is not obvious how we could, after the fact, compensate
1569 the wrongly attributed statistics. */
1571 //This test only makes sense once the state is known and if there is no
1572 //missing events. We need to silently ignore schedchange coming after a
1573 //process_free, or it causes glitches. (FIXME)
1574 //if(unlikely(process->pid != pid_out)) {
1575 // g_assert(process->pid == 0);
1578 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1579 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1580 process
->state
->change
= s
->parent
.timestamp
;
1582 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1583 else process
->state
->s
= LTTV_STATE_WAIT
;
1584 process
->state
->change
= s
->parent
.timestamp
;
1588 exit_process(s
, process
); /* EXIT_DEAD */
1589 /* see sched.h for states */
1591 process
= ts
->running_process
[cpu
] =
1592 lttv_state_find_process_or_create(
1593 (LttvTraceState
*)s
->parent
.t_context
,
1595 &s
->parent
.timestamp
);
1596 process
->state
->s
= LTTV_STATE_RUN
;
1598 if(process
->usertrace
)
1599 process
->usertrace
->cpu
= cpu
;
1600 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1601 process
->state
->change
= s
->parent
.timestamp
;
1605 static gboolean
process_fork(void *hook_data
, void *call_data
)
1607 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1608 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1609 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1612 LttvProcessState
*zombie_process
;
1614 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1615 LttvProcessState
*process
= ts
->running_process
[cpu
];
1616 LttvProcessState
*child_process
;
1619 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1622 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1624 /* Mathieu : it seems like the process might have been scheduled in before the
1625 * fork, and, in a rare case, might be the current process. This might happen
1626 * in a SMP case where we don't have enough precision on the clocks.
1628 * Test reenabled after precision fixes on time. (Mathieu) */
1630 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1632 if(unlikely(zombie_process
!= NULL
)) {
1633 /* Reutilisation of PID. Only now we are sure that the old PID
1634 * has been released. FIXME : should know when release_task happens instead.
1636 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1638 for(i
=0; i
< num_cpus
; i
++) {
1639 g_assert(zombie_process
!= ts
->running_process
[i
]);
1642 exit_process(s
, zombie_process
);
1645 g_assert(process
->pid
!= child_pid
);
1646 // FIXME : Add this test in the "known state" section
1647 // g_assert(process->pid == parent_pid);
1648 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1649 if(child_process
== NULL
) {
1650 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1651 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1653 /* The process has already been created : due to time imprecision between
1654 * multiple CPUs : it has been scheduled in before creation. Note that we
1655 * shouldn't have this kind of imprecision.
1657 * Simply put a correct parent.
1659 g_assert(0); /* This is a problematic case : the process has been created
1660 before the fork event */
1661 child_process
->ppid
= process
->pid
;
1663 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1664 child_process
->name
= process
->name
;
1665 child_process
->brand
= process
->brand
;
1670 /* We stamp a newly created process as kernel_thread */
1671 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1673 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1674 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1675 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1678 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1679 LttvProcessState
*process
;
1680 LttvExecutionState
*es
;
1683 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1685 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1686 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1687 es
->t
= LTTV_STATE_SYSCALL
;
1688 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1693 static gboolean
process_exit(void *hook_data
, void *call_data
)
1695 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1696 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1697 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1701 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1702 LttvProcessState
*process
; // = ts->running_process[cpu];
1704 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1706 // FIXME : Add this test in the "known state" section
1707 // g_assert(process->pid == pid);
1709 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1710 if(likely(process
!= NULL
)) {
1711 process
->state
->s
= LTTV_STATE_EXIT
;
1716 static gboolean
process_free(void *hook_data
, void *call_data
)
1718 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1719 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1720 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1721 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1723 LttvProcessState
*process
;
1725 /* PID of the process to release */
1726 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1728 g_assert(release_pid
!= 0);
1730 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1732 if(likely(process
!= NULL
)) {
1733 /* release_task is happening at kernel level : we can now safely release
1734 * the data structure of the process */
1735 //This test is fun, though, as it may happen that
1736 //at time t : CPU 0 : process_free
1737 //at time t+150ns : CPU 1 : schedule out
1738 //Clearly due to time imprecision, we disable it. (Mathieu)
1739 //If this weird case happen, we have no choice but to put the
1740 //Currently running process on the cpu to 0.
1741 //I re-enable it following time precision fixes. (Mathieu)
1742 //Well, in the case where an process is freed by a process on another CPU
1743 //and still scheduled, it happens that this is the schedchange that will
1744 //drop the last reference count. Do not free it here!
1745 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1747 for(i
=0; i
< num_cpus
; i
++) {
1748 //g_assert(process != ts->running_process[i]);
1749 if(process
== ts
->running_process
[i
]) {
1750 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1754 if(i
== num_cpus
) /* process is not scheduled */
1755 exit_process(s
, process
);
1762 static gboolean
process_exec(void *hook_data
, void *call_data
)
1764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1765 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1767 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1770 LttvProcessState
*process
= ts
->running_process
[cpu
];
1772 /* PID of the process to release */
1773 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1774 //name = ltt_event_get_string(e, thf->f1);
1775 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1777 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1778 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1779 memcpy(null_term_name
, name_begin
, name_len
);
1780 null_term_name
[name_len
] = '\0';
1782 process
->name
= g_quark_from_string(null_term_name
);
1783 process
->brand
= LTTV_STATE_UNBRANDED
;
1784 g_free(null_term_name
);
1788 static gboolean
thread_brand(void *hook_data
, void *call_data
)
1790 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1791 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1792 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1793 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1796 LttvProcessState
*process
= ts
->running_process
[cpu
];
1798 name
= ltt_event_get_string(e
, thf
->f1
);
1799 process
->brand
= g_quark_from_string(name
);
1804 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1806 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1807 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1808 //It's slow : optimise later by doing this before reading trace.
1809 LttEventType
*et
= ltt_event_eventtype(e
);
1811 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1816 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1817 LttvProcessState
*process
= ts
->running_process
[cpu
];
1818 LttvProcessState
*parent_process
;
1819 LttField
*f4
, *f5
, *f6
, *f7
;
1820 GQuark type
, mode
, submode
, status
;
1821 LttvExecutionState
*es
;
1824 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1827 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1830 command
= ltt_event_get_string(e
, thf
->f3
);
1833 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1834 type
= ltt_enum_string_get(ltt_field_type(f4
),
1835 ltt_event_get_unsigned(e
, f4
));
1838 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1839 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1840 ltt_event_get_unsigned(e
, f5
));
1843 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1844 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1845 ltt_event_get_unsigned(e
, f6
));
1848 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1849 status
= ltt_enum_string_get(ltt_field_type(f7
),
1850 ltt_event_get_unsigned(e
, f7
));
1852 /* The process might exist if a process was forked while performing the sate dump. */
1853 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1854 if(process
== NULL
) {
1855 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1856 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1857 pid
, g_quark_from_string(command
),
1858 &s
->parent
.timestamp
);
1860 /* Keep the stack bottom : a running user mode */
1861 /* Disabled because of inconsistencies in the current statedump states. */
1862 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1863 /* Only keep the bottom */
1864 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1865 es
= process
->state
= &g_array_index(process
->execution_stack
,
1866 LttvExecutionState
, 0);
1867 es
->t
= LTTV_STATE_SYSCALL
;
1871 /* On top of it : */
1872 es
= process
->state
= &g_array_index(process
->execution_stack
,
1873 LttvExecutionState
, 1);
1874 es
->t
= LTTV_STATE_USER_MODE
;
1881 es
= process
->state
= &g_array_index(process
->execution_stack
,
1882 LttvExecutionState
, 1);
1883 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1884 es
->s
= LTTV_STATE_UNNAMED
;
1885 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1889 /* The process has already been created :
1890 * Probably was forked while dumping the process state or
1891 * was simply scheduled in prior to get the state dump event.
1892 * We know for sure if it is a user space thread.
1894 process
->ppid
= parent_pid
;
1895 process
->name
= g_quark_from_string(command
);
1896 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1897 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1898 es
->t
= LTTV_STATE_USER_MODE
;
1899 /* Don't mess around with the stack, it will eventually become
1900 * ok after the end of state dump. */
1906 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1908 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1910 lttv_state_add_event_hooks(tss
);
1915 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1917 LttvTraceset
*traceset
= self
->parent
.ts
;
1919 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1923 LttvTracefileState
*tfs
;
1927 LttvTraceHookByFacility
*thf
;
1929 LttvTraceHook
*hook
;
1931 LttvAttributeValue val
;
1936 nb_trace
= lttv_traceset_number(traceset
);
1937 for(i
= 0 ; i
< nb_trace
; i
++) {
1938 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1940 /* Find the eventtype id for the following events and register the
1941 associated by id hooks. */
1943 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
1944 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
1947 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1948 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1949 LTT_FIELD_SYSCALL_ID
, 0, 0,
1950 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1953 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1954 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1956 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1959 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1960 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1961 LTT_FIELD_TRAP_ID
, 0, 0,
1962 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1965 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1966 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1968 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1971 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1972 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1973 LTT_FIELD_IRQ_ID
, 0, 0,
1974 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1977 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1978 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1980 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1983 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1984 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1985 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1986 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1989 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1990 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1992 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1995 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1996 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1997 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1998 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2001 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2002 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2003 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
2004 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2007 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2008 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2009 LTT_FIELD_PID
, 0, 0,
2010 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2014 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2015 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2016 LTT_FIELD_PID
, 0, 0,
2017 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2020 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2021 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2022 LTT_FIELD_PID
, 0, 0,
2023 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2026 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2027 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2028 LTT_FIELD_FILENAME
, 0, 0,
2029 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2032 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2033 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2034 LTT_FIELD_NAME
, 0, 0,
2035 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2038 /* statedump-related hooks */
2039 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2040 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2041 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2042 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2045 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2046 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2047 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2048 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2051 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2052 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2053 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2054 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2057 hooks
= g_array_set_size(hooks
, hn
);
2059 /* Add these hooks to each event_by_id hooks list */
2061 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2063 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2065 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2066 LttvTracefileContext
*, j
));
2068 for(k
= 0 ; k
< hooks
->len
; k
++) {
2069 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2070 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2071 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2073 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2080 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2081 *(val
.v_pointer
) = hooks
;
2085 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2087 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2089 lttv_state_remove_event_hooks(tss
);
2094 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2096 LttvTraceset
*traceset
= self
->parent
.ts
;
2098 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2102 LttvTracefileState
*tfs
;
2106 LttvTraceHook
*hook
;
2108 LttvTraceHookByFacility
*thf
;
2110 LttvAttributeValue val
;
2112 nb_trace
= lttv_traceset_number(traceset
);
2113 for(i
= 0 ; i
< nb_trace
; i
++) {
2114 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2115 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2116 hooks
= *(val
.v_pointer
);
2118 /* Remove these hooks from each event_by_id hooks list */
2120 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2122 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2124 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2125 LttvTracefileContext
*, j
));
2127 for(k
= 0 ; k
< hooks
->len
; k
++) {
2128 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2129 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2130 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2132 lttv_hooks_remove_data(
2133 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2139 for(k
= 0 ; k
< hooks
->len
; k
++)
2140 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2141 g_array_free(hooks
, TRUE
);
2145 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2147 guint
*event_count
= (guint
*)hook_data
;
2149 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2150 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2155 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2157 LttvTracefileState
*tfcs
;
2159 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2161 LttEventPosition
*ep
;
2167 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2169 LttvAttributeValue value
;
2171 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2172 LTTV_STATE_SAVED_STATES
);
2173 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2174 value
= lttv_attribute_add(saved_states_tree
,
2175 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2176 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2177 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2178 *(value
.v_time
) = self
->parent
.timestamp
;
2179 lttv_state_save(tcs
, saved_state_tree
);
2180 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2181 self
->parent
.timestamp
.tv_nsec
);
2183 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2188 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2190 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2192 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2197 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2205 static gboolean
block_start(void *hook_data
, void *call_data
)
2207 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2209 LttvTracefileState
*tfcs
;
2211 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2213 LttEventPosition
*ep
;
2215 guint i
, nb_block
, nb_event
, nb_tracefile
;
2219 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2221 LttvAttributeValue value
;
2223 ep
= ltt_event_position_new();
2225 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2227 /* Count the number of events added since the last block end in any
2230 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2232 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2233 LttvTracefileContext
, i
));
2234 ltt_event_position(tfcs
->parent
.e
, ep
);
2235 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2236 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2237 tfcs
->saved_position
= nb_event
;
2241 if(tcs
->nb_event
>= tcs
->save_interval
) {
2242 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2243 LTTV_STATE_SAVED_STATES
);
2244 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2245 value
= lttv_attribute_add(saved_states_tree
,
2246 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2247 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2248 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2249 *(value
.v_time
) = self
->parent
.timestamp
;
2250 lttv_state_save(tcs
, saved_state_tree
);
2252 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2253 self
->parent
.timestamp
.tv_nsec
);
2255 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2261 static gboolean
block_end(void *hook_data
, void *call_data
)
2263 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2265 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2269 LttEventPosition
*ep
;
2271 guint nb_block
, nb_event
;
2273 ep
= ltt_event_position_new();
2274 ltt_event_position(self
->parent
.e
, ep
);
2275 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2276 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2277 self
->saved_position
= 0;
2278 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2285 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2287 LttvTraceset
*traceset
= self
->parent
.ts
;
2289 guint i
, j
, nb_trace
, nb_tracefile
;
2293 LttvTracefileState
*tfs
;
2295 LttvTraceHook hook_start
, hook_end
;
2297 nb_trace
= lttv_traceset_number(traceset
);
2298 for(i
= 0 ; i
< nb_trace
; i
++) {
2299 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2301 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2302 NULL
, NULL
, block_start
, &hook_start
);
2303 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2304 NULL
, NULL
, block_end
, &hook_end
);
2306 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2308 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2310 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2311 LttvTracefileContext
, j
));
2312 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2313 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2314 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2315 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2321 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2323 LttvTraceset
*traceset
= self
->parent
.ts
;
2325 guint i
, j
, nb_trace
, nb_tracefile
;
2329 LttvTracefileState
*tfs
;
2332 nb_trace
= lttv_traceset_number(traceset
);
2333 for(i
= 0 ; i
< nb_trace
; i
++) {
2335 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2336 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2338 guint
*event_count
= g_new(guint
, 1);
2341 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2343 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2344 LttvTracefileContext
*, j
));
2345 lttv_hooks_add(tfs
->parent
.event
,
2346 state_save_event_hook
,
2353 lttv_process_traceset_begin(&self
->parent
,
2354 NULL
, NULL
, NULL
, NULL
, NULL
);
2358 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2360 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2362 lttv_state_save_add_event_hooks(tss
);
2369 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2371 LttvTraceset
*traceset
= self
->parent
.ts
;
2373 guint i
, j
, nb_trace
, nb_tracefile
;
2377 LttvTracefileState
*tfs
;
2379 LttvTraceHook hook_start
, hook_end
;
2381 nb_trace
= lttv_traceset_number(traceset
);
2382 for(i
= 0 ; i
< nb_trace
; i
++) {
2383 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2385 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2386 NULL
, NULL
, block_start
, &hook_start
);
2388 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2389 NULL
, NULL
, block_end
, &hook_end
);
2391 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2393 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2395 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2396 LttvTracefileContext
, j
));
2397 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2398 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2399 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2400 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2406 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2408 LttvTraceset
*traceset
= self
->parent
.ts
;
2410 guint i
, j
, nb_trace
, nb_tracefile
;
2414 LttvTracefileState
*tfs
;
2416 LttvHooks
*after_trace
= lttv_hooks_new();
2418 lttv_hooks_add(after_trace
,
2419 state_save_after_trace_hook
,
2424 lttv_process_traceset_end(&self
->parent
,
2425 NULL
, after_trace
, NULL
, NULL
, NULL
);
2427 lttv_hooks_destroy(after_trace
);
2429 nb_trace
= lttv_traceset_number(traceset
);
2430 for(i
= 0 ; i
< nb_trace
; i
++) {
2432 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2433 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2435 guint
*event_count
= NULL
;
2437 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2439 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2440 LttvTracefileContext
*, j
));
2441 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2442 state_save_event_hook
);
2444 if(event_count
) g_free(event_count
);
2448 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2450 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2452 lttv_state_save_remove_event_hooks(tss
);
2457 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2459 LttvTraceset
*traceset
= self
->parent
.ts
;
2463 int min_pos
, mid_pos
, max_pos
;
2465 guint call_rest
= 0;
2467 LttvTraceState
*tcs
;
2469 LttvAttributeValue value
;
2471 LttvAttributeType type
;
2473 LttvAttributeName name
;
2477 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2479 //g_tree_destroy(self->parent.pqueue);
2480 //self->parent.pqueue = g_tree_new(compare_tracefile);
2482 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2484 nb_trace
= lttv_traceset_number(traceset
);
2485 for(i
= 0 ; i
< nb_trace
; i
++) {
2486 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2488 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2489 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2490 LTTV_STATE_SAVED_STATES
);
2493 if(saved_states_tree
) {
2494 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2495 mid_pos
= max_pos
/ 2;
2496 while(min_pos
< max_pos
) {
2497 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2499 g_assert(type
== LTTV_GOBJECT
);
2500 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2501 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2503 g_assert(type
== LTTV_TIME
);
2504 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2506 closest_tree
= saved_state_tree
;
2508 else max_pos
= mid_pos
- 1;
2510 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2514 /* restore the closest earlier saved state */
2516 lttv_state_restore(tcs
, closest_tree
);
2520 /* There is no saved state, yet we want to have it. Restart at T0 */
2522 restore_init_state(tcs
);
2523 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2526 /* We want to seek quickly without restoring/updating the state */
2528 restore_init_state(tcs
);
2529 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2532 if(!call_rest
) g_info("NOT Calling restore");
2537 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2543 traceset_state_finalize (LttvTracesetState
*self
)
2545 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2546 finalize(G_OBJECT(self
));
2551 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2553 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2555 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2556 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2557 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2558 klass
->new_traceset_context
= new_traceset_context
;
2559 klass
->new_trace_context
= new_trace_context
;
2560 klass
->new_tracefile_context
= new_tracefile_context
;
2565 lttv_traceset_state_get_type(void)
2567 static GType type
= 0;
2569 static const GTypeInfo info
= {
2570 sizeof (LttvTracesetStateClass
),
2571 NULL
, /* base_init */
2572 NULL
, /* base_finalize */
2573 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2574 NULL
, /* class_finalize */
2575 NULL
, /* class_data */
2576 sizeof (LttvTracesetState
),
2577 0, /* n_preallocs */
2578 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2579 NULL
/* value handling */
2582 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2590 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2596 trace_state_finalize (LttvTraceState
*self
)
2598 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2599 finalize(G_OBJECT(self
));
2604 trace_state_class_init (LttvTraceStateClass
*klass
)
2606 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2608 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2609 klass
->state_save
= state_save
;
2610 klass
->state_restore
= state_restore
;
2611 klass
->state_saved_free
= state_saved_free
;
2616 lttv_trace_state_get_type(void)
2618 static GType type
= 0;
2620 static const GTypeInfo info
= {
2621 sizeof (LttvTraceStateClass
),
2622 NULL
, /* base_init */
2623 NULL
, /* base_finalize */
2624 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2625 NULL
, /* class_finalize */
2626 NULL
, /* class_data */
2627 sizeof (LttvTraceState
),
2628 0, /* n_preallocs */
2629 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2630 NULL
/* value handling */
2633 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2634 "LttvTraceStateType", &info
, 0);
2641 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2647 tracefile_state_finalize (LttvTracefileState
*self
)
2649 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2650 finalize(G_OBJECT(self
));
2655 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2657 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2659 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2664 lttv_tracefile_state_get_type(void)
2666 static GType type
= 0;
2668 static const GTypeInfo info
= {
2669 sizeof (LttvTracefileStateClass
),
2670 NULL
, /* base_init */
2671 NULL
, /* base_finalize */
2672 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2673 NULL
, /* class_finalize */
2674 NULL
, /* class_data */
2675 sizeof (LttvTracefileState
),
2676 0, /* n_preallocs */
2677 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2678 NULL
/* value handling */
2681 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2682 "LttvTracefileStateType", &info
, 0);
2688 static void module_init()
2690 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2691 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
2692 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2693 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2694 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2695 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2696 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2697 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2698 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2699 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2700 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2701 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2702 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2703 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2704 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2705 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2706 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2707 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2708 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2709 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2710 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2711 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2712 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2713 LTTV_STATE_EVENT
= g_quark_from_string("event");
2714 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2715 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2716 LTTV_STATE_TIME
= g_quark_from_string("time");
2717 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2718 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2719 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2720 g_quark_from_string("trace_state_use_count");
2723 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2724 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2725 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2726 LTT_FACILITY_FS
= g_quark_from_string("fs");
2727 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2728 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2731 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2732 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2733 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2734 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2735 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2736 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2737 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2738 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2739 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2740 LTT_EVENT_FORK
= g_quark_from_string("fork");
2741 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2742 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2743 LTT_EVENT_FREE
= g_quark_from_string("free");
2744 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2745 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2746 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2747 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2748 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
2751 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2752 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2753 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2754 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2755 LTT_FIELD_OUT
= g_quark_from_string("out");
2756 LTT_FIELD_IN
= g_quark_from_string("in");
2757 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2758 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2759 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2760 LTT_FIELD_PID
= g_quark_from_string("pid");
2761 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2762 LTT_FIELD_NAME
= g_quark_from_string("name");
2763 LTT_FIELD_TYPE
= g_quark_from_string("type");
2764 LTT_FIELD_MODE
= g_quark_from_string("mode");
2765 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2766 LTT_FIELD_STATUS
= g_quark_from_string("status");
2767 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2768 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2772 static void module_destroy()
2777 LTTV_MODULE("state", "State computation", \
2778 "Update the system state, possibly saving it at intervals", \
2779 module_init
, module_destroy
)