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
;
1669 /* We stamp a newly created process as kernel_thread */
1670 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1672 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1673 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1674 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1677 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1678 LttvProcessState
*process
;
1679 LttvExecutionState
*es
;
1682 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1684 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1685 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1686 es
->t
= LTTV_STATE_SYSCALL
;
1687 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1692 static gboolean
process_exit(void *hook_data
, void *call_data
)
1694 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1695 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1696 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1700 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1701 LttvProcessState
*process
; // = ts->running_process[cpu];
1703 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1705 // FIXME : Add this test in the "known state" section
1706 // g_assert(process->pid == pid);
1708 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1709 if(likely(process
!= NULL
)) {
1710 process
->state
->s
= LTTV_STATE_EXIT
;
1715 static gboolean
process_free(void *hook_data
, void *call_data
)
1717 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1718 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1719 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1720 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1722 LttvProcessState
*process
;
1724 /* PID of the process to release */
1725 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1727 g_assert(release_pid
!= 0);
1729 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1731 if(likely(process
!= NULL
)) {
1732 /* release_task is happening at kernel level : we can now safely release
1733 * the data structure of the process */
1734 //This test is fun, though, as it may happen that
1735 //at time t : CPU 0 : process_free
1736 //at time t+150ns : CPU 1 : schedule out
1737 //Clearly due to time imprecision, we disable it. (Mathieu)
1738 //If this weird case happen, we have no choice but to put the
1739 //Currently running process on the cpu to 0.
1740 //I re-enable it following time precision fixes. (Mathieu)
1741 //Well, in the case where an process is freed by a process on another CPU
1742 //and still scheduled, it happens that this is the schedchange that will
1743 //drop the last reference count. Do not free it here!
1744 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1746 for(i
=0; i
< num_cpus
; i
++) {
1747 //g_assert(process != ts->running_process[i]);
1748 if(process
== ts
->running_process
[i
]) {
1749 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1753 if(i
== num_cpus
) /* process is not scheduled */
1754 exit_process(s
, process
);
1761 static gboolean
process_exec(void *hook_data
, void *call_data
)
1763 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1764 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1765 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1766 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1769 LttvProcessState
*process
= ts
->running_process
[cpu
];
1771 /* PID of the process to release */
1772 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1773 //name = ltt_event_get_string(e, thf->f1);
1774 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1776 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1777 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1778 memcpy(null_term_name
, name_begin
, name_len
);
1779 null_term_name
[name_len
] = '\0';
1781 process
->name
= g_quark_from_string(null_term_name
);
1782 g_free(null_term_name
);
1786 static gboolean
thread_brand(void *hook_data
, void *call_data
)
1788 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1789 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1790 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1791 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1794 LttvProcessState
*process
= ts
->running_process
[cpu
];
1796 name
= ltt_event_get_string(e
, thf
->f1
);
1797 process
->brand
= g_quark_from_string(name
);
1802 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1804 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1805 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1806 //It's slow : optimise later by doing this before reading trace.
1807 LttEventType
*et
= ltt_event_eventtype(e
);
1809 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1814 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1815 LttvProcessState
*process
= ts
->running_process
[cpu
];
1816 LttvProcessState
*parent_process
;
1817 LttField
*f4
, *f5
, *f6
, *f7
;
1818 GQuark type
, mode
, submode
, status
;
1819 LttvExecutionState
*es
;
1822 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1825 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1828 command
= ltt_event_get_string(e
, thf
->f3
);
1831 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1832 type
= ltt_enum_string_get(ltt_field_type(f4
),
1833 ltt_event_get_unsigned(e
, f4
));
1836 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1837 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1838 ltt_event_get_unsigned(e
, f5
));
1841 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1842 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1843 ltt_event_get_unsigned(e
, f6
));
1846 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1847 status
= ltt_enum_string_get(ltt_field_type(f7
),
1848 ltt_event_get_unsigned(e
, f7
));
1850 /* The process might exist if a process was forked while performing the sate dump. */
1851 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1852 if(process
== NULL
) {
1853 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1854 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1855 pid
, g_quark_from_string(command
),
1856 &s
->parent
.timestamp
);
1858 /* Keep the stack bottom : a running user mode */
1859 /* Disabled because of inconsistencies in the current statedump states. */
1860 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1861 /* Only keep the bottom */
1862 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1863 es
= process
->state
= &g_array_index(process
->execution_stack
,
1864 LttvExecutionState
, 0);
1865 es
->t
= LTTV_STATE_SYSCALL
;
1869 /* On top of it : */
1870 es
= process
->state
= &g_array_index(process
->execution_stack
,
1871 LttvExecutionState
, 1);
1872 es
->t
= LTTV_STATE_USER_MODE
;
1879 es
= process
->state
= &g_array_index(process
->execution_stack
,
1880 LttvExecutionState
, 1);
1881 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1882 es
->s
= LTTV_STATE_UNNAMED
;
1883 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1887 /* The process has already been created :
1888 * Probably was forked while dumping the process state or
1889 * was simply scheduled in prior to get the state dump event.
1890 * We know for sure if it is a user space thread.
1892 process
->ppid
= parent_pid
;
1893 process
->name
= g_quark_from_string(command
);
1894 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1895 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1896 es
->t
= LTTV_STATE_USER_MODE
;
1897 /* Don't mess around with the stack, it will eventually become
1898 * ok after the end of state dump. */
1904 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1906 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1908 lttv_state_add_event_hooks(tss
);
1913 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1915 LttvTraceset
*traceset
= self
->parent
.ts
;
1917 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1921 LttvTracefileState
*tfs
;
1925 LttvTraceHookByFacility
*thf
;
1927 LttvTraceHook
*hook
;
1929 LttvAttributeValue val
;
1934 nb_trace
= lttv_traceset_number(traceset
);
1935 for(i
= 0 ; i
< nb_trace
; i
++) {
1936 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1938 /* Find the eventtype id for the following events and register the
1939 associated by id hooks. */
1941 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
1942 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
1945 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1946 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1947 LTT_FIELD_SYSCALL_ID
, 0, 0,
1948 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1951 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1952 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1954 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1957 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1958 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1959 LTT_FIELD_TRAP_ID
, 0, 0,
1960 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1963 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1964 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1966 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1969 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1970 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1971 LTT_FIELD_IRQ_ID
, 0, 0,
1972 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1975 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1976 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1978 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1981 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1982 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1983 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1984 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1987 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1988 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1990 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1993 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1994 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1995 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1996 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1999 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2000 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2001 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
2002 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2005 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2006 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2007 LTT_FIELD_PID
, 0, 0,
2008 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2012 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2013 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2014 LTT_FIELD_PID
, 0, 0,
2015 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2018 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2019 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2020 LTT_FIELD_PID
, 0, 0,
2021 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2024 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2025 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2026 LTT_FIELD_FILENAME
, 0, 0,
2027 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2030 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2031 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2032 LTT_FIELD_NAME
, 0, 0,
2033 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2036 /* statedump-related hooks */
2037 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2038 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2039 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2040 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2043 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2044 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2045 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2046 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2049 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2050 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2051 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2052 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2055 hooks
= g_array_set_size(hooks
, hn
);
2057 /* Add these hooks to each event_by_id hooks list */
2059 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2061 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2063 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2064 LttvTracefileContext
*, j
));
2066 for(k
= 0 ; k
< hooks
->len
; k
++) {
2067 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2068 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2069 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2071 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2078 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2079 *(val
.v_pointer
) = hooks
;
2083 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2085 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2087 lttv_state_remove_event_hooks(tss
);
2092 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2094 LttvTraceset
*traceset
= self
->parent
.ts
;
2096 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2100 LttvTracefileState
*tfs
;
2104 LttvTraceHook
*hook
;
2106 LttvTraceHookByFacility
*thf
;
2108 LttvAttributeValue val
;
2110 nb_trace
= lttv_traceset_number(traceset
);
2111 for(i
= 0 ; i
< nb_trace
; i
++) {
2112 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2113 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2114 hooks
= *(val
.v_pointer
);
2116 /* Remove these hooks from each event_by_id hooks list */
2118 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2120 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2122 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2123 LttvTracefileContext
*, j
));
2125 for(k
= 0 ; k
< hooks
->len
; k
++) {
2126 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2127 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2128 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2130 lttv_hooks_remove_data(
2131 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2137 for(k
= 0 ; k
< hooks
->len
; k
++)
2138 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2139 g_array_free(hooks
, TRUE
);
2143 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2145 guint
*event_count
= (guint
*)hook_data
;
2147 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2148 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2153 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2155 LttvTracefileState
*tfcs
;
2157 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2159 LttEventPosition
*ep
;
2165 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2167 LttvAttributeValue value
;
2169 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2170 LTTV_STATE_SAVED_STATES
);
2171 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2172 value
= lttv_attribute_add(saved_states_tree
,
2173 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2174 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2175 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2176 *(value
.v_time
) = self
->parent
.timestamp
;
2177 lttv_state_save(tcs
, saved_state_tree
);
2178 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2179 self
->parent
.timestamp
.tv_nsec
);
2181 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2186 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2188 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2190 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2195 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2203 static gboolean
block_start(void *hook_data
, void *call_data
)
2205 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2207 LttvTracefileState
*tfcs
;
2209 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2211 LttEventPosition
*ep
;
2213 guint i
, nb_block
, nb_event
, nb_tracefile
;
2217 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2219 LttvAttributeValue value
;
2221 ep
= ltt_event_position_new();
2223 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2225 /* Count the number of events added since the last block end in any
2228 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2230 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2231 LttvTracefileContext
, i
));
2232 ltt_event_position(tfcs
->parent
.e
, ep
);
2233 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2234 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2235 tfcs
->saved_position
= nb_event
;
2239 if(tcs
->nb_event
>= tcs
->save_interval
) {
2240 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2241 LTTV_STATE_SAVED_STATES
);
2242 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2243 value
= lttv_attribute_add(saved_states_tree
,
2244 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2245 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2246 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2247 *(value
.v_time
) = self
->parent
.timestamp
;
2248 lttv_state_save(tcs
, saved_state_tree
);
2250 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2251 self
->parent
.timestamp
.tv_nsec
);
2253 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2259 static gboolean
block_end(void *hook_data
, void *call_data
)
2261 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2263 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2267 LttEventPosition
*ep
;
2269 guint nb_block
, nb_event
;
2271 ep
= ltt_event_position_new();
2272 ltt_event_position(self
->parent
.e
, ep
);
2273 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2274 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2275 self
->saved_position
= 0;
2276 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2283 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2285 LttvTraceset
*traceset
= self
->parent
.ts
;
2287 guint i
, j
, nb_trace
, nb_tracefile
;
2291 LttvTracefileState
*tfs
;
2293 LttvTraceHook hook_start
, hook_end
;
2295 nb_trace
= lttv_traceset_number(traceset
);
2296 for(i
= 0 ; i
< nb_trace
; i
++) {
2297 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2299 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2300 NULL
, NULL
, block_start
, &hook_start
);
2301 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2302 NULL
, NULL
, block_end
, &hook_end
);
2304 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2306 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2308 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2309 LttvTracefileContext
, j
));
2310 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2311 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2312 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2313 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2319 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2321 LttvTraceset
*traceset
= self
->parent
.ts
;
2323 guint i
, j
, nb_trace
, nb_tracefile
;
2327 LttvTracefileState
*tfs
;
2330 nb_trace
= lttv_traceset_number(traceset
);
2331 for(i
= 0 ; i
< nb_trace
; i
++) {
2333 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2334 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2336 guint
*event_count
= g_new(guint
, 1);
2339 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2341 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2342 LttvTracefileContext
*, j
));
2343 lttv_hooks_add(tfs
->parent
.event
,
2344 state_save_event_hook
,
2351 lttv_process_traceset_begin(&self
->parent
,
2352 NULL
, NULL
, NULL
, NULL
, NULL
);
2356 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2358 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2360 lttv_state_save_add_event_hooks(tss
);
2367 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2369 LttvTraceset
*traceset
= self
->parent
.ts
;
2371 guint i
, j
, nb_trace
, nb_tracefile
;
2375 LttvTracefileState
*tfs
;
2377 LttvTraceHook hook_start
, hook_end
;
2379 nb_trace
= lttv_traceset_number(traceset
);
2380 for(i
= 0 ; i
< nb_trace
; i
++) {
2381 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2383 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2384 NULL
, NULL
, block_start
, &hook_start
);
2386 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2387 NULL
, NULL
, block_end
, &hook_end
);
2389 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2391 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2393 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2394 LttvTracefileContext
, j
));
2395 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2396 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2397 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2398 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2404 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2406 LttvTraceset
*traceset
= self
->parent
.ts
;
2408 guint i
, j
, nb_trace
, nb_tracefile
;
2412 LttvTracefileState
*tfs
;
2414 LttvHooks
*after_trace
= lttv_hooks_new();
2416 lttv_hooks_add(after_trace
,
2417 state_save_after_trace_hook
,
2422 lttv_process_traceset_end(&self
->parent
,
2423 NULL
, after_trace
, NULL
, NULL
, NULL
);
2425 lttv_hooks_destroy(after_trace
);
2427 nb_trace
= lttv_traceset_number(traceset
);
2428 for(i
= 0 ; i
< nb_trace
; i
++) {
2430 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2431 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2433 guint
*event_count
= NULL
;
2435 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2437 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2438 LttvTracefileContext
*, j
));
2439 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2440 state_save_event_hook
);
2442 if(event_count
) g_free(event_count
);
2446 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2448 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2450 lttv_state_save_remove_event_hooks(tss
);
2455 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2457 LttvTraceset
*traceset
= self
->parent
.ts
;
2461 int min_pos
, mid_pos
, max_pos
;
2463 guint call_rest
= 0;
2465 LttvTraceState
*tcs
;
2467 LttvAttributeValue value
;
2469 LttvAttributeType type
;
2471 LttvAttributeName name
;
2475 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2477 //g_tree_destroy(self->parent.pqueue);
2478 //self->parent.pqueue = g_tree_new(compare_tracefile);
2480 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2482 nb_trace
= lttv_traceset_number(traceset
);
2483 for(i
= 0 ; i
< nb_trace
; i
++) {
2484 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2486 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2487 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2488 LTTV_STATE_SAVED_STATES
);
2491 if(saved_states_tree
) {
2492 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2493 mid_pos
= max_pos
/ 2;
2494 while(min_pos
< max_pos
) {
2495 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2497 g_assert(type
== LTTV_GOBJECT
);
2498 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2499 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2501 g_assert(type
== LTTV_TIME
);
2502 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2504 closest_tree
= saved_state_tree
;
2506 else max_pos
= mid_pos
- 1;
2508 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2512 /* restore the closest earlier saved state */
2514 lttv_state_restore(tcs
, closest_tree
);
2518 /* There is no saved state, yet we want to have it. Restart at T0 */
2520 restore_init_state(tcs
);
2521 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2524 /* We want to seek quickly without restoring/updating the state */
2526 restore_init_state(tcs
);
2527 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2530 if(!call_rest
) g_info("NOT Calling restore");
2535 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2541 traceset_state_finalize (LttvTracesetState
*self
)
2543 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2544 finalize(G_OBJECT(self
));
2549 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2551 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2553 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2554 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2555 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2556 klass
->new_traceset_context
= new_traceset_context
;
2557 klass
->new_trace_context
= new_trace_context
;
2558 klass
->new_tracefile_context
= new_tracefile_context
;
2563 lttv_traceset_state_get_type(void)
2565 static GType type
= 0;
2567 static const GTypeInfo info
= {
2568 sizeof (LttvTracesetStateClass
),
2569 NULL
, /* base_init */
2570 NULL
, /* base_finalize */
2571 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2572 NULL
, /* class_finalize */
2573 NULL
, /* class_data */
2574 sizeof (LttvTracesetState
),
2575 0, /* n_preallocs */
2576 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2577 NULL
/* value handling */
2580 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2588 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2594 trace_state_finalize (LttvTraceState
*self
)
2596 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2597 finalize(G_OBJECT(self
));
2602 trace_state_class_init (LttvTraceStateClass
*klass
)
2604 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2606 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2607 klass
->state_save
= state_save
;
2608 klass
->state_restore
= state_restore
;
2609 klass
->state_saved_free
= state_saved_free
;
2614 lttv_trace_state_get_type(void)
2616 static GType type
= 0;
2618 static const GTypeInfo info
= {
2619 sizeof (LttvTraceStateClass
),
2620 NULL
, /* base_init */
2621 NULL
, /* base_finalize */
2622 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2623 NULL
, /* class_finalize */
2624 NULL
, /* class_data */
2625 sizeof (LttvTraceState
),
2626 0, /* n_preallocs */
2627 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2628 NULL
/* value handling */
2631 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2632 "LttvTraceStateType", &info
, 0);
2639 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2645 tracefile_state_finalize (LttvTracefileState
*self
)
2647 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2648 finalize(G_OBJECT(self
));
2653 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2655 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2657 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2662 lttv_tracefile_state_get_type(void)
2664 static GType type
= 0;
2666 static const GTypeInfo info
= {
2667 sizeof (LttvTracefileStateClass
),
2668 NULL
, /* base_init */
2669 NULL
, /* base_finalize */
2670 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2671 NULL
, /* class_finalize */
2672 NULL
, /* class_data */
2673 sizeof (LttvTracefileState
),
2674 0, /* n_preallocs */
2675 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2676 NULL
/* value handling */
2679 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2680 "LttvTracefileStateType", &info
, 0);
2686 static void module_init()
2688 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2689 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
2690 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2691 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2692 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2693 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2694 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2695 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2696 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2697 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2698 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2699 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2700 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2701 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2702 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2703 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2704 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2705 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2706 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2707 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2708 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2709 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2710 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2711 LTTV_STATE_EVENT
= g_quark_from_string("event");
2712 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2713 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2714 LTTV_STATE_TIME
= g_quark_from_string("time");
2715 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2716 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2717 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2718 g_quark_from_string("trace_state_use_count");
2721 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2722 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2723 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2724 LTT_FACILITY_FS
= g_quark_from_string("fs");
2725 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2726 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2729 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2730 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2731 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2732 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2733 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2734 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2735 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2736 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2737 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2738 LTT_EVENT_FORK
= g_quark_from_string("fork");
2739 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2740 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2741 LTT_EVENT_FREE
= g_quark_from_string("free");
2742 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2743 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2744 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2745 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2746 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
2749 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2750 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2751 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2752 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2753 LTT_FIELD_OUT
= g_quark_from_string("out");
2754 LTT_FIELD_IN
= g_quark_from_string("in");
2755 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2756 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2757 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2758 LTT_FIELD_PID
= g_quark_from_string("pid");
2759 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2760 LTT_FIELD_NAME
= g_quark_from_string("name");
2761 LTT_FIELD_TYPE
= g_quark_from_string("type");
2762 LTT_FIELD_MODE
= g_quark_from_string("mode");
2763 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2764 LTT_FIELD_STATUS
= g_quark_from_string("status");
2765 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2766 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2770 static void module_destroy()
2775 LTTV_MODULE("state", "State computation", \
2776 "Update the system state, possibly saving it at intervals", \
2777 module_init
, module_destroy
)