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
;
424 process
= (LttvProcessState
*)value
;
426 " <PROCESS CORE=%p PID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
427 process
, process
->pid
, process
->ppid
, g_quark_to_string(process
->type
),
428 process
->creation_time
.tv_sec
,
429 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
430 g_quark_to_string(process
->brand
),
433 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
434 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
435 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
436 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
437 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
438 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
439 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
441 fprintf(fp
, " </PROCESS>\n");
445 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
447 guint i
, nb_tracefile
, nb_block
, offset
;
450 LttvTracefileState
*tfcs
;
454 LttEventPosition
*ep
;
458 ep
= ltt_event_position_new();
460 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
462 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
464 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
465 for(i
=0;i
<nb_cpus
;i
++) {
466 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
467 i
, self
->running_process
[i
]->pid
);
470 nb_tracefile
= self
->parent
.tracefiles
->len
;
472 for(i
= 0 ; i
< nb_tracefile
; i
++) {
474 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
475 LttvTracefileContext
*, i
));
476 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
477 tfcs
->parent
.timestamp
.tv_sec
,
478 tfcs
->parent
.timestamp
.tv_nsec
);
479 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
480 if(e
== NULL
) fprintf(fp
,"/>\n");
482 ltt_event_position(e
, ep
);
483 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
484 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
489 fprintf(fp
,"</PROCESS_STATE>");
493 /* Copy each process from an existing hash table to a new one */
495 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
497 LttvProcessState
*process
, *new_process
;
499 GHashTable
*new_processes
= (GHashTable
*)user_data
;
503 process
= (LttvProcessState
*)value
;
504 new_process
= g_new(LttvProcessState
, 1);
505 *new_process
= *process
;
506 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
507 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
508 new_process
->execution_stack
=
509 g_array_set_size(new_process
->execution_stack
,
510 process
->execution_stack
->len
);
511 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
512 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
513 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
515 new_process
->state
= &g_array_index(new_process
->execution_stack
,
516 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
517 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
519 new_process
->user_stack
=
520 g_array_set_size(new_process
->user_stack
,
521 process
->user_stack
->len
);
522 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
523 g_array_index(new_process
->user_stack
, guint64
, i
) =
524 g_array_index(process
->user_stack
, guint64
, i
);
526 new_process
->current_function
= process
->current_function
;
527 g_hash_table_insert(new_processes
, new_process
, new_process
);
531 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
533 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
535 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
536 return new_processes
;
540 /* The saved state for each trace contains a member "processes", which
541 stores a copy of the process table, and a member "tracefiles" with
542 one entry per tracefile. Each tracefile has a "process" member pointing
543 to the current process and a "position" member storing the tracefile
544 position (needed to seek to the current "next" event. */
546 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
548 guint i
, nb_tracefile
, nb_cpus
;
550 LttvTracefileState
*tfcs
;
552 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
554 guint
*running_process
;
556 LttvAttributeType type
;
558 LttvAttributeValue value
;
560 LttvAttributeName name
;
562 LttEventPosition
*ep
;
564 tracefiles_tree
= lttv_attribute_find_subdir(container
,
565 LTTV_STATE_TRACEFILES
);
567 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
569 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
571 /* Add the currently running processes array */
572 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
573 running_process
= g_new(guint
, nb_cpus
);
574 for(i
=0;i
<nb_cpus
;i
++) {
575 running_process
[i
] = self
->running_process
[i
]->pid
;
577 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
579 *(value
.v_pointer
) = running_process
;
581 g_info("State save");
583 nb_tracefile
= self
->parent
.tracefiles
->len
;
585 for(i
= 0 ; i
< nb_tracefile
; i
++) {
587 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
588 LttvTracefileContext
*, i
));
589 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
590 value
= lttv_attribute_add(tracefiles_tree
, i
,
592 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
594 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
596 *(value
.v_uint
) = tfcs
->process
->pid
;
598 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
600 /* Only save the position if the tfs has not infinite time. */
601 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
602 // && current_tfcs != tfcs) {
603 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
604 *(value
.v_pointer
) = NULL
;
606 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
607 ep
= ltt_event_position_new();
608 ltt_event_position(e
, ep
);
609 *(value
.v_pointer
) = ep
;
611 guint nb_block
, offset
;
614 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
615 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
617 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
623 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
625 guint i
, nb_tracefile
, pid
, nb_cpus
;
627 LttvTracefileState
*tfcs
;
629 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
631 guint
*running_process
;
633 LttvAttributeType type
;
635 LttvAttributeValue value
;
637 LttvAttributeName name
;
641 LttEventPosition
*ep
;
643 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
645 tracefiles_tree
= lttv_attribute_find_subdir(container
,
646 LTTV_STATE_TRACEFILES
);
648 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
650 g_assert(type
== LTTV_POINTER
);
651 lttv_state_free_process_table(self
->processes
);
652 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
654 /* Add the currently running processes array */
655 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
656 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
658 g_assert(type
== LTTV_POINTER
);
659 running_process
= *(value
.v_pointer
);
660 for(i
=0;i
<nb_cpus
;i
++) {
661 pid
= running_process
[i
];
662 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
663 g_assert(self
->running_process
[i
] != NULL
);
667 nb_tracefile
= self
->parent
.tracefiles
->len
;
669 //g_tree_destroy(tsc->pqueue);
670 //tsc->pqueue = g_tree_new(compare_tracefile);
672 for(i
= 0 ; i
< nb_tracefile
; i
++) {
674 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
675 LttvTracefileContext
*, i
));
676 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
677 g_assert(type
== LTTV_GOBJECT
);
678 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
680 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
682 g_assert(type
== LTTV_UINT
);
683 pid
= *(value
.v_uint
);
684 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
686 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
688 g_assert(type
== LTTV_POINTER
);
689 //g_assert(*(value.v_pointer) != NULL);
690 ep
= *(value
.v_pointer
);
691 g_assert(tfcs
->parent
.t_context
!= NULL
);
693 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
694 g_tree_remove(tsc
->pqueue
, tfc
);
697 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
698 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
699 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
700 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
701 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
703 tfc
->timestamp
= ltt_time_infinite
;
709 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
711 guint i
, nb_tracefile
, nb_cpus
;
713 LttvTracefileState
*tfcs
;
715 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
717 guint
*running_process
;
719 LttvAttributeType type
;
721 LttvAttributeValue value
;
723 LttvAttributeName name
;
727 LttEventPosition
*ep
;
729 tracefiles_tree
= lttv_attribute_find_subdir(container
,
730 LTTV_STATE_TRACEFILES
);
731 g_object_ref(G_OBJECT(tracefiles_tree
));
732 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
734 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
736 g_assert(type
== LTTV_POINTER
);
737 lttv_state_free_process_table(*(value
.v_pointer
));
738 *(value
.v_pointer
) = NULL
;
739 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
741 /* Free running processes array */
742 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
743 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
745 g_assert(type
== LTTV_POINTER
);
746 running_process
= *(value
.v_pointer
);
747 g_free(running_process
);
749 nb_tracefile
= self
->parent
.tracefiles
->len
;
751 for(i
= 0 ; i
< nb_tracefile
; i
++) {
753 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
754 LttvTracefileContext
*, i
));
755 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
756 g_assert(type
== LTTV_GOBJECT
);
757 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
759 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
761 g_assert(type
== LTTV_POINTER
);
762 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
764 g_object_unref(G_OBJECT(tracefiles_tree
));
768 static void free_saved_state(LttvTraceState
*self
)
772 LttvAttributeType type
;
774 LttvAttributeValue value
;
776 LttvAttributeName name
;
780 LttvAttribute
*saved_states
;
782 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
783 LTTV_STATE_SAVED_STATES
);
785 nb
= lttv_attribute_get_number(saved_states
);
786 for(i
= 0 ; i
< nb
; i
++) {
787 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
788 g_assert(type
== LTTV_GOBJECT
);
789 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
792 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
797 create_max_time(LttvTraceState
*tcs
)
799 LttvAttributeValue v
;
801 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
803 g_assert(*(v
.v_pointer
) == NULL
);
804 *(v
.v_pointer
) = g_new(LttTime
,1);
805 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
810 get_max_time(LttvTraceState
*tcs
)
812 LttvAttributeValue v
;
814 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
816 g_assert(*(v
.v_pointer
) != NULL
);
817 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
822 free_max_time(LttvTraceState
*tcs
)
824 LttvAttributeValue v
;
826 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
828 g_free(*(v
.v_pointer
));
829 *(v
.v_pointer
) = NULL
;
833 typedef struct _LttvNameTables
{
834 // FIXME GQuark *eventtype_names;
835 GQuark
*syscall_names
;
840 GQuark
*soft_irq_names
;
845 create_name_tables(LttvTraceState
*tcs
)
849 GQuark f_name
, e_name
;
853 LttvTraceHookByFacility
*thf
;
859 GString
*fe_name
= g_string_new("");
861 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
863 LttvAttributeValue v
;
865 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
867 g_assert(*(v
.v_pointer
) == NULL
);
868 *(v
.v_pointer
) = name_tables
;
869 #if 0 // Use iteration over the facilities_by_name and then list all event
870 // types of each facility
871 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
872 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
873 for(i
= 0 ; i
< nb
; i
++) {
874 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
875 e_name
= ltt_eventtype_name(et
);
876 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
877 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
878 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
881 if(!lttv_trace_find_hook(tcs
->parent
.t
,
882 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
883 LTT_FIELD_SYSCALL_ID
, 0, 0,
886 thf
= lttv_trace_hook_get_first(&h
);
888 t
= ltt_field_type(thf
->f1
);
889 nb
= ltt_type_element_number(t
);
891 lttv_trace_hook_destroy(&h
);
893 name_tables
->syscall_names
= g_new(GQuark
, nb
);
894 name_tables
->nb_syscalls
= nb
;
896 for(i
= 0 ; i
< nb
; i
++) {
897 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
900 //name_tables->syscall_names = g_new(GQuark, 256);
901 //for(i = 0 ; i < 256 ; i++) {
902 // g_string_printf(fe_name, "syscall %d", i);
903 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
906 name_tables
->syscall_names
= NULL
;
907 name_tables
->nb_syscalls
= 0;
910 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
911 LTT_EVENT_TRAP_ENTRY
,
912 LTT_FIELD_TRAP_ID
, 0, 0,
915 thf
= lttv_trace_hook_get_first(&h
);
917 t
= ltt_field_type(thf
->f1
);
918 //nb = ltt_type_element_number(t);
920 lttv_trace_hook_destroy(&h
);
923 name_tables->trap_names = g_new(GQuark, nb);
924 for(i = 0 ; i < nb ; i++) {
925 name_tables->trap_names[i] = g_quark_from_string(
926 ltt_enum_string_get(t, i));
929 name_tables
->nb_traps
= 256;
930 name_tables
->trap_names
= g_new(GQuark
, 256);
931 for(i
= 0 ; i
< 256 ; i
++) {
932 g_string_printf(fe_name
, "trap %d", i
);
933 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
936 name_tables
->trap_names
= NULL
;
937 name_tables
->nb_traps
= 0;
940 if(!lttv_trace_find_hook(tcs
->parent
.t
,
941 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
942 LTT_FIELD_IRQ_ID
, 0, 0,
945 thf
= lttv_trace_hook_get_first(&h
);
947 t
= ltt_field_type(thf
->f1
);
948 //nb = ltt_type_element_number(t);
950 lttv_trace_hook_destroy(&h
);
953 name_tables->irq_names = g_new(GQuark, nb);
954 for(i = 0 ; i < nb ; i++) {
955 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
959 name_tables
->irq_names
= g_new(GQuark
, 256);
960 for(i
= 0 ; i
< 256 ; i
++) {
961 g_string_printf(fe_name
, "irq %d", i
);
962 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
965 name_tables
->irq_names
= NULL
;
968 name_tables->soft_irq_names = g_new(GQuark, nb);
969 for(i = 0 ; i < nb ; i++) {
970 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
974 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
975 for(i
= 0 ; i
< 256 ; i
++) {
976 g_string_printf(fe_name
, "softirq %d", i
);
977 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
981 g_string_free(fe_name
, TRUE
);
986 get_name_tables(LttvTraceState
*tcs
)
988 LttvNameTables
*name_tables
;
990 LttvAttributeValue v
;
992 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
994 g_assert(*(v
.v_pointer
) != NULL
);
995 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
996 //tcs->eventtype_names = name_tables->eventtype_names;
997 tcs
->syscall_names
= name_tables
->syscall_names
;
998 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
999 tcs
->trap_names
= name_tables
->trap_names
;
1000 tcs
->nb_traps
= name_tables
->nb_traps
;
1001 tcs
->irq_names
= name_tables
->irq_names
;
1002 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1007 free_name_tables(LttvTraceState
*tcs
)
1009 LttvNameTables
*name_tables
;
1011 LttvAttributeValue v
;
1013 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1015 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1016 *(v
.v_pointer
) = NULL
;
1018 // g_free(name_tables->eventtype_names);
1019 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1020 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1021 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1022 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1023 if(name_tables
) g_free(name_tables
);
1026 #ifdef HASH_TABLE_DEBUG
1028 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1030 LttvProcessState
*process
= (LttvProcessState
*)value
;
1032 /* Test for process corruption */
1033 guint stack_len
= process
->execution_stack
->len
;
1036 static void hash_table_check(GHashTable
*table
)
1038 g_hash_table_foreach(table
, test_process
, NULL
);
1045 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1048 LttvExecutionState
*es
;
1050 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1051 guint cpu
= tfs
->cpu
;
1053 #ifdef HASH_TABLE_DEBUG
1054 hash_table_check(ts
->processes
);
1056 LttvProcessState
*process
= ts
->running_process
[cpu
];
1058 guint depth
= process
->execution_stack
->len
;
1060 process
->execution_stack
=
1061 g_array_set_size(process
->execution_stack
, depth
+ 1);
1064 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1066 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1069 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1070 es
->cum_cpu_time
= ltt_time_zero
;
1071 es
->s
= process
->state
->s
;
1072 process
->state
= es
;
1076 * return 1 when empty, else 0 */
1077 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1078 LttvTracefileState
*tfs
)
1080 guint cpu
= tfs
->cpu
;
1081 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1083 guint depth
= process
->execution_stack
->len
;
1089 process
->execution_stack
=
1090 g_array_set_size(process
->execution_stack
, depth
- 1);
1091 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1093 process
->state
->change
= tfs
->parent
.timestamp
;
1098 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1100 guint cpu
= tfs
->cpu
;
1101 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1102 LttvProcessState
*process
= ts
->running_process
[cpu
];
1104 guint depth
= process
->execution_stack
->len
;
1106 if(process
->state
->t
!= t
){
1107 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1108 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1109 g_info("process state has %s when pop_int is %s\n",
1110 g_quark_to_string(process
->state
->t
),
1111 g_quark_to_string(t
));
1112 g_info("{ %u, %u, %s, %s, %s }\n",
1115 g_quark_to_string(process
->name
),
1116 g_quark_to_string(process
->brand
),
1117 g_quark_to_string(process
->state
->s
));
1122 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1123 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1127 process
->execution_stack
=
1128 g_array_set_size(process
->execution_stack
, depth
- 1);
1129 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1131 process
->state
->change
= tfs
->parent
.timestamp
;
1134 struct search_result
{
1135 const LttTime
*time
; /* Requested time */
1136 LttTime
*best
; /* Best result */
1139 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1141 const LttTime
*elem_time
= (const LttTime
*)a
;
1142 /* Explicit non const cast */
1143 struct search_result
*res
= (struct search_result
*)b
;
1145 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1146 /* The usertrace was created before the schedchange */
1147 /* Get larger keys */
1149 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1150 /* The usertrace was created after the schedchange time */
1151 /* Get smaller keys */
1153 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1154 res
->best
= elem_time
;
1157 res
->best
= elem_time
;
1164 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1165 guint pid
, const LttTime
*timestamp
)
1167 LttvTracefileState
*tfs
= NULL
;
1168 struct search_result res
;
1169 /* Find the usertrace associated with a pid and time interval.
1170 * Search in the usertraces by PID (within a hash) and then, for each
1171 * corresponding element of the array, find the first one with creation
1172 * timestamp the lowest, but higher or equal to "timestamp". */
1173 res
.time
= timestamp
;
1175 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1176 if(usertrace_tree
) {
1177 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1179 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1187 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1188 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1190 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1192 LttvExecutionState
*es
;
1194 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1199 process
->tgid
= tgid
;
1201 process
->name
= name
;
1202 process
->brand
= LTTV_STATE_UNBRANDED
;
1203 //process->last_cpu = tfs->cpu_name;
1204 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1205 process
->type
= LTTV_STATE_USER_THREAD
;
1206 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1207 process
->current_function
= 0; //function 0x0 by default.
1209 g_info("Process %u, core %p", process
->pid
, process
);
1210 g_hash_table_insert(tcs
->processes
, process
, process
);
1213 process
->ppid
= parent
->pid
;
1214 process
->creation_time
= *timestamp
;
1217 /* No parent. This process exists but we are missing all information about
1218 its creation. The birth time is set to zero but we remember the time of
1223 process
->creation_time
= ltt_time_zero
;
1226 process
->insertion_time
= *timestamp
;
1227 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1228 process
->creation_time
.tv_nsec
);
1229 process
->pid_time
= g_quark_from_string(buffer
);
1231 //process->last_cpu = tfs->cpu_name;
1232 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1233 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1234 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1235 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1236 es
= process
->state
= &g_array_index(process
->execution_stack
,
1237 LttvExecutionState
, 0);
1238 es
->t
= LTTV_STATE_USER_MODE
;
1239 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1240 es
->entry
= *timestamp
;
1241 //g_assert(timestamp->tv_sec != 0);
1242 es
->change
= *timestamp
;
1243 es
->cum_cpu_time
= ltt_time_zero
;
1244 es
->s
= LTTV_STATE_RUN
;
1246 es
= process
->state
= &g_array_index(process
->execution_stack
,
1247 LttvExecutionState
, 1);
1248 es
->t
= LTTV_STATE_SYSCALL
;
1249 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1250 es
->entry
= *timestamp
;
1251 //g_assert(timestamp->tv_sec != 0);
1252 es
->change
= *timestamp
;
1253 es
->cum_cpu_time
= ltt_time_zero
;
1254 es
->s
= LTTV_STATE_WAIT_FORK
;
1256 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1257 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1258 sizeof(guint64
), 0);
1263 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1266 LttvProcessState key
;
1267 LttvProcessState
*process
;
1271 process
= g_hash_table_lookup(ts
->processes
, &key
);
1276 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1279 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1280 LttvExecutionState
*es
;
1282 /* Put ltt_time_zero creation time for unexisting processes */
1283 if(unlikely(process
== NULL
)) {
1284 process
= lttv_state_create_process(ts
,
1285 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1286 /* We are not sure is it's a kernel thread or normal thread, put the
1287 * bottom stack state to unknown */
1288 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1289 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1294 /* FIXME : this function should be called when we receive an event telling that
1295 * release_task has been called in the kernel. In happens generally when
1296 * the parent waits for its child terminaison, but may also happen in special
1297 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1298 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1299 * of a killed thread ground, but isn't the leader.
1301 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1303 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1304 LttvProcessState key
;
1306 key
.pid
= process
->pid
;
1307 key
.cpu
= process
->cpu
;
1308 g_hash_table_remove(ts
->processes
, &key
);
1309 g_array_free(process
->execution_stack
, TRUE
);
1310 g_array_free(process
->user_stack
, TRUE
);
1315 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1317 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1318 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1323 static void lttv_state_free_process_table(GHashTable
*processes
)
1325 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1326 g_hash_table_destroy(processes
);
1330 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1332 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1333 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1334 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1335 LttField
*f
= thf
->f1
;
1337 LttvExecutionSubmode submode
;
1339 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1340 guint syscall
= ltt_event_get_unsigned(e
, f
);
1342 if(syscall
< nb_syscalls
) {
1343 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1346 /* Fixup an incomplete syscall table */
1347 GString
*string
= g_string_new("");
1348 g_string_printf(string
, "syscall %u", syscall
);
1349 submode
= g_quark_from_string(string
->str
);
1350 g_string_free(string
, TRUE
);
1352 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1357 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1359 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1361 pop_state(s
, LTTV_STATE_SYSCALL
);
1366 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1368 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1369 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1370 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1371 LttField
*f
= thf
->f1
;
1373 LttvExecutionSubmode submode
;
1375 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1376 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1378 if(trap
< nb_traps
) {
1379 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1381 /* Fixup an incomplete trap table */
1382 GString
*string
= g_string_new("");
1383 g_string_printf(string
, "trap %llu", trap
);
1384 submode
= g_quark_from_string(string
->str
);
1385 g_string_free(string
, TRUE
);
1388 push_state(s
, LTTV_STATE_TRAP
, submode
);
1393 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1395 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1397 pop_state(s
, LTTV_STATE_TRAP
);
1402 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1404 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1405 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1406 guint8 fac_id
= ltt_event_facility_id(e
);
1407 guint8 ev_id
= ltt_event_eventtype_id(e
);
1408 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1409 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1410 g_assert(thf
->f1
!= NULL
);
1411 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1412 LttField
*f
= thf
->f1
;
1414 LttvExecutionSubmode submode
;
1416 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1417 ltt_event_get_unsigned(e
, f
)];
1419 /* Do something with the info about being in user or system mode when int? */
1420 push_state(s
, LTTV_STATE_IRQ
, submode
);
1424 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1426 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1428 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1434 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1436 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1438 pop_state(s
, LTTV_STATE_IRQ
);
1442 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1444 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1445 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1446 guint8 fac_id
= ltt_event_facility_id(e
);
1447 guint8 ev_id
= ltt_event_eventtype_id(e
);
1448 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1449 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1450 g_assert(thf
->f1
!= NULL
);
1451 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1452 LttField
*f
= thf
->f1
;
1454 LttvExecutionSubmode submode
;
1456 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1457 ltt_event_get_long_unsigned(e
, f
)];
1459 /* Do something with the info about being in user or system mode when int? */
1460 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1464 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1468 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1469 guint cpu
= tfs
->cpu
;
1470 LttvProcessState
*process
= ts
->running_process
[cpu
];
1472 guint depth
= process
->user_stack
->len
;
1474 process
->user_stack
=
1475 g_array_set_size(process
->user_stack
, depth
+ 1);
1477 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1478 *new_func
= funcptr
;
1479 process
->current_function
= funcptr
;
1482 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1484 guint cpu
= tfs
->cpu
;
1485 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1486 LttvProcessState
*process
= ts
->running_process
[cpu
];
1488 if(process
->current_function
!= funcptr
){
1489 g_info("Different functions (%lu.%09lu): ignore it\n",
1490 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1491 g_info("process state has %llu when pop_function is %llu\n",
1492 process
->current_function
, funcptr
);
1493 g_info("{ %u, %u, %s, %s, %s }\n",
1496 g_quark_to_string(process
->name
),
1497 g_quark_to_string(process
->brand
),
1498 g_quark_to_string(process
->state
->s
));
1501 guint depth
= process
->user_stack
->len
;
1504 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1505 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1509 process
->user_stack
=
1510 g_array_set_size(process
->user_stack
, depth
- 1);
1511 process
->current_function
=
1512 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1516 static gboolean
function_entry(void *hook_data
, void *call_data
)
1518 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1519 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1520 guint8 fac_id
= ltt_event_facility_id(e
);
1521 guint8 ev_id
= ltt_event_eventtype_id(e
);
1522 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1523 g_assert(thf
->f1
!= NULL
);
1524 LttField
*f
= thf
->f1
;
1525 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1527 push_function(s
, funcptr
);
1531 static gboolean
function_exit(void *hook_data
, void *call_data
)
1533 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1534 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1535 guint8 fac_id
= ltt_event_facility_id(e
);
1536 guint8 ev_id
= ltt_event_eventtype_id(e
);
1537 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1538 g_assert(thf
->f1
!= NULL
);
1539 LttField
*f
= thf
->f1
;
1540 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1542 LttvExecutionSubmode submode
;
1544 pop_function(s
, funcptr
);
1548 static gboolean
schedchange(void *hook_data
, void *call_data
)
1550 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1552 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1553 LttvProcessState
*process
= ts
->running_process
[cpu
];
1554 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1556 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1557 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1558 guint pid_in
, pid_out
;
1561 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1562 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1563 state_out
= ltt_event_get_int(e
, thf
->f3
);
1565 if(likely(process
!= NULL
)) {
1567 /* We could not know but it was not the idle process executing.
1568 This should only happen at the beginning, before the first schedule
1569 event, and when the initial information (current process for each CPU)
1570 is missing. It is not obvious how we could, after the fact, compensate
1571 the wrongly attributed statistics. */
1573 //This test only makes sense once the state is known and if there is no
1574 //missing events. We need to silently ignore schedchange coming after a
1575 //process_free, or it causes glitches. (FIXME)
1576 //if(unlikely(process->pid != pid_out)) {
1577 // g_assert(process->pid == 0);
1580 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1581 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1582 process
->state
->change
= s
->parent
.timestamp
;
1584 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1585 else process
->state
->s
= LTTV_STATE_WAIT
;
1586 process
->state
->change
= s
->parent
.timestamp
;
1590 exit_process(s
, process
); /* EXIT_DEAD */
1591 /* see sched.h for states */
1593 process
= ts
->running_process
[cpu
] =
1594 lttv_state_find_process_or_create(
1595 (LttvTraceState
*)s
->parent
.t_context
,
1597 &s
->parent
.timestamp
);
1598 process
->state
->s
= LTTV_STATE_RUN
;
1600 if(process
->usertrace
)
1601 process
->usertrace
->cpu
= cpu
;
1602 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1603 process
->state
->change
= s
->parent
.timestamp
;
1607 static gboolean
process_fork(void *hook_data
, void *call_data
)
1609 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1610 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1611 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1613 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
1614 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
1615 LttvProcessState
*zombie_process
;
1617 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1618 LttvProcessState
*process
= ts
->running_process
[cpu
];
1619 LttvProcessState
*child_process
;
1622 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1625 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1626 s
->parent
.target_pid
= child_pid
;
1629 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
1630 else child_tgid
= 0;
1632 /* Mathieu : it seems like the process might have been scheduled in before the
1633 * fork, and, in a rare case, might be the current process. This might happen
1634 * in a SMP case where we don't have enough precision on the clocks.
1636 * Test reenabled after precision fixes on time. (Mathieu) */
1638 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1640 if(unlikely(zombie_process
!= NULL
)) {
1641 /* Reutilisation of PID. Only now we are sure that the old PID
1642 * has been released. FIXME : should know when release_task happens instead.
1644 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1646 for(i
=0; i
< num_cpus
; i
++) {
1647 g_assert(zombie_process
!= ts
->running_process
[i
]);
1650 exit_process(s
, zombie_process
);
1653 g_assert(process
->pid
!= child_pid
);
1654 // FIXME : Add this test in the "known state" section
1655 // g_assert(process->pid == parent_pid);
1656 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1657 if(child_process
== NULL
) {
1658 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1659 child_pid
, child_tgid
,
1660 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1662 /* The process has already been created : due to time imprecision between
1663 * multiple CPUs : it has been scheduled in before creation. Note that we
1664 * shouldn't have this kind of imprecision.
1666 * Simply put a correct parent.
1668 g_assert(0); /* This is a problematic case : the process has been created
1669 before the fork event */
1670 child_process
->ppid
= process
->pid
;
1671 child_process
->tgid
= child_tgid
;
1673 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1674 child_process
->name
= process
->name
;
1675 child_process
->brand
= process
->brand
;
1680 /* We stamp a newly created process as kernel_thread */
1681 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1683 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1684 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1685 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1688 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1689 LttvProcessState
*process
;
1690 LttvExecutionState
*es
;
1693 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1694 s
->parent
.target_pid
= pid
;
1696 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1697 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1698 es
->t
= LTTV_STATE_SYSCALL
;
1699 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1704 static gboolean
process_exit(void *hook_data
, void *call_data
)
1706 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1707 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1708 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1712 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1713 LttvProcessState
*process
; // = ts->running_process[cpu];
1715 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1716 s
->parent
.target_pid
= pid
;
1718 // FIXME : Add this test in the "known state" section
1719 // g_assert(process->pid == pid);
1721 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1722 if(likely(process
!= NULL
)) {
1723 process
->state
->s
= LTTV_STATE_EXIT
;
1728 static gboolean
process_free(void *hook_data
, void *call_data
)
1730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1731 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1732 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1733 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1735 LttvProcessState
*process
;
1737 /* PID of the process to release */
1738 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1739 s
->parent
.target_pid
= release_pid
;
1741 g_assert(release_pid
!= 0);
1743 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1745 if(likely(process
!= NULL
)) {
1746 /* release_task is happening at kernel level : we can now safely release
1747 * the data structure of the process */
1748 //This test is fun, though, as it may happen that
1749 //at time t : CPU 0 : process_free
1750 //at time t+150ns : CPU 1 : schedule out
1751 //Clearly due to time imprecision, we disable it. (Mathieu)
1752 //If this weird case happen, we have no choice but to put the
1753 //Currently running process on the cpu to 0.
1754 //I re-enable it following time precision fixes. (Mathieu)
1755 //Well, in the case where an process is freed by a process on another CPU
1756 //and still scheduled, it happens that this is the schedchange that will
1757 //drop the last reference count. Do not free it here!
1758 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1760 for(i
=0; i
< num_cpus
; i
++) {
1761 //g_assert(process != ts->running_process[i]);
1762 if(process
== ts
->running_process
[i
]) {
1763 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1767 if(i
== num_cpus
) /* process is not scheduled */
1768 exit_process(s
, process
);
1775 static gboolean
process_exec(void *hook_data
, void *call_data
)
1777 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1778 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1779 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1780 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1783 LttvProcessState
*process
= ts
->running_process
[cpu
];
1785 /* PID of the process to release */
1786 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1787 //name = ltt_event_get_string(e, thf->f1);
1788 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1790 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1791 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1792 memcpy(null_term_name
, name_begin
, name_len
);
1793 null_term_name
[name_len
] = '\0';
1795 process
->name
= g_quark_from_string(null_term_name
);
1796 process
->brand
= LTTV_STATE_UNBRANDED
;
1797 g_free(null_term_name
);
1801 static gboolean
thread_brand(void *hook_data
, void *call_data
)
1803 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1804 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1805 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1806 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1809 LttvProcessState
*process
= ts
->running_process
[cpu
];
1811 name
= ltt_event_get_string(e
, thf
->f1
);
1812 process
->brand
= g_quark_from_string(name
);
1817 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1819 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1820 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1821 //It's slow : optimise later by doing this before reading trace.
1822 LttEventType
*et
= ltt_event_eventtype(e
);
1824 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1830 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1831 LttvProcessState
*process
= ts
->running_process
[cpu
];
1832 LttvProcessState
*parent_process
;
1833 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
1834 GQuark type
, mode
, submode
, status
;
1835 LttvExecutionState
*es
;
1838 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1839 s
->parent
.target_pid
= pid
;
1842 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1845 command
= ltt_event_get_string(e
, thf
->f3
);
1848 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1849 type
= ltt_enum_string_get(ltt_field_type(f4
),
1850 ltt_event_get_unsigned(e
, f4
));
1853 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1854 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1855 ltt_event_get_unsigned(e
, f5
));
1858 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1859 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1860 ltt_event_get_unsigned(e
, f6
));
1863 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1864 status
= ltt_enum_string_get(ltt_field_type(f7
),
1865 ltt_event_get_unsigned(e
, f7
));
1868 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
1869 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
1872 /* The process might exist if a process was forked while performing the state
1874 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1875 if(process
== NULL
) {
1876 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1877 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1878 pid
, tgid
, g_quark_from_string(command
),
1879 &s
->parent
.timestamp
);
1881 /* Keep the stack bottom : a running user mode */
1882 /* Disabled because of inconsistencies in the current statedump states. */
1883 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1884 /* Only keep the bottom */
1885 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1886 es
= process
->state
= &g_array_index(process
->execution_stack
,
1887 LttvExecutionState
, 0);
1888 es
->t
= LTTV_STATE_SYSCALL
;
1892 /* On top of it : */
1893 es
= process
->state
= &g_array_index(process
->execution_stack
,
1894 LttvExecutionState
, 1);
1895 es
->t
= LTTV_STATE_USER_MODE
;
1902 es
= process
->state
= &g_array_index(process
->execution_stack
,
1903 LttvExecutionState
, 1);
1904 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1905 es
->s
= LTTV_STATE_UNNAMED
;
1906 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1910 /* The process has already been created :
1911 * Probably was forked while dumping the process state or
1912 * was simply scheduled in prior to get the state dump event.
1913 * We know for sure if it is a user space thread.
1915 process
->ppid
= parent_pid
;
1916 process
->tgid
= tgid
;
1917 process
->name
= g_quark_from_string(command
);
1918 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1919 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1920 es
->t
= LTTV_STATE_USER_MODE
;
1921 /* Don't mess around with the stack, it will eventually become
1922 * ok after the end of state dump. */
1928 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1930 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1932 lttv_state_add_event_hooks(tss
);
1937 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1939 LttvTraceset
*traceset
= self
->parent
.ts
;
1941 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1945 LttvTracefileState
*tfs
;
1949 LttvTraceHookByFacility
*thf
;
1951 LttvTraceHook
*hook
;
1953 LttvAttributeValue val
;
1958 nb_trace
= lttv_traceset_number(traceset
);
1959 for(i
= 0 ; i
< nb_trace
; i
++) {
1960 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1962 /* Find the eventtype id for the following events and register the
1963 associated by id hooks. */
1965 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
1966 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
1969 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1970 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1971 LTT_FIELD_SYSCALL_ID
, 0, 0,
1972 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1975 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1976 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1978 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1981 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1982 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1983 LTT_FIELD_TRAP_ID
, 0, 0,
1984 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1987 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1988 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1990 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1993 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1994 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1995 LTT_FIELD_IRQ_ID
, 0, 0,
1996 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1999 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2000 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2002 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2005 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2006 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2007 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2008 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2011 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2012 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2014 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2017 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2018 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2019 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2020 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2023 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2024 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2025 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2026 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2029 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2030 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2031 LTT_FIELD_PID
, 0, 0,
2032 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2036 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2037 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2038 LTT_FIELD_PID
, 0, 0,
2039 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2042 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2043 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2044 LTT_FIELD_PID
, 0, 0,
2045 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2048 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2049 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2050 LTT_FIELD_FILENAME
, 0, 0,
2051 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2054 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2055 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2056 LTT_FIELD_NAME
, 0, 0,
2057 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2060 /* statedump-related hooks */
2061 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2062 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2063 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2064 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2067 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2068 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2069 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2070 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2073 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2074 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2075 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2076 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2079 hooks
= g_array_set_size(hooks
, hn
);
2081 /* Add these hooks to each event_by_id hooks list */
2083 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2085 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2087 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2088 LttvTracefileContext
*, j
));
2090 for(k
= 0 ; k
< hooks
->len
; k
++) {
2091 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2092 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2093 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2095 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2102 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2103 *(val
.v_pointer
) = hooks
;
2107 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2109 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2111 lttv_state_remove_event_hooks(tss
);
2116 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2118 LttvTraceset
*traceset
= self
->parent
.ts
;
2120 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2124 LttvTracefileState
*tfs
;
2128 LttvTraceHook
*hook
;
2130 LttvTraceHookByFacility
*thf
;
2132 LttvAttributeValue val
;
2134 nb_trace
= lttv_traceset_number(traceset
);
2135 for(i
= 0 ; i
< nb_trace
; i
++) {
2136 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2137 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2138 hooks
= *(val
.v_pointer
);
2140 /* Remove these hooks from each event_by_id hooks list */
2142 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2144 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2146 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2147 LttvTracefileContext
*, j
));
2149 for(k
= 0 ; k
< hooks
->len
; k
++) {
2150 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2151 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2152 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2154 lttv_hooks_remove_data(
2155 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2161 for(k
= 0 ; k
< hooks
->len
; k
++)
2162 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2163 g_array_free(hooks
, TRUE
);
2167 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2169 guint
*event_count
= (guint
*)hook_data
;
2171 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2172 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2177 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2179 LttvTracefileState
*tfcs
;
2181 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2183 LttEventPosition
*ep
;
2189 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2191 LttvAttributeValue value
;
2193 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2194 LTTV_STATE_SAVED_STATES
);
2195 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2196 value
= lttv_attribute_add(saved_states_tree
,
2197 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2198 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2199 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2200 *(value
.v_time
) = self
->parent
.timestamp
;
2201 lttv_state_save(tcs
, saved_state_tree
);
2202 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2203 self
->parent
.timestamp
.tv_nsec
);
2205 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2210 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2212 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2214 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2219 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2227 static gboolean
block_start(void *hook_data
, void *call_data
)
2229 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2231 LttvTracefileState
*tfcs
;
2233 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2235 LttEventPosition
*ep
;
2237 guint i
, nb_block
, nb_event
, nb_tracefile
;
2241 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2243 LttvAttributeValue value
;
2245 ep
= ltt_event_position_new();
2247 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2249 /* Count the number of events added since the last block end in any
2252 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2254 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2255 LttvTracefileContext
, i
));
2256 ltt_event_position(tfcs
->parent
.e
, ep
);
2257 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2258 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2259 tfcs
->saved_position
= nb_event
;
2263 if(tcs
->nb_event
>= tcs
->save_interval
) {
2264 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2265 LTTV_STATE_SAVED_STATES
);
2266 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2267 value
= lttv_attribute_add(saved_states_tree
,
2268 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2269 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2270 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2271 *(value
.v_time
) = self
->parent
.timestamp
;
2272 lttv_state_save(tcs
, saved_state_tree
);
2274 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2275 self
->parent
.timestamp
.tv_nsec
);
2277 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2283 static gboolean
block_end(void *hook_data
, void *call_data
)
2285 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2287 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2291 LttEventPosition
*ep
;
2293 guint nb_block
, nb_event
;
2295 ep
= ltt_event_position_new();
2296 ltt_event_position(self
->parent
.e
, ep
);
2297 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2298 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2299 self
->saved_position
= 0;
2300 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2307 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2309 LttvTraceset
*traceset
= self
->parent
.ts
;
2311 guint i
, j
, nb_trace
, nb_tracefile
;
2315 LttvTracefileState
*tfs
;
2317 LttvTraceHook hook_start
, hook_end
;
2319 nb_trace
= lttv_traceset_number(traceset
);
2320 for(i
= 0 ; i
< nb_trace
; i
++) {
2321 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2323 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2324 NULL
, NULL
, block_start
, &hook_start
);
2325 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2326 NULL
, NULL
, block_end
, &hook_end
);
2328 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2330 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2332 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2333 LttvTracefileContext
, j
));
2334 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2335 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2336 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2337 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2343 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2345 LttvTraceset
*traceset
= self
->parent
.ts
;
2347 guint i
, j
, nb_trace
, nb_tracefile
;
2351 LttvTracefileState
*tfs
;
2354 nb_trace
= lttv_traceset_number(traceset
);
2355 for(i
= 0 ; i
< nb_trace
; i
++) {
2357 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2358 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2360 guint
*event_count
= g_new(guint
, 1);
2363 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2365 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2366 LttvTracefileContext
*, j
));
2367 lttv_hooks_add(tfs
->parent
.event
,
2368 state_save_event_hook
,
2375 lttv_process_traceset_begin(&self
->parent
,
2376 NULL
, NULL
, NULL
, NULL
, NULL
);
2380 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2382 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2384 lttv_state_save_add_event_hooks(tss
);
2391 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2393 LttvTraceset
*traceset
= self
->parent
.ts
;
2395 guint i
, j
, nb_trace
, nb_tracefile
;
2399 LttvTracefileState
*tfs
;
2401 LttvTraceHook hook_start
, hook_end
;
2403 nb_trace
= lttv_traceset_number(traceset
);
2404 for(i
= 0 ; i
< nb_trace
; i
++) {
2405 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2407 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2408 NULL
, NULL
, block_start
, &hook_start
);
2410 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2411 NULL
, NULL
, block_end
, &hook_end
);
2413 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2415 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2417 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2418 LttvTracefileContext
, j
));
2419 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2420 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2421 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2422 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2428 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2430 LttvTraceset
*traceset
= self
->parent
.ts
;
2432 guint i
, j
, nb_trace
, nb_tracefile
;
2436 LttvTracefileState
*tfs
;
2438 LttvHooks
*after_trace
= lttv_hooks_new();
2440 lttv_hooks_add(after_trace
,
2441 state_save_after_trace_hook
,
2446 lttv_process_traceset_end(&self
->parent
,
2447 NULL
, after_trace
, NULL
, NULL
, NULL
);
2449 lttv_hooks_destroy(after_trace
);
2451 nb_trace
= lttv_traceset_number(traceset
);
2452 for(i
= 0 ; i
< nb_trace
; i
++) {
2454 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2455 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2457 guint
*event_count
= NULL
;
2459 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2461 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2462 LttvTracefileContext
*, j
));
2463 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2464 state_save_event_hook
);
2466 if(event_count
) g_free(event_count
);
2470 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2472 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2474 lttv_state_save_remove_event_hooks(tss
);
2479 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2481 LttvTraceset
*traceset
= self
->parent
.ts
;
2485 int min_pos
, mid_pos
, max_pos
;
2487 guint call_rest
= 0;
2489 LttvTraceState
*tcs
;
2491 LttvAttributeValue value
;
2493 LttvAttributeType type
;
2495 LttvAttributeName name
;
2499 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2501 //g_tree_destroy(self->parent.pqueue);
2502 //self->parent.pqueue = g_tree_new(compare_tracefile);
2504 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2506 nb_trace
= lttv_traceset_number(traceset
);
2507 for(i
= 0 ; i
< nb_trace
; i
++) {
2508 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2510 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2511 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2512 LTTV_STATE_SAVED_STATES
);
2515 if(saved_states_tree
) {
2516 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2517 mid_pos
= max_pos
/ 2;
2518 while(min_pos
< max_pos
) {
2519 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2521 g_assert(type
== LTTV_GOBJECT
);
2522 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2523 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2525 g_assert(type
== LTTV_TIME
);
2526 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2528 closest_tree
= saved_state_tree
;
2530 else max_pos
= mid_pos
- 1;
2532 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2536 /* restore the closest earlier saved state */
2538 lttv_state_restore(tcs
, closest_tree
);
2542 /* There is no saved state, yet we want to have it. Restart at T0 */
2544 restore_init_state(tcs
);
2545 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2548 /* We want to seek quickly without restoring/updating the state */
2550 restore_init_state(tcs
);
2551 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2554 if(!call_rest
) g_info("NOT Calling restore");
2559 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2565 traceset_state_finalize (LttvTracesetState
*self
)
2567 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2568 finalize(G_OBJECT(self
));
2573 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2575 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2577 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2578 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2579 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2580 klass
->new_traceset_context
= new_traceset_context
;
2581 klass
->new_trace_context
= new_trace_context
;
2582 klass
->new_tracefile_context
= new_tracefile_context
;
2587 lttv_traceset_state_get_type(void)
2589 static GType type
= 0;
2591 static const GTypeInfo info
= {
2592 sizeof (LttvTracesetStateClass
),
2593 NULL
, /* base_init */
2594 NULL
, /* base_finalize */
2595 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2596 NULL
, /* class_finalize */
2597 NULL
, /* class_data */
2598 sizeof (LttvTracesetState
),
2599 0, /* n_preallocs */
2600 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2601 NULL
/* value handling */
2604 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2612 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2618 trace_state_finalize (LttvTraceState
*self
)
2620 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2621 finalize(G_OBJECT(self
));
2626 trace_state_class_init (LttvTraceStateClass
*klass
)
2628 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2630 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2631 klass
->state_save
= state_save
;
2632 klass
->state_restore
= state_restore
;
2633 klass
->state_saved_free
= state_saved_free
;
2638 lttv_trace_state_get_type(void)
2640 static GType type
= 0;
2642 static const GTypeInfo info
= {
2643 sizeof (LttvTraceStateClass
),
2644 NULL
, /* base_init */
2645 NULL
, /* base_finalize */
2646 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2647 NULL
, /* class_finalize */
2648 NULL
, /* class_data */
2649 sizeof (LttvTraceState
),
2650 0, /* n_preallocs */
2651 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2652 NULL
/* value handling */
2655 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2656 "LttvTraceStateType", &info
, 0);
2663 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2669 tracefile_state_finalize (LttvTracefileState
*self
)
2671 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2672 finalize(G_OBJECT(self
));
2677 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2679 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2681 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2686 lttv_tracefile_state_get_type(void)
2688 static GType type
= 0;
2690 static const GTypeInfo info
= {
2691 sizeof (LttvTracefileStateClass
),
2692 NULL
, /* base_init */
2693 NULL
, /* base_finalize */
2694 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2695 NULL
, /* class_finalize */
2696 NULL
, /* class_data */
2697 sizeof (LttvTracefileState
),
2698 0, /* n_preallocs */
2699 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2700 NULL
/* value handling */
2703 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2704 "LttvTracefileStateType", &info
, 0);
2710 static void module_init()
2712 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2713 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
2714 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2715 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2716 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2717 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2718 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2719 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2720 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2721 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2722 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2723 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2724 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2725 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2726 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2727 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2728 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2729 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2730 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2731 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2732 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2733 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2734 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2735 LTTV_STATE_EVENT
= g_quark_from_string("event");
2736 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2737 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2738 LTTV_STATE_TIME
= g_quark_from_string("time");
2739 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2740 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2741 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2742 g_quark_from_string("trace_state_use_count");
2745 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2746 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2747 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2748 LTT_FACILITY_FS
= g_quark_from_string("fs");
2749 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2750 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2753 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2754 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2755 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2756 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2757 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2758 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2759 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2760 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2761 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2762 LTT_EVENT_FORK
= g_quark_from_string("fork");
2763 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2764 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2765 LTT_EVENT_FREE
= g_quark_from_string("free");
2766 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2767 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2768 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2769 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2770 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
2773 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2774 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2775 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2776 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2777 LTT_FIELD_OUT
= g_quark_from_string("out");
2778 LTT_FIELD_IN
= g_quark_from_string("in");
2779 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2780 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2781 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2782 LTT_FIELD_PID
= g_quark_from_string("pid");
2783 LTT_FIELD_TGID
= g_quark_from_string("tgid");
2784 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2785 LTT_FIELD_NAME
= g_quark_from_string("name");
2786 LTT_FIELD_TYPE
= g_quark_from_string("type");
2787 LTT_FIELD_MODE
= g_quark_from_string("mode");
2788 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2789 LTT_FIELD_STATUS
= g_quark_from_string("status");
2790 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2791 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2795 static void module_destroy()
2800 LTTV_MODULE("state", "State computation", \
2801 "Update the system state, possibly saving it at intervals", \
2802 module_init
, module_destroy
)