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,
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
31 #include <ltt/marker-desc.h>
34 #include <ltt/ltt-private.h>
39 * usertrace is there only to be able to update the current CPU of the
40 * usertraces when there is a schedchange. it is a way to link the ProcessState
41 * to the associated usertrace. Link only created upon thread creation.
43 * The cpu id is necessary : it gives us back the current ProcessState when we
44 * are considering data from the usertrace.
47 #define PREALLOCATED_EXECUTION_STACK 10
53 LTT_CHANNEL_GLOBAL_STATE
,
54 LTT_CHANNEL_IRQ_STATE
,
55 LTT_CHANNEL_MODULE_STATE
,
56 LTT_CHANNEL_NETIF_STATE
,
57 LTT_CHANNEL_SOFTIRQ_STATE
,
58 LTT_CHANNEL_SWAP_STATE
,
59 LTT_CHANNEL_SYSCALL_STATE
,
60 LTT_CHANNEL_TASK_STATE
,
65 LTT_CHANNEL_USERSPACE
,
71 LTT_EVENT_SYSCALL_ENTRY
,
72 LTT_EVENT_SYSCALL_EXIT
,
73 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
74 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
75 LTT_EVENT_PAGE_FAULT_ENTRY
,
76 LTT_EVENT_PAGE_FAULT_EXIT
,
81 LTT_EVENT_SOFT_IRQ_RAISE
,
82 LTT_EVENT_SOFT_IRQ_ENTRY
,
83 LTT_EVENT_SOFT_IRQ_EXIT
,
84 LTT_EVENT_SCHED_SCHEDULE
,
85 LTT_EVENT_PROCESS_FORK
,
86 LTT_EVENT_KTHREAD_CREATE
,
87 LTT_EVENT_PROCESS_EXIT
,
88 LTT_EVENT_PROCESS_FREE
,
90 LTT_EVENT_PROCESS_STATE
,
91 LTT_EVENT_STATEDUMP_END
,
92 LTT_EVENT_FUNCTION_ENTRY
,
93 LTT_EVENT_FUNCTION_EXIT
,
94 LTT_EVENT_THREAD_BRAND
,
95 LTT_EVENT_REQUEST_ISSUE
,
96 LTT_EVENT_REQUEST_COMPLETE
,
97 LTT_EVENT_LIST_INTERRUPT
,
98 LTT_EVENT_SYS_CALL_TABLE
,
99 LTT_EVENT_SOFTIRQ_VEC
,
100 LTT_EVENT_KPROBE_TABLE
;
105 LTT_FIELD_SYSCALL_ID
,
108 LTT_FIELD_SOFT_IRQ_ID
,
111 LTT_FIELD_PREV_STATE
,
112 LTT_FIELD_PARENT_PID
,
116 LTT_FIELD_CHILD_TGID
,
135 LTTV_STATE_MODE_UNKNOWN
,
136 LTTV_STATE_USER_MODE
,
143 LTTV_STATE_SUBMODE_UNKNOWN
,
144 LTTV_STATE_SUBMODE_NONE
;
148 LTTV_STATE_WAIT_FORK
,
157 LTTV_STATE_UNBRANDED
;
160 LTTV_STATE_USER_THREAD
,
161 LTTV_STATE_KERNEL_THREAD
;
179 LTTV_BDEV_BUSY_READING
,
180 LTTV_BDEV_BUSY_WRITING
;
183 LTTV_STATE_TRACEFILES
,
184 LTTV_STATE_PROCESSES
,
186 LTTV_STATE_RUNNING_PROCESS
,
188 LTTV_STATE_SAVED_STATES
,
189 LTTV_STATE_SAVED_STATES_TIME
,
192 LTTV_STATE_NAME_TABLES
,
193 LTTV_STATE_TRACE_STATE_USE_COUNT
,
194 LTTV_STATE_RESOURCE_CPUS
,
195 LTTV_STATE_RESOURCE_CPUS_COUNT
,
196 LTTV_STATE_RESOURCE_IRQS
,
197 LTTV_STATE_RESOURCE_SOFT_IRQS
,
198 LTTV_STATE_RESOURCE_TRAPS
,
199 LTTV_STATE_RESOURCE_BLKDEVS
;
201 static void create_max_time(LttvTraceState
*tcs
);
203 static void get_max_time(LttvTraceState
*tcs
);
205 static void free_max_time(LttvTraceState
*tcs
);
207 static void create_name_tables(LttvTraceState
*tcs
);
209 static void get_name_tables(LttvTraceState
*tcs
);
211 static void free_name_tables(LttvTraceState
*tcs
);
213 static void free_saved_state(LttvTraceState
*tcs
);
215 static void lttv_state_free_process_table(GHashTable
*processes
);
217 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
218 GPtrArray
*quarktable
);
220 /* Resource function prototypes */
221 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
222 static LttvBdevState
*bdevstate_new(void);
223 static void bdevstate_free(LttvBdevState
*);
224 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
225 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
228 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
230 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
234 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
236 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
240 void lttv_state_state_saved_free(LttvTraceState
*self
,
241 LttvAttribute
*container
)
243 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
247 guint
process_hash(gconstpointer key
)
249 guint pid
= ((const LttvProcessState
*)key
)->pid
;
250 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
254 /* If the hash table hash function is well distributed,
255 * the process_equal should compare different pid */
256 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
258 const LttvProcessState
*process_a
, *process_b
;
261 process_a
= (const LttvProcessState
*)a
;
262 process_b
= (const LttvProcessState
*)b
;
264 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
265 else if(likely(process_a
->pid
== 0 &&
266 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
271 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
273 g_tree_destroy((GTree
*)value
);
276 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
278 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
279 g_hash_table_destroy(usertraces
);
282 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
287 static guint
check_expand(nb
, id
)
292 return max(id
+ 1, nb
* 2);
295 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
296 guint nb
, guint new_nb
)
298 /* Expand an incomplete table */
299 GQuark
*old_table
= *table
;
300 *table
= g_new(GQuark
, new_nb
);
301 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
304 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
305 guint new_nb
, const char *def_string
)
308 GString
*fe_name
= g_string_new("");
309 for(i
= nb
; i
< new_nb
; i
++) {
310 g_string_printf(fe_name
, "%s %d", def_string
, i
);
311 table
[i
] = g_quark_from_string(fe_name
->str
);
313 g_string_free(fe_name
, TRUE
);
316 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
318 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
319 if(likely(new_nb
== ts
->nb_syscalls
))
321 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
322 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
323 /* Update the table size */
324 ts
->nb_syscalls
= new_nb
;
327 static void expand_trap_table(LttvTraceState
*ts
, int id
)
329 guint new_nb
= check_expand(ts
->nb_traps
, id
);
331 if(likely(new_nb
== ts
->nb_traps
))
333 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
334 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
335 /* Update the table size */
336 ts
->nb_traps
= new_nb
;
338 LttvTrapState
*old_table
= ts
->trap_states
;
339 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
340 memcpy(ts
->trap_states
, old_table
,
341 ts
->nb_traps
* sizeof(LttvTrapState
));
342 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
343 ts
->trap_states
[i
].running
= 0;
346 static void expand_irq_table(LttvTraceState
*ts
, int id
)
348 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
350 if(likely(new_nb
== ts
->nb_irqs
))
352 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
353 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
355 LttvIRQState
*old_table
= ts
->irq_states
;
356 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
357 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
358 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
359 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
362 /* Update the table size */
363 ts
->nb_irqs
= new_nb
;
366 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
368 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
370 if(likely(new_nb
== ts
->nb_soft_irqs
))
372 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
373 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
375 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
376 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
377 memcpy(ts
->soft_irq_states
, old_table
,
378 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
379 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
380 ts
->soft_irq_states
[i
].running
= 0;
382 /* Update the table size */
383 ts
->nb_soft_irqs
= new_nb
;
387 restore_init_state(LttvTraceState
*self
)
389 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
391 //LttvTracefileState *tfcs;
393 LttTime start_time
, end_time
;
395 /* Free the process tables */
396 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
397 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
398 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
399 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
402 /* Seek time to beginning */
403 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
404 // closest. It's the tracecontext job to seek the trace to the beginning
405 // anyway : the init state might be used at the middle of the trace as well...
406 //g_tree_destroy(self->parent.ts_context->pqueue);
407 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
409 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
411 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
413 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
414 nb_irqs
= self
->nb_irqs
;
415 nb_soft_irqs
= self
->nb_soft_irqs
;
416 nb_traps
= self
->nb_traps
;
418 /* Put the per cpu running_process to beginning state : process 0. */
419 for(i
=0; i
< nb_cpus
; i
++) {
420 LttvExecutionState
*es
;
421 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
422 LTTV_STATE_UNNAMED
, &start_time
);
423 /* We are not sure is it's a kernel thread or normal thread, put the
424 * bottom stack state to unknown */
425 self
->running_process
[i
]->execution_stack
=
426 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
427 es
= self
->running_process
[i
]->state
=
428 &g_array_index(self
->running_process
[i
]->execution_stack
,
429 LttvExecutionState
, 0);
430 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
431 es
->s
= LTTV_STATE_UNNAMED
;
433 //self->running_process[i]->state->s = LTTV_STATE_RUN;
434 self
->running_process
[i
]->cpu
= i
;
436 /* reset cpu states */
437 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
438 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
439 self
->cpu_states
[i
].last_irq
= -1;
440 self
->cpu_states
[i
].last_soft_irq
= -1;
441 self
->cpu_states
[i
].last_trap
= -1;
445 /* reset irq states */
446 for(i
=0; i
<nb_irqs
; i
++) {
447 if(self
->irq_states
[i
].mode_stack
->len
> 0)
448 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
451 /* reset softirq states */
452 for(i
=0; i
<nb_soft_irqs
; i
++) {
453 self
->soft_irq_states
[i
].pending
= 0;
454 self
->soft_irq_states
[i
].running
= 0;
457 /* reset trap states */
458 for(i
=0; i
<nb_traps
; i
++) {
459 self
->trap_states
[i
].running
= 0;
462 /* reset bdev states */
463 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
464 //g_hash_table_steal_all(self->bdev_states);
465 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
468 nb_tracefile
= self
->parent
.tracefiles
->len
;
470 for(i
= 0 ; i
< nb_tracefile
; i
++) {
472 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
473 LttvTracefileContext
*, i
));
474 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
475 // tfcs->saved_position = 0;
476 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
477 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
478 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
479 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
484 //static LttTime time_zero = {0,0};
486 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
489 const LttTime
*t1
= (const LttTime
*)a
;
490 const LttTime
*t2
= (const LttTime
*)b
;
492 return ltt_time_compare(*t1
, *t2
);
495 static void free_usertrace_key(gpointer data
)
500 #define MAX_STRING_LEN 4096
503 state_load_saved_states(LttvTraceState
*tcs
)
506 GPtrArray
*quarktable
;
507 const char *trace_path
;
511 tcs
->has_precomputed_states
= FALSE
;
515 gchar buf
[MAX_STRING_LEN
];
518 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
519 strncpy(path
, trace_path
, PATH_MAX
-1);
520 count
= strnlen(trace_path
, PATH_MAX
-1);
521 // quarktable : open, test
522 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
523 fp
= fopen(path
, "r");
525 quarktable
= g_ptr_array_sized_new(4096);
527 /* Index 0 is null */
529 if(hdr
== EOF
) return;
530 g_assert(hdr
== HDR_QUARKS
);
534 if(hdr
== EOF
) break;
535 g_assert(hdr
== HDR_QUARK
);
536 g_ptr_array_set_size(quarktable
, q
+1);
539 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
540 if(buf
[i
] == '\0' || feof(fp
)) break;
543 len
= strnlen(buf
, MAX_STRING_LEN
-1);
544 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
545 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
551 // saved_states : open, test
552 strncpy(path
, trace_path
, PATH_MAX
-1);
553 count
= strnlen(trace_path
, PATH_MAX
-1);
554 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
555 fp
= fopen(path
, "r");
559 if(hdr
!= HDR_TRACE
) goto end
;
561 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
563 tcs
->has_precomputed_states
= TRUE
;
568 /* Free the quarktable */
569 for(i
=0; i
<quarktable
->len
; i
++) {
570 string
= g_ptr_array_index (quarktable
, i
);
573 g_ptr_array_free(quarktable
, TRUE
);
578 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
580 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
583 LttvTraceContext
*tc
;
587 LttvTracefileState
*tfcs
;
589 LttvAttributeValue v
;
591 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
592 init((LttvTracesetContext
*)self
, ts
);
594 nb_trace
= lttv_traceset_number(ts
);
595 for(i
= 0 ; i
< nb_trace
; i
++) {
596 tc
= self
->parent
.traces
[i
];
597 tcs
= LTTV_TRACE_STATE(tc
);
598 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
599 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
603 if(*(v
.v_uint
) == 1) {
604 create_name_tables(tcs
);
605 create_max_time(tcs
);
607 get_name_tables(tcs
);
610 nb_tracefile
= tc
->tracefiles
->len
;
611 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
612 nb_irq
= tcs
->nb_irqs
;
613 tcs
->processes
= NULL
;
614 tcs
->usertraces
= NULL
;
615 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
617 /* init cpu resource stuff */
618 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
619 for(j
= 0; j
<nb_cpu
; j
++) {
620 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
621 tcs
->cpu_states
[j
].last_irq
= -1;
622 tcs
->cpu_states
[j
].last_soft_irq
= -1;
623 tcs
->cpu_states
[j
].last_trap
= -1;
624 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
627 /* init irq resource stuff */
628 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
629 for(j
= 0; j
<nb_irq
; j
++) {
630 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
631 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
634 /* init soft irq stuff */
635 /* the kernel has a statically fixed max of 32 softirqs */
636 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
638 /* init trap stuff */
639 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
641 /* init bdev resource stuff */
642 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
644 restore_init_state(tcs
);
645 for(j
= 0 ; j
< nb_tracefile
; j
++) {
647 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
648 LttvTracefileContext
*, j
));
649 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
650 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
651 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
652 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
653 /* It's a Usertrace */
654 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
655 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
656 GUINT_TO_POINTER(tid
));
657 if(!usertrace_tree
) {
658 usertrace_tree
= g_tree_new_full(compare_usertraces
,
659 NULL
, free_usertrace_key
, NULL
);
660 g_hash_table_insert(tcs
->usertraces
,
661 GUINT_TO_POINTER(tid
), usertrace_tree
);
663 LttTime
*timestamp
= g_new(LttTime
, 1);
664 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
665 ltt_tracefile_creation(tfcs
->parent
.tf
));
666 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
670 /* See if the trace has saved states */
671 state_load_saved_states(tcs
);
676 fini(LttvTracesetState
*self
)
682 //LttvTracefileState *tfcs;
684 LttvAttributeValue v
;
686 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
687 for(i
= 0 ; i
< nb_trace
; i
++) {
688 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
689 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
692 g_assert(*(v
.v_uint
) != 0);
695 if(*(v
.v_uint
) == 0) {
696 free_name_tables(tcs
);
698 free_saved_state(tcs
);
700 g_free(tcs
->running_process
);
701 tcs
->running_process
= NULL
;
702 lttv_state_free_process_table(tcs
->processes
);
703 lttv_state_free_usertraces(tcs
->usertraces
);
704 tcs
->processes
= NULL
;
705 tcs
->usertraces
= NULL
;
707 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
708 fini((LttvTracesetContext
*)self
);
712 static LttvTracesetContext
*
713 new_traceset_context(LttvTracesetContext
*self
)
715 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
719 static LttvTraceContext
*
720 new_trace_context(LttvTracesetContext
*self
)
722 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
726 static LttvTracefileContext
*
727 new_tracefile_context(LttvTracesetContext
*self
)
729 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
733 /* Write the process state of the trace */
735 static void write_process_state(gpointer key
, gpointer value
,
738 LttvProcessState
*process
;
740 LttvExecutionState
*es
;
742 FILE *fp
= (FILE *)user_data
;
747 process
= (LttvProcessState
*)value
;
749 " <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\" FREE_EVENTS=\"%u\">\n",
750 process
, process
->pid
, process
->tgid
, process
->ppid
,
751 g_quark_to_string(process
->type
),
752 process
->creation_time
.tv_sec
,
753 process
->creation_time
.tv_nsec
,
754 process
->insertion_time
.tv_sec
,
755 process
->insertion_time
.tv_nsec
,
756 g_quark_to_string(process
->name
),
757 g_quark_to_string(process
->brand
),
758 process
->cpu
, process
->free_events
);
760 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
761 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
762 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
763 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
764 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
765 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
766 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
769 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
770 address
= g_array_index(process
->user_stack
, guint64
, i
);
771 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n",
775 if(process
->usertrace
) {
776 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
777 g_quark_to_string(process
->usertrace
->tracefile_name
),
778 process
->usertrace
->cpu
);
782 fprintf(fp
, " </PROCESS>\n");
786 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
788 guint i
, nb_tracefile
, nb_block
, offset
;
791 LttvTracefileState
*tfcs
;
795 LttEventPosition
*ep
;
799 ep
= ltt_event_position_new();
801 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
803 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
805 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
806 for(i
=0;i
<nb_cpus
;i
++) {
807 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
808 i
, self
->running_process
[i
]->pid
);
811 nb_tracefile
= self
->parent
.tracefiles
->len
;
813 for(i
= 0 ; i
< nb_tracefile
; i
++) {
815 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
816 LttvTracefileContext
*, i
));
817 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
818 tfcs
->parent
.timestamp
.tv_sec
,
819 tfcs
->parent
.timestamp
.tv_nsec
);
820 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
821 if(e
== NULL
) fprintf(fp
,"/>\n");
823 ltt_event_position(e
, ep
);
824 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
825 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
830 fprintf(fp
,"</PROCESS_STATE>\n");
834 static void write_process_state_raw(gpointer key
, gpointer value
,
837 LttvProcessState
*process
;
839 LttvExecutionState
*es
;
841 FILE *fp
= (FILE *)user_data
;
846 process
= (LttvProcessState
*)value
;
847 fputc(HDR_PROCESS
, fp
);
848 //fwrite(&header, sizeof(header), 1, fp);
849 //fprintf(fp, "%s", g_quark_to_string(process->type));
851 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
852 //fprintf(fp, "%s", g_quark_to_string(process->name));
854 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
855 //fprintf(fp, "%s", g_quark_to_string(process->brand));
857 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
858 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
859 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
860 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
861 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
862 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
863 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
864 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
868 " <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",
869 process
, process
->pid
, process
->tgid
, process
->ppid
,
870 g_quark_to_string(process
->type
),
871 process
->creation_time
.tv_sec
,
872 process
->creation_time
.tv_nsec
,
873 process
->insertion_time
.tv_sec
,
874 process
->insertion_time
.tv_nsec
,
875 g_quark_to_string(process
->name
),
876 g_quark_to_string(process
->brand
),
880 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
881 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
884 //fprintf(fp, "%s", g_quark_to_string(es->t));
886 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
887 //fprintf(fp, "%s", g_quark_to_string(es->n));
889 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
890 //fprintf(fp, "%s", g_quark_to_string(es->s));
892 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
893 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
894 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
895 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
897 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
898 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
899 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
900 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
901 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
905 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
906 address
= g_array_index(process
->user_stack
, guint64
, i
);
907 fputc(HDR_USER_STACK
, fp
);
908 fwrite(&address
, sizeof(address
), 1, fp
);
910 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
915 if(process
->usertrace
) {
916 fputc(HDR_USERTRACE
, fp
);
917 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
919 fwrite(&process
->usertrace
->tracefile_name
,
920 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
921 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
923 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
924 g_quark_to_string(process
->usertrace
->tracefile_name
),
925 process
->usertrace
->cpu
);
932 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
934 guint i
, nb_tracefile
, nb_block
, offset
;
937 LttvTracefileState
*tfcs
;
941 LttEventPosition
*ep
;
945 ep
= ltt_event_position_new();
947 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
948 fputc(HDR_PROCESS_STATE
, fp
);
949 fwrite(&t
, sizeof(t
), 1, fp
);
951 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
953 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
954 for(i
=0;i
<nb_cpus
;i
++) {
956 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
957 fwrite(&self
->running_process
[i
]->pid
,
958 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
959 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
960 // i, self->running_process[i]->pid);
963 nb_tracefile
= self
->parent
.tracefiles
->len
;
965 for(i
= 0 ; i
< nb_tracefile
; i
++) {
967 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
968 LttvTracefileContext
*, i
));
969 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
970 // tfcs->parent.timestamp.tv_sec,
971 // tfcs->parent.timestamp.tv_nsec);
972 fputc(HDR_TRACEFILE
, fp
);
973 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
974 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
975 * position following : end of trace */
976 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
978 ltt_event_position(e
, ep
);
979 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
980 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
982 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
983 fwrite(&offset
, sizeof(offset
), 1, fp
);
984 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
991 /* Read process state from a file */
993 /* Called because a HDR_PROCESS was found */
994 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
995 GPtrArray
*quarktable
)
997 LttvExecutionState
*es
;
998 LttvProcessState
*process
, *parent_process
;
999 LttvProcessState tmp
;
1004 /* TODO : check return value */
1005 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1006 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1007 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1008 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1009 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1010 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1011 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1012 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1013 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1014 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1017 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1019 /* We must link to the parent */
1020 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1022 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1023 if(process
== NULL
) {
1024 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1026 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1027 &tmp
.creation_time
);
1030 process
->insertion_time
= tmp
.insertion_time
;
1031 process
->creation_time
= tmp
.creation_time
;
1032 process
->type
= g_quark_from_string(
1033 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1034 process
->tgid
= tmp
.tgid
;
1035 process
->ppid
= tmp
.ppid
;
1036 process
->brand
= g_quark_from_string(
1037 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1039 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1040 process
->free_events
= tmp
.free_events
;
1043 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1045 gint hdr
= fgetc(fp
);
1046 if(hdr
== EOF
) goto end_loop
;
1050 process
->execution_stack
=
1051 g_array_set_size(process
->execution_stack
,
1052 process
->execution_stack
->len
+ 1);
1053 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1054 process
->execution_stack
->len
-1);
1055 process
->state
= es
;
1057 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1058 es
->t
= g_quark_from_string(
1059 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1060 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1061 es
->n
= g_quark_from_string(
1062 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1063 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1064 es
->s
= g_quark_from_string(
1065 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1066 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1067 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1068 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1070 case HDR_USER_STACK
:
1071 process
->user_stack
= g_array_set_size(process
->user_stack
,
1072 process
->user_stack
->len
+ 1);
1073 address
= &g_array_index(process
->user_stack
, guint64
,
1074 process
->user_stack
->len
-1);
1075 fread(address
, sizeof(address
), 1, fp
);
1076 process
->current_function
= *address
;
1079 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1080 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1092 /* Called because a HDR_PROCESS_STATE was found */
1093 /* Append a saved state to the trace states */
1094 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1096 guint i
, nb_tracefile
, nb_block
, offset
;
1098 LttvTracefileState
*tfcs
;
1100 LttEventPosition
*ep
;
1108 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1110 LttvAttributeValue value
;
1111 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1112 ep
= ltt_event_position_new();
1114 restore_init_state(self
);
1116 fread(&t
, sizeof(t
), 1, fp
);
1119 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1121 if(hdr
== EOF
) goto end_loop
;
1125 /* Call read_process_state_raw */
1126 read_process_state_raw(self
, fp
, quarktable
);
1134 case HDR_USER_STACK
:
1136 case HDR_PROCESS_STATE
:
1142 g_error("Error while parsing saved state file : unknown data header %d",
1148 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1149 for(i
=0;i
<nb_cpus
;i
++) {
1152 g_assert(hdr
== HDR_CPU
);
1153 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1154 g_assert(i
== cpu_num
);
1155 fread(&self
->running_process
[i
]->pid
,
1156 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1159 nb_tracefile
= self
->parent
.tracefiles
->len
;
1161 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1163 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1164 LttvTracefileContext
*, i
));
1165 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1166 // tfcs->parent.timestamp.tv_sec,
1167 // tfcs->parent.timestamp.tv_nsec);
1168 g_tree_remove(pqueue
, &tfcs
->parent
);
1170 g_assert(hdr
== HDR_TRACEFILE
);
1171 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1172 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1173 * position following : end of trace */
1174 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1175 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1176 fread(&offset
, sizeof(offset
), 1, fp
);
1177 fread(&tsc
, sizeof(tsc
), 1, fp
);
1178 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1179 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1181 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1186 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1187 LTTV_STATE_SAVED_STATES
);
1188 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1189 value
= lttv_attribute_add(saved_states_tree
,
1190 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1191 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1192 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1193 *(value
.v_time
) = t
;
1194 lttv_state_save(self
, saved_state_tree
);
1195 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1198 *(self
->max_time_state_recomputed_in_seek
) = t
;
1202 /* Called when a HDR_TRACE is found */
1203 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1204 GPtrArray
*quarktable
)
1209 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1211 if(hdr
== EOF
) goto end_loop
;
1214 case HDR_PROCESS_STATE
:
1215 /* Call read_process_state_raw */
1216 lttv_state_read_raw(tcs
, fp
, quarktable
);
1224 case HDR_USER_STACK
:
1228 g_error("Error while parsing saved state file :"
1229 " unexpected data header %d",
1233 g_error("Error while parsing saved state file : unknown data header %d",
1238 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1239 restore_init_state(tcs
);
1240 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1246 /* Copy each process from an existing hash table to a new one */
1248 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1250 LttvProcessState
*process
, *new_process
;
1252 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1256 process
= (LttvProcessState
*)value
;
1257 new_process
= g_new(LttvProcessState
, 1);
1258 *new_process
= *process
;
1259 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1260 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1261 new_process
->execution_stack
=
1262 g_array_set_size(new_process
->execution_stack
,
1263 process
->execution_stack
->len
);
1264 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1265 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1266 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1268 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1269 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1270 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1271 sizeof(guint64
), 0);
1272 new_process
->user_stack
=
1273 g_array_set_size(new_process
->user_stack
,
1274 process
->user_stack
->len
);
1275 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1276 g_array_index(new_process
->user_stack
, guint64
, i
) =
1277 g_array_index(process
->user_stack
, guint64
, i
);
1279 new_process
->current_function
= process
->current_function
;
1280 g_hash_table_insert(new_processes
, new_process
, new_process
);
1284 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1286 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1288 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1289 return new_processes
;
1292 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1295 LttvCPUState
*retval
;
1297 retval
= g_new(LttvCPUState
, n
);
1299 for(i
=0; i
<n
; i
++) {
1300 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1301 retval
[i
].last_irq
= states
[i
].last_irq
;
1302 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1303 retval
[i
].last_trap
= states
[i
].last_trap
;
1304 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1305 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1306 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1313 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1317 for(i
=0; i
<n
; i
++) {
1318 g_array_free(states
[i
].mode_stack
, TRUE
);
1324 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1327 LttvIRQState
*retval
;
1329 retval
= g_new(LttvIRQState
, n
);
1331 for(i
=0; i
<n
; i
++) {
1332 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1333 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1334 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1335 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1342 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1346 for(i
=0; i
<n
; i
++) {
1347 g_array_free(states
[i
].mode_stack
, TRUE
);
1353 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1356 LttvSoftIRQState
*retval
;
1358 retval
= g_new(LttvSoftIRQState
, n
);
1360 for(i
=0; i
<n
; i
++) {
1361 retval
[i
].pending
= states
[i
].pending
;
1362 retval
[i
].running
= states
[i
].running
;
1368 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1373 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1376 LttvTrapState
*retval
;
1378 retval
= g_new(LttvTrapState
, n
);
1380 for(i
=0; i
<n
; i
++) {
1381 retval
[i
].running
= states
[i
].running
;
1387 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1392 /* bdevstate stuff */
1394 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1396 gint devcode_gint
= devcode
;
1397 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1399 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1400 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1402 gint
* key
= g_new(gint
, 1);
1404 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1412 static LttvBdevState
*bdevstate_new(void)
1414 LttvBdevState
*retval
;
1415 retval
= g_new(LttvBdevState
, 1);
1416 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1421 static void bdevstate_free(LttvBdevState
*bds
)
1423 g_array_free(bds
->mode_stack
, TRUE
);
1427 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1429 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1431 bdevstate_free(bds
);
1434 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1436 LttvBdevState
*retval
;
1438 retval
= bdevstate_new();
1439 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1444 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1446 //GHashTable *ht = (GHashTable *)u;
1447 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1448 LttvBdevState
*newbds
;
1450 newbds
= bdevstate_copy(bds
);
1452 g_hash_table_insert(u
, k
, newbds
);
1455 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1459 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1461 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1466 /* Free a hashtable and the LttvBdevState structures its values
1469 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1471 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1472 g_hash_table_destroy(ht
);
1475 /* The saved state for each trace contains a member "processes", which
1476 stores a copy of the process table, and a member "tracefiles" with
1477 one entry per tracefile. Each tracefile has a "process" member pointing
1478 to the current process and a "position" member storing the tracefile
1479 position (needed to seek to the current "next" event. */
1481 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1483 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1485 LttvTracefileState
*tfcs
;
1487 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1489 guint
*running_process
;
1491 LttvAttributeValue value
;
1493 LttEventPosition
*ep
;
1495 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1496 LTTV_STATE_TRACEFILES
);
1498 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1500 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1502 /* Add the currently running processes array */
1503 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1504 running_process
= g_new(guint
, nb_cpus
);
1505 for(i
=0;i
<nb_cpus
;i
++) {
1506 running_process
[i
] = self
->running_process
[i
]->pid
;
1508 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1510 *(value
.v_pointer
) = running_process
;
1512 g_info("State save");
1514 nb_tracefile
= self
->parent
.tracefiles
->len
;
1516 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1518 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1519 LttvTracefileContext
*, i
));
1520 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1521 value
= lttv_attribute_add(tracefiles_tree
, i
,
1523 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1525 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1527 *(value
.v_uint
) = tfcs
->process
->pid
;
1529 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1531 /* Only save the position if the tfs has not infinite time. */
1532 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1533 // && current_tfcs != tfcs) {
1534 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1535 *(value
.v_pointer
) = NULL
;
1537 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1538 ep
= ltt_event_position_new();
1539 ltt_event_position(e
, ep
);
1540 *(value
.v_pointer
) = ep
;
1542 guint nb_block
, offset
;
1545 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1546 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
, offset
,
1548 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1552 /* save the cpu state */
1554 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1556 *(value
.v_uint
) = nb_cpus
;
1558 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1560 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1563 /* save the irq state */
1564 nb_irqs
= self
->nb_irqs
;
1566 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1568 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1571 /* save the soft irq state */
1572 nb_soft_irqs
= self
->nb_soft_irqs
;
1574 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1576 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1579 /* save the trap state */
1580 nb_traps
= self
->nb_traps
;
1582 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1584 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1587 /* save the blkdev states */
1588 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1590 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1594 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1596 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1598 LttvTracefileState
*tfcs
;
1600 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1602 guint
*running_process
;
1604 LttvAttributeType type
;
1606 LttvAttributeValue value
;
1608 LttvAttributeName name
;
1612 LttEventPosition
*ep
;
1614 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1616 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1617 LTTV_STATE_TRACEFILES
);
1619 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1621 g_assert(type
== LTTV_POINTER
);
1622 lttv_state_free_process_table(self
->processes
);
1623 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1625 /* Add the currently running processes array */
1626 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1627 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1629 g_assert(type
== LTTV_POINTER
);
1630 running_process
= *(value
.v_pointer
);
1631 for(i
=0;i
<nb_cpus
;i
++) {
1632 pid
= running_process
[i
];
1633 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1634 g_assert(self
->running_process
[i
] != NULL
);
1637 nb_tracefile
= self
->parent
.tracefiles
->len
;
1639 //g_tree_destroy(tsc->pqueue);
1640 //tsc->pqueue = g_tree_new(compare_tracefile);
1642 /* restore cpu resource states */
1643 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1644 g_assert(type
== LTTV_POINTER
);
1645 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1646 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1648 /* restore irq resource states */
1649 nb_irqs
= self
->nb_irqs
;
1650 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1651 g_assert(type
== LTTV_POINTER
);
1652 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1653 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1655 /* restore soft irq resource states */
1656 nb_soft_irqs
= self
->nb_soft_irqs
;
1657 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1658 g_assert(type
== LTTV_POINTER
);
1659 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1660 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1662 /* restore trap resource states */
1663 nb_traps
= self
->nb_traps
;
1664 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1665 g_assert(type
== LTTV_POINTER
);
1666 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1667 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1669 /* restore the blkdev states */
1670 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1671 g_assert(type
== LTTV_POINTER
);
1672 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1673 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1675 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1677 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1678 LttvTracefileContext
*, i
));
1679 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1680 g_assert(type
== LTTV_GOBJECT
);
1681 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1683 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1685 g_assert(type
== LTTV_UINT
);
1686 pid
= *(value
.v_uint
);
1687 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1689 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1691 g_assert(type
== LTTV_POINTER
);
1692 //g_assert(*(value.v_pointer) != NULL);
1693 ep
= *(value
.v_pointer
);
1694 g_assert(tfcs
->parent
.t_context
!= NULL
);
1696 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1698 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1699 g_tree_remove(tsc
->pqueue
, tfc
);
1702 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1703 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1704 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1705 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1706 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1708 tfc
->timestamp
= ltt_time_infinite
;
1714 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1716 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1718 LttvTracefileState
*tfcs
;
1720 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1722 guint
*running_process
;
1724 LttvAttributeType type
;
1726 LttvAttributeValue value
;
1728 LttvAttributeName name
;
1732 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1733 LTTV_STATE_TRACEFILES
);
1734 g_object_ref(G_OBJECT(tracefiles_tree
));
1735 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1737 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1739 g_assert(type
== LTTV_POINTER
);
1740 lttv_state_free_process_table(*(value
.v_pointer
));
1741 *(value
.v_pointer
) = NULL
;
1742 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1744 /* Free running processes array */
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1747 g_assert(type
== LTTV_POINTER
);
1748 running_process
= *(value
.v_pointer
);
1749 g_free(running_process
);
1751 /* free cpu resource states */
1752 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1753 g_assert(type
== LTTV_UINT
);
1754 nb_cpus
= *value
.v_uint
;
1755 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1756 g_assert(type
== LTTV_POINTER
);
1757 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1759 /* free irq resource states */
1760 nb_irqs
= self
->nb_irqs
;
1761 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1762 g_assert(type
== LTTV_POINTER
);
1763 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1765 /* free softirq resource states */
1766 nb_softirqs
= self
->nb_irqs
;
1767 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1768 g_assert(type
== LTTV_POINTER
);
1769 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1771 /* free the blkdev states */
1772 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1773 g_assert(type
== LTTV_POINTER
);
1774 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1776 nb_tracefile
= self
->parent
.tracefiles
->len
;
1778 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1780 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1781 LttvTracefileContext
*, i
));
1782 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1783 g_assert(type
== LTTV_GOBJECT
);
1784 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1786 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1788 g_assert(type
== LTTV_POINTER
);
1789 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1791 g_object_unref(G_OBJECT(tracefiles_tree
));
1795 static void free_saved_state(LttvTraceState
*self
)
1799 LttvAttributeType type
;
1801 LttvAttributeValue value
;
1803 LttvAttributeName name
;
1807 LttvAttribute
*saved_states
;
1809 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1810 LTTV_STATE_SAVED_STATES
);
1812 nb
= lttv_attribute_get_number(saved_states
);
1813 for(i
= 0 ; i
< nb
; i
++) {
1814 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1815 g_assert(type
== LTTV_GOBJECT
);
1816 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1819 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1824 create_max_time(LttvTraceState
*tcs
)
1826 LttvAttributeValue v
;
1828 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1830 g_assert(*(v
.v_pointer
) == NULL
);
1831 *(v
.v_pointer
) = g_new(LttTime
,1);
1832 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1837 get_max_time(LttvTraceState
*tcs
)
1839 LttvAttributeValue v
;
1841 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1843 g_assert(*(v
.v_pointer
) != NULL
);
1844 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1849 free_max_time(LttvTraceState
*tcs
)
1851 LttvAttributeValue v
;
1853 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1855 g_free(*(v
.v_pointer
));
1856 *(v
.v_pointer
) = NULL
;
1860 typedef struct _LttvNameTables
{
1861 // FIXME GQuark *eventtype_names;
1862 GQuark
*syscall_names
;
1868 GQuark
*soft_irq_names
;
1874 create_name_tables(LttvTraceState
*tcs
)
1878 GString
*fe_name
= g_string_new("");
1880 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1882 LttvAttributeValue v
;
1886 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1888 g_assert(*(v
.v_pointer
) == NULL
);
1889 *(v
.v_pointer
) = name_tables
;
1891 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1893 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1895 LTT_EVENT_SYSCALL_ENTRY
,
1896 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1897 NULL
, NULL
, &hooks
)) {
1899 // th = lttv_trace_hook_get_first(&th);
1901 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1902 // nb = ltt_type_element_number(t);
1904 // name_tables->syscall_names = g_new(GQuark, nb);
1905 // name_tables->nb_syscalls = nb;
1907 // for(i = 0 ; i < nb ; i++) {
1908 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1909 // if(!name_tables->syscall_names[i]) {
1910 // GString *string = g_string_new("");
1911 // g_string_printf(string, "syscall %u", i);
1912 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1913 // g_string_free(string, TRUE);
1917 name_tables
->nb_syscalls
= 256;
1918 name_tables
->syscall_names
= g_new(GQuark
, 256);
1919 for(i
= 0 ; i
< 256 ; i
++) {
1920 g_string_printf(fe_name
, "syscall %d", i
);
1921 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1924 name_tables
->syscall_names
= NULL
;
1925 name_tables
->nb_syscalls
= 0;
1927 lttv_trace_hook_remove_all(&hooks
);
1929 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1931 LTT_EVENT_TRAP_ENTRY
,
1932 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1933 NULL
, NULL
, &hooks
)) {
1935 // th = lttv_trace_hook_get_first(&th);
1937 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1938 // //nb = ltt_type_element_number(t);
1940 // name_tables->trap_names = g_new(GQuark, nb);
1941 // for(i = 0 ; i < nb ; i++) {
1942 // name_tables->trap_names[i] = g_quark_from_string(
1943 // ltt_enum_string_get(t, i));
1946 name_tables
->nb_traps
= 256;
1947 name_tables
->trap_names
= g_new(GQuark
, 256);
1948 for(i
= 0 ; i
< 256 ; i
++) {
1949 g_string_printf(fe_name
, "trap %d", i
);
1950 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1953 name_tables
->trap_names
= NULL
;
1954 name_tables
->nb_traps
= 0;
1956 lttv_trace_hook_remove_all(&hooks
);
1958 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1960 LTT_EVENT_IRQ_ENTRY
,
1961 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1962 NULL
, NULL
, &hooks
)) {
1965 name_tables->irq_names = g_new(GQuark, nb);
1966 for(i = 0 ; i < nb ; i++) {
1967 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1971 name_tables
->nb_irqs
= 256;
1972 name_tables
->irq_names
= g_new(GQuark
, 256);
1973 for(i
= 0 ; i
< 256 ; i
++) {
1974 g_string_printf(fe_name
, "irq %d", i
);
1975 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1978 name_tables
->nb_irqs
= 0;
1979 name_tables
->irq_names
= NULL
;
1981 lttv_trace_hook_remove_all(&hooks
);
1983 name_tables->soft_irq_names = g_new(GQuark, nb);
1984 for(i = 0 ; i < nb ; i++) {
1985 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1989 /* the kernel is limited to 32 statically defined softirqs */
1990 name_tables
->nb_softirqs
= 32;
1991 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1992 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1993 g_string_printf(fe_name
, "softirq %d", i
);
1994 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1996 g_array_free(hooks
, TRUE
);
1998 g_string_free(fe_name
, TRUE
);
2003 get_name_tables(LttvTraceState
*tcs
)
2005 LttvNameTables
*name_tables
;
2007 LttvAttributeValue v
;
2009 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2011 g_assert(*(v
.v_pointer
) != NULL
);
2012 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2013 //tcs->eventtype_names = name_tables->eventtype_names;
2014 tcs
->syscall_names
= name_tables
->syscall_names
;
2015 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2016 tcs
->trap_names
= name_tables
->trap_names
;
2017 tcs
->nb_traps
= name_tables
->nb_traps
;
2018 tcs
->irq_names
= name_tables
->irq_names
;
2019 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2020 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2021 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2026 free_name_tables(LttvTraceState
*tcs
)
2028 LttvNameTables
*name_tables
;
2030 LttvAttributeValue v
;
2032 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2034 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2035 *(v
.v_pointer
) = NULL
;
2037 // g_free(name_tables->eventtype_names);
2038 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2039 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2040 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2041 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2042 if(name_tables
) g_free(name_tables
);
2045 #ifdef HASH_TABLE_DEBUG
2047 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2049 LttvProcessState
*process
= (LttvProcessState
*)value
;
2051 /* Test for process corruption */
2052 guint stack_len
= process
->execution_stack
->len
;
2055 static void hash_table_check(GHashTable
*table
)
2057 g_hash_table_foreach(table
, test_process
, NULL
);
2063 /* clears the stack and sets the state passed as argument */
2064 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2066 g_array_set_size(cpust
->mode_stack
, 1);
2067 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2070 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2072 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2073 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2076 static void cpu_pop_mode(LttvCPUState
*cpust
)
2078 if(cpust
->mode_stack
->len
<= 1)
2079 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2081 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2084 /* clears the stack and sets the state passed as argument */
2085 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2087 g_array_set_size(bdevst
->mode_stack
, 1);
2088 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2091 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2093 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2094 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2097 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2099 if(bdevst
->mode_stack
->len
<= 1)
2100 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2102 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2105 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2107 g_array_set_size(irqst
->mode_stack
, 1);
2108 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2111 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2113 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2114 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2117 static void irq_pop_mode(LttvIRQState
*irqst
)
2119 if(irqst
->mode_stack
->len
<= 1)
2120 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2122 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2125 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2128 LttvExecutionState
*es
;
2130 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2131 guint cpu
= tfs
->cpu
;
2133 #ifdef HASH_TABLE_DEBUG
2134 hash_table_check(ts
->processes
);
2136 LttvProcessState
*process
= ts
->running_process
[cpu
];
2138 guint depth
= process
->execution_stack
->len
;
2140 process
->execution_stack
=
2141 g_array_set_size(process
->execution_stack
, depth
+ 1);
2144 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2146 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2149 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2150 es
->cum_cpu_time
= ltt_time_zero
;
2151 es
->s
= process
->state
->s
;
2152 process
->state
= es
;
2156 * return 1 when empty, else 0 */
2157 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2158 LttvTracefileState
*tfs
)
2160 guint depth
= process
->execution_stack
->len
;
2166 process
->execution_stack
=
2167 g_array_set_size(process
->execution_stack
, depth
- 1);
2168 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2170 process
->state
->change
= tfs
->parent
.timestamp
;
2175 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2177 guint cpu
= tfs
->cpu
;
2178 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2179 LttvProcessState
*process
= ts
->running_process
[cpu
];
2181 guint depth
= process
->execution_stack
->len
;
2183 if(process
->state
->t
!= t
){
2184 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2185 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2186 g_info("process state has %s when pop_int is %s\n",
2187 g_quark_to_string(process
->state
->t
),
2188 g_quark_to_string(t
));
2189 g_info("{ %u, %u, %s, %s, %s }\n",
2192 g_quark_to_string(process
->name
),
2193 g_quark_to_string(process
->brand
),
2194 g_quark_to_string(process
->state
->s
));
2199 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2200 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2204 process
->execution_stack
=
2205 g_array_set_size(process
->execution_stack
, depth
- 1);
2206 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2208 process
->state
->change
= tfs
->parent
.timestamp
;
2211 struct search_result
{
2212 const LttTime
*time
; /* Requested time */
2213 LttTime
*best
; /* Best result */
2216 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2218 const LttTime
*elem_time
= (const LttTime
*)a
;
2219 /* Explicit non const cast */
2220 struct search_result
*res
= (struct search_result
*)b
;
2222 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2223 /* The usertrace was created before the schedchange */
2224 /* Get larger keys */
2226 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2227 /* The usertrace was created after the schedchange time */
2228 /* Get smaller keys */
2230 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2231 res
->best
= (LttTime
*)elem_time
;
2234 res
->best
= (LttTime
*)elem_time
;
2241 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2242 guint pid
, const LttTime
*timestamp
)
2244 LttvTracefileState
*tfs
= NULL
;
2245 struct search_result res
;
2246 /* Find the usertrace associated with a pid and time interval.
2247 * Search in the usertraces by PID (within a hash) and then, for each
2248 * corresponding element of the array, find the first one with creation
2249 * timestamp the lowest, but higher or equal to "timestamp". */
2250 res
.time
= timestamp
;
2252 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2253 GUINT_TO_POINTER(pid
));
2254 if(usertrace_tree
) {
2255 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2257 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2265 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2266 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2268 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2270 LttvExecutionState
*es
;
2275 process
->tgid
= tgid
;
2277 process
->name
= name
;
2278 process
->brand
= LTTV_STATE_UNBRANDED
;
2279 //process->last_cpu = tfs->cpu_name;
2280 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2281 process
->type
= LTTV_STATE_USER_THREAD
;
2282 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2283 process
->current_function
= 0; //function 0x0 by default.
2285 g_info("Process %u, core %p", process
->pid
, process
);
2286 g_hash_table_insert(tcs
->processes
, process
, process
);
2289 process
->ppid
= parent
->pid
;
2290 process
->creation_time
= *timestamp
;
2293 /* No parent. This process exists but we are missing all information about
2294 its creation. The birth time is set to zero but we remember the time of
2299 process
->creation_time
= ltt_time_zero
;
2302 process
->insertion_time
= *timestamp
;
2303 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2304 process
->creation_time
.tv_nsec
);
2305 process
->pid_time
= g_quark_from_string(buffer
);
2307 process
->free_events
= 0;
2308 //process->last_cpu = tfs->cpu_name;
2309 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2310 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2311 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2312 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2313 es
= process
->state
= &g_array_index(process
->execution_stack
,
2314 LttvExecutionState
, 0);
2315 es
->t
= LTTV_STATE_USER_MODE
;
2316 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2317 es
->entry
= *timestamp
;
2318 //g_assert(timestamp->tv_sec != 0);
2319 es
->change
= *timestamp
;
2320 es
->cum_cpu_time
= ltt_time_zero
;
2321 es
->s
= LTTV_STATE_RUN
;
2323 es
= process
->state
= &g_array_index(process
->execution_stack
,
2324 LttvExecutionState
, 1);
2325 es
->t
= LTTV_STATE_SYSCALL
;
2326 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2327 es
->entry
= *timestamp
;
2328 //g_assert(timestamp->tv_sec != 0);
2329 es
->change
= *timestamp
;
2330 es
->cum_cpu_time
= ltt_time_zero
;
2331 es
->s
= LTTV_STATE_WAIT_FORK
;
2333 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2334 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2335 sizeof(guint64
), 0);
2340 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2343 LttvProcessState key
;
2344 LttvProcessState
*process
;
2348 process
= g_hash_table_lookup(ts
->processes
, &key
);
2353 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2354 const LttTime
*timestamp
)
2356 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2357 LttvExecutionState
*es
;
2359 /* Put ltt_time_zero creation time for unexisting processes */
2360 if(unlikely(process
== NULL
)) {
2361 process
= lttv_state_create_process(ts
,
2362 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2363 /* We are not sure is it's a kernel thread or normal thread, put the
2364 * bottom stack state to unknown */
2365 process
->execution_stack
=
2366 g_array_set_size(process
->execution_stack
, 1);
2367 process
->state
= es
=
2368 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2369 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2370 es
->s
= LTTV_STATE_UNNAMED
;
2375 /* FIXME : this function should be called when we receive an event telling that
2376 * release_task has been called in the kernel. In happens generally when
2377 * the parent waits for its child terminaison, but may also happen in special
2378 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2379 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2380 * of a killed thread group, but isn't the leader.
2382 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2384 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2385 LttvProcessState key
;
2387 /* Wait for both schedule with exit dead and process free to happen.
2388 * They can happen in any order. */
2389 if (++(process
->free_events
) < 2)
2392 key
.pid
= process
->pid
;
2393 key
.cpu
= process
->cpu
;
2394 g_hash_table_remove(ts
->processes
, &key
);
2395 g_array_free(process
->execution_stack
, TRUE
);
2396 g_array_free(process
->user_stack
, TRUE
);
2402 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2404 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2405 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2410 static void lttv_state_free_process_table(GHashTable
*processes
)
2412 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2413 g_hash_table_destroy(processes
);
2417 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2419 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2421 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2422 LttvProcessState
*process
= ts
->running_process
[cpu
];
2423 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2424 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2425 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2426 LttvExecutionSubmode submode
;
2428 guint syscall
= ltt_event_get_unsigned(e
, f
);
2429 expand_syscall_table(ts
, syscall
);
2430 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2431 /* There can be no system call from PID 0 : unknown state */
2432 if(process
->pid
!= 0)
2433 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2438 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2440 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2442 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2443 LttvProcessState
*process
= ts
->running_process
[cpu
];
2445 /* There can be no system call from PID 0 : unknown state */
2446 if(process
->pid
!= 0)
2447 pop_state(s
, LTTV_STATE_SYSCALL
);
2452 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2454 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2455 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2456 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2457 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2458 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2460 LttvExecutionSubmode submode
;
2462 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2464 expand_trap_table(ts
, trap
);
2466 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2468 push_state(s
, LTTV_STATE_TRAP
, submode
);
2470 /* update cpu status */
2471 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2473 /* update trap status */
2474 s
->cpu_state
->last_trap
= trap
;
2475 ts
->trap_states
[trap
].running
++;
2480 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2482 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2483 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2484 gint trap
= s
->cpu_state
->last_trap
;
2486 pop_state(s
, LTTV_STATE_TRAP
);
2488 /* update cpu status */
2489 cpu_pop_mode(s
->cpu_state
);
2491 /* update trap status */
2493 if(ts
->trap_states
[trap
].running
)
2494 ts
->trap_states
[trap
].running
--;
2499 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2501 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2502 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2503 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2504 //guint8 ev_id = ltt_event_eventtype_id(e);
2505 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2506 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2508 LttvExecutionSubmode submode
;
2509 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2511 expand_irq_table(ts
, irq
);
2513 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2515 /* Do something with the info about being in user or system mode when int? */
2516 push_state(s
, LTTV_STATE_IRQ
, submode
);
2518 /* update cpu status */
2519 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2521 /* update irq status */
2522 s
->cpu_state
->last_irq
= irq
;
2523 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2528 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2530 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2531 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2532 gint softirq
= s
->cpu_state
->last_soft_irq
;
2534 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2536 /* update softirq status */
2538 if(ts
->soft_irq_states
[softirq
].running
)
2539 ts
->soft_irq_states
[softirq
].running
--;
2541 /* update cpu status */
2542 cpu_pop_mode(s
->cpu_state
);
2547 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2549 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2550 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2552 pop_state(s
, LTTV_STATE_IRQ
);
2554 /* update cpu status */
2555 cpu_pop_mode(s
->cpu_state
);
2557 /* update irq status */
2558 if (s
->cpu_state
->last_irq
!= -1)
2559 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2564 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2566 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2567 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2568 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2569 //guint8 ev_id = ltt_event_eventtype_id(e);
2570 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2571 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2573 LttvExecutionSubmode submode
;
2574 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2575 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2577 if(softirq
< nb_softirqs
) {
2578 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2580 /* Fixup an incomplete irq table */
2581 GString
*string
= g_string_new("");
2582 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2583 submode
= g_quark_from_string(string
->str
);
2584 g_string_free(string
, TRUE
);
2587 /* update softirq status */
2588 /* a soft irq raises are not cumulative */
2589 ts
->soft_irq_states
[softirq
].pending
=1;
2594 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2596 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2597 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2598 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2599 //guint8 ev_id = ltt_event_eventtype_id(e);
2600 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2601 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2602 LttvExecutionSubmode submode
;
2603 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2604 expand_soft_irq_table(ts
, softirq
);
2605 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2607 /* Do something with the info about being in user or system mode when int? */
2608 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2610 /* update cpu status */
2611 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2613 /* update softirq status */
2614 s
->cpu_state
->last_soft_irq
= softirq
;
2615 if(ts
->soft_irq_states
[softirq
].pending
)
2616 ts
->soft_irq_states
[softirq
].pending
--;
2617 ts
->soft_irq_states
[softirq
].running
++;
2622 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2624 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2625 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2626 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2627 //guint8 ev_id = ltt_event_eventtype_id(e);
2628 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2630 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2631 lttv_trace_get_hook_field(th
, 0)));
2632 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2634 expand_irq_table(ts
, irq
);
2635 ts
->irq_names
[irq
] = action
;
2641 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2643 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2644 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2645 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2646 //guint8 ev_id = ltt_event_eventtype_id(e);
2647 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2649 guint major
= ltt_event_get_long_unsigned(e
,
2650 lttv_trace_get_hook_field(th
, 0));
2651 guint minor
= ltt_event_get_long_unsigned(e
,
2652 lttv_trace_get_hook_field(th
, 1));
2653 guint oper
= ltt_event_get_long_unsigned(e
,
2654 lttv_trace_get_hook_field(th
, 2));
2655 guint16 devcode
= MKDEV(major
,minor
);
2657 /* have we seen this block device before? */
2658 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2661 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2663 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2668 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2670 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2671 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2672 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2673 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2675 guint major
= ltt_event_get_long_unsigned(e
,
2676 lttv_trace_get_hook_field(th
, 0));
2677 guint minor
= ltt_event_get_long_unsigned(e
,
2678 lttv_trace_get_hook_field(th
, 1));
2679 //guint oper = ltt_event_get_long_unsigned(e,
2680 // lttv_trace_get_hook_field(th, 2));
2681 guint16 devcode
= MKDEV(major
,minor
);
2683 /* have we seen this block device before? */
2684 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2686 /* update block device */
2687 bdev_pop_mode(bdev
);
2692 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2696 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2697 guint cpu
= tfs
->cpu
;
2698 LttvProcessState
*process
= ts
->running_process
[cpu
];
2700 guint depth
= process
->user_stack
->len
;
2702 process
->user_stack
=
2703 g_array_set_size(process
->user_stack
, depth
+ 1);
2705 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2706 *new_func
= funcptr
;
2707 process
->current_function
= funcptr
;
2710 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2712 guint cpu
= tfs
->cpu
;
2713 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2714 LttvProcessState
*process
= ts
->running_process
[cpu
];
2716 if(process
->current_function
!= funcptr
){
2717 g_info("Different functions (%lu.%09lu): ignore it\n",
2718 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2719 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2720 process
->current_function
, funcptr
);
2721 g_info("{ %u, %u, %s, %s, %s }\n",
2724 g_quark_to_string(process
->name
),
2725 g_quark_to_string(process
->brand
),
2726 g_quark_to_string(process
->state
->s
));
2729 guint depth
= process
->user_stack
->len
;
2732 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2733 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2737 process
->user_stack
=
2738 g_array_set_size(process
->user_stack
, depth
- 1);
2739 process
->current_function
=
2740 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2744 static gboolean
function_entry(void *hook_data
, void *call_data
)
2746 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2747 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2748 //guint8 ev_id = ltt_event_eventtype_id(e);
2749 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2750 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2751 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2753 push_function(s
, funcptr
);
2757 static gboolean
function_exit(void *hook_data
, void *call_data
)
2759 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2760 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2761 //guint8 ev_id = ltt_event_eventtype_id(e);
2762 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2763 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2764 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2766 pop_function(s
, funcptr
);
2770 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2772 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2773 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2774 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2775 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2780 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2781 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2782 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2784 expand_syscall_table(ts
, id
);
2785 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2790 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2792 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2793 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2794 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2795 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2800 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2801 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2802 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2804 expand_soft_irq_table(ts
, id
);
2805 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2810 static gboolean
schedchange(void *hook_data
, void *call_data
)
2812 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2814 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2815 LttvProcessState
*process
= ts
->running_process
[cpu
];
2816 //LttvProcessState *old_process = ts->running_process[cpu];
2818 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2819 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2820 guint pid_in
, pid_out
;
2823 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2824 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2825 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2827 if(likely(process
!= NULL
)) {
2829 /* We could not know but it was not the idle process executing.
2830 This should only happen at the beginning, before the first schedule
2831 event, and when the initial information (current process for each CPU)
2832 is missing. It is not obvious how we could, after the fact, compensate
2833 the wrongly attributed statistics. */
2835 //This test only makes sense once the state is known and if there is no
2836 //missing events. We need to silently ignore schedchange coming after a
2837 //process_free, or it causes glitches. (FIXME)
2838 //if(unlikely(process->pid != pid_out)) {
2839 // g_assert(process->pid == 0);
2841 if(process
->pid
== 0
2842 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2844 /* Scheduling out of pid 0 at beginning of the trace :
2845 * we know for sure it is in syscall mode at this point. */
2846 g_assert(process
->execution_stack
->len
== 1);
2847 process
->state
->t
= LTTV_STATE_SYSCALL
;
2848 process
->state
->s
= LTTV_STATE_WAIT
;
2849 process
->state
->change
= s
->parent
.timestamp
;
2850 process
->state
->entry
= s
->parent
.timestamp
;
2853 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2854 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2855 process
->state
->change
= s
->parent
.timestamp
;
2857 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2858 else process
->state
->s
= LTTV_STATE_WAIT
;
2859 process
->state
->change
= s
->parent
.timestamp
;
2862 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2863 /* see sched.h for states */
2864 if (!exit_process(s
, process
)) {
2865 process
->state
->s
= LTTV_STATE_DEAD
;
2866 process
->state
->change
= s
->parent
.timestamp
;
2871 process
= ts
->running_process
[cpu
] =
2872 lttv_state_find_process_or_create(
2873 (LttvTraceState
*)s
->parent
.t_context
,
2875 &s
->parent
.timestamp
);
2876 process
->state
->s
= LTTV_STATE_RUN
;
2878 if(process
->usertrace
)
2879 process
->usertrace
->cpu
= cpu
;
2880 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2881 process
->state
->change
= s
->parent
.timestamp
;
2883 /* update cpu status */
2885 /* going to idle task */
2886 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2888 /* scheduling a real task.
2889 * we must be careful here:
2890 * if we just schedule()'ed to a process that is
2891 * in a trap, we must put the cpu in trap mode
2893 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2894 if(process
->state
->t
== LTTV_STATE_TRAP
)
2895 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2901 static gboolean
process_fork(void *hook_data
, void *call_data
)
2903 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2904 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2905 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2907 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2908 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2909 //LttvProcessState *zombie_process;
2911 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2912 LttvProcessState
*process
= ts
->running_process
[cpu
];
2913 LttvProcessState
*child_process
;
2914 struct marker_field
*f
;
2917 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2920 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2921 s
->parent
.target_pid
= child_pid
;
2924 f
= lttv_trace_get_hook_field(th
, 2);
2926 child_tgid
= ltt_event_get_unsigned(e
, f
);
2930 /* Mathieu : it seems like the process might have been scheduled in before the
2931 * fork, and, in a rare case, might be the current process. This might happen
2932 * in a SMP case where we don't have enough precision on the clocks.
2934 * Test reenabled after precision fixes on time. (Mathieu) */
2936 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2938 if(unlikely(zombie_process
!= NULL
)) {
2939 /* Reutilisation of PID. Only now we are sure that the old PID
2940 * has been released. FIXME : should know when release_task happens instead.
2942 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2944 for(i
=0; i
< num_cpus
; i
++) {
2945 g_assert(zombie_process
!= ts
->running_process
[i
]);
2948 exit_process(s
, zombie_process
);
2951 g_assert(process
->pid
!= child_pid
);
2952 // FIXME : Add this test in the "known state" section
2953 // g_assert(process->pid == parent_pid);
2954 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2955 if(child_process
== NULL
) {
2956 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2957 child_pid
, child_tgid
,
2958 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2960 /* The process has already been created : due to time imprecision between
2961 * multiple CPUs : it has been scheduled in before creation. Note that we
2962 * shouldn't have this kind of imprecision.
2964 * Simply put a correct parent.
2966 g_error("Process %u has been created at [%lu.%09lu] "
2967 "and inserted at [%lu.%09lu] before \n"
2968 "fork on cpu %u[%lu.%09lu].\n"
2969 "Probably an unsynchronized TSC problem on the traced machine.",
2971 child_process
->creation_time
.tv_sec
,
2972 child_process
->creation_time
.tv_nsec
,
2973 child_process
->insertion_time
.tv_sec
,
2974 child_process
->insertion_time
.tv_nsec
,
2975 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
2976 //g_assert(0); /* This is a problematic case : the process has been created
2977 // before the fork event */
2978 child_process
->ppid
= process
->pid
;
2979 child_process
->tgid
= child_tgid
;
2981 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2982 child_process
->name
= process
->name
;
2983 child_process
->brand
= process
->brand
;
2988 /* We stamp a newly created process as kernel_thread.
2989 * The thread should not be running yet. */
2990 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2992 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2993 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2994 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2996 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2997 LttvProcessState
*process
;
2998 LttvExecutionState
*es
;
3001 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3002 s
->parent
.target_pid
= pid
;
3004 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3006 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3007 process
->execution_stack
=
3008 g_array_set_size(process
->execution_stack
, 1);
3009 es
= process
->state
=
3010 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3011 es
->t
= LTTV_STATE_SYSCALL
;
3013 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3018 static gboolean
process_exit(void *hook_data
, void *call_data
)
3020 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3021 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3022 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3024 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3025 LttvProcessState
*process
; // = ts->running_process[cpu];
3027 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3028 s
->parent
.target_pid
= pid
;
3030 // FIXME : Add this test in the "known state" section
3031 // g_assert(process->pid == pid);
3033 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3034 if(likely(process
!= NULL
)) {
3035 process
->state
->s
= LTTV_STATE_EXIT
;
3040 static gboolean
process_free(void *hook_data
, void *call_data
)
3042 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3043 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3044 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3045 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3047 LttvProcessState
*process
;
3049 /* PID of the process to release */
3050 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3051 s
->parent
.target_pid
= release_pid
;
3053 g_assert(release_pid
!= 0);
3055 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3056 if(likely(process
!= NULL
))
3057 exit_process(s
, process
);
3060 if(likely(process
!= NULL
)) {
3061 /* release_task is happening at kernel level : we can now safely release
3062 * the data structure of the process */
3063 //This test is fun, though, as it may happen that
3064 //at time t : CPU 0 : process_free
3065 //at time t+150ns : CPU 1 : schedule out
3066 //Clearly due to time imprecision, we disable it. (Mathieu)
3067 //If this weird case happen, we have no choice but to put the
3068 //Currently running process on the cpu to 0.
3069 //I re-enable it following time precision fixes. (Mathieu)
3070 //Well, in the case where an process is freed by a process on another CPU
3071 //and still scheduled, it happens that this is the schedchange that will
3072 //drop the last reference count. Do not free it here!
3073 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3075 for(i
=0; i
< num_cpus
; i
++) {
3076 //g_assert(process != ts->running_process[i]);
3077 if(process
== ts
->running_process
[i
]) {
3078 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3082 if(i
== num_cpus
) /* process is not scheduled */
3083 exit_process(s
, process
);
3090 static gboolean
process_exec(void *hook_data
, void *call_data
)
3092 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3093 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3094 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3095 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3098 LttvProcessState
*process
= ts
->running_process
[cpu
];
3100 #if 0//how to use a sequence that must be transformed in a string
3101 /* PID of the process to release */
3102 guint64 name_len
= ltt_event_field_element_number(e
,
3103 lttv_trace_get_hook_field(th
, 0));
3104 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3105 LttField
*child
= ltt_event_field_element_select(e
,
3106 lttv_trace_get_hook_field(th
, 0), 0);
3108 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3109 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3110 memcpy(null_term_name
, name_begin
, name_len
);
3111 null_term_name
[name_len
] = '\0';
3112 process
->name
= g_quark_from_string(null_term_name
);
3115 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3116 lttv_trace_get_hook_field(th
, 0)));
3117 process
->brand
= LTTV_STATE_UNBRANDED
;
3118 //g_free(null_term_name);
3122 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3124 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3125 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3126 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3127 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3130 LttvProcessState
*process
= ts
->running_process
[cpu
];
3132 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3133 process
->brand
= g_quark_from_string(name
);
3138 static void fix_process(gpointer key
, gpointer value
,
3141 LttvProcessState
*process
;
3142 LttvExecutionState
*es
;
3143 process
= (LttvProcessState
*)value
;
3144 LttTime
*timestamp
= (LttTime
*)user_data
;
3146 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3147 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3148 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3149 es
->t
= LTTV_STATE_SYSCALL
;
3150 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3151 es
->entry
= *timestamp
;
3152 es
->change
= *timestamp
;
3153 es
->cum_cpu_time
= ltt_time_zero
;
3154 if(es
->s
== LTTV_STATE_UNNAMED
)
3155 es
->s
= LTTV_STATE_WAIT
;
3158 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3159 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3160 es
->t
= LTTV_STATE_USER_MODE
;
3161 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3162 es
->entry
= *timestamp
;
3163 //g_assert(timestamp->tv_sec != 0);
3164 es
->change
= *timestamp
;
3165 es
->cum_cpu_time
= ltt_time_zero
;
3166 if(es
->s
== LTTV_STATE_UNNAMED
)
3167 es
->s
= LTTV_STATE_RUN
;
3169 if(process
->execution_stack
->len
== 1) {
3170 /* Still in bottom unknown mode, means never did a system call
3171 * May be either in user mode, syscall mode, running or waiting.*/
3172 /* FIXME : we may be tagging syscall mode when being user mode */
3173 process
->execution_stack
=
3174 g_array_set_size(process
->execution_stack
, 2);
3175 es
= process
->state
= &g_array_index(process
->execution_stack
,
3176 LttvExecutionState
, 1);
3177 es
->t
= LTTV_STATE_SYSCALL
;
3178 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3179 es
->entry
= *timestamp
;
3180 //g_assert(timestamp->tv_sec != 0);
3181 es
->change
= *timestamp
;
3182 es
->cum_cpu_time
= ltt_time_zero
;
3183 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3184 es
->s
= LTTV_STATE_WAIT
;
3190 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3192 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3193 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3194 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3195 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3196 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3198 /* For all processes */
3199 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3200 /* else, if stack[0] is unknown, set to user mode, running */
3202 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3207 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3209 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3210 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3211 //It's slow : optimise later by doing this before reading trace.
3212 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3218 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3219 LttvProcessState
*process
= ts
->running_process
[cpu
];
3220 LttvProcessState
*parent_process
;
3221 struct marker_field
*f
;
3222 GQuark type
, mode
, submode
, status
;
3223 LttvExecutionState
*es
;
3227 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3228 s
->parent
.target_pid
= pid
;
3231 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3234 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3237 f
= lttv_trace_get_hook_field(th
, 3);
3238 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3240 //FIXME: type is rarely used, enum must match possible types.
3243 f
= lttv_trace_get_hook_field(th
, 4);
3244 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3247 f
= lttv_trace_get_hook_field(th
, 5);
3248 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3251 f
= lttv_trace_get_hook_field(th
, 6);
3252 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3255 f
= lttv_trace_get_hook_field(th
, 7);
3257 tgid
= ltt_event_get_unsigned(e
, f
);
3262 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3263 for(i
=0; i
<nb_cpus
; i
++) {
3264 process
= lttv_state_find_process(ts
, i
, pid
);
3265 g_assert(process
!= NULL
);
3267 process
->ppid
= parent_pid
;
3268 process
->tgid
= tgid
;
3269 process
->name
= g_quark_from_string(command
);
3271 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3272 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3276 /* The process might exist if a process was forked while performing the
3278 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3279 if(process
== NULL
) {
3280 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3281 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3282 pid
, tgid
, g_quark_from_string(command
),
3283 &s
->parent
.timestamp
);
3285 /* Keep the stack bottom : a running user mode */
3286 /* Disabled because of inconsistencies in the current statedump states. */
3287 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3288 /* Only keep the bottom
3289 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3290 /* Will cause expected trap when in fact being syscall (even after end of
3292 * Will cause expected interrupt when being syscall. (only before end of
3293 * statedump event) */
3294 // This will cause a "popping last state on stack, ignoring it."
3295 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3296 es
= process
->state
= &g_array_index(process
->execution_stack
,
3297 LttvExecutionState
, 0);
3298 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3299 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3300 es
->s
= LTTV_STATE_UNNAMED
;
3301 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3303 es
->t
= LTTV_STATE_SYSCALL
;
3308 /* User space process :
3309 * bottom : user mode
3310 * either currently running or scheduled out.
3311 * can be scheduled out because interrupted in (user mode or in syscall)
3312 * or because of an explicit call to the scheduler in syscall. Note that
3313 * the scheduler call comes after the irq_exit, so never in interrupt
3315 // temp workaround : set size to 1 : only have user mode bottom of stack.
3316 // will cause g_info message of expected syscall mode when in fact being
3317 // in user mode. Can also cause expected trap when in fact being user
3318 // mode in the event of a page fault reenabling interrupts in the handler.
3319 // Expected syscall and trap can also happen after the end of statedump
3320 // This will cause a "popping last state on stack, ignoring it."
3321 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3322 es
= process
->state
= &g_array_index(process
->execution_stack
,
3323 LttvExecutionState
, 0);
3324 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3325 es
->s
= LTTV_STATE_UNNAMED
;
3326 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3328 es
->t
= LTTV_STATE_USER_MODE
;
3336 es
= process
->state
= &g_array_index(process
->execution_stack
,
3337 LttvExecutionState
, 1);
3338 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3339 es
->s
= LTTV_STATE_UNNAMED
;
3340 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3344 /* The process has already been created :
3345 * Probably was forked while dumping the process state or
3346 * was simply scheduled in prior to get the state dump event.
3348 process
->ppid
= parent_pid
;
3349 process
->tgid
= tgid
;
3350 process
->name
= g_quark_from_string(command
);
3351 process
->type
= type
;
3353 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3355 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3356 if(type
== LTTV_STATE_KERNEL_THREAD
)
3357 es
->t
= LTTV_STATE_SYSCALL
;
3359 es
->t
= LTTV_STATE_USER_MODE
;
3362 /* Don't mess around with the stack, it will eventually become
3363 * ok after the end of state dump. */
3370 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3372 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3374 lttv_state_add_event_hooks(tss
);
3379 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3381 LttvTraceset
*traceset
= self
->parent
.ts
;
3383 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3387 LttvTracefileState
*tfs
;
3393 LttvAttributeValue val
;
3395 nb_trace
= lttv_traceset_number(traceset
);
3396 for(i
= 0 ; i
< nb_trace
; i
++) {
3397 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3399 /* Find the eventtype id for the following events and register the
3400 associated by id hooks. */
3402 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3403 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3406 lttv_trace_find_hook(ts
->parent
.t
,
3408 LTT_EVENT_SYSCALL_ENTRY
,
3409 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3410 syscall_entry
, NULL
, &hooks
);
3412 lttv_trace_find_hook(ts
->parent
.t
,
3414 LTT_EVENT_SYSCALL_EXIT
,
3416 syscall_exit
, NULL
, &hooks
);
3418 lttv_trace_find_hook(ts
->parent
.t
,
3420 LTT_EVENT_TRAP_ENTRY
,
3421 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3422 trap_entry
, NULL
, &hooks
);
3424 lttv_trace_find_hook(ts
->parent
.t
,
3426 LTT_EVENT_TRAP_EXIT
,
3428 trap_exit
, NULL
, &hooks
);
3430 lttv_trace_find_hook(ts
->parent
.t
,
3432 LTT_EVENT_PAGE_FAULT_ENTRY
,
3433 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3434 trap_entry
, NULL
, &hooks
);
3436 lttv_trace_find_hook(ts
->parent
.t
,
3438 LTT_EVENT_PAGE_FAULT_EXIT
,
3440 trap_exit
, NULL
, &hooks
);
3442 lttv_trace_find_hook(ts
->parent
.t
,
3444 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3445 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3446 trap_entry
, NULL
, &hooks
);
3448 lttv_trace_find_hook(ts
->parent
.t
,
3450 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3452 trap_exit
, NULL
, &hooks
);
3454 lttv_trace_find_hook(ts
->parent
.t
,
3456 LTT_EVENT_IRQ_ENTRY
,
3457 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3458 irq_entry
, NULL
, &hooks
);
3460 lttv_trace_find_hook(ts
->parent
.t
,
3464 irq_exit
, NULL
, &hooks
);
3466 lttv_trace_find_hook(ts
->parent
.t
,
3468 LTT_EVENT_SOFT_IRQ_RAISE
,
3469 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3470 soft_irq_raise
, NULL
, &hooks
);
3472 lttv_trace_find_hook(ts
->parent
.t
,
3474 LTT_EVENT_SOFT_IRQ_ENTRY
,
3475 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3476 soft_irq_entry
, NULL
, &hooks
);
3478 lttv_trace_find_hook(ts
->parent
.t
,
3480 LTT_EVENT_SOFT_IRQ_EXIT
,
3482 soft_irq_exit
, NULL
, &hooks
);
3484 lttv_trace_find_hook(ts
->parent
.t
,
3486 LTT_EVENT_SCHED_SCHEDULE
,
3487 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3488 LTT_FIELD_PREV_STATE
),
3489 schedchange
, NULL
, &hooks
);
3491 lttv_trace_find_hook(ts
->parent
.t
,
3493 LTT_EVENT_PROCESS_FORK
,
3494 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3495 LTT_FIELD_CHILD_TGID
),
3496 process_fork
, NULL
, &hooks
);
3498 lttv_trace_find_hook(ts
->parent
.t
,
3500 LTT_EVENT_KTHREAD_CREATE
,
3501 FIELD_ARRAY(LTT_FIELD_PID
),
3502 process_kernel_thread
, NULL
, &hooks
);
3504 lttv_trace_find_hook(ts
->parent
.t
,
3506 LTT_EVENT_PROCESS_EXIT
,
3507 FIELD_ARRAY(LTT_FIELD_PID
),
3508 process_exit
, NULL
, &hooks
);
3510 lttv_trace_find_hook(ts
->parent
.t
,
3512 LTT_EVENT_PROCESS_FREE
,
3513 FIELD_ARRAY(LTT_FIELD_PID
),
3514 process_free
, NULL
, &hooks
);
3516 lttv_trace_find_hook(ts
->parent
.t
,
3519 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3520 process_exec
, NULL
, &hooks
);
3522 lttv_trace_find_hook(ts
->parent
.t
,
3523 LTT_CHANNEL_USERSPACE
,
3524 LTT_EVENT_THREAD_BRAND
,
3525 FIELD_ARRAY(LTT_FIELD_NAME
),
3526 thread_brand
, NULL
, &hooks
);
3528 /* statedump-related hooks */
3529 lttv_trace_find_hook(ts
->parent
.t
,
3530 LTT_CHANNEL_TASK_STATE
,
3531 LTT_EVENT_PROCESS_STATE
,
3532 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3533 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3534 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3535 enum_process_state
, NULL
, &hooks
);
3537 lttv_trace_find_hook(ts
->parent
.t
,
3538 LTT_CHANNEL_GLOBAL_STATE
,
3539 LTT_EVENT_STATEDUMP_END
,
3541 statedump_end
, NULL
, &hooks
);
3543 lttv_trace_find_hook(ts
->parent
.t
,
3544 LTT_CHANNEL_IRQ_STATE
,
3545 LTT_EVENT_LIST_INTERRUPT
,
3546 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3547 enum_interrupt
, NULL
, &hooks
);
3549 lttv_trace_find_hook(ts
->parent
.t
,
3551 LTT_EVENT_REQUEST_ISSUE
,
3552 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3553 bdev_request_issue
, NULL
, &hooks
);
3555 lttv_trace_find_hook(ts
->parent
.t
,
3557 LTT_EVENT_REQUEST_COMPLETE
,
3558 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3559 bdev_request_complete
, NULL
, &hooks
);
3561 lttv_trace_find_hook(ts
->parent
.t
,
3562 LTT_CHANNEL_USERSPACE
,
3563 LTT_EVENT_FUNCTION_ENTRY
,
3564 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3565 function_entry
, NULL
, &hooks
);
3567 lttv_trace_find_hook(ts
->parent
.t
,
3568 LTT_CHANNEL_USERSPACE
,
3569 LTT_EVENT_FUNCTION_EXIT
,
3570 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3571 function_exit
, NULL
, &hooks
);
3573 lttv_trace_find_hook(ts
->parent
.t
,
3574 LTT_CHANNEL_SYSCALL_STATE
,
3575 LTT_EVENT_SYS_CALL_TABLE
,
3576 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3577 dump_syscall
, NULL
, &hooks
);
3579 lttv_trace_find_hook(ts
->parent
.t
,
3580 LTT_CHANNEL_SOFTIRQ_STATE
,
3581 LTT_EVENT_SOFTIRQ_VEC
,
3582 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3583 dump_softirq
, NULL
, &hooks
);
3585 /* Add these hooks to each event_by_id hooks list */
3587 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3589 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3591 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3592 LttvTracefileContext
*, j
));
3594 for(k
= 0 ; k
< hooks
->len
; k
++) {
3595 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3596 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3598 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3604 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3605 *(val
.v_pointer
) = hooks
;
3609 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3611 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3613 lttv_state_remove_event_hooks(tss
);
3618 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3620 LttvTraceset
*traceset
= self
->parent
.ts
;
3622 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3626 LttvTracefileState
*tfs
;
3632 LttvAttributeValue val
;
3634 nb_trace
= lttv_traceset_number(traceset
);
3635 for(i
= 0 ; i
< nb_trace
; i
++) {
3636 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3638 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3639 hooks
= *(val
.v_pointer
);
3641 /* Remove these hooks from each event_by_id hooks list */
3643 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3645 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3647 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3648 LttvTracefileContext
*, j
));
3650 for(k
= 0 ; k
< hooks
->len
; k
++) {
3651 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3652 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3653 lttv_hooks_remove_data(
3654 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3659 lttv_trace_hook_remove_all(&hooks
);
3660 g_array_free(hooks
, TRUE
);
3664 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3666 guint
*event_count
= (guint
*)hook_data
;
3668 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3669 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3674 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3676 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3678 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3680 LttvAttributeValue value
;
3682 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3683 LTTV_STATE_SAVED_STATES
);
3684 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3685 value
= lttv_attribute_add(saved_states_tree
,
3686 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3687 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3688 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3689 *(value
.v_time
) = self
->parent
.timestamp
;
3690 lttv_state_save(tcs
, saved_state_tree
);
3691 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3692 self
->parent
.timestamp
.tv_nsec
);
3694 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3699 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3701 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3703 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3708 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3716 static gboolean
block_start(void *hook_data
, void *call_data
)
3718 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3720 LttvTracefileState
*tfcs
;
3722 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3724 LttEventPosition
*ep
;
3726 guint i
, nb_block
, nb_event
, nb_tracefile
;
3730 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3732 LttvAttributeValue value
;
3734 ep
= ltt_event_position_new();
3736 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3738 /* Count the number of events added since the last block end in any
3741 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3743 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3744 LttvTracefileContext
, i
));
3745 ltt_event_position(tfcs
->parent
.e
, ep
);
3746 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3747 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3748 tfcs
->saved_position
= nb_event
;
3752 if(tcs
->nb_event
>= tcs
->save_interval
) {
3753 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3754 LTTV_STATE_SAVED_STATES
);
3755 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3756 value
= lttv_attribute_add(saved_states_tree
,
3757 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3758 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3759 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3760 *(value
.v_time
) = self
->parent
.timestamp
;
3761 lttv_state_save(tcs
, saved_state_tree
);
3763 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3764 self
->parent
.timestamp
.tv_nsec
);
3766 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3772 static gboolean
block_end(void *hook_data
, void *call_data
)
3774 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3776 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3780 LttEventPosition
*ep
;
3782 guint nb_block
, nb_event
;
3784 ep
= ltt_event_position_new();
3785 ltt_event_position(self
->parent
.e
, ep
);
3786 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3787 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3788 self
->saved_position
= 0;
3789 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3796 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3798 LttvTraceset
*traceset
= self
->parent
.ts
;
3800 guint i
, j
, nb_trace
, nb_tracefile
;
3804 LttvTracefileState
*tfs
;
3806 LttvTraceHook hook_start
, hook_end
;
3808 nb_trace
= lttv_traceset_number(traceset
);
3809 for(i
= 0 ; i
< nb_trace
; i
++) {
3810 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3812 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3813 NULL
, NULL
, block_start
, &hook_start
);
3814 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3815 NULL
, NULL
, block_end
, &hook_end
);
3817 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3819 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3821 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3822 LttvTracefileContext
, j
));
3823 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3824 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3825 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3826 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3832 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3834 LttvTraceset
*traceset
= self
->parent
.ts
;
3836 guint i
, j
, nb_trace
, nb_tracefile
;
3840 LttvTracefileState
*tfs
;
3843 nb_trace
= lttv_traceset_number(traceset
);
3844 for(i
= 0 ; i
< nb_trace
; i
++) {
3846 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3847 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3849 if(ts
->has_precomputed_states
) continue;
3851 guint
*event_count
= g_new(guint
, 1);
3854 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3856 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3857 LttvTracefileContext
*, j
));
3858 lttv_hooks_add(tfs
->parent
.event
,
3859 state_save_event_hook
,
3866 lttv_process_traceset_begin(&self
->parent
,
3867 NULL
, NULL
, NULL
, NULL
, NULL
);
3871 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3873 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3875 lttv_state_save_add_event_hooks(tss
);
3882 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3884 LttvTraceset
*traceset
= self
->parent
.ts
;
3886 guint i
, j
, nb_trace
, nb_tracefile
;
3890 LttvTracefileState
*tfs
;
3892 LttvTraceHook hook_start
, hook_end
;
3894 nb_trace
= lttv_traceset_number(traceset
);
3895 for(i
= 0 ; i
< nb_trace
; i
++) {
3896 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3898 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3899 NULL
, NULL
, block_start
, &hook_start
);
3901 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3902 NULL
, NULL
, block_end
, &hook_end
);
3904 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3906 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3908 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3909 LttvTracefileContext
, j
));
3910 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3911 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3912 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3913 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3919 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3921 LttvTraceset
*traceset
= self
->parent
.ts
;
3923 guint i
, j
, nb_trace
, nb_tracefile
;
3927 LttvTracefileState
*tfs
;
3929 LttvHooks
*after_trace
= lttv_hooks_new();
3931 lttv_hooks_add(after_trace
,
3932 state_save_after_trace_hook
,
3937 lttv_process_traceset_end(&self
->parent
,
3938 NULL
, after_trace
, NULL
, NULL
, NULL
);
3940 lttv_hooks_destroy(after_trace
);
3942 nb_trace
= lttv_traceset_number(traceset
);
3943 for(i
= 0 ; i
< nb_trace
; i
++) {
3945 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3946 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3948 if(ts
->has_precomputed_states
) continue;
3950 guint
*event_count
= NULL
;
3952 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3954 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3955 LttvTracefileContext
*, j
));
3956 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3957 state_save_event_hook
);
3959 if(event_count
) g_free(event_count
);
3963 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3965 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3967 lttv_state_save_remove_event_hooks(tss
);
3972 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3974 LttvTraceset
*traceset
= self
->parent
.ts
;
3978 int min_pos
, mid_pos
, max_pos
;
3980 guint call_rest
= 0;
3982 LttvTraceState
*tcs
;
3984 LttvAttributeValue value
;
3986 LttvAttributeType type
;
3988 LttvAttributeName name
;
3992 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
3994 //g_tree_destroy(self->parent.pqueue);
3995 //self->parent.pqueue = g_tree_new(compare_tracefile);
3997 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3999 nb_trace
= lttv_traceset_number(traceset
);
4000 for(i
= 0 ; i
< nb_trace
; i
++) {
4001 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4003 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4004 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4005 LTTV_STATE_SAVED_STATES
);
4008 if(saved_states_tree
) {
4009 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4010 mid_pos
= max_pos
/ 2;
4011 while(min_pos
< max_pos
) {
4012 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
4014 g_assert(type
== LTTV_GOBJECT
);
4015 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4016 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
4018 g_assert(type
== LTTV_TIME
);
4019 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4021 closest_tree
= saved_state_tree
;
4023 else max_pos
= mid_pos
- 1;
4025 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4029 /* restore the closest earlier saved state */
4031 lttv_state_restore(tcs
, closest_tree
);
4035 /* There is no saved state, yet we want to have it. Restart at T0 */
4037 restore_init_state(tcs
);
4038 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4041 /* We want to seek quickly without restoring/updating the state */
4043 restore_init_state(tcs
);
4044 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4047 if(!call_rest
) g_info("NOT Calling restore");
4052 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4058 traceset_state_finalize (LttvTracesetState
*self
)
4060 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4061 finalize(G_OBJECT(self
));
4066 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4068 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4070 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4071 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4072 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4073 klass
->new_traceset_context
= new_traceset_context
;
4074 klass
->new_trace_context
= new_trace_context
;
4075 klass
->new_tracefile_context
= new_tracefile_context
;
4080 lttv_traceset_state_get_type(void)
4082 static GType type
= 0;
4084 static const GTypeInfo info
= {
4085 sizeof (LttvTracesetStateClass
),
4086 NULL
, /* base_init */
4087 NULL
, /* base_finalize */
4088 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4089 NULL
, /* class_finalize */
4090 NULL
, /* class_data */
4091 sizeof (LttvTracesetState
),
4092 0, /* n_preallocs */
4093 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4094 NULL
/* value handling */
4097 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4105 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4111 trace_state_finalize (LttvTraceState
*self
)
4113 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4114 finalize(G_OBJECT(self
));
4119 trace_state_class_init (LttvTraceStateClass
*klass
)
4121 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4123 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4124 klass
->state_save
= state_save
;
4125 klass
->state_restore
= state_restore
;
4126 klass
->state_saved_free
= state_saved_free
;
4131 lttv_trace_state_get_type(void)
4133 static GType type
= 0;
4135 static const GTypeInfo info
= {
4136 sizeof (LttvTraceStateClass
),
4137 NULL
, /* base_init */
4138 NULL
, /* base_finalize */
4139 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4140 NULL
, /* class_finalize */
4141 NULL
, /* class_data */
4142 sizeof (LttvTraceState
),
4143 0, /* n_preallocs */
4144 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4145 NULL
/* value handling */
4148 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4149 "LttvTraceStateType", &info
, 0);
4156 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4162 tracefile_state_finalize (LttvTracefileState
*self
)
4164 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4165 finalize(G_OBJECT(self
));
4170 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4172 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4174 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4179 lttv_tracefile_state_get_type(void)
4181 static GType type
= 0;
4183 static const GTypeInfo info
= {
4184 sizeof (LttvTracefileStateClass
),
4185 NULL
, /* base_init */
4186 NULL
, /* base_finalize */
4187 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4188 NULL
, /* class_finalize */
4189 NULL
, /* class_data */
4190 sizeof (LttvTracefileState
),
4191 0, /* n_preallocs */
4192 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4193 NULL
/* value handling */
4196 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4197 "LttvTracefileStateType", &info
, 0);
4203 static void module_init()
4205 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4206 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4207 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4208 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4209 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4210 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4211 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4212 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4213 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4214 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4215 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4216 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4217 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4218 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4219 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4220 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4221 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4222 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4223 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4224 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4225 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4226 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4227 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4228 LTTV_STATE_EVENT
= g_quark_from_string("event");
4229 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4230 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4231 LTTV_STATE_TIME
= g_quark_from_string("time");
4232 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4233 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4234 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4235 g_quark_from_string("trace_state_use_count");
4236 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4237 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4238 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4239 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4240 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4241 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4243 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4244 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4245 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4246 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4247 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4248 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4249 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4250 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4251 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4252 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4253 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4254 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4255 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4256 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4257 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4259 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4260 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4261 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4262 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4263 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4264 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4265 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4266 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4267 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4268 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4269 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4270 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4271 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4272 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4273 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4274 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4275 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4276 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4277 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4278 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4279 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4280 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4281 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4282 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4283 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4284 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4285 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4286 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4287 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4288 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4290 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4291 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4292 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4293 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4294 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4295 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4296 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4297 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4298 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4299 LTT_FIELD_PID
= g_quark_from_string("pid");
4300 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4301 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4302 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4303 LTT_FIELD_NAME
= g_quark_from_string("name");
4304 LTT_FIELD_TYPE
= g_quark_from_string("type");
4305 LTT_FIELD_MODE
= g_quark_from_string("mode");
4306 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4307 LTT_FIELD_STATUS
= g_quark_from_string("status");
4308 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4309 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4310 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4311 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4312 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4313 LTT_FIELD_ACTION
= g_quark_from_string("action");
4314 LTT_FIELD_ID
= g_quark_from_string("id");
4315 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4316 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4317 LTT_FIELD_IP
= g_quark_from_string("ip");
4319 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4320 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4321 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4322 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4323 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4324 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4326 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4327 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4328 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4330 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4331 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4332 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4333 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4336 static void module_destroy()
4341 LTTV_MODULE("state", "State computation", \
4342 "Update the system state, possibly saving it at intervals", \
4343 module_init
, module_destroy
)