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
;
104 LTT_FIELD_SYSCALL_ID
,
107 LTT_FIELD_SOFT_IRQ_ID
,
110 LTT_FIELD_PREV_STATE
,
111 LTT_FIELD_PARENT_PID
,
115 LTT_FIELD_CHILD_TGID
,
133 LTTV_STATE_MODE_UNKNOWN
,
134 LTTV_STATE_USER_MODE
,
141 LTTV_STATE_SUBMODE_UNKNOWN
,
142 LTTV_STATE_SUBMODE_NONE
;
146 LTTV_STATE_WAIT_FORK
,
155 LTTV_STATE_UNBRANDED
;
158 LTTV_STATE_USER_THREAD
,
159 LTTV_STATE_KERNEL_THREAD
;
177 LTTV_BDEV_BUSY_READING
,
178 LTTV_BDEV_BUSY_WRITING
;
181 LTTV_STATE_TRACEFILES
,
182 LTTV_STATE_PROCESSES
,
184 LTTV_STATE_RUNNING_PROCESS
,
186 LTTV_STATE_SAVED_STATES
,
187 LTTV_STATE_SAVED_STATES_TIME
,
190 LTTV_STATE_NAME_TABLES
,
191 LTTV_STATE_TRACE_STATE_USE_COUNT
,
192 LTTV_STATE_RESOURCE_CPUS
,
193 LTTV_STATE_RESOURCE_CPUS_COUNT
,
194 LTTV_STATE_RESOURCE_IRQS
,
195 LTTV_STATE_RESOURCE_SOFT_IRQS
,
196 LTTV_STATE_RESOURCE_TRAPS
,
197 LTTV_STATE_RESOURCE_BLKDEVS
;
199 static void create_max_time(LttvTraceState
*tcs
);
201 static void get_max_time(LttvTraceState
*tcs
);
203 static void free_max_time(LttvTraceState
*tcs
);
205 static void create_name_tables(LttvTraceState
*tcs
);
207 static void get_name_tables(LttvTraceState
*tcs
);
209 static void free_name_tables(LttvTraceState
*tcs
);
211 static void free_saved_state(LttvTraceState
*tcs
);
213 static void lttv_state_free_process_table(GHashTable
*processes
);
215 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
216 GPtrArray
*quarktable
);
218 /* Resource function prototypes */
219 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
220 static LttvBdevState
*bdevstate_new(void);
221 static void bdevstate_free(LttvBdevState
*);
222 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
223 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
226 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
228 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
232 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
234 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
238 void lttv_state_state_saved_free(LttvTraceState
*self
,
239 LttvAttribute
*container
)
241 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
245 guint
process_hash(gconstpointer key
)
247 guint pid
= ((const LttvProcessState
*)key
)->pid
;
248 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
252 /* If the hash table hash function is well distributed,
253 * the process_equal should compare different pid */
254 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
256 const LttvProcessState
*process_a
, *process_b
;
259 process_a
= (const LttvProcessState
*)a
;
260 process_b
= (const LttvProcessState
*)b
;
262 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
263 else if(likely(process_a
->pid
== 0 &&
264 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
269 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
271 g_tree_destroy((GTree
*)value
);
274 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
276 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
277 g_hash_table_destroy(usertraces
);
280 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
285 static guint
check_expand(nb
, id
)
290 return max(id
+ 1, nb
* 2);
293 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
294 guint nb
, guint new_nb
)
296 /* Expand an incomplete table */
297 GQuark
*old_table
= *table
;
298 *table
= g_new(GQuark
, new_nb
);
299 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
302 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
303 guint new_nb
, const char *def_string
)
306 GString
*fe_name
= g_string_new("");
307 for(i
= nb
; i
< new_nb
; i
++) {
308 g_string_printf(fe_name
, "%s %d", def_string
, i
);
309 table
[i
] = g_quark_from_string(fe_name
->str
);
311 g_string_free(fe_name
, TRUE
);
314 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
316 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
317 if(likely(new_nb
== ts
->nb_syscalls
))
319 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
320 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
321 /* Update the table size */
322 ts
->nb_syscalls
= new_nb
;
325 static void expand_trap_table(LttvTraceState
*ts
, int id
)
327 guint new_nb
= check_expand(ts
->nb_traps
, id
);
329 if(likely(new_nb
== ts
->nb_traps
))
331 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
332 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
333 /* Update the table size */
334 ts
->nb_traps
= new_nb
;
336 LttvTrapState
*old_table
= ts
->trap_states
;
337 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
338 memcpy(ts
->trap_states
, old_table
,
339 ts
->nb_traps
* sizeof(LttvTrapState
));
340 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
341 ts
->trap_states
[i
].running
= 0;
344 static void expand_irq_table(LttvTraceState
*ts
, int id
)
346 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
348 if(likely(new_nb
== ts
->nb_irqs
))
350 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
351 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
353 LttvIRQState
*old_table
= ts
->irq_states
;
354 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
355 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
356 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
357 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
360 /* Update the table size */
361 ts
->nb_irqs
= new_nb
;
364 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
366 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
368 if(likely(new_nb
== ts
->nb_soft_irqs
))
370 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
371 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
373 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
374 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
375 memcpy(ts
->soft_irq_states
, old_table
,
376 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
377 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
378 ts
->soft_irq_states
[i
].running
= 0;
380 /* Update the table size */
381 ts
->nb_soft_irqs
= new_nb
;
385 restore_init_state(LttvTraceState
*self
)
387 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
389 //LttvTracefileState *tfcs;
391 LttTime start_time
, end_time
;
393 /* Free the process tables */
394 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
395 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
396 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
397 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
400 /* Seek time to beginning */
401 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
402 // closest. It's the tracecontext job to seek the trace to the beginning
403 // anyway : the init state might be used at the middle of the trace as well...
404 //g_tree_destroy(self->parent.ts_context->pqueue);
405 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
407 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
409 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
411 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
412 nb_irqs
= self
->nb_irqs
;
413 nb_soft_irqs
= self
->nb_soft_irqs
;
414 nb_traps
= self
->nb_traps
;
416 /* Put the per cpu running_process to beginning state : process 0. */
417 for(i
=0; i
< nb_cpus
; i
++) {
418 LttvExecutionState
*es
;
419 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
420 LTTV_STATE_UNNAMED
, &start_time
);
421 /* We are not sure is it's a kernel thread or normal thread, put the
422 * bottom stack state to unknown */
423 self
->running_process
[i
]->execution_stack
=
424 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
425 es
= self
->running_process
[i
]->state
=
426 &g_array_index(self
->running_process
[i
]->execution_stack
,
427 LttvExecutionState
, 0);
428 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
429 es
->s
= LTTV_STATE_UNNAMED
;
431 //self->running_process[i]->state->s = LTTV_STATE_RUN;
432 self
->running_process
[i
]->cpu
= i
;
434 /* reset cpu states */
435 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
436 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
437 self
->cpu_states
[i
].last_irq
= -1;
438 self
->cpu_states
[i
].last_soft_irq
= -1;
439 self
->cpu_states
[i
].last_trap
= -1;
443 /* reset irq states */
444 for(i
=0; i
<nb_irqs
; i
++) {
445 if(self
->irq_states
[i
].mode_stack
->len
> 0)
446 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
449 /* reset softirq states */
450 for(i
=0; i
<nb_soft_irqs
; i
++) {
451 self
->soft_irq_states
[i
].pending
= 0;
452 self
->soft_irq_states
[i
].running
= 0;
455 /* reset trap states */
456 for(i
=0; i
<nb_traps
; i
++) {
457 self
->trap_states
[i
].running
= 0;
460 /* reset bdev states */
461 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
462 //g_hash_table_steal_all(self->bdev_states);
463 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
466 nb_tracefile
= self
->parent
.tracefiles
->len
;
468 for(i
= 0 ; i
< nb_tracefile
; i
++) {
470 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
471 LttvTracefileContext
*, i
));
472 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
473 // tfcs->saved_position = 0;
474 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
475 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
476 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
477 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
482 //static LttTime time_zero = {0,0};
484 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
487 const LttTime
*t1
= (const LttTime
*)a
;
488 const LttTime
*t2
= (const LttTime
*)b
;
490 return ltt_time_compare(*t1
, *t2
);
493 static void free_usertrace_key(gpointer data
)
498 #define MAX_STRING_LEN 4096
501 state_load_saved_states(LttvTraceState
*tcs
)
504 GPtrArray
*quarktable
;
505 const char *trace_path
;
509 tcs
->has_precomputed_states
= FALSE
;
513 gchar buf
[MAX_STRING_LEN
];
516 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
517 strncpy(path
, trace_path
, PATH_MAX
-1);
518 count
= strnlen(trace_path
, PATH_MAX
-1);
519 // quarktable : open, test
520 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
521 fp
= fopen(path
, "r");
523 quarktable
= g_ptr_array_sized_new(4096);
525 /* Index 0 is null */
527 if(hdr
== EOF
) return;
528 g_assert(hdr
== HDR_QUARKS
);
532 if(hdr
== EOF
) break;
533 g_assert(hdr
== HDR_QUARK
);
534 g_ptr_array_set_size(quarktable
, q
+1);
537 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
538 if(buf
[i
] == '\0' || feof(fp
)) break;
541 len
= strnlen(buf
, MAX_STRING_LEN
-1);
542 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
543 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
549 // saved_states : open, test
550 strncpy(path
, trace_path
, PATH_MAX
-1);
551 count
= strnlen(trace_path
, PATH_MAX
-1);
552 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
553 fp
= fopen(path
, "r");
557 if(hdr
!= HDR_TRACE
) goto end
;
559 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
561 tcs
->has_precomputed_states
= TRUE
;
566 /* Free the quarktable */
567 for(i
=0; i
<quarktable
->len
; i
++) {
568 string
= g_ptr_array_index (quarktable
, i
);
571 g_ptr_array_free(quarktable
, TRUE
);
576 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
578 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
581 LttvTraceContext
*tc
;
585 LttvTracefileState
*tfcs
;
587 LttvAttributeValue v
;
589 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
590 init((LttvTracesetContext
*)self
, ts
);
592 nb_trace
= lttv_traceset_number(ts
);
593 for(i
= 0 ; i
< nb_trace
; i
++) {
594 tc
= self
->parent
.traces
[i
];
595 tcs
= LTTV_TRACE_STATE(tc
);
596 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
597 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
601 if(*(v
.v_uint
) == 1) {
602 create_name_tables(tcs
);
603 create_max_time(tcs
);
605 get_name_tables(tcs
);
608 nb_tracefile
= tc
->tracefiles
->len
;
609 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
610 nb_irq
= tcs
->nb_irqs
;
611 tcs
->processes
= NULL
;
612 tcs
->usertraces
= NULL
;
613 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
615 /* init cpu resource stuff */
616 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
617 for(j
= 0; j
<nb_cpu
; j
++) {
618 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
619 tcs
->cpu_states
[j
].last_irq
= -1;
620 tcs
->cpu_states
[j
].last_soft_irq
= -1;
621 tcs
->cpu_states
[j
].last_trap
= -1;
622 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
625 /* init irq resource stuff */
626 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
627 for(j
= 0; j
<nb_irq
; j
++) {
628 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
629 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
632 /* init soft irq stuff */
633 /* the kernel has a statically fixed max of 32 softirqs */
634 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
636 /* init trap stuff */
637 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
639 /* init bdev resource stuff */
640 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
642 restore_init_state(tcs
);
643 for(j
= 0 ; j
< nb_tracefile
; j
++) {
645 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
646 LttvTracefileContext
*, j
));
647 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
648 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
649 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
650 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
651 /* It's a Usertrace */
652 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
653 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
654 GUINT_TO_POINTER(tid
));
655 if(!usertrace_tree
) {
656 usertrace_tree
= g_tree_new_full(compare_usertraces
,
657 NULL
, free_usertrace_key
, NULL
);
658 g_hash_table_insert(tcs
->usertraces
,
659 GUINT_TO_POINTER(tid
), usertrace_tree
);
661 LttTime
*timestamp
= g_new(LttTime
, 1);
662 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
663 ltt_tracefile_creation(tfcs
->parent
.tf
));
664 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
668 /* See if the trace has saved states */
669 state_load_saved_states(tcs
);
674 fini(LttvTracesetState
*self
)
680 //LttvTracefileState *tfcs;
682 LttvAttributeValue v
;
684 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
685 for(i
= 0 ; i
< nb_trace
; i
++) {
686 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
687 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
690 g_assert(*(v
.v_uint
) != 0);
693 if(*(v
.v_uint
) == 0) {
694 free_name_tables(tcs
);
696 free_saved_state(tcs
);
698 g_free(tcs
->running_process
);
699 tcs
->running_process
= NULL
;
700 lttv_state_free_process_table(tcs
->processes
);
701 lttv_state_free_usertraces(tcs
->usertraces
);
702 tcs
->processes
= NULL
;
703 tcs
->usertraces
= NULL
;
705 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
706 fini((LttvTracesetContext
*)self
);
710 static LttvTracesetContext
*
711 new_traceset_context(LttvTracesetContext
*self
)
713 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
717 static LttvTraceContext
*
718 new_trace_context(LttvTracesetContext
*self
)
720 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
724 static LttvTracefileContext
*
725 new_tracefile_context(LttvTracesetContext
*self
)
727 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
731 /* Write the process state of the trace */
733 static void write_process_state(gpointer key
, gpointer value
,
736 LttvProcessState
*process
;
738 LttvExecutionState
*es
;
740 FILE *fp
= (FILE *)user_data
;
745 process
= (LttvProcessState
*)value
;
747 " <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",
748 process
, process
->pid
, process
->tgid
, process
->ppid
,
749 g_quark_to_string(process
->type
),
750 process
->creation_time
.tv_sec
,
751 process
->creation_time
.tv_nsec
,
752 process
->insertion_time
.tv_sec
,
753 process
->insertion_time
.tv_nsec
,
754 g_quark_to_string(process
->name
),
755 g_quark_to_string(process
->brand
),
756 process
->cpu
, process
->free_events
);
758 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
759 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
760 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
761 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
762 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
763 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
764 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
767 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
768 address
= g_array_index(process
->user_stack
, guint64
, i
);
769 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n",
773 if(process
->usertrace
) {
774 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
775 g_quark_to_string(process
->usertrace
->tracefile_name
),
776 process
->usertrace
->cpu
);
780 fprintf(fp
, " </PROCESS>\n");
784 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
786 guint i
, nb_tracefile
, nb_block
, offset
;
789 LttvTracefileState
*tfcs
;
793 LttEventPosition
*ep
;
797 ep
= ltt_event_position_new();
799 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
801 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
803 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
804 for(i
=0;i
<nb_cpus
;i
++) {
805 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
806 i
, self
->running_process
[i
]->pid
);
809 nb_tracefile
= self
->parent
.tracefiles
->len
;
811 for(i
= 0 ; i
< nb_tracefile
; i
++) {
813 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
814 LttvTracefileContext
*, i
));
815 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
816 tfcs
->parent
.timestamp
.tv_sec
,
817 tfcs
->parent
.timestamp
.tv_nsec
);
818 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
819 if(e
== NULL
) fprintf(fp
,"/>\n");
821 ltt_event_position(e
, ep
);
822 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
823 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
828 fprintf(fp
,"</PROCESS_STATE>\n");
832 static void write_process_state_raw(gpointer key
, gpointer value
,
835 LttvProcessState
*process
;
837 LttvExecutionState
*es
;
839 FILE *fp
= (FILE *)user_data
;
844 process
= (LttvProcessState
*)value
;
845 fputc(HDR_PROCESS
, fp
);
846 //fwrite(&header, sizeof(header), 1, fp);
847 //fprintf(fp, "%s", g_quark_to_string(process->type));
849 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
850 //fprintf(fp, "%s", g_quark_to_string(process->name));
852 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
853 //fprintf(fp, "%s", g_quark_to_string(process->brand));
855 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
856 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
857 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
858 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
859 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
860 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
861 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
862 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
866 " <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",
867 process
, process
->pid
, process
->tgid
, process
->ppid
,
868 g_quark_to_string(process
->type
),
869 process
->creation_time
.tv_sec
,
870 process
->creation_time
.tv_nsec
,
871 process
->insertion_time
.tv_sec
,
872 process
->insertion_time
.tv_nsec
,
873 g_quark_to_string(process
->name
),
874 g_quark_to_string(process
->brand
),
878 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
879 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
882 //fprintf(fp, "%s", g_quark_to_string(es->t));
884 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
885 //fprintf(fp, "%s", g_quark_to_string(es->n));
887 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
888 //fprintf(fp, "%s", g_quark_to_string(es->s));
890 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
891 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
892 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
893 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
895 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
896 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
897 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
898 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
899 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
903 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
904 address
= g_array_index(process
->user_stack
, guint64
, i
);
905 fputc(HDR_USER_STACK
, fp
);
906 fwrite(&address
, sizeof(address
), 1, fp
);
908 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
913 if(process
->usertrace
) {
914 fputc(HDR_USERTRACE
, fp
);
915 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
917 fwrite(&process
->usertrace
->tracefile_name
,
918 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
919 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
921 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
922 g_quark_to_string(process
->usertrace
->tracefile_name
),
923 process
->usertrace
->cpu
);
930 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
932 guint i
, nb_tracefile
, nb_block
, offset
;
935 LttvTracefileState
*tfcs
;
939 LttEventPosition
*ep
;
943 ep
= ltt_event_position_new();
945 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
946 fputc(HDR_PROCESS_STATE
, fp
);
947 fwrite(&t
, sizeof(t
), 1, fp
);
949 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
951 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
952 for(i
=0;i
<nb_cpus
;i
++) {
954 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
955 fwrite(&self
->running_process
[i
]->pid
,
956 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
957 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
958 // i, self->running_process[i]->pid);
961 nb_tracefile
= self
->parent
.tracefiles
->len
;
963 for(i
= 0 ; i
< nb_tracefile
; i
++) {
965 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
966 LttvTracefileContext
*, i
));
967 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
968 // tfcs->parent.timestamp.tv_sec,
969 // tfcs->parent.timestamp.tv_nsec);
970 fputc(HDR_TRACEFILE
, fp
);
971 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
972 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
973 * position following : end of trace */
974 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
976 ltt_event_position(e
, ep
);
977 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
978 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
980 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
981 fwrite(&offset
, sizeof(offset
), 1, fp
);
982 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
989 /* Read process state from a file */
991 /* Called because a HDR_PROCESS was found */
992 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
993 GPtrArray
*quarktable
)
995 LttvExecutionState
*es
;
996 LttvProcessState
*process
, *parent_process
;
997 LttvProcessState tmp
;
1002 /* TODO : check return value */
1003 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1004 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1005 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1006 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1007 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1008 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1009 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1010 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1011 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1012 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1015 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1017 /* We must link to the parent */
1018 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1020 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1021 if(process
== NULL
) {
1022 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1024 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1025 &tmp
.creation_time
);
1028 process
->insertion_time
= tmp
.insertion_time
;
1029 process
->creation_time
= tmp
.creation_time
;
1030 process
->type
= g_quark_from_string(
1031 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1032 process
->tgid
= tmp
.tgid
;
1033 process
->ppid
= tmp
.ppid
;
1034 process
->brand
= g_quark_from_string(
1035 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1037 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1038 process
->free_events
= tmp
.free_events
;
1041 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1043 gint hdr
= fgetc(fp
);
1044 if(hdr
== EOF
) goto end_loop
;
1048 process
->execution_stack
=
1049 g_array_set_size(process
->execution_stack
,
1050 process
->execution_stack
->len
+ 1);
1051 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1052 process
->execution_stack
->len
-1);
1053 process
->state
= es
;
1055 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1056 es
->t
= g_quark_from_string(
1057 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1058 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1059 es
->n
= g_quark_from_string(
1060 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1061 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1062 es
->s
= g_quark_from_string(
1063 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1064 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1065 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1066 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1068 case HDR_USER_STACK
:
1069 process
->user_stack
= g_array_set_size(process
->user_stack
,
1070 process
->user_stack
->len
+ 1);
1071 address
= &g_array_index(process
->user_stack
, guint64
,
1072 process
->user_stack
->len
-1);
1073 fread(address
, sizeof(address
), 1, fp
);
1074 process
->current_function
= *address
;
1077 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1078 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1090 /* Called because a HDR_PROCESS_STATE was found */
1091 /* Append a saved state to the trace states */
1092 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1094 guint i
, nb_tracefile
, nb_block
, offset
;
1096 LttvTracefileState
*tfcs
;
1098 LttEventPosition
*ep
;
1106 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1108 LttvAttributeValue value
;
1109 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1110 ep
= ltt_event_position_new();
1112 restore_init_state(self
);
1114 fread(&t
, sizeof(t
), 1, fp
);
1117 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1119 if(hdr
== EOF
) goto end_loop
;
1123 /* Call read_process_state_raw */
1124 read_process_state_raw(self
, fp
, quarktable
);
1132 case HDR_USER_STACK
:
1134 case HDR_PROCESS_STATE
:
1140 g_error("Error while parsing saved state file : unknown data header %d",
1146 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1147 for(i
=0;i
<nb_cpus
;i
++) {
1150 g_assert(hdr
== HDR_CPU
);
1151 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1152 g_assert(i
== cpu_num
);
1153 fread(&self
->running_process
[i
]->pid
,
1154 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1157 nb_tracefile
= self
->parent
.tracefiles
->len
;
1159 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1161 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1162 LttvTracefileContext
*, i
));
1163 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1164 // tfcs->parent.timestamp.tv_sec,
1165 // tfcs->parent.timestamp.tv_nsec);
1166 g_tree_remove(pqueue
, &tfcs
->parent
);
1168 g_assert(hdr
== HDR_TRACEFILE
);
1169 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1170 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1171 * position following : end of trace */
1172 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1173 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1174 fread(&offset
, sizeof(offset
), 1, fp
);
1175 fread(&tsc
, sizeof(tsc
), 1, fp
);
1176 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1177 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1179 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1184 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1185 LTTV_STATE_SAVED_STATES
);
1186 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1187 value
= lttv_attribute_add(saved_states_tree
,
1188 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1189 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1190 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1191 *(value
.v_time
) = t
;
1192 lttv_state_save(self
, saved_state_tree
);
1193 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1196 *(self
->max_time_state_recomputed_in_seek
) = t
;
1200 /* Called when a HDR_TRACE is found */
1201 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1202 GPtrArray
*quarktable
)
1207 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1209 if(hdr
== EOF
) goto end_loop
;
1212 case HDR_PROCESS_STATE
:
1213 /* Call read_process_state_raw */
1214 lttv_state_read_raw(tcs
, fp
, quarktable
);
1222 case HDR_USER_STACK
:
1226 g_error("Error while parsing saved state file :"
1227 " unexpected data header %d",
1231 g_error("Error while parsing saved state file : unknown data header %d",
1236 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1237 restore_init_state(tcs
);
1238 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1244 /* Copy each process from an existing hash table to a new one */
1246 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1248 LttvProcessState
*process
, *new_process
;
1250 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1254 process
= (LttvProcessState
*)value
;
1255 new_process
= g_new(LttvProcessState
, 1);
1256 *new_process
= *process
;
1257 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1258 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1259 new_process
->execution_stack
=
1260 g_array_set_size(new_process
->execution_stack
,
1261 process
->execution_stack
->len
);
1262 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1263 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1264 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1266 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1267 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1268 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1269 sizeof(guint64
), 0);
1270 new_process
->user_stack
=
1271 g_array_set_size(new_process
->user_stack
,
1272 process
->user_stack
->len
);
1273 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1274 g_array_index(new_process
->user_stack
, guint64
, i
) =
1275 g_array_index(process
->user_stack
, guint64
, i
);
1277 new_process
->current_function
= process
->current_function
;
1278 g_hash_table_insert(new_processes
, new_process
, new_process
);
1282 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1284 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1286 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1287 return new_processes
;
1290 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1293 LttvCPUState
*retval
;
1295 retval
= g_new(LttvCPUState
, n
);
1297 for(i
=0; i
<n
; i
++) {
1298 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1299 retval
[i
].last_irq
= states
[i
].last_irq
;
1300 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1301 retval
[i
].last_trap
= states
[i
].last_trap
;
1302 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1303 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1304 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1311 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1315 for(i
=0; i
<n
; i
++) {
1316 g_array_free(states
[i
].mode_stack
, TRUE
);
1322 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1325 LttvIRQState
*retval
;
1327 retval
= g_new(LttvIRQState
, n
);
1329 for(i
=0; i
<n
; i
++) {
1330 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1331 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1332 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1333 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1340 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1344 for(i
=0; i
<n
; i
++) {
1345 g_array_free(states
[i
].mode_stack
, TRUE
);
1351 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1354 LttvSoftIRQState
*retval
;
1356 retval
= g_new(LttvSoftIRQState
, n
);
1358 for(i
=0; i
<n
; i
++) {
1359 retval
[i
].pending
= states
[i
].pending
;
1360 retval
[i
].running
= states
[i
].running
;
1366 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1371 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1374 LttvTrapState
*retval
;
1376 retval
= g_new(LttvTrapState
, n
);
1378 for(i
=0; i
<n
; i
++) {
1379 retval
[i
].running
= states
[i
].running
;
1385 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1390 /* bdevstate stuff */
1392 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1394 gint devcode_gint
= devcode
;
1395 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1397 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1398 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1400 gint
* key
= g_new(gint
, 1);
1402 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1410 static LttvBdevState
*bdevstate_new(void)
1412 LttvBdevState
*retval
;
1413 retval
= g_new(LttvBdevState
, 1);
1414 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1419 static void bdevstate_free(LttvBdevState
*bds
)
1421 g_array_free(bds
->mode_stack
, TRUE
);
1425 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1427 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1429 bdevstate_free(bds
);
1432 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1434 LttvBdevState
*retval
;
1436 retval
= bdevstate_new();
1437 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1442 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1444 //GHashTable *ht = (GHashTable *)u;
1445 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1446 LttvBdevState
*newbds
;
1448 newbds
= bdevstate_copy(bds
);
1450 g_hash_table_insert(u
, k
, newbds
);
1453 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1457 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1459 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1464 /* Free a hashtable and the LttvBdevState structures its values
1467 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1469 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1470 g_hash_table_destroy(ht
);
1473 /* The saved state for each trace contains a member "processes", which
1474 stores a copy of the process table, and a member "tracefiles" with
1475 one entry per tracefile. Each tracefile has a "process" member pointing
1476 to the current process and a "position" member storing the tracefile
1477 position (needed to seek to the current "next" event. */
1479 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1481 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1483 LttvTracefileState
*tfcs
;
1485 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1487 guint
*running_process
;
1489 LttvAttributeValue value
;
1491 LttEventPosition
*ep
;
1493 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1494 LTTV_STATE_TRACEFILES
);
1496 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1498 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1500 /* Add the currently running processes array */
1501 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1502 running_process
= g_new(guint
, nb_cpus
);
1503 for(i
=0;i
<nb_cpus
;i
++) {
1504 running_process
[i
] = self
->running_process
[i
]->pid
;
1506 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1508 *(value
.v_pointer
) = running_process
;
1510 g_info("State save");
1512 nb_tracefile
= self
->parent
.tracefiles
->len
;
1514 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1516 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1517 LttvTracefileContext
*, i
));
1518 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1519 value
= lttv_attribute_add(tracefiles_tree
, i
,
1521 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1523 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1525 *(value
.v_uint
) = tfcs
->process
->pid
;
1527 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1529 /* Only save the position if the tfs has not infinite time. */
1530 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1531 // && current_tfcs != tfcs) {
1532 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1533 *(value
.v_pointer
) = NULL
;
1535 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1536 ep
= ltt_event_position_new();
1537 ltt_event_position(e
, ep
);
1538 *(value
.v_pointer
) = ep
;
1540 guint nb_block
, offset
;
1543 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1544 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
, offset
,
1546 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1550 /* save the cpu state */
1552 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1554 *(value
.v_uint
) = nb_cpus
;
1556 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1558 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1561 /* save the irq state */
1562 nb_irqs
= self
->nb_irqs
;
1564 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1566 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1569 /* save the soft irq state */
1570 nb_soft_irqs
= self
->nb_soft_irqs
;
1572 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1574 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1577 /* save the trap state */
1578 nb_traps
= self
->nb_traps
;
1580 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1582 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1585 /* save the blkdev states */
1586 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1588 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1592 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1594 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1596 LttvTracefileState
*tfcs
;
1598 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1600 guint
*running_process
;
1602 LttvAttributeType type
;
1604 LttvAttributeValue value
;
1606 LttvAttributeName name
;
1610 LttEventPosition
*ep
;
1612 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1614 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1615 LTTV_STATE_TRACEFILES
);
1617 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1619 g_assert(type
== LTTV_POINTER
);
1620 lttv_state_free_process_table(self
->processes
);
1621 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1623 /* Add the currently running processes array */
1624 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1625 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1627 g_assert(type
== LTTV_POINTER
);
1628 running_process
= *(value
.v_pointer
);
1629 for(i
=0;i
<nb_cpus
;i
++) {
1630 pid
= running_process
[i
];
1631 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1632 g_assert(self
->running_process
[i
] != NULL
);
1635 nb_tracefile
= self
->parent
.tracefiles
->len
;
1637 //g_tree_destroy(tsc->pqueue);
1638 //tsc->pqueue = g_tree_new(compare_tracefile);
1640 /* restore cpu resource states */
1641 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1642 g_assert(type
== LTTV_POINTER
);
1643 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1644 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1646 /* restore irq resource states */
1647 nb_irqs
= self
->nb_irqs
;
1648 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1649 g_assert(type
== LTTV_POINTER
);
1650 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1651 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1653 /* restore soft irq resource states */
1654 nb_soft_irqs
= self
->nb_soft_irqs
;
1655 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1656 g_assert(type
== LTTV_POINTER
);
1657 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1658 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1660 /* restore trap resource states */
1661 nb_traps
= self
->nb_traps
;
1662 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1663 g_assert(type
== LTTV_POINTER
);
1664 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1665 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1667 /* restore the blkdev states */
1668 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1669 g_assert(type
== LTTV_POINTER
);
1670 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1671 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1673 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1675 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1676 LttvTracefileContext
*, i
));
1677 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1678 g_assert(type
== LTTV_GOBJECT
);
1679 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1681 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1683 g_assert(type
== LTTV_UINT
);
1684 pid
= *(value
.v_uint
);
1685 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1687 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1689 g_assert(type
== LTTV_POINTER
);
1690 //g_assert(*(value.v_pointer) != NULL);
1691 ep
= *(value
.v_pointer
);
1692 g_assert(tfcs
->parent
.t_context
!= NULL
);
1694 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1696 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1697 g_tree_remove(tsc
->pqueue
, tfc
);
1700 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1701 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1702 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1703 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1704 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1706 tfc
->timestamp
= ltt_time_infinite
;
1712 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1714 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1716 LttvTracefileState
*tfcs
;
1718 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1720 guint
*running_process
;
1722 LttvAttributeType type
;
1724 LttvAttributeValue value
;
1726 LttvAttributeName name
;
1730 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1731 LTTV_STATE_TRACEFILES
);
1732 g_object_ref(G_OBJECT(tracefiles_tree
));
1733 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1735 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1737 g_assert(type
== LTTV_POINTER
);
1738 lttv_state_free_process_table(*(value
.v_pointer
));
1739 *(value
.v_pointer
) = NULL
;
1740 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1742 /* Free running processes array */
1743 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1745 g_assert(type
== LTTV_POINTER
);
1746 running_process
= *(value
.v_pointer
);
1747 g_free(running_process
);
1749 /* free cpu resource states */
1750 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1751 g_assert(type
== LTTV_UINT
);
1752 nb_cpus
= *value
.v_uint
;
1753 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1754 g_assert(type
== LTTV_POINTER
);
1755 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1757 /* free irq resource states */
1758 nb_irqs
= self
->nb_irqs
;
1759 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1760 g_assert(type
== LTTV_POINTER
);
1761 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1763 /* free softirq resource states */
1764 nb_softirqs
= self
->nb_irqs
;
1765 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1766 g_assert(type
== LTTV_POINTER
);
1767 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1769 /* free the blkdev states */
1770 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1771 g_assert(type
== LTTV_POINTER
);
1772 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1774 nb_tracefile
= self
->parent
.tracefiles
->len
;
1776 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1778 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1779 LttvTracefileContext
*, i
));
1780 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1781 g_assert(type
== LTTV_GOBJECT
);
1782 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1784 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1786 g_assert(type
== LTTV_POINTER
);
1787 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1789 g_object_unref(G_OBJECT(tracefiles_tree
));
1793 static void free_saved_state(LttvTraceState
*self
)
1797 LttvAttributeType type
;
1799 LttvAttributeValue value
;
1801 LttvAttributeName name
;
1805 LttvAttribute
*saved_states
;
1807 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1808 LTTV_STATE_SAVED_STATES
);
1810 nb
= lttv_attribute_get_number(saved_states
);
1811 for(i
= 0 ; i
< nb
; i
++) {
1812 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1813 g_assert(type
== LTTV_GOBJECT
);
1814 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1817 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1822 create_max_time(LttvTraceState
*tcs
)
1824 LttvAttributeValue v
;
1826 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1828 g_assert(*(v
.v_pointer
) == NULL
);
1829 *(v
.v_pointer
) = g_new(LttTime
,1);
1830 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1835 get_max_time(LttvTraceState
*tcs
)
1837 LttvAttributeValue v
;
1839 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1841 g_assert(*(v
.v_pointer
) != NULL
);
1842 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1847 free_max_time(LttvTraceState
*tcs
)
1849 LttvAttributeValue v
;
1851 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1853 g_free(*(v
.v_pointer
));
1854 *(v
.v_pointer
) = NULL
;
1858 typedef struct _LttvNameTables
{
1859 // FIXME GQuark *eventtype_names;
1860 GQuark
*syscall_names
;
1866 GQuark
*soft_irq_names
;
1872 create_name_tables(LttvTraceState
*tcs
)
1876 GString
*fe_name
= g_string_new("");
1878 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1880 LttvAttributeValue v
;
1884 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1886 g_assert(*(v
.v_pointer
) == NULL
);
1887 *(v
.v_pointer
) = name_tables
;
1889 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1891 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1893 LTT_EVENT_SYSCALL_ENTRY
,
1894 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1895 NULL
, NULL
, &hooks
)) {
1897 // th = lttv_trace_hook_get_first(&th);
1899 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1900 // nb = ltt_type_element_number(t);
1902 // name_tables->syscall_names = g_new(GQuark, nb);
1903 // name_tables->nb_syscalls = nb;
1905 // for(i = 0 ; i < nb ; i++) {
1906 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1907 // if(!name_tables->syscall_names[i]) {
1908 // GString *string = g_string_new("");
1909 // g_string_printf(string, "syscall %u", i);
1910 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1911 // g_string_free(string, TRUE);
1915 name_tables
->nb_syscalls
= 256;
1916 name_tables
->syscall_names
= g_new(GQuark
, 256);
1917 for(i
= 0 ; i
< 256 ; i
++) {
1918 g_string_printf(fe_name
, "syscall %d", i
);
1919 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1922 name_tables
->syscall_names
= NULL
;
1923 name_tables
->nb_syscalls
= 0;
1925 lttv_trace_hook_remove_all(&hooks
);
1927 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1929 LTT_EVENT_TRAP_ENTRY
,
1930 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1931 NULL
, NULL
, &hooks
)) {
1933 // th = lttv_trace_hook_get_first(&th);
1935 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1936 // //nb = ltt_type_element_number(t);
1938 // name_tables->trap_names = g_new(GQuark, nb);
1939 // for(i = 0 ; i < nb ; i++) {
1940 // name_tables->trap_names[i] = g_quark_from_string(
1941 // ltt_enum_string_get(t, i));
1944 name_tables
->nb_traps
= 256;
1945 name_tables
->trap_names
= g_new(GQuark
, 256);
1946 for(i
= 0 ; i
< 256 ; i
++) {
1947 g_string_printf(fe_name
, "trap %d", i
);
1948 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1951 name_tables
->trap_names
= NULL
;
1952 name_tables
->nb_traps
= 0;
1954 lttv_trace_hook_remove_all(&hooks
);
1956 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1958 LTT_EVENT_IRQ_ENTRY
,
1959 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1960 NULL
, NULL
, &hooks
)) {
1963 name_tables->irq_names = g_new(GQuark, nb);
1964 for(i = 0 ; i < nb ; i++) {
1965 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1969 name_tables
->nb_irqs
= 256;
1970 name_tables
->irq_names
= g_new(GQuark
, 256);
1971 for(i
= 0 ; i
< 256 ; i
++) {
1972 g_string_printf(fe_name
, "irq %d", i
);
1973 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1976 name_tables
->nb_irqs
= 0;
1977 name_tables
->irq_names
= NULL
;
1979 lttv_trace_hook_remove_all(&hooks
);
1981 name_tables->soft_irq_names = g_new(GQuark, nb);
1982 for(i = 0 ; i < nb ; i++) {
1983 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1987 /* the kernel is limited to 32 statically defined softirqs */
1988 name_tables
->nb_softirqs
= 32;
1989 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1990 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1991 g_string_printf(fe_name
, "softirq %d", i
);
1992 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1994 g_array_free(hooks
, TRUE
);
1996 g_string_free(fe_name
, TRUE
);
2001 get_name_tables(LttvTraceState
*tcs
)
2003 LttvNameTables
*name_tables
;
2005 LttvAttributeValue v
;
2007 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2009 g_assert(*(v
.v_pointer
) != NULL
);
2010 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2011 //tcs->eventtype_names = name_tables->eventtype_names;
2012 tcs
->syscall_names
= name_tables
->syscall_names
;
2013 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2014 tcs
->trap_names
= name_tables
->trap_names
;
2015 tcs
->nb_traps
= name_tables
->nb_traps
;
2016 tcs
->irq_names
= name_tables
->irq_names
;
2017 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2018 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2019 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2024 free_name_tables(LttvTraceState
*tcs
)
2026 LttvNameTables
*name_tables
;
2028 LttvAttributeValue v
;
2030 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2032 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2033 *(v
.v_pointer
) = NULL
;
2035 // g_free(name_tables->eventtype_names);
2036 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2037 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2038 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2039 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2040 if(name_tables
) g_free(name_tables
);
2043 #ifdef HASH_TABLE_DEBUG
2045 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2047 LttvProcessState
*process
= (LttvProcessState
*)value
;
2049 /* Test for process corruption */
2050 guint stack_len
= process
->execution_stack
->len
;
2053 static void hash_table_check(GHashTable
*table
)
2055 g_hash_table_foreach(table
, test_process
, NULL
);
2061 /* clears the stack and sets the state passed as argument */
2062 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2064 g_array_set_size(cpust
->mode_stack
, 1);
2065 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2068 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2070 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2071 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2074 static void cpu_pop_mode(LttvCPUState
*cpust
)
2076 if(cpust
->mode_stack
->len
<= 1)
2077 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2079 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2082 /* clears the stack and sets the state passed as argument */
2083 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2085 g_array_set_size(bdevst
->mode_stack
, 1);
2086 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2089 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2091 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2092 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2095 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2097 if(bdevst
->mode_stack
->len
<= 1)
2098 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2100 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2103 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2105 g_array_set_size(irqst
->mode_stack
, 1);
2106 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2109 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2111 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2112 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2115 static void irq_pop_mode(LttvIRQState
*irqst
)
2117 if(irqst
->mode_stack
->len
<= 1)
2118 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2120 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2123 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2126 LttvExecutionState
*es
;
2128 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2129 guint cpu
= tfs
->cpu
;
2131 #ifdef HASH_TABLE_DEBUG
2132 hash_table_check(ts
->processes
);
2134 LttvProcessState
*process
= ts
->running_process
[cpu
];
2136 guint depth
= process
->execution_stack
->len
;
2138 process
->execution_stack
=
2139 g_array_set_size(process
->execution_stack
, depth
+ 1);
2142 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2144 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2147 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2148 es
->cum_cpu_time
= ltt_time_zero
;
2149 es
->s
= process
->state
->s
;
2150 process
->state
= es
;
2154 * return 1 when empty, else 0 */
2155 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2156 LttvTracefileState
*tfs
)
2158 guint depth
= process
->execution_stack
->len
;
2164 process
->execution_stack
=
2165 g_array_set_size(process
->execution_stack
, depth
- 1);
2166 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2168 process
->state
->change
= tfs
->parent
.timestamp
;
2173 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2175 guint cpu
= tfs
->cpu
;
2176 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2177 LttvProcessState
*process
= ts
->running_process
[cpu
];
2179 guint depth
= process
->execution_stack
->len
;
2181 if(process
->state
->t
!= t
){
2182 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2183 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2184 g_info("process state has %s when pop_int is %s\n",
2185 g_quark_to_string(process
->state
->t
),
2186 g_quark_to_string(t
));
2187 g_info("{ %u, %u, %s, %s, %s }\n",
2190 g_quark_to_string(process
->name
),
2191 g_quark_to_string(process
->brand
),
2192 g_quark_to_string(process
->state
->s
));
2197 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2198 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2202 process
->execution_stack
=
2203 g_array_set_size(process
->execution_stack
, depth
- 1);
2204 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2206 process
->state
->change
= tfs
->parent
.timestamp
;
2209 struct search_result
{
2210 const LttTime
*time
; /* Requested time */
2211 LttTime
*best
; /* Best result */
2214 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2216 const LttTime
*elem_time
= (const LttTime
*)a
;
2217 /* Explicit non const cast */
2218 struct search_result
*res
= (struct search_result
*)b
;
2220 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2221 /* The usertrace was created before the schedchange */
2222 /* Get larger keys */
2224 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2225 /* The usertrace was created after the schedchange time */
2226 /* Get smaller keys */
2228 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2229 res
->best
= (LttTime
*)elem_time
;
2232 res
->best
= (LttTime
*)elem_time
;
2239 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2240 guint pid
, const LttTime
*timestamp
)
2242 LttvTracefileState
*tfs
= NULL
;
2243 struct search_result res
;
2244 /* Find the usertrace associated with a pid and time interval.
2245 * Search in the usertraces by PID (within a hash) and then, for each
2246 * corresponding element of the array, find the first one with creation
2247 * timestamp the lowest, but higher or equal to "timestamp". */
2248 res
.time
= timestamp
;
2250 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2251 GUINT_TO_POINTER(pid
));
2252 if(usertrace_tree
) {
2253 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2255 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2263 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2264 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2266 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2268 LttvExecutionState
*es
;
2273 process
->tgid
= tgid
;
2275 process
->name
= name
;
2276 process
->brand
= LTTV_STATE_UNBRANDED
;
2277 //process->last_cpu = tfs->cpu_name;
2278 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2279 process
->type
= LTTV_STATE_USER_THREAD
;
2280 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2281 process
->current_function
= 0; //function 0x0 by default.
2283 g_info("Process %u, core %p", process
->pid
, process
);
2284 g_hash_table_insert(tcs
->processes
, process
, process
);
2287 process
->ppid
= parent
->pid
;
2288 process
->creation_time
= *timestamp
;
2291 /* No parent. This process exists but we are missing all information about
2292 its creation. The birth time is set to zero but we remember the time of
2297 process
->creation_time
= ltt_time_zero
;
2300 process
->insertion_time
= *timestamp
;
2301 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2302 process
->creation_time
.tv_nsec
);
2303 process
->pid_time
= g_quark_from_string(buffer
);
2305 process
->free_events
= 0;
2306 //process->last_cpu = tfs->cpu_name;
2307 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2308 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2309 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2310 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2311 es
= process
->state
= &g_array_index(process
->execution_stack
,
2312 LttvExecutionState
, 0);
2313 es
->t
= LTTV_STATE_USER_MODE
;
2314 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2315 es
->entry
= *timestamp
;
2316 //g_assert(timestamp->tv_sec != 0);
2317 es
->change
= *timestamp
;
2318 es
->cum_cpu_time
= ltt_time_zero
;
2319 es
->s
= LTTV_STATE_RUN
;
2321 es
= process
->state
= &g_array_index(process
->execution_stack
,
2322 LttvExecutionState
, 1);
2323 es
->t
= LTTV_STATE_SYSCALL
;
2324 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2325 es
->entry
= *timestamp
;
2326 //g_assert(timestamp->tv_sec != 0);
2327 es
->change
= *timestamp
;
2328 es
->cum_cpu_time
= ltt_time_zero
;
2329 es
->s
= LTTV_STATE_WAIT_FORK
;
2331 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2332 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2333 sizeof(guint64
), 0);
2338 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2341 LttvProcessState key
;
2342 LttvProcessState
*process
;
2346 process
= g_hash_table_lookup(ts
->processes
, &key
);
2351 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2352 const LttTime
*timestamp
)
2354 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2355 LttvExecutionState
*es
;
2357 /* Put ltt_time_zero creation time for unexisting processes */
2358 if(unlikely(process
== NULL
)) {
2359 process
= lttv_state_create_process(ts
,
2360 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2361 /* We are not sure is it's a kernel thread or normal thread, put the
2362 * bottom stack state to unknown */
2363 process
->execution_stack
=
2364 g_array_set_size(process
->execution_stack
, 1);
2365 process
->state
= es
=
2366 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2367 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2368 es
->s
= LTTV_STATE_UNNAMED
;
2373 /* FIXME : this function should be called when we receive an event telling that
2374 * release_task has been called in the kernel. In happens generally when
2375 * the parent waits for its child terminaison, but may also happen in special
2376 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2377 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2378 * of a killed thread group, but isn't the leader.
2380 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2382 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2383 LttvProcessState key
;
2385 /* Wait for both schedule with exit dead and process free to happen.
2386 * They can happen in any order. */
2387 if (++(process
->free_events
) < 2)
2390 key
.pid
= process
->pid
;
2391 key
.cpu
= process
->cpu
;
2392 g_hash_table_remove(ts
->processes
, &key
);
2393 g_array_free(process
->execution_stack
, TRUE
);
2394 g_array_free(process
->user_stack
, TRUE
);
2400 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2402 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2403 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2408 static void lttv_state_free_process_table(GHashTable
*processes
)
2410 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2411 g_hash_table_destroy(processes
);
2415 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2417 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2419 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2420 LttvProcessState
*process
= ts
->running_process
[cpu
];
2421 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2422 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2423 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2424 LttvExecutionSubmode submode
;
2426 guint syscall
= ltt_event_get_unsigned(e
, f
);
2427 expand_syscall_table(ts
, syscall
);
2428 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2429 /* There can be no system call from PID 0 : unknown state */
2430 if(process
->pid
!= 0)
2431 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2436 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2438 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2440 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2441 LttvProcessState
*process
= ts
->running_process
[cpu
];
2443 /* There can be no system call from PID 0 : unknown state */
2444 if(process
->pid
!= 0)
2445 pop_state(s
, LTTV_STATE_SYSCALL
);
2450 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2452 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2453 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2454 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2455 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2456 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2458 LttvExecutionSubmode submode
;
2460 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2462 expand_trap_table(ts
, trap
);
2464 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2466 push_state(s
, LTTV_STATE_TRAP
, submode
);
2468 /* update cpu status */
2469 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2471 /* update trap status */
2472 s
->cpu_state
->last_trap
= trap
;
2473 ts
->trap_states
[trap
].running
++;
2478 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2480 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2481 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2482 gint trap
= s
->cpu_state
->last_trap
;
2484 pop_state(s
, LTTV_STATE_TRAP
);
2486 /* update cpu status */
2487 cpu_pop_mode(s
->cpu_state
);
2489 /* update trap status */
2491 if(ts
->trap_states
[trap
].running
)
2492 ts
->trap_states
[trap
].running
--;
2497 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2499 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2500 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2501 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2502 //guint8 ev_id = ltt_event_eventtype_id(e);
2503 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2504 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2506 LttvExecutionSubmode submode
;
2507 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2509 expand_irq_table(ts
, irq
);
2511 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2513 /* Do something with the info about being in user or system mode when int? */
2514 push_state(s
, LTTV_STATE_IRQ
, submode
);
2516 /* update cpu status */
2517 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2519 /* update irq status */
2520 s
->cpu_state
->last_irq
= irq
;
2521 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2526 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2528 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2529 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2530 gint softirq
= s
->cpu_state
->last_soft_irq
;
2532 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2534 /* update softirq status */
2536 if(ts
->soft_irq_states
[softirq
].running
)
2537 ts
->soft_irq_states
[softirq
].running
--;
2539 /* update cpu status */
2540 cpu_pop_mode(s
->cpu_state
);
2545 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2547 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2548 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2550 pop_state(s
, LTTV_STATE_IRQ
);
2552 /* update cpu status */
2553 cpu_pop_mode(s
->cpu_state
);
2555 /* update irq status */
2556 if (s
->cpu_state
->last_irq
!= -1)
2557 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2562 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2564 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2565 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2566 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2567 //guint8 ev_id = ltt_event_eventtype_id(e);
2568 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2569 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2571 LttvExecutionSubmode submode
;
2572 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2573 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2575 if(softirq
< nb_softirqs
) {
2576 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2578 /* Fixup an incomplete irq table */
2579 GString
*string
= g_string_new("");
2580 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2581 submode
= g_quark_from_string(string
->str
);
2582 g_string_free(string
, TRUE
);
2585 /* update softirq status */
2586 /* a soft irq raises are not cumulative */
2587 ts
->soft_irq_states
[softirq
].pending
=1;
2592 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2594 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2595 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2596 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2597 //guint8 ev_id = ltt_event_eventtype_id(e);
2598 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2599 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2600 LttvExecutionSubmode submode
;
2601 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2602 expand_soft_irq_table(ts
, softirq
);
2603 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2605 /* Do something with the info about being in user or system mode when int? */
2606 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2608 /* update cpu status */
2609 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2611 /* update softirq status */
2612 s
->cpu_state
->last_soft_irq
= softirq
;
2613 if(ts
->soft_irq_states
[softirq
].pending
)
2614 ts
->soft_irq_states
[softirq
].pending
--;
2615 ts
->soft_irq_states
[softirq
].running
++;
2620 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2622 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2623 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2624 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2625 //guint8 ev_id = ltt_event_eventtype_id(e);
2626 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2628 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2629 lttv_trace_get_hook_field(th
, 0)));
2630 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2632 expand_irq_table(ts
, irq
);
2633 ts
->irq_names
[irq
] = action
;
2639 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2641 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2642 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2643 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2644 //guint8 ev_id = ltt_event_eventtype_id(e);
2645 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2647 guint major
= ltt_event_get_long_unsigned(e
,
2648 lttv_trace_get_hook_field(th
, 0));
2649 guint minor
= ltt_event_get_long_unsigned(e
,
2650 lttv_trace_get_hook_field(th
, 1));
2651 guint oper
= ltt_event_get_long_unsigned(e
,
2652 lttv_trace_get_hook_field(th
, 2));
2653 guint16 devcode
= MKDEV(major
,minor
);
2655 /* have we seen this block device before? */
2656 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2659 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2661 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2666 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2668 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2669 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2670 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2671 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2673 guint major
= ltt_event_get_long_unsigned(e
,
2674 lttv_trace_get_hook_field(th
, 0));
2675 guint minor
= ltt_event_get_long_unsigned(e
,
2676 lttv_trace_get_hook_field(th
, 1));
2677 //guint oper = ltt_event_get_long_unsigned(e,
2678 // lttv_trace_get_hook_field(th, 2));
2679 guint16 devcode
= MKDEV(major
,minor
);
2681 /* have we seen this block device before? */
2682 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2684 /* update block device */
2685 bdev_pop_mode(bdev
);
2690 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2694 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2695 guint cpu
= tfs
->cpu
;
2696 LttvProcessState
*process
= ts
->running_process
[cpu
];
2698 guint depth
= process
->user_stack
->len
;
2700 process
->user_stack
=
2701 g_array_set_size(process
->user_stack
, depth
+ 1);
2703 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2704 *new_func
= funcptr
;
2705 process
->current_function
= funcptr
;
2708 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2710 guint cpu
= tfs
->cpu
;
2711 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2712 LttvProcessState
*process
= ts
->running_process
[cpu
];
2714 if(process
->current_function
!= funcptr
){
2715 g_info("Different functions (%lu.%09lu): ignore it\n",
2716 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2717 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2718 process
->current_function
, funcptr
);
2719 g_info("{ %u, %u, %s, %s, %s }\n",
2722 g_quark_to_string(process
->name
),
2723 g_quark_to_string(process
->brand
),
2724 g_quark_to_string(process
->state
->s
));
2727 guint depth
= process
->user_stack
->len
;
2730 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2731 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2735 process
->user_stack
=
2736 g_array_set_size(process
->user_stack
, depth
- 1);
2737 process
->current_function
=
2738 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2742 static gboolean
function_entry(void *hook_data
, void *call_data
)
2744 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2745 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2746 //guint8 ev_id = ltt_event_eventtype_id(e);
2747 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2748 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2749 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2751 push_function(s
, funcptr
);
2755 static gboolean
function_exit(void *hook_data
, void *call_data
)
2757 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2758 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2759 //guint8 ev_id = ltt_event_eventtype_id(e);
2760 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2761 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2762 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2764 pop_function(s
, funcptr
);
2768 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2770 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2771 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2772 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2773 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2778 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2779 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2780 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2782 expand_syscall_table(ts
, id
);
2783 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2788 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2790 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2791 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2792 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2793 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2798 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2799 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2800 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2802 expand_soft_irq_table(ts
, id
);
2803 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2808 static gboolean
schedchange(void *hook_data
, void *call_data
)
2810 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2812 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2813 LttvProcessState
*process
= ts
->running_process
[cpu
];
2814 //LttvProcessState *old_process = ts->running_process[cpu];
2816 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2817 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2818 guint pid_in
, pid_out
;
2821 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2822 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2823 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2825 if(likely(process
!= NULL
)) {
2827 /* We could not know but it was not the idle process executing.
2828 This should only happen at the beginning, before the first schedule
2829 event, and when the initial information (current process for each CPU)
2830 is missing. It is not obvious how we could, after the fact, compensate
2831 the wrongly attributed statistics. */
2833 //This test only makes sense once the state is known and if there is no
2834 //missing events. We need to silently ignore schedchange coming after a
2835 //process_free, or it causes glitches. (FIXME)
2836 //if(unlikely(process->pid != pid_out)) {
2837 // g_assert(process->pid == 0);
2839 if(process
->pid
== 0
2840 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2842 /* Scheduling out of pid 0 at beginning of the trace :
2843 * we know for sure it is in syscall mode at this point. */
2844 g_assert(process
->execution_stack
->len
== 1);
2845 process
->state
->t
= LTTV_STATE_SYSCALL
;
2846 process
->state
->s
= LTTV_STATE_WAIT
;
2847 process
->state
->change
= s
->parent
.timestamp
;
2848 process
->state
->entry
= s
->parent
.timestamp
;
2851 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2852 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2853 process
->state
->change
= s
->parent
.timestamp
;
2855 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2856 else process
->state
->s
= LTTV_STATE_WAIT
;
2857 process
->state
->change
= s
->parent
.timestamp
;
2860 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2861 /* see sched.h for states */
2862 if (!exit_process(s
, process
)) {
2863 process
->state
->s
= LTTV_STATE_DEAD
;
2864 process
->state
->change
= s
->parent
.timestamp
;
2869 process
= ts
->running_process
[cpu
] =
2870 lttv_state_find_process_or_create(
2871 (LttvTraceState
*)s
->parent
.t_context
,
2873 &s
->parent
.timestamp
);
2874 process
->state
->s
= LTTV_STATE_RUN
;
2876 if(process
->usertrace
)
2877 process
->usertrace
->cpu
= cpu
;
2878 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2879 process
->state
->change
= s
->parent
.timestamp
;
2881 /* update cpu status */
2883 /* going to idle task */
2884 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2886 /* scheduling a real task.
2887 * we must be careful here:
2888 * if we just schedule()'ed to a process that is
2889 * in a trap, we must put the cpu in trap mode
2891 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2892 if(process
->state
->t
== LTTV_STATE_TRAP
)
2893 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2899 static gboolean
process_fork(void *hook_data
, void *call_data
)
2901 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2902 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2903 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2905 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2906 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2907 //LttvProcessState *zombie_process;
2909 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2910 LttvProcessState
*process
= ts
->running_process
[cpu
];
2911 LttvProcessState
*child_process
;
2912 struct marker_field
*f
;
2915 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2918 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2919 s
->parent
.target_pid
= child_pid
;
2922 f
= lttv_trace_get_hook_field(th
, 2);
2924 child_tgid
= ltt_event_get_unsigned(e
, f
);
2928 /* Mathieu : it seems like the process might have been scheduled in before the
2929 * fork, and, in a rare case, might be the current process. This might happen
2930 * in a SMP case where we don't have enough precision on the clocks.
2932 * Test reenabled after precision fixes on time. (Mathieu) */
2934 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2936 if(unlikely(zombie_process
!= NULL
)) {
2937 /* Reutilisation of PID. Only now we are sure that the old PID
2938 * has been released. FIXME : should know when release_task happens instead.
2940 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2942 for(i
=0; i
< num_cpus
; i
++) {
2943 g_assert(zombie_process
!= ts
->running_process
[i
]);
2946 exit_process(s
, zombie_process
);
2949 g_assert(process
->pid
!= child_pid
);
2950 // FIXME : Add this test in the "known state" section
2951 // g_assert(process->pid == parent_pid);
2952 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2953 if(child_process
== NULL
) {
2954 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2955 child_pid
, child_tgid
,
2956 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2958 /* The process has already been created : due to time imprecision between
2959 * multiple CPUs : it has been scheduled in before creation. Note that we
2960 * shouldn't have this kind of imprecision.
2962 * Simply put a correct parent.
2964 g_error("Process %u has been created at [%lu.%09lu] "
2965 "and inserted at [%lu.%09lu] before \n"
2966 "fork on cpu %u[%lu.%09lu].\n"
2967 "Probably an unsynchronized TSC problem on the traced machine.",
2969 child_process
->creation_time
.tv_sec
,
2970 child_process
->creation_time
.tv_nsec
,
2971 child_process
->insertion_time
.tv_sec
,
2972 child_process
->insertion_time
.tv_nsec
,
2973 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
2974 //g_assert(0); /* This is a problematic case : the process has been created
2975 // before the fork event */
2976 child_process
->ppid
= process
->pid
;
2977 child_process
->tgid
= child_tgid
;
2979 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2980 child_process
->name
= process
->name
;
2981 child_process
->brand
= process
->brand
;
2986 /* We stamp a newly created process as kernel_thread.
2987 * The thread should not be running yet. */
2988 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2990 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2991 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2992 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2994 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2995 LttvProcessState
*process
;
2996 LttvExecutionState
*es
;
2999 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3000 s
->parent
.target_pid
= pid
;
3002 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3004 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3005 process
->execution_stack
=
3006 g_array_set_size(process
->execution_stack
, 1);
3007 es
= process
->state
=
3008 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3009 es
->t
= LTTV_STATE_SYSCALL
;
3011 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3016 static gboolean
process_exit(void *hook_data
, void *call_data
)
3018 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3019 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3020 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3022 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3023 LttvProcessState
*process
; // = ts->running_process[cpu];
3025 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3026 s
->parent
.target_pid
= pid
;
3028 // FIXME : Add this test in the "known state" section
3029 // g_assert(process->pid == pid);
3031 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3032 if(likely(process
!= NULL
)) {
3033 process
->state
->s
= LTTV_STATE_EXIT
;
3038 static gboolean
process_free(void *hook_data
, void *call_data
)
3040 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3041 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3042 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3043 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3045 LttvProcessState
*process
;
3047 /* PID of the process to release */
3048 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3049 s
->parent
.target_pid
= release_pid
;
3051 g_assert(release_pid
!= 0);
3053 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3054 if(likely(process
!= NULL
))
3055 exit_process(s
, process
);
3058 if(likely(process
!= NULL
)) {
3059 /* release_task is happening at kernel level : we can now safely release
3060 * the data structure of the process */
3061 //This test is fun, though, as it may happen that
3062 //at time t : CPU 0 : process_free
3063 //at time t+150ns : CPU 1 : schedule out
3064 //Clearly due to time imprecision, we disable it. (Mathieu)
3065 //If this weird case happen, we have no choice but to put the
3066 //Currently running process on the cpu to 0.
3067 //I re-enable it following time precision fixes. (Mathieu)
3068 //Well, in the case where an process is freed by a process on another CPU
3069 //and still scheduled, it happens that this is the schedchange that will
3070 //drop the last reference count. Do not free it here!
3071 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3073 for(i
=0; i
< num_cpus
; i
++) {
3074 //g_assert(process != ts->running_process[i]);
3075 if(process
== ts
->running_process
[i
]) {
3076 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3080 if(i
== num_cpus
) /* process is not scheduled */
3081 exit_process(s
, process
);
3088 static gboolean
process_exec(void *hook_data
, void *call_data
)
3090 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3091 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3092 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3093 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3096 LttvProcessState
*process
= ts
->running_process
[cpu
];
3098 #if 0//how to use a sequence that must be transformed in a string
3099 /* PID of the process to release */
3100 guint64 name_len
= ltt_event_field_element_number(e
,
3101 lttv_trace_get_hook_field(th
, 0));
3102 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3103 LttField
*child
= ltt_event_field_element_select(e
,
3104 lttv_trace_get_hook_field(th
, 0), 0);
3106 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3107 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3108 memcpy(null_term_name
, name_begin
, name_len
);
3109 null_term_name
[name_len
] = '\0';
3110 process
->name
= g_quark_from_string(null_term_name
);
3113 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3114 lttv_trace_get_hook_field(th
, 0)));
3115 process
->brand
= LTTV_STATE_UNBRANDED
;
3116 //g_free(null_term_name);
3120 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3122 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3123 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3124 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3125 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3128 LttvProcessState
*process
= ts
->running_process
[cpu
];
3130 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3131 process
->brand
= g_quark_from_string(name
);
3136 static void fix_process(gpointer key
, gpointer value
,
3139 LttvProcessState
*process
;
3140 LttvExecutionState
*es
;
3141 process
= (LttvProcessState
*)value
;
3142 LttTime
*timestamp
= (LttTime
*)user_data
;
3144 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3145 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3146 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3147 es
->t
= LTTV_STATE_SYSCALL
;
3148 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3149 es
->entry
= *timestamp
;
3150 es
->change
= *timestamp
;
3151 es
->cum_cpu_time
= ltt_time_zero
;
3152 if(es
->s
== LTTV_STATE_UNNAMED
)
3153 es
->s
= LTTV_STATE_WAIT
;
3156 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3157 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3158 es
->t
= LTTV_STATE_USER_MODE
;
3159 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3160 es
->entry
= *timestamp
;
3161 //g_assert(timestamp->tv_sec != 0);
3162 es
->change
= *timestamp
;
3163 es
->cum_cpu_time
= ltt_time_zero
;
3164 if(es
->s
== LTTV_STATE_UNNAMED
)
3165 es
->s
= LTTV_STATE_RUN
;
3167 if(process
->execution_stack
->len
== 1) {
3168 /* Still in bottom unknown mode, means never did a system call
3169 * May be either in user mode, syscall mode, running or waiting.*/
3170 /* FIXME : we may be tagging syscall mode when being user mode */
3171 process
->execution_stack
=
3172 g_array_set_size(process
->execution_stack
, 2);
3173 es
= process
->state
= &g_array_index(process
->execution_stack
,
3174 LttvExecutionState
, 1);
3175 es
->t
= LTTV_STATE_SYSCALL
;
3176 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3177 es
->entry
= *timestamp
;
3178 //g_assert(timestamp->tv_sec != 0);
3179 es
->change
= *timestamp
;
3180 es
->cum_cpu_time
= ltt_time_zero
;
3181 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3182 es
->s
= LTTV_STATE_WAIT
;
3188 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3190 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3191 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3192 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3193 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3194 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3196 /* For all processes */
3197 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3198 /* else, if stack[0] is unknown, set to user mode, running */
3200 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3205 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3207 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3208 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3209 //It's slow : optimise later by doing this before reading trace.
3210 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3216 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3217 LttvProcessState
*process
= ts
->running_process
[cpu
];
3218 LttvProcessState
*parent_process
;
3219 struct marker_field
*f
;
3220 GQuark type
, mode
, submode
, status
;
3221 LttvExecutionState
*es
;
3225 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3226 s
->parent
.target_pid
= pid
;
3229 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3232 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3235 f
= lttv_trace_get_hook_field(th
, 3);
3236 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3238 //FIXME: type is rarely used, enum must match possible types.
3241 f
= lttv_trace_get_hook_field(th
, 4);
3242 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3245 f
= lttv_trace_get_hook_field(th
, 5);
3246 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3249 f
= lttv_trace_get_hook_field(th
, 6);
3250 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3253 f
= lttv_trace_get_hook_field(th
, 7);
3255 tgid
= ltt_event_get_unsigned(e
, f
);
3260 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3261 for(i
=0; i
<nb_cpus
; i
++) {
3262 process
= lttv_state_find_process(ts
, i
, pid
);
3263 g_assert(process
!= NULL
);
3265 process
->ppid
= parent_pid
;
3266 process
->tgid
= tgid
;
3267 process
->name
= g_quark_from_string(command
);
3269 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3270 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3274 /* The process might exist if a process was forked while performing the
3276 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3277 if(process
== NULL
) {
3278 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3279 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3280 pid
, tgid
, g_quark_from_string(command
),
3281 &s
->parent
.timestamp
);
3283 /* Keep the stack bottom : a running user mode */
3284 /* Disabled because of inconsistencies in the current statedump states. */
3285 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3286 /* Only keep the bottom
3287 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3288 /* Will cause expected trap when in fact being syscall (even after end of
3290 * Will cause expected interrupt when being syscall. (only before end of
3291 * statedump event) */
3292 // This will cause a "popping last state on stack, ignoring it."
3293 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3294 es
= process
->state
= &g_array_index(process
->execution_stack
,
3295 LttvExecutionState
, 0);
3296 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3297 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3298 es
->s
= LTTV_STATE_UNNAMED
;
3299 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3301 es
->t
= LTTV_STATE_SYSCALL
;
3306 /* User space process :
3307 * bottom : user mode
3308 * either currently running or scheduled out.
3309 * can be scheduled out because interrupted in (user mode or in syscall)
3310 * or because of an explicit call to the scheduler in syscall. Note that
3311 * the scheduler call comes after the irq_exit, so never in interrupt
3313 // temp workaround : set size to 1 : only have user mode bottom of stack.
3314 // will cause g_info message of expected syscall mode when in fact being
3315 // in user mode. Can also cause expected trap when in fact being user
3316 // mode in the event of a page fault reenabling interrupts in the handler.
3317 // Expected syscall and trap can also happen after the end of statedump
3318 // This will cause a "popping last state on stack, ignoring it."
3319 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3320 es
= process
->state
= &g_array_index(process
->execution_stack
,
3321 LttvExecutionState
, 0);
3322 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3323 es
->s
= LTTV_STATE_UNNAMED
;
3324 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3326 es
->t
= LTTV_STATE_USER_MODE
;
3334 es
= process
->state
= &g_array_index(process
->execution_stack
,
3335 LttvExecutionState
, 1);
3336 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3337 es
->s
= LTTV_STATE_UNNAMED
;
3338 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3342 /* The process has already been created :
3343 * Probably was forked while dumping the process state or
3344 * was simply scheduled in prior to get the state dump event.
3346 process
->ppid
= parent_pid
;
3347 process
->tgid
= tgid
;
3348 process
->name
= g_quark_from_string(command
);
3349 process
->type
= type
;
3351 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3353 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3354 if(type
== LTTV_STATE_KERNEL_THREAD
)
3355 es
->t
= LTTV_STATE_SYSCALL
;
3357 es
->t
= LTTV_STATE_USER_MODE
;
3360 /* Don't mess around with the stack, it will eventually become
3361 * ok after the end of state dump. */
3368 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3370 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3372 lttv_state_add_event_hooks(tss
);
3377 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3379 LttvTraceset
*traceset
= self
->parent
.ts
;
3381 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3385 LttvTracefileState
*tfs
;
3391 LttvAttributeValue val
;
3393 nb_trace
= lttv_traceset_number(traceset
);
3394 for(i
= 0 ; i
< nb_trace
; i
++) {
3395 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3397 /* Find the eventtype id for the following events and register the
3398 associated by id hooks. */
3400 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3401 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3404 lttv_trace_find_hook(ts
->parent
.t
,
3406 LTT_EVENT_SYSCALL_ENTRY
,
3407 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3408 syscall_entry
, NULL
, &hooks
);
3410 lttv_trace_find_hook(ts
->parent
.t
,
3412 LTT_EVENT_SYSCALL_EXIT
,
3414 syscall_exit
, NULL
, &hooks
);
3416 lttv_trace_find_hook(ts
->parent
.t
,
3418 LTT_EVENT_TRAP_ENTRY
,
3419 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3420 trap_entry
, NULL
, &hooks
);
3422 lttv_trace_find_hook(ts
->parent
.t
,
3424 LTT_EVENT_TRAP_EXIT
,
3426 trap_exit
, NULL
, &hooks
);
3428 lttv_trace_find_hook(ts
->parent
.t
,
3430 LTT_EVENT_PAGE_FAULT_ENTRY
,
3431 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3432 trap_entry
, NULL
, &hooks
);
3434 lttv_trace_find_hook(ts
->parent
.t
,
3436 LTT_EVENT_PAGE_FAULT_EXIT
,
3438 trap_exit
, NULL
, &hooks
);
3440 lttv_trace_find_hook(ts
->parent
.t
,
3442 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3443 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3444 trap_entry
, NULL
, &hooks
);
3446 lttv_trace_find_hook(ts
->parent
.t
,
3448 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3450 trap_exit
, NULL
, &hooks
);
3452 lttv_trace_find_hook(ts
->parent
.t
,
3454 LTT_EVENT_IRQ_ENTRY
,
3455 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3456 irq_entry
, NULL
, &hooks
);
3458 lttv_trace_find_hook(ts
->parent
.t
,
3462 irq_exit
, NULL
, &hooks
);
3464 lttv_trace_find_hook(ts
->parent
.t
,
3466 LTT_EVENT_SOFT_IRQ_RAISE
,
3467 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3468 soft_irq_raise
, NULL
, &hooks
);
3470 lttv_trace_find_hook(ts
->parent
.t
,
3472 LTT_EVENT_SOFT_IRQ_ENTRY
,
3473 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3474 soft_irq_entry
, NULL
, &hooks
);
3476 lttv_trace_find_hook(ts
->parent
.t
,
3478 LTT_EVENT_SOFT_IRQ_EXIT
,
3480 soft_irq_exit
, NULL
, &hooks
);
3482 lttv_trace_find_hook(ts
->parent
.t
,
3484 LTT_EVENT_SCHED_SCHEDULE
,
3485 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3486 LTT_FIELD_PREV_STATE
),
3487 schedchange
, NULL
, &hooks
);
3489 lttv_trace_find_hook(ts
->parent
.t
,
3491 LTT_EVENT_PROCESS_FORK
,
3492 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3493 LTT_FIELD_CHILD_TGID
),
3494 process_fork
, NULL
, &hooks
);
3496 lttv_trace_find_hook(ts
->parent
.t
,
3498 LTT_EVENT_KTHREAD_CREATE
,
3499 FIELD_ARRAY(LTT_FIELD_PID
),
3500 process_kernel_thread
, NULL
, &hooks
);
3502 lttv_trace_find_hook(ts
->parent
.t
,
3504 LTT_EVENT_PROCESS_EXIT
,
3505 FIELD_ARRAY(LTT_FIELD_PID
),
3506 process_exit
, NULL
, &hooks
);
3508 lttv_trace_find_hook(ts
->parent
.t
,
3510 LTT_EVENT_PROCESS_FREE
,
3511 FIELD_ARRAY(LTT_FIELD_PID
),
3512 process_free
, NULL
, &hooks
);
3514 lttv_trace_find_hook(ts
->parent
.t
,
3517 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3518 process_exec
, NULL
, &hooks
);
3520 lttv_trace_find_hook(ts
->parent
.t
,
3521 LTT_CHANNEL_USERSPACE
,
3522 LTT_EVENT_THREAD_BRAND
,
3523 FIELD_ARRAY(LTT_FIELD_NAME
),
3524 thread_brand
, NULL
, &hooks
);
3526 /* statedump-related hooks */
3527 lttv_trace_find_hook(ts
->parent
.t
,
3528 LTT_CHANNEL_TASK_STATE
,
3529 LTT_EVENT_PROCESS_STATE
,
3530 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3531 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3532 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3533 enum_process_state
, NULL
, &hooks
);
3535 lttv_trace_find_hook(ts
->parent
.t
,
3536 LTT_CHANNEL_GLOBAL_STATE
,
3537 LTT_EVENT_STATEDUMP_END
,
3539 statedump_end
, NULL
, &hooks
);
3541 lttv_trace_find_hook(ts
->parent
.t
,
3542 LTT_CHANNEL_IRQ_STATE
,
3543 LTT_EVENT_LIST_INTERRUPT
,
3544 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3545 enum_interrupt
, NULL
, &hooks
);
3547 lttv_trace_find_hook(ts
->parent
.t
,
3549 LTT_EVENT_REQUEST_ISSUE
,
3550 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3551 bdev_request_issue
, NULL
, &hooks
);
3553 lttv_trace_find_hook(ts
->parent
.t
,
3555 LTT_EVENT_REQUEST_COMPLETE
,
3556 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3557 bdev_request_complete
, NULL
, &hooks
);
3559 lttv_trace_find_hook(ts
->parent
.t
,
3560 LTT_CHANNEL_USERSPACE
,
3561 LTT_EVENT_FUNCTION_ENTRY
,
3562 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3563 function_entry
, NULL
, &hooks
);
3565 lttv_trace_find_hook(ts
->parent
.t
,
3566 LTT_CHANNEL_USERSPACE
,
3567 LTT_EVENT_FUNCTION_EXIT
,
3568 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3569 function_exit
, NULL
, &hooks
);
3571 lttv_trace_find_hook(ts
->parent
.t
,
3572 LTT_CHANNEL_SYSCALL_STATE
,
3573 LTT_EVENT_SYS_CALL_TABLE
,
3574 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3575 dump_syscall
, NULL
, &hooks
);
3577 lttv_trace_find_hook(ts
->parent
.t
,
3578 LTT_CHANNEL_SOFTIRQ_STATE
,
3579 LTT_EVENT_SOFTIRQ_VEC
,
3580 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3581 dump_softirq
, NULL
, &hooks
);
3583 /* Add these hooks to each event_by_id hooks list */
3585 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3587 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3589 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3590 LttvTracefileContext
*, j
));
3592 for(k
= 0 ; k
< hooks
->len
; k
++) {
3593 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3594 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3596 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3602 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3603 *(val
.v_pointer
) = hooks
;
3607 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3609 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3611 lttv_state_remove_event_hooks(tss
);
3616 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3618 LttvTraceset
*traceset
= self
->parent
.ts
;
3620 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3624 LttvTracefileState
*tfs
;
3630 LttvAttributeValue val
;
3632 nb_trace
= lttv_traceset_number(traceset
);
3633 for(i
= 0 ; i
< nb_trace
; i
++) {
3634 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3636 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3637 hooks
= *(val
.v_pointer
);
3639 /* Remove these hooks from each event_by_id hooks list */
3641 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3643 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3645 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3646 LttvTracefileContext
*, j
));
3648 for(k
= 0 ; k
< hooks
->len
; k
++) {
3649 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3650 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3651 lttv_hooks_remove_data(
3652 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3657 lttv_trace_hook_remove_all(&hooks
);
3658 g_array_free(hooks
, TRUE
);
3662 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3664 guint
*event_count
= (guint
*)hook_data
;
3666 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3667 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3672 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3674 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3676 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3678 LttvAttributeValue value
;
3680 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3681 LTTV_STATE_SAVED_STATES
);
3682 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3683 value
= lttv_attribute_add(saved_states_tree
,
3684 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3685 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3686 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3687 *(value
.v_time
) = self
->parent
.timestamp
;
3688 lttv_state_save(tcs
, saved_state_tree
);
3689 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3690 self
->parent
.timestamp
.tv_nsec
);
3692 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3697 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3699 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3701 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3706 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3714 static gboolean
block_start(void *hook_data
, void *call_data
)
3716 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3718 LttvTracefileState
*tfcs
;
3720 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3722 LttEventPosition
*ep
;
3724 guint i
, nb_block
, nb_event
, nb_tracefile
;
3728 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3730 LttvAttributeValue value
;
3732 ep
= ltt_event_position_new();
3734 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3736 /* Count the number of events added since the last block end in any
3739 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3741 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3742 LttvTracefileContext
, i
));
3743 ltt_event_position(tfcs
->parent
.e
, ep
);
3744 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3745 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3746 tfcs
->saved_position
= nb_event
;
3750 if(tcs
->nb_event
>= tcs
->save_interval
) {
3751 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3752 LTTV_STATE_SAVED_STATES
);
3753 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3754 value
= lttv_attribute_add(saved_states_tree
,
3755 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3756 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3757 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3758 *(value
.v_time
) = self
->parent
.timestamp
;
3759 lttv_state_save(tcs
, saved_state_tree
);
3761 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3762 self
->parent
.timestamp
.tv_nsec
);
3764 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3770 static gboolean
block_end(void *hook_data
, void *call_data
)
3772 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3774 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3778 LttEventPosition
*ep
;
3780 guint nb_block
, nb_event
;
3782 ep
= ltt_event_position_new();
3783 ltt_event_position(self
->parent
.e
, ep
);
3784 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3785 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3786 self
->saved_position
= 0;
3787 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3794 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3796 LttvTraceset
*traceset
= self
->parent
.ts
;
3798 guint i
, j
, nb_trace
, nb_tracefile
;
3802 LttvTracefileState
*tfs
;
3804 LttvTraceHook hook_start
, hook_end
;
3806 nb_trace
= lttv_traceset_number(traceset
);
3807 for(i
= 0 ; i
< nb_trace
; i
++) {
3808 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3810 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3811 NULL
, NULL
, block_start
, &hook_start
);
3812 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3813 NULL
, NULL
, block_end
, &hook_end
);
3815 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3817 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3819 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3820 LttvTracefileContext
, j
));
3821 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3822 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3823 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3824 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3830 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3832 LttvTraceset
*traceset
= self
->parent
.ts
;
3834 guint i
, j
, nb_trace
, nb_tracefile
;
3838 LttvTracefileState
*tfs
;
3841 nb_trace
= lttv_traceset_number(traceset
);
3842 for(i
= 0 ; i
< nb_trace
; i
++) {
3844 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3845 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3847 if(ts
->has_precomputed_states
) continue;
3849 guint
*event_count
= g_new(guint
, 1);
3852 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3854 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3855 LttvTracefileContext
*, j
));
3856 lttv_hooks_add(tfs
->parent
.event
,
3857 state_save_event_hook
,
3864 lttv_process_traceset_begin(&self
->parent
,
3865 NULL
, NULL
, NULL
, NULL
, NULL
);
3869 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3871 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3873 lttv_state_save_add_event_hooks(tss
);
3880 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3882 LttvTraceset
*traceset
= self
->parent
.ts
;
3884 guint i
, j
, nb_trace
, nb_tracefile
;
3888 LttvTracefileState
*tfs
;
3890 LttvTraceHook hook_start
, hook_end
;
3892 nb_trace
= lttv_traceset_number(traceset
);
3893 for(i
= 0 ; i
< nb_trace
; i
++) {
3894 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3896 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3897 NULL
, NULL
, block_start
, &hook_start
);
3899 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3900 NULL
, NULL
, block_end
, &hook_end
);
3902 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3904 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3906 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3907 LttvTracefileContext
, j
));
3908 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3909 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3910 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3911 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3917 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3919 LttvTraceset
*traceset
= self
->parent
.ts
;
3921 guint i
, j
, nb_trace
, nb_tracefile
;
3925 LttvTracefileState
*tfs
;
3927 LttvHooks
*after_trace
= lttv_hooks_new();
3929 lttv_hooks_add(after_trace
,
3930 state_save_after_trace_hook
,
3935 lttv_process_traceset_end(&self
->parent
,
3936 NULL
, after_trace
, NULL
, NULL
, NULL
);
3938 lttv_hooks_destroy(after_trace
);
3940 nb_trace
= lttv_traceset_number(traceset
);
3941 for(i
= 0 ; i
< nb_trace
; i
++) {
3943 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3944 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3946 if(ts
->has_precomputed_states
) continue;
3948 guint
*event_count
= NULL
;
3950 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3952 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3953 LttvTracefileContext
*, j
));
3954 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3955 state_save_event_hook
);
3957 if(event_count
) g_free(event_count
);
3961 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3963 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3965 lttv_state_save_remove_event_hooks(tss
);
3970 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3972 LttvTraceset
*traceset
= self
->parent
.ts
;
3976 int min_pos
, mid_pos
, max_pos
;
3978 guint call_rest
= 0;
3980 LttvTraceState
*tcs
;
3982 LttvAttributeValue value
;
3984 LttvAttributeType type
;
3986 LttvAttributeName name
;
3990 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
3992 //g_tree_destroy(self->parent.pqueue);
3993 //self->parent.pqueue = g_tree_new(compare_tracefile);
3995 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3997 nb_trace
= lttv_traceset_number(traceset
);
3998 for(i
= 0 ; i
< nb_trace
; i
++) {
3999 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4001 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4002 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4003 LTTV_STATE_SAVED_STATES
);
4006 if(saved_states_tree
) {
4007 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4008 mid_pos
= max_pos
/ 2;
4009 while(min_pos
< max_pos
) {
4010 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
4012 g_assert(type
== LTTV_GOBJECT
);
4013 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4014 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
4016 g_assert(type
== LTTV_TIME
);
4017 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4019 closest_tree
= saved_state_tree
;
4021 else max_pos
= mid_pos
- 1;
4023 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4027 /* restore the closest earlier saved state */
4029 lttv_state_restore(tcs
, closest_tree
);
4033 /* There is no saved state, yet we want to have it. Restart at T0 */
4035 restore_init_state(tcs
);
4036 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4039 /* We want to seek quickly without restoring/updating the state */
4041 restore_init_state(tcs
);
4042 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4045 if(!call_rest
) g_info("NOT Calling restore");
4050 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4056 traceset_state_finalize (LttvTracesetState
*self
)
4058 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4059 finalize(G_OBJECT(self
));
4064 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4066 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4068 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4069 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4070 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4071 klass
->new_traceset_context
= new_traceset_context
;
4072 klass
->new_trace_context
= new_trace_context
;
4073 klass
->new_tracefile_context
= new_tracefile_context
;
4078 lttv_traceset_state_get_type(void)
4080 static GType type
= 0;
4082 static const GTypeInfo info
= {
4083 sizeof (LttvTracesetStateClass
),
4084 NULL
, /* base_init */
4085 NULL
, /* base_finalize */
4086 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4087 NULL
, /* class_finalize */
4088 NULL
, /* class_data */
4089 sizeof (LttvTracesetState
),
4090 0, /* n_preallocs */
4091 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4092 NULL
/* value handling */
4095 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4103 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4109 trace_state_finalize (LttvTraceState
*self
)
4111 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4112 finalize(G_OBJECT(self
));
4117 trace_state_class_init (LttvTraceStateClass
*klass
)
4119 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4121 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4122 klass
->state_save
= state_save
;
4123 klass
->state_restore
= state_restore
;
4124 klass
->state_saved_free
= state_saved_free
;
4129 lttv_trace_state_get_type(void)
4131 static GType type
= 0;
4133 static const GTypeInfo info
= {
4134 sizeof (LttvTraceStateClass
),
4135 NULL
, /* base_init */
4136 NULL
, /* base_finalize */
4137 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4138 NULL
, /* class_finalize */
4139 NULL
, /* class_data */
4140 sizeof (LttvTraceState
),
4141 0, /* n_preallocs */
4142 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4143 NULL
/* value handling */
4146 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4147 "LttvTraceStateType", &info
, 0);
4154 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4160 tracefile_state_finalize (LttvTracefileState
*self
)
4162 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4163 finalize(G_OBJECT(self
));
4168 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4170 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4172 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4177 lttv_tracefile_state_get_type(void)
4179 static GType type
= 0;
4181 static const GTypeInfo info
= {
4182 sizeof (LttvTracefileStateClass
),
4183 NULL
, /* base_init */
4184 NULL
, /* base_finalize */
4185 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4186 NULL
, /* class_finalize */
4187 NULL
, /* class_data */
4188 sizeof (LttvTracefileState
),
4189 0, /* n_preallocs */
4190 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4191 NULL
/* value handling */
4194 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4195 "LttvTracefileStateType", &info
, 0);
4201 static void module_init()
4203 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4204 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4205 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4206 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4207 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4208 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4209 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4210 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4211 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4212 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4213 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4214 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4215 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4216 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4217 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4218 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4219 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4220 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4221 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4222 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4223 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4224 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4225 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4226 LTTV_STATE_EVENT
= g_quark_from_string("event");
4227 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4228 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4229 LTTV_STATE_TIME
= g_quark_from_string("time");
4230 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4231 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4232 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4233 g_quark_from_string("trace_state_use_count");
4234 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4235 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4236 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4237 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4238 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4239 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4241 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4242 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4243 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4244 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4245 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4246 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4247 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4248 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4249 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4250 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4251 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4252 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4253 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4254 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4255 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4257 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4258 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4259 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4260 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4261 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4262 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4263 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4264 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4265 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4266 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4267 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4268 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4269 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4270 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4271 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4272 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4273 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4274 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4275 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4276 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4277 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4278 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4279 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4280 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4281 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4282 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4283 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4284 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4285 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4287 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4288 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4289 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4290 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4291 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4292 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4293 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4294 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4295 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4296 LTT_FIELD_PID
= g_quark_from_string("pid");
4297 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4298 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4299 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4300 LTT_FIELD_NAME
= g_quark_from_string("name");
4301 LTT_FIELD_TYPE
= g_quark_from_string("type");
4302 LTT_FIELD_MODE
= g_quark_from_string("mode");
4303 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4304 LTT_FIELD_STATUS
= g_quark_from_string("status");
4305 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4306 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4307 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4308 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4309 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4310 LTT_FIELD_ACTION
= g_quark_from_string("action");
4311 LTT_FIELD_ID
= g_quark_from_string("id");
4312 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4313 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4315 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4316 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4317 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4318 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4319 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4320 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4322 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4323 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4324 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4326 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4327 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4328 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4329 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4332 static void module_destroy()
4337 LTTV_MODULE("state", "State computation", \
4338 "Update the system state, possibly saving it at intervals", \
4339 module_init
, module_destroy
)