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
,
91 LTTV_STATE_MODE_UNKNOWN
,
99 LTTV_STATE_SUBMODE_UNKNOWN
,
100 LTTV_STATE_SUBMODE_NONE
;
104 LTTV_STATE_UNBRANDED
,
105 LTTV_STATE_WAIT_FORK
,
114 LTTV_STATE_USER_THREAD
,
115 LTTV_STATE_KERNEL_THREAD
;
118 LTTV_STATE_TRACEFILES
,
119 LTTV_STATE_PROCESSES
,
121 LTTV_STATE_RUNNING_PROCESS
,
123 LTTV_STATE_SAVED_STATES
,
124 LTTV_STATE_SAVED_STATES_TIME
,
127 LTTV_STATE_NAME_TABLES
,
128 LTTV_STATE_TRACE_STATE_USE_COUNT
;
130 static void create_max_time(LttvTraceState
*tcs
);
132 static void get_max_time(LttvTraceState
*tcs
);
134 static void free_max_time(LttvTraceState
*tcs
);
136 static void create_name_tables(LttvTraceState
*tcs
);
138 static void get_name_tables(LttvTraceState
*tcs
);
140 static void free_name_tables(LttvTraceState
*tcs
);
142 static void free_saved_state(LttvTraceState
*tcs
);
144 static void lttv_state_free_process_table(GHashTable
*processes
);
147 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
149 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
153 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
155 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
159 void lttv_state_state_saved_free(LttvTraceState
*self
,
160 LttvAttribute
*container
)
162 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
166 guint
process_hash(gconstpointer key
)
168 guint pid
= ((const LttvProcessState
*)key
)->pid
;
169 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
173 /* If the hash table hash function is well distributed,
174 * the process_equal should compare different pid */
175 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
177 const LttvProcessState
*process_a
, *process_b
;
180 process_a
= (const LttvProcessState
*)a
;
181 process_b
= (const LttvProcessState
*)b
;
183 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
184 else if(likely(process_a
->pid
== 0 &&
185 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
190 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
192 g_tree_destroy((GTree
*)value
);
195 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
197 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
198 g_hash_table_destroy(usertraces
);
204 restore_init_state(LttvTraceState
*self
)
208 LttvTracefileState
*tfcs
;
210 LttTime start_time
, end_time
;
212 /* Free the process tables */
213 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
214 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
215 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
216 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
219 /* Seek time to beginning */
220 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
221 // closest. It's the tracecontext job to seek the trace to the beginning
222 // anyway : the init state might be used at the middle of the trace as well...
223 //g_tree_destroy(self->parent.ts_context->pqueue);
224 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
226 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
228 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
230 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
232 /* Put the per cpu running_process to beginning state : process 0. */
233 for(i
=0; i
< nb_cpus
; i
++) {
234 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
235 LTTV_STATE_UNNAMED
, &start_time
);
236 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
237 self
->running_process
[i
]->cpu
= i
;
241 nb_tracefile
= self
->parent
.tracefiles
->len
;
243 for(i
= 0 ; i
< nb_tracefile
; i
++) {
245 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
246 LttvTracefileContext
*, i
));
247 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
248 // tfcs->saved_position = 0;
249 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
250 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
251 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
252 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
257 //static LttTime time_zero = {0,0};
259 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
262 const LttTime
*t1
= (const LttTime
*)a
;
263 const LttTime
*t2
= (const LttTime
*)b
;
265 return ltt_time_compare(*t1
, *t2
);
268 static void free_usertrace_key(gpointer data
)
274 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
276 guint i
, j
, nb_trace
, nb_tracefile
;
278 LttvTraceContext
*tc
;
282 LttvTracefileState
*tfcs
;
284 LttvAttributeValue v
;
286 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
287 init((LttvTracesetContext
*)self
, ts
);
289 nb_trace
= lttv_traceset_number(ts
);
290 for(i
= 0 ; i
< nb_trace
; i
++) {
291 tc
= self
->parent
.traces
[i
];
292 tcs
= LTTV_TRACE_STATE(tc
);
293 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
294 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
298 if(*(v
.v_uint
) == 1) {
299 create_name_tables(tcs
);
300 create_max_time(tcs
);
302 get_name_tables(tcs
);
305 nb_tracefile
= tc
->tracefiles
->len
;
306 tcs
->processes
= NULL
;
307 tcs
->usertraces
= NULL
;
308 tcs
->running_process
= g_new(LttvProcessState
*,
309 ltt_trace_get_num_cpu(tc
->t
));
310 restore_init_state(tcs
);
311 for(j
= 0 ; j
< nb_tracefile
; j
++) {
313 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
314 LttvTracefileContext
*, j
));
315 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
316 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
318 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
319 /* It's a Usertrace */
320 LttvProcessState
*process
;
322 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
323 ltt_tracefile_creation(tfcs
->parent
.tf
));
324 process
= lttv_state_find_process_or_create(
326 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
328 process
->usertrace
= tfcs
;
332 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
333 /* It's a Usertrace */
334 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
335 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
337 if(!usertrace_tree
) {
338 usertrace_tree
= g_tree_new_full(compare_usertraces
,
339 NULL
, free_usertrace_key
, NULL
);
340 g_hash_table_insert(tcs
->usertraces
,
341 (gpointer
)tid
, usertrace_tree
);
343 LttTime
*timestamp
= g_new(LttTime
, 1);
344 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
345 ltt_tracefile_creation(tfcs
->parent
.tf
));
346 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
354 fini(LttvTracesetState
*self
)
360 LttvTracefileState
*tfcs
;
362 LttvAttributeValue v
;
364 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
365 for(i
= 0 ; i
< nb_trace
; i
++) {
366 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
367 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
370 g_assert(*(v
.v_uint
) != 0);
373 if(*(v
.v_uint
) == 0) {
374 free_name_tables(tcs
);
376 free_saved_state(tcs
);
378 g_free(tcs
->running_process
);
379 tcs
->running_process
= NULL
;
380 lttv_state_free_process_table(tcs
->processes
);
381 lttv_state_free_usertraces(tcs
->usertraces
);
382 tcs
->processes
= NULL
;
383 tcs
->usertraces
= NULL
;
385 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
386 fini((LttvTracesetContext
*)self
);
390 static LttvTracesetContext
*
391 new_traceset_context(LttvTracesetContext
*self
)
393 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
397 static LttvTraceContext
*
398 new_trace_context(LttvTracesetContext
*self
)
400 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
404 static LttvTracefileContext
*
405 new_tracefile_context(LttvTracesetContext
*self
)
407 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
411 /* Write the process state of the trace */
413 static void write_process_state(gpointer key
, gpointer value
,
416 LttvProcessState
*process
;
418 LttvExecutionState
*es
;
420 FILE *fp
= (FILE *)user_data
;
425 process
= (LttvProcessState
*)value
;
427 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
428 process
, process
->pid
, process
->tgid
, process
->ppid
,
429 g_quark_to_string(process
->type
),
430 process
->creation_time
.tv_sec
,
431 process
->creation_time
.tv_nsec
,
432 process
->insertion_time
.tv_sec
,
433 process
->insertion_time
.tv_nsec
,
434 g_quark_to_string(process
->name
),
435 g_quark_to_string(process
->brand
),
439 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
440 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
441 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
442 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
443 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
444 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
445 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
448 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
449 address
= &g_array_index(process
->user_stack
, guint64
, i
);
450 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
454 if(process
->usertrace
) {
455 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
456 process
->usertrace
->tracefile_name
,
457 process
->usertrace
->cpu
);
461 fprintf(fp
, " </PROCESS>\n");
465 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
467 guint i
, nb_tracefile
, nb_block
, offset
;
470 LttvTracefileState
*tfcs
;
474 LttEventPosition
*ep
;
478 ep
= ltt_event_position_new();
480 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
482 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
484 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
485 for(i
=0;i
<nb_cpus
;i
++) {
486 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
487 i
, self
->running_process
[i
]->pid
);
490 nb_tracefile
= self
->parent
.tracefiles
->len
;
492 for(i
= 0 ; i
< nb_tracefile
; i
++) {
494 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
495 LttvTracefileContext
*, i
));
496 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
497 tfcs
->parent
.timestamp
.tv_sec
,
498 tfcs
->parent
.timestamp
.tv_nsec
);
499 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
500 if(e
== NULL
) fprintf(fp
,"/>\n");
502 ltt_event_position(e
, ep
);
503 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
504 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
509 fprintf(fp
,"</PROCESS_STATE>");
513 /* Copy each process from an existing hash table to a new one */
515 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
517 LttvProcessState
*process
, *new_process
;
519 GHashTable
*new_processes
= (GHashTable
*)user_data
;
523 process
= (LttvProcessState
*)value
;
524 new_process
= g_new(LttvProcessState
, 1);
525 *new_process
= *process
;
526 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
527 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
528 new_process
->execution_stack
=
529 g_array_set_size(new_process
->execution_stack
,
530 process
->execution_stack
->len
);
531 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
532 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
533 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
535 new_process
->state
= &g_array_index(new_process
->execution_stack
,
536 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
537 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
539 new_process
->user_stack
=
540 g_array_set_size(new_process
->user_stack
,
541 process
->user_stack
->len
);
542 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
543 g_array_index(new_process
->user_stack
, guint64
, i
) =
544 g_array_index(process
->user_stack
, guint64
, i
);
546 new_process
->current_function
= process
->current_function
;
547 g_hash_table_insert(new_processes
, new_process
, new_process
);
551 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
553 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
555 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
556 return new_processes
;
560 /* The saved state for each trace contains a member "processes", which
561 stores a copy of the process table, and a member "tracefiles" with
562 one entry per tracefile. Each tracefile has a "process" member pointing
563 to the current process and a "position" member storing the tracefile
564 position (needed to seek to the current "next" event. */
566 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
568 guint i
, nb_tracefile
, nb_cpus
;
570 LttvTracefileState
*tfcs
;
572 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
574 guint
*running_process
;
576 LttvAttributeType type
;
578 LttvAttributeValue value
;
580 LttvAttributeName name
;
582 LttEventPosition
*ep
;
584 tracefiles_tree
= lttv_attribute_find_subdir(container
,
585 LTTV_STATE_TRACEFILES
);
587 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
589 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
591 /* Add the currently running processes array */
592 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
593 running_process
= g_new(guint
, nb_cpus
);
594 for(i
=0;i
<nb_cpus
;i
++) {
595 running_process
[i
] = self
->running_process
[i
]->pid
;
597 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
599 *(value
.v_pointer
) = running_process
;
601 g_info("State save");
603 nb_tracefile
= self
->parent
.tracefiles
->len
;
605 for(i
= 0 ; i
< nb_tracefile
; i
++) {
607 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
608 LttvTracefileContext
*, i
));
609 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
610 value
= lttv_attribute_add(tracefiles_tree
, i
,
612 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
614 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
616 *(value
.v_uint
) = tfcs
->process
->pid
;
618 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
620 /* Only save the position if the tfs has not infinite time. */
621 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
622 // && current_tfcs != tfcs) {
623 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
624 *(value
.v_pointer
) = NULL
;
626 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
627 ep
= ltt_event_position_new();
628 ltt_event_position(e
, ep
);
629 *(value
.v_pointer
) = ep
;
631 guint nb_block
, offset
;
634 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
635 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
637 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
643 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
645 guint i
, nb_tracefile
, pid
, nb_cpus
;
647 LttvTracefileState
*tfcs
;
649 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
651 guint
*running_process
;
653 LttvAttributeType type
;
655 LttvAttributeValue value
;
657 LttvAttributeName name
;
661 LttEventPosition
*ep
;
663 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
665 tracefiles_tree
= lttv_attribute_find_subdir(container
,
666 LTTV_STATE_TRACEFILES
);
668 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
670 g_assert(type
== LTTV_POINTER
);
671 lttv_state_free_process_table(self
->processes
);
672 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
674 /* Add the currently running processes array */
675 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
676 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
678 g_assert(type
== LTTV_POINTER
);
679 running_process
= *(value
.v_pointer
);
680 for(i
=0;i
<nb_cpus
;i
++) {
681 pid
= running_process
[i
];
682 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
683 g_assert(self
->running_process
[i
] != NULL
);
687 nb_tracefile
= self
->parent
.tracefiles
->len
;
689 //g_tree_destroy(tsc->pqueue);
690 //tsc->pqueue = g_tree_new(compare_tracefile);
692 for(i
= 0 ; i
< nb_tracefile
; i
++) {
694 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
695 LttvTracefileContext
*, i
));
696 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
697 g_assert(type
== LTTV_GOBJECT
);
698 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
700 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
702 g_assert(type
== LTTV_UINT
);
703 pid
= *(value
.v_uint
);
704 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
706 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
708 g_assert(type
== LTTV_POINTER
);
709 //g_assert(*(value.v_pointer) != NULL);
710 ep
= *(value
.v_pointer
);
711 g_assert(tfcs
->parent
.t_context
!= NULL
);
713 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
714 g_tree_remove(tsc
->pqueue
, tfc
);
717 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
718 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
719 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
720 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
721 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
723 tfc
->timestamp
= ltt_time_infinite
;
729 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
731 guint i
, nb_tracefile
, nb_cpus
;
733 LttvTracefileState
*tfcs
;
735 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
737 guint
*running_process
;
739 LttvAttributeType type
;
741 LttvAttributeValue value
;
743 LttvAttributeName name
;
747 LttEventPosition
*ep
;
749 tracefiles_tree
= lttv_attribute_find_subdir(container
,
750 LTTV_STATE_TRACEFILES
);
751 g_object_ref(G_OBJECT(tracefiles_tree
));
752 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
754 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
756 g_assert(type
== LTTV_POINTER
);
757 lttv_state_free_process_table(*(value
.v_pointer
));
758 *(value
.v_pointer
) = NULL
;
759 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
761 /* Free running processes array */
762 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
763 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
765 g_assert(type
== LTTV_POINTER
);
766 running_process
= *(value
.v_pointer
);
767 g_free(running_process
);
769 nb_tracefile
= self
->parent
.tracefiles
->len
;
771 for(i
= 0 ; i
< nb_tracefile
; i
++) {
773 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
774 LttvTracefileContext
*, i
));
775 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
776 g_assert(type
== LTTV_GOBJECT
);
777 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
779 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
781 g_assert(type
== LTTV_POINTER
);
782 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
784 g_object_unref(G_OBJECT(tracefiles_tree
));
788 static void free_saved_state(LttvTraceState
*self
)
792 LttvAttributeType type
;
794 LttvAttributeValue value
;
796 LttvAttributeName name
;
800 LttvAttribute
*saved_states
;
802 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
803 LTTV_STATE_SAVED_STATES
);
805 nb
= lttv_attribute_get_number(saved_states
);
806 for(i
= 0 ; i
< nb
; i
++) {
807 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
808 g_assert(type
== LTTV_GOBJECT
);
809 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
812 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
817 create_max_time(LttvTraceState
*tcs
)
819 LttvAttributeValue v
;
821 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
823 g_assert(*(v
.v_pointer
) == NULL
);
824 *(v
.v_pointer
) = g_new(LttTime
,1);
825 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
830 get_max_time(LttvTraceState
*tcs
)
832 LttvAttributeValue v
;
834 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
836 g_assert(*(v
.v_pointer
) != NULL
);
837 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
842 free_max_time(LttvTraceState
*tcs
)
844 LttvAttributeValue v
;
846 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
848 g_free(*(v
.v_pointer
));
849 *(v
.v_pointer
) = NULL
;
853 typedef struct _LttvNameTables
{
854 // FIXME GQuark *eventtype_names;
855 GQuark
*syscall_names
;
860 GQuark
*soft_irq_names
;
865 create_name_tables(LttvTraceState
*tcs
)
869 GQuark f_name
, e_name
;
873 LttvTraceHookByFacility
*thf
;
879 GString
*fe_name
= g_string_new("");
881 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
883 LttvAttributeValue v
;
885 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
887 g_assert(*(v
.v_pointer
) == NULL
);
888 *(v
.v_pointer
) = name_tables
;
889 #if 0 // Use iteration over the facilities_by_name and then list all event
890 // types of each facility
891 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
892 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
893 for(i
= 0 ; i
< nb
; i
++) {
894 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
895 e_name
= ltt_eventtype_name(et
);
896 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
897 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
898 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
901 if(!lttv_trace_find_hook(tcs
->parent
.t
,
902 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
903 LTT_FIELD_SYSCALL_ID
, 0, 0,
906 thf
= lttv_trace_hook_get_first(&h
);
908 t
= ltt_field_type(thf
->f1
);
909 nb
= ltt_type_element_number(t
);
911 lttv_trace_hook_destroy(&h
);
913 name_tables
->syscall_names
= g_new(GQuark
, nb
);
914 name_tables
->nb_syscalls
= nb
;
916 for(i
= 0 ; i
< nb
; i
++) {
917 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
920 //name_tables->syscall_names = g_new(GQuark, 256);
921 //for(i = 0 ; i < 256 ; i++) {
922 // g_string_printf(fe_name, "syscall %d", i);
923 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
926 name_tables
->syscall_names
= NULL
;
927 name_tables
->nb_syscalls
= 0;
930 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
931 LTT_EVENT_TRAP_ENTRY
,
932 LTT_FIELD_TRAP_ID
, 0, 0,
935 thf
= lttv_trace_hook_get_first(&h
);
937 t
= ltt_field_type(thf
->f1
);
938 //nb = ltt_type_element_number(t);
940 lttv_trace_hook_destroy(&h
);
943 name_tables->trap_names = g_new(GQuark, nb);
944 for(i = 0 ; i < nb ; i++) {
945 name_tables->trap_names[i] = g_quark_from_string(
946 ltt_enum_string_get(t, i));
949 name_tables
->nb_traps
= 256;
950 name_tables
->trap_names
= g_new(GQuark
, 256);
951 for(i
= 0 ; i
< 256 ; i
++) {
952 g_string_printf(fe_name
, "trap %d", i
);
953 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
956 name_tables
->trap_names
= NULL
;
957 name_tables
->nb_traps
= 0;
960 if(!lttv_trace_find_hook(tcs
->parent
.t
,
961 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
962 LTT_FIELD_IRQ_ID
, 0, 0,
965 thf
= lttv_trace_hook_get_first(&h
);
967 t
= ltt_field_type(thf
->f1
);
968 //nb = ltt_type_element_number(t);
970 lttv_trace_hook_destroy(&h
);
973 name_tables->irq_names = g_new(GQuark, nb);
974 for(i = 0 ; i < nb ; i++) {
975 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
979 name_tables
->irq_names
= g_new(GQuark
, 256);
980 for(i
= 0 ; i
< 256 ; i
++) {
981 g_string_printf(fe_name
, "irq %d", i
);
982 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
985 name_tables
->irq_names
= NULL
;
988 name_tables->soft_irq_names = g_new(GQuark, nb);
989 for(i = 0 ; i < nb ; i++) {
990 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
994 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
995 for(i
= 0 ; i
< 256 ; i
++) {
996 g_string_printf(fe_name
, "softirq %d", i
);
997 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1001 g_string_free(fe_name
, TRUE
);
1006 get_name_tables(LttvTraceState
*tcs
)
1008 LttvNameTables
*name_tables
;
1010 LttvAttributeValue v
;
1012 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1014 g_assert(*(v
.v_pointer
) != NULL
);
1015 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1016 //tcs->eventtype_names = name_tables->eventtype_names;
1017 tcs
->syscall_names
= name_tables
->syscall_names
;
1018 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1019 tcs
->trap_names
= name_tables
->trap_names
;
1020 tcs
->nb_traps
= name_tables
->nb_traps
;
1021 tcs
->irq_names
= name_tables
->irq_names
;
1022 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1027 free_name_tables(LttvTraceState
*tcs
)
1029 LttvNameTables
*name_tables
;
1031 LttvAttributeValue v
;
1033 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1035 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1036 *(v
.v_pointer
) = NULL
;
1038 // g_free(name_tables->eventtype_names);
1039 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1040 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1041 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1042 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1043 if(name_tables
) g_free(name_tables
);
1046 #ifdef HASH_TABLE_DEBUG
1048 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1050 LttvProcessState
*process
= (LttvProcessState
*)value
;
1052 /* Test for process corruption */
1053 guint stack_len
= process
->execution_stack
->len
;
1056 static void hash_table_check(GHashTable
*table
)
1058 g_hash_table_foreach(table
, test_process
, NULL
);
1065 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1068 LttvExecutionState
*es
;
1070 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1071 guint cpu
= tfs
->cpu
;
1073 #ifdef HASH_TABLE_DEBUG
1074 hash_table_check(ts
->processes
);
1076 LttvProcessState
*process
= ts
->running_process
[cpu
];
1078 guint depth
= process
->execution_stack
->len
;
1080 process
->execution_stack
=
1081 g_array_set_size(process
->execution_stack
, depth
+ 1);
1084 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1086 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1089 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1090 es
->cum_cpu_time
= ltt_time_zero
;
1091 es
->s
= process
->state
->s
;
1092 process
->state
= es
;
1096 * return 1 when empty, else 0 */
1097 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1098 LttvTracefileState
*tfs
)
1100 guint cpu
= tfs
->cpu
;
1101 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1103 guint depth
= process
->execution_stack
->len
;
1109 process
->execution_stack
=
1110 g_array_set_size(process
->execution_stack
, depth
- 1);
1111 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1113 process
->state
->change
= tfs
->parent
.timestamp
;
1118 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1120 guint cpu
= tfs
->cpu
;
1121 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1122 LttvProcessState
*process
= ts
->running_process
[cpu
];
1124 guint depth
= process
->execution_stack
->len
;
1126 if(process
->state
->t
!= t
){
1127 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1128 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1129 g_info("process state has %s when pop_int is %s\n",
1130 g_quark_to_string(process
->state
->t
),
1131 g_quark_to_string(t
));
1132 g_info("{ %u, %u, %s, %s, %s }\n",
1135 g_quark_to_string(process
->name
),
1136 g_quark_to_string(process
->brand
),
1137 g_quark_to_string(process
->state
->s
));
1142 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1143 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1147 process
->execution_stack
=
1148 g_array_set_size(process
->execution_stack
, depth
- 1);
1149 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1151 process
->state
->change
= tfs
->parent
.timestamp
;
1154 struct search_result
{
1155 const LttTime
*time
; /* Requested time */
1156 LttTime
*best
; /* Best result */
1159 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1161 const LttTime
*elem_time
= (const LttTime
*)a
;
1162 /* Explicit non const cast */
1163 struct search_result
*res
= (struct search_result
*)b
;
1165 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1166 /* The usertrace was created before the schedchange */
1167 /* Get larger keys */
1169 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1170 /* The usertrace was created after the schedchange time */
1171 /* Get smaller keys */
1173 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1174 res
->best
= elem_time
;
1177 res
->best
= elem_time
;
1184 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1185 guint pid
, const LttTime
*timestamp
)
1187 LttvTracefileState
*tfs
= NULL
;
1188 struct search_result res
;
1189 /* Find the usertrace associated with a pid and time interval.
1190 * Search in the usertraces by PID (within a hash) and then, for each
1191 * corresponding element of the array, find the first one with creation
1192 * timestamp the lowest, but higher or equal to "timestamp". */
1193 res
.time
= timestamp
;
1195 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1196 if(usertrace_tree
) {
1197 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1199 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1207 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1208 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1210 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1212 LttvExecutionState
*es
;
1214 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1219 process
->tgid
= tgid
;
1221 process
->name
= name
;
1222 process
->brand
= LTTV_STATE_UNBRANDED
;
1223 //process->last_cpu = tfs->cpu_name;
1224 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1225 process
->type
= LTTV_STATE_USER_THREAD
;
1226 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1227 process
->current_function
= 0; //function 0x0 by default.
1229 g_info("Process %u, core %p", process
->pid
, process
);
1230 g_hash_table_insert(tcs
->processes
, process
, process
);
1233 process
->ppid
= parent
->pid
;
1234 process
->creation_time
= *timestamp
;
1237 /* No parent. This process exists but we are missing all information about
1238 its creation. The birth time is set to zero but we remember the time of
1243 process
->creation_time
= ltt_time_zero
;
1246 process
->insertion_time
= *timestamp
;
1247 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1248 process
->creation_time
.tv_nsec
);
1249 process
->pid_time
= g_quark_from_string(buffer
);
1251 //process->last_cpu = tfs->cpu_name;
1252 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1253 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1254 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1255 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1256 es
= process
->state
= &g_array_index(process
->execution_stack
,
1257 LttvExecutionState
, 0);
1258 es
->t
= LTTV_STATE_USER_MODE
;
1259 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1260 es
->entry
= *timestamp
;
1261 //g_assert(timestamp->tv_sec != 0);
1262 es
->change
= *timestamp
;
1263 es
->cum_cpu_time
= ltt_time_zero
;
1264 es
->s
= LTTV_STATE_RUN
;
1266 es
= process
->state
= &g_array_index(process
->execution_stack
,
1267 LttvExecutionState
, 1);
1268 es
->t
= LTTV_STATE_SYSCALL
;
1269 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1270 es
->entry
= *timestamp
;
1271 //g_assert(timestamp->tv_sec != 0);
1272 es
->change
= *timestamp
;
1273 es
->cum_cpu_time
= ltt_time_zero
;
1274 es
->s
= LTTV_STATE_WAIT_FORK
;
1276 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1277 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1278 sizeof(guint64
), 0);
1283 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1286 LttvProcessState key
;
1287 LttvProcessState
*process
;
1291 process
= g_hash_table_lookup(ts
->processes
, &key
);
1296 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1299 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1300 LttvExecutionState
*es
;
1302 /* Put ltt_time_zero creation time for unexisting processes */
1303 if(unlikely(process
== NULL
)) {
1304 process
= lttv_state_create_process(ts
,
1305 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1306 /* We are not sure is it's a kernel thread or normal thread, put the
1307 * bottom stack state to unknown */
1308 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1309 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1314 /* FIXME : this function should be called when we receive an event telling that
1315 * release_task has been called in the kernel. In happens generally when
1316 * the parent waits for its child terminaison, but may also happen in special
1317 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1318 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1319 * of a killed thread ground, but isn't the leader.
1321 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1323 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1324 LttvProcessState key
;
1326 key
.pid
= process
->pid
;
1327 key
.cpu
= process
->cpu
;
1328 g_hash_table_remove(ts
->processes
, &key
);
1329 g_array_free(process
->execution_stack
, TRUE
);
1330 g_array_free(process
->user_stack
, TRUE
);
1335 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1337 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1338 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1343 static void lttv_state_free_process_table(GHashTable
*processes
)
1345 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1346 g_hash_table_destroy(processes
);
1350 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1352 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1353 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1354 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1355 LttField
*f
= thf
->f1
;
1357 LttvExecutionSubmode submode
;
1359 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1360 guint syscall
= ltt_event_get_unsigned(e
, f
);
1362 if(syscall
< nb_syscalls
) {
1363 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1366 /* Fixup an incomplete syscall table */
1367 GString
*string
= g_string_new("");
1368 g_string_printf(string
, "syscall %u", syscall
);
1369 submode
= g_quark_from_string(string
->str
);
1370 g_string_free(string
, TRUE
);
1372 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1377 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1379 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1381 pop_state(s
, LTTV_STATE_SYSCALL
);
1386 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1388 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1389 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1390 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1391 LttField
*f
= thf
->f1
;
1393 LttvExecutionSubmode submode
;
1395 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1396 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1398 if(trap
< nb_traps
) {
1399 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1401 /* Fixup an incomplete trap table */
1402 GString
*string
= g_string_new("");
1403 g_string_printf(string
, "trap %llu", trap
);
1404 submode
= g_quark_from_string(string
->str
);
1405 g_string_free(string
, TRUE
);
1408 push_state(s
, LTTV_STATE_TRAP
, submode
);
1413 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1415 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1417 pop_state(s
, LTTV_STATE_TRAP
);
1422 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1424 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1425 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1426 guint8 fac_id
= ltt_event_facility_id(e
);
1427 guint8 ev_id
= ltt_event_eventtype_id(e
);
1428 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1429 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1430 g_assert(thf
->f1
!= NULL
);
1431 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1432 LttField
*f
= thf
->f1
;
1434 LttvExecutionSubmode submode
;
1436 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1437 ltt_event_get_unsigned(e
, f
)];
1439 /* Do something with the info about being in user or system mode when int? */
1440 push_state(s
, LTTV_STATE_IRQ
, submode
);
1444 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1446 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1448 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1454 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1456 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1458 pop_state(s
, LTTV_STATE_IRQ
);
1462 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1464 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1465 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1466 guint8 fac_id
= ltt_event_facility_id(e
);
1467 guint8 ev_id
= ltt_event_eventtype_id(e
);
1468 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1469 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1470 g_assert(thf
->f1
!= NULL
);
1471 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1472 LttField
*f
= thf
->f1
;
1474 LttvExecutionSubmode submode
;
1476 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1477 ltt_event_get_long_unsigned(e
, f
)];
1479 /* Do something with the info about being in user or system mode when int? */
1480 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1484 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1488 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1489 guint cpu
= tfs
->cpu
;
1490 LttvProcessState
*process
= ts
->running_process
[cpu
];
1492 guint depth
= process
->user_stack
->len
;
1494 process
->user_stack
=
1495 g_array_set_size(process
->user_stack
, depth
+ 1);
1497 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1498 *new_func
= funcptr
;
1499 process
->current_function
= funcptr
;
1502 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1504 guint cpu
= tfs
->cpu
;
1505 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1506 LttvProcessState
*process
= ts
->running_process
[cpu
];
1508 if(process
->current_function
!= funcptr
){
1509 g_info("Different functions (%lu.%09lu): ignore it\n",
1510 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1511 g_info("process state has %llu when pop_function is %llu\n",
1512 process
->current_function
, funcptr
);
1513 g_info("{ %u, %u, %s, %s, %s }\n",
1516 g_quark_to_string(process
->name
),
1517 g_quark_to_string(process
->brand
),
1518 g_quark_to_string(process
->state
->s
));
1521 guint depth
= process
->user_stack
->len
;
1524 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1525 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1529 process
->user_stack
=
1530 g_array_set_size(process
->user_stack
, depth
- 1);
1531 process
->current_function
=
1532 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1536 static gboolean
function_entry(void *hook_data
, void *call_data
)
1538 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1539 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1540 guint8 fac_id
= ltt_event_facility_id(e
);
1541 guint8 ev_id
= ltt_event_eventtype_id(e
);
1542 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1543 g_assert(thf
->f1
!= NULL
);
1544 LttField
*f
= thf
->f1
;
1545 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1547 push_function(s
, funcptr
);
1551 static gboolean
function_exit(void *hook_data
, void *call_data
)
1553 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1554 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1555 guint8 fac_id
= ltt_event_facility_id(e
);
1556 guint8 ev_id
= ltt_event_eventtype_id(e
);
1557 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1558 g_assert(thf
->f1
!= NULL
);
1559 LttField
*f
= thf
->f1
;
1560 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1562 LttvExecutionSubmode submode
;
1564 pop_function(s
, funcptr
);
1568 static gboolean
schedchange(void *hook_data
, void *call_data
)
1570 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1572 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1573 LttvProcessState
*process
= ts
->running_process
[cpu
];
1574 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1576 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1577 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1578 guint pid_in
, pid_out
;
1581 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1582 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1583 state_out
= ltt_event_get_int(e
, thf
->f3
);
1585 if(likely(process
!= NULL
)) {
1587 /* We could not know but it was not the idle process executing.
1588 This should only happen at the beginning, before the first schedule
1589 event, and when the initial information (current process for each CPU)
1590 is missing. It is not obvious how we could, after the fact, compensate
1591 the wrongly attributed statistics. */
1593 //This test only makes sense once the state is known and if there is no
1594 //missing events. We need to silently ignore schedchange coming after a
1595 //process_free, or it causes glitches. (FIXME)
1596 //if(unlikely(process->pid != pid_out)) {
1597 // g_assert(process->pid == 0);
1600 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1601 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1602 process
->state
->change
= s
->parent
.timestamp
;
1604 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1605 else process
->state
->s
= LTTV_STATE_WAIT
;
1606 process
->state
->change
= s
->parent
.timestamp
;
1610 exit_process(s
, process
); /* EXIT_DEAD */
1611 /* see sched.h for states */
1613 process
= ts
->running_process
[cpu
] =
1614 lttv_state_find_process_or_create(
1615 (LttvTraceState
*)s
->parent
.t_context
,
1617 &s
->parent
.timestamp
);
1618 process
->state
->s
= LTTV_STATE_RUN
;
1620 if(process
->usertrace
)
1621 process
->usertrace
->cpu
= cpu
;
1622 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1623 process
->state
->change
= s
->parent
.timestamp
;
1627 static gboolean
process_fork(void *hook_data
, void *call_data
)
1629 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1630 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1631 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1633 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
1634 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
1635 LttvProcessState
*zombie_process
;
1637 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1638 LttvProcessState
*process
= ts
->running_process
[cpu
];
1639 LttvProcessState
*child_process
;
1642 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1645 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1646 s
->parent
.target_pid
= child_pid
;
1649 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
1650 else child_tgid
= 0;
1652 /* Mathieu : it seems like the process might have been scheduled in before the
1653 * fork, and, in a rare case, might be the current process. This might happen
1654 * in a SMP case where we don't have enough precision on the clocks.
1656 * Test reenabled after precision fixes on time. (Mathieu) */
1658 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1660 if(unlikely(zombie_process
!= NULL
)) {
1661 /* Reutilisation of PID. Only now we are sure that the old PID
1662 * has been released. FIXME : should know when release_task happens instead.
1664 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1666 for(i
=0; i
< num_cpus
; i
++) {
1667 g_assert(zombie_process
!= ts
->running_process
[i
]);
1670 exit_process(s
, zombie_process
);
1673 g_assert(process
->pid
!= child_pid
);
1674 // FIXME : Add this test in the "known state" section
1675 // g_assert(process->pid == parent_pid);
1676 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1677 if(child_process
== NULL
) {
1678 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1679 child_pid
, child_tgid
,
1680 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1682 /* The process has already been created : due to time imprecision between
1683 * multiple CPUs : it has been scheduled in before creation. Note that we
1684 * shouldn't have this kind of imprecision.
1686 * Simply put a correct parent.
1688 g_assert(0); /* This is a problematic case : the process has been created
1689 before the fork event */
1690 child_process
->ppid
= process
->pid
;
1691 child_process
->tgid
= child_tgid
;
1693 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1694 child_process
->name
= process
->name
;
1695 child_process
->brand
= process
->brand
;
1700 /* We stamp a newly created process as kernel_thread */
1701 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1703 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1704 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1705 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1708 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1709 LttvProcessState
*process
;
1710 LttvExecutionState
*es
;
1713 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1714 s
->parent
.target_pid
= pid
;
1716 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1717 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1718 es
->t
= LTTV_STATE_SYSCALL
;
1719 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1724 static gboolean
process_exit(void *hook_data
, void *call_data
)
1726 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1727 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1728 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1732 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1733 LttvProcessState
*process
; // = ts->running_process[cpu];
1735 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1736 s
->parent
.target_pid
= pid
;
1738 // FIXME : Add this test in the "known state" section
1739 // g_assert(process->pid == pid);
1741 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1742 if(likely(process
!= NULL
)) {
1743 process
->state
->s
= LTTV_STATE_EXIT
;
1748 static gboolean
process_free(void *hook_data
, void *call_data
)
1750 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1751 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1752 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1753 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1755 LttvProcessState
*process
;
1757 /* PID of the process to release */
1758 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1759 s
->parent
.target_pid
= release_pid
;
1761 g_assert(release_pid
!= 0);
1763 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1765 if(likely(process
!= NULL
)) {
1766 /* release_task is happening at kernel level : we can now safely release
1767 * the data structure of the process */
1768 //This test is fun, though, as it may happen that
1769 //at time t : CPU 0 : process_free
1770 //at time t+150ns : CPU 1 : schedule out
1771 //Clearly due to time imprecision, we disable it. (Mathieu)
1772 //If this weird case happen, we have no choice but to put the
1773 //Currently running process on the cpu to 0.
1774 //I re-enable it following time precision fixes. (Mathieu)
1775 //Well, in the case where an process is freed by a process on another CPU
1776 //and still scheduled, it happens that this is the schedchange that will
1777 //drop the last reference count. Do not free it here!
1778 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1780 for(i
=0; i
< num_cpus
; i
++) {
1781 //g_assert(process != ts->running_process[i]);
1782 if(process
== ts
->running_process
[i
]) {
1783 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1787 if(i
== num_cpus
) /* process is not scheduled */
1788 exit_process(s
, process
);
1795 static gboolean
process_exec(void *hook_data
, void *call_data
)
1797 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1798 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1799 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1800 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1803 LttvProcessState
*process
= ts
->running_process
[cpu
];
1805 /* PID of the process to release */
1806 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1807 //name = ltt_event_get_string(e, thf->f1);
1808 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1810 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1811 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1812 memcpy(null_term_name
, name_begin
, name_len
);
1813 null_term_name
[name_len
] = '\0';
1815 process
->name
= g_quark_from_string(null_term_name
);
1816 process
->brand
= LTTV_STATE_UNBRANDED
;
1817 g_free(null_term_name
);
1821 static gboolean
thread_brand(void *hook_data
, void *call_data
)
1823 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1824 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1825 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1826 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1829 LttvProcessState
*process
= ts
->running_process
[cpu
];
1831 name
= ltt_event_get_string(e
, thf
->f1
);
1832 process
->brand
= g_quark_from_string(name
);
1837 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1839 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1840 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1841 //It's slow : optimise later by doing this before reading trace.
1842 LttEventType
*et
= ltt_event_eventtype(e
);
1844 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1850 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1851 LttvProcessState
*process
= ts
->running_process
[cpu
];
1852 LttvProcessState
*parent_process
;
1853 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
1854 GQuark type
, mode
, submode
, status
;
1855 LttvExecutionState
*es
;
1858 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1859 s
->parent
.target_pid
= pid
;
1862 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1865 command
= ltt_event_get_string(e
, thf
->f3
);
1868 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1869 type
= ltt_enum_string_get(ltt_field_type(f4
),
1870 ltt_event_get_unsigned(e
, f4
));
1873 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1874 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1875 ltt_event_get_unsigned(e
, f5
));
1878 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1879 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1880 ltt_event_get_unsigned(e
, f6
));
1883 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1884 status
= ltt_enum_string_get(ltt_field_type(f7
),
1885 ltt_event_get_unsigned(e
, f7
));
1888 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
1889 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
1892 /* The process might exist if a process was forked while performing the state
1894 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1895 if(process
== NULL
) {
1896 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1897 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1898 pid
, tgid
, g_quark_from_string(command
),
1899 &s
->parent
.timestamp
);
1901 /* Keep the stack bottom : a running user mode */
1902 /* Disabled because of inconsistencies in the current statedump states. */
1903 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1904 /* Only keep the bottom */
1905 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1906 es
= process
->state
= &g_array_index(process
->execution_stack
,
1907 LttvExecutionState
, 0);
1908 es
->t
= LTTV_STATE_SYSCALL
;
1912 /* On top of it : */
1913 es
= process
->state
= &g_array_index(process
->execution_stack
,
1914 LttvExecutionState
, 1);
1915 es
->t
= LTTV_STATE_USER_MODE
;
1922 es
= process
->state
= &g_array_index(process
->execution_stack
,
1923 LttvExecutionState
, 1);
1924 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1925 es
->s
= LTTV_STATE_UNNAMED
;
1926 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1930 /* The process has already been created :
1931 * Probably was forked while dumping the process state or
1932 * was simply scheduled in prior to get the state dump event.
1933 * We know for sure if it is a user space thread.
1935 process
->ppid
= parent_pid
;
1936 process
->tgid
= tgid
;
1937 process
->name
= g_quark_from_string(command
);
1938 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1939 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1940 es
->t
= LTTV_STATE_USER_MODE
;
1941 /* Don't mess around with the stack, it will eventually become
1942 * ok after the end of state dump. */
1948 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1950 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1952 lttv_state_add_event_hooks(tss
);
1957 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1959 LttvTraceset
*traceset
= self
->parent
.ts
;
1961 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1965 LttvTracefileState
*tfs
;
1969 LttvTraceHookByFacility
*thf
;
1971 LttvTraceHook
*hook
;
1973 LttvAttributeValue val
;
1978 nb_trace
= lttv_traceset_number(traceset
);
1979 for(i
= 0 ; i
< nb_trace
; i
++) {
1980 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1982 /* Find the eventtype id for the following events and register the
1983 associated by id hooks. */
1985 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
1986 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
1989 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1990 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1991 LTT_FIELD_SYSCALL_ID
, 0, 0,
1992 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1995 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1996 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1998 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2001 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2002 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2003 LTT_FIELD_TRAP_ID
, 0, 0,
2004 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2007 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2008 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2010 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2013 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2014 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2015 LTT_FIELD_IRQ_ID
, 0, 0,
2016 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2019 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2020 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2022 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2025 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2026 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2027 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2028 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2031 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2032 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2034 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2037 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2038 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2039 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2040 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2043 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2044 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2045 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2046 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2049 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2050 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2051 LTT_FIELD_PID
, 0, 0,
2052 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2056 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2057 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2058 LTT_FIELD_PID
, 0, 0,
2059 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2062 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2063 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2064 LTT_FIELD_PID
, 0, 0,
2065 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2068 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2069 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2070 LTT_FIELD_FILENAME
, 0, 0,
2071 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2074 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2075 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2076 LTT_FIELD_NAME
, 0, 0,
2077 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2080 /* statedump-related hooks */
2081 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2082 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2083 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2084 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2087 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2088 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2089 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2090 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2093 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2094 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2095 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2096 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2099 hooks
= g_array_set_size(hooks
, hn
);
2101 /* Add these hooks to each event_by_id hooks list */
2103 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2105 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2107 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2108 LttvTracefileContext
*, j
));
2110 for(k
= 0 ; k
< hooks
->len
; k
++) {
2111 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2112 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2113 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2115 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2122 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2123 *(val
.v_pointer
) = hooks
;
2127 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2129 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2131 lttv_state_remove_event_hooks(tss
);
2136 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2138 LttvTraceset
*traceset
= self
->parent
.ts
;
2140 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2144 LttvTracefileState
*tfs
;
2148 LttvTraceHook
*hook
;
2150 LttvTraceHookByFacility
*thf
;
2152 LttvAttributeValue val
;
2154 nb_trace
= lttv_traceset_number(traceset
);
2155 for(i
= 0 ; i
< nb_trace
; i
++) {
2156 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2157 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2158 hooks
= *(val
.v_pointer
);
2160 /* Remove these hooks from each event_by_id hooks list */
2162 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2164 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2166 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2167 LttvTracefileContext
*, j
));
2169 for(k
= 0 ; k
< hooks
->len
; k
++) {
2170 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2171 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2172 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2174 lttv_hooks_remove_data(
2175 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2181 for(k
= 0 ; k
< hooks
->len
; k
++)
2182 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2183 g_array_free(hooks
, TRUE
);
2187 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2189 guint
*event_count
= (guint
*)hook_data
;
2191 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2192 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2197 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2199 LttvTracefileState
*tfcs
;
2201 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2203 LttEventPosition
*ep
;
2209 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2211 LttvAttributeValue value
;
2213 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2214 LTTV_STATE_SAVED_STATES
);
2215 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2216 value
= lttv_attribute_add(saved_states_tree
,
2217 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2218 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2219 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2220 *(value
.v_time
) = self
->parent
.timestamp
;
2221 lttv_state_save(tcs
, saved_state_tree
);
2222 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2223 self
->parent
.timestamp
.tv_nsec
);
2225 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2230 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2232 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2234 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2239 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2247 static gboolean
block_start(void *hook_data
, void *call_data
)
2249 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2251 LttvTracefileState
*tfcs
;
2253 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2255 LttEventPosition
*ep
;
2257 guint i
, nb_block
, nb_event
, nb_tracefile
;
2261 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2263 LttvAttributeValue value
;
2265 ep
= ltt_event_position_new();
2267 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2269 /* Count the number of events added since the last block end in any
2272 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2274 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2275 LttvTracefileContext
, i
));
2276 ltt_event_position(tfcs
->parent
.e
, ep
);
2277 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2278 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2279 tfcs
->saved_position
= nb_event
;
2283 if(tcs
->nb_event
>= tcs
->save_interval
) {
2284 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2285 LTTV_STATE_SAVED_STATES
);
2286 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2287 value
= lttv_attribute_add(saved_states_tree
,
2288 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2289 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2290 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2291 *(value
.v_time
) = self
->parent
.timestamp
;
2292 lttv_state_save(tcs
, saved_state_tree
);
2294 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2295 self
->parent
.timestamp
.tv_nsec
);
2297 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2303 static gboolean
block_end(void *hook_data
, void *call_data
)
2305 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2307 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2311 LttEventPosition
*ep
;
2313 guint nb_block
, nb_event
;
2315 ep
= ltt_event_position_new();
2316 ltt_event_position(self
->parent
.e
, ep
);
2317 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2318 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2319 self
->saved_position
= 0;
2320 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2327 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2329 LttvTraceset
*traceset
= self
->parent
.ts
;
2331 guint i
, j
, nb_trace
, nb_tracefile
;
2335 LttvTracefileState
*tfs
;
2337 LttvTraceHook hook_start
, hook_end
;
2339 nb_trace
= lttv_traceset_number(traceset
);
2340 for(i
= 0 ; i
< nb_trace
; i
++) {
2341 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2343 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2344 NULL
, NULL
, block_start
, &hook_start
);
2345 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2346 NULL
, NULL
, block_end
, &hook_end
);
2348 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2350 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2352 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2353 LttvTracefileContext
, j
));
2354 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2355 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2356 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2357 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2363 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2365 LttvTraceset
*traceset
= self
->parent
.ts
;
2367 guint i
, j
, nb_trace
, nb_tracefile
;
2371 LttvTracefileState
*tfs
;
2374 nb_trace
= lttv_traceset_number(traceset
);
2375 for(i
= 0 ; i
< nb_trace
; i
++) {
2377 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2378 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2380 guint
*event_count
= g_new(guint
, 1);
2383 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2385 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2386 LttvTracefileContext
*, j
));
2387 lttv_hooks_add(tfs
->parent
.event
,
2388 state_save_event_hook
,
2395 lttv_process_traceset_begin(&self
->parent
,
2396 NULL
, NULL
, NULL
, NULL
, NULL
);
2400 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2402 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2404 lttv_state_save_add_event_hooks(tss
);
2411 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2413 LttvTraceset
*traceset
= self
->parent
.ts
;
2415 guint i
, j
, nb_trace
, nb_tracefile
;
2419 LttvTracefileState
*tfs
;
2421 LttvTraceHook hook_start
, hook_end
;
2423 nb_trace
= lttv_traceset_number(traceset
);
2424 for(i
= 0 ; i
< nb_trace
; i
++) {
2425 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2427 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2428 NULL
, NULL
, block_start
, &hook_start
);
2430 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2431 NULL
, NULL
, block_end
, &hook_end
);
2433 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2435 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2437 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2438 LttvTracefileContext
, j
));
2439 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2440 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2441 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2442 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2448 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2450 LttvTraceset
*traceset
= self
->parent
.ts
;
2452 guint i
, j
, nb_trace
, nb_tracefile
;
2456 LttvTracefileState
*tfs
;
2458 LttvHooks
*after_trace
= lttv_hooks_new();
2460 lttv_hooks_add(after_trace
,
2461 state_save_after_trace_hook
,
2466 lttv_process_traceset_end(&self
->parent
,
2467 NULL
, after_trace
, NULL
, NULL
, NULL
);
2469 lttv_hooks_destroy(after_trace
);
2471 nb_trace
= lttv_traceset_number(traceset
);
2472 for(i
= 0 ; i
< nb_trace
; i
++) {
2474 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2475 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2477 guint
*event_count
= NULL
;
2479 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2481 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2482 LttvTracefileContext
*, j
));
2483 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2484 state_save_event_hook
);
2486 if(event_count
) g_free(event_count
);
2490 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2492 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2494 lttv_state_save_remove_event_hooks(tss
);
2499 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2501 LttvTraceset
*traceset
= self
->parent
.ts
;
2505 int min_pos
, mid_pos
, max_pos
;
2507 guint call_rest
= 0;
2509 LttvTraceState
*tcs
;
2511 LttvAttributeValue value
;
2513 LttvAttributeType type
;
2515 LttvAttributeName name
;
2519 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2521 //g_tree_destroy(self->parent.pqueue);
2522 //self->parent.pqueue = g_tree_new(compare_tracefile);
2524 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2526 nb_trace
= lttv_traceset_number(traceset
);
2527 for(i
= 0 ; i
< nb_trace
; i
++) {
2528 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2530 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2531 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2532 LTTV_STATE_SAVED_STATES
);
2535 if(saved_states_tree
) {
2536 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2537 mid_pos
= max_pos
/ 2;
2538 while(min_pos
< max_pos
) {
2539 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2541 g_assert(type
== LTTV_GOBJECT
);
2542 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2543 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2545 g_assert(type
== LTTV_TIME
);
2546 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2548 closest_tree
= saved_state_tree
;
2550 else max_pos
= mid_pos
- 1;
2552 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2556 /* restore the closest earlier saved state */
2558 lttv_state_restore(tcs
, closest_tree
);
2562 /* There is no saved state, yet we want to have it. Restart at T0 */
2564 restore_init_state(tcs
);
2565 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2568 /* We want to seek quickly without restoring/updating the state */
2570 restore_init_state(tcs
);
2571 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2574 if(!call_rest
) g_info("NOT Calling restore");
2579 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2585 traceset_state_finalize (LttvTracesetState
*self
)
2587 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2588 finalize(G_OBJECT(self
));
2593 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2595 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2597 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2598 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2599 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2600 klass
->new_traceset_context
= new_traceset_context
;
2601 klass
->new_trace_context
= new_trace_context
;
2602 klass
->new_tracefile_context
= new_tracefile_context
;
2607 lttv_traceset_state_get_type(void)
2609 static GType type
= 0;
2611 static const GTypeInfo info
= {
2612 sizeof (LttvTracesetStateClass
),
2613 NULL
, /* base_init */
2614 NULL
, /* base_finalize */
2615 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2616 NULL
, /* class_finalize */
2617 NULL
, /* class_data */
2618 sizeof (LttvTracesetState
),
2619 0, /* n_preallocs */
2620 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2621 NULL
/* value handling */
2624 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2632 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2638 trace_state_finalize (LttvTraceState
*self
)
2640 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2641 finalize(G_OBJECT(self
));
2646 trace_state_class_init (LttvTraceStateClass
*klass
)
2648 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2650 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2651 klass
->state_save
= state_save
;
2652 klass
->state_restore
= state_restore
;
2653 klass
->state_saved_free
= state_saved_free
;
2658 lttv_trace_state_get_type(void)
2660 static GType type
= 0;
2662 static const GTypeInfo info
= {
2663 sizeof (LttvTraceStateClass
),
2664 NULL
, /* base_init */
2665 NULL
, /* base_finalize */
2666 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2667 NULL
, /* class_finalize */
2668 NULL
, /* class_data */
2669 sizeof (LttvTraceState
),
2670 0, /* n_preallocs */
2671 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2672 NULL
/* value handling */
2675 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2676 "LttvTraceStateType", &info
, 0);
2683 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2689 tracefile_state_finalize (LttvTracefileState
*self
)
2691 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2692 finalize(G_OBJECT(self
));
2697 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2699 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2701 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2706 lttv_tracefile_state_get_type(void)
2708 static GType type
= 0;
2710 static const GTypeInfo info
= {
2711 sizeof (LttvTracefileStateClass
),
2712 NULL
, /* base_init */
2713 NULL
, /* base_finalize */
2714 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2715 NULL
, /* class_finalize */
2716 NULL
, /* class_data */
2717 sizeof (LttvTracefileState
),
2718 0, /* n_preallocs */
2719 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2720 NULL
/* value handling */
2723 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2724 "LttvTracefileStateType", &info
, 0);
2730 static void module_init()
2732 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2733 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
2734 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2735 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2736 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2737 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2738 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2739 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2740 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2741 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2742 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2743 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2744 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2745 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2746 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2747 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2748 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2749 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2750 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2751 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2752 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2753 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2754 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2755 LTTV_STATE_EVENT
= g_quark_from_string("event");
2756 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2757 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2758 LTTV_STATE_TIME
= g_quark_from_string("time");
2759 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2760 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2761 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2762 g_quark_from_string("trace_state_use_count");
2765 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2766 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2767 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2768 LTT_FACILITY_FS
= g_quark_from_string("fs");
2769 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2770 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2773 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2774 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2775 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2776 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2777 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2778 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2779 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2780 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2781 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2782 LTT_EVENT_FORK
= g_quark_from_string("fork");
2783 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2784 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2785 LTT_EVENT_FREE
= g_quark_from_string("free");
2786 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2787 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2788 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2789 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2790 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
2793 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2794 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2795 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2796 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2797 LTT_FIELD_OUT
= g_quark_from_string("out");
2798 LTT_FIELD_IN
= g_quark_from_string("in");
2799 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2800 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2801 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2802 LTT_FIELD_PID
= g_quark_from_string("pid");
2803 LTT_FIELD_TGID
= g_quark_from_string("tgid");
2804 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2805 LTT_FIELD_NAME
= g_quark_from_string("name");
2806 LTT_FIELD_TYPE
= g_quark_from_string("type");
2807 LTT_FIELD_MODE
= g_quark_from_string("mode");
2808 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2809 LTT_FIELD_STATUS
= g_quark_from_string("status");
2810 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2811 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2815 static void module_destroy()
2820 LTTV_MODULE("state", "State computation", \
2821 "Update the system state, possibly saving it at intervals", \
2822 module_init
, module_destroy
)