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
,
77 LTT_EVENT_SOFT_IRQ_RAISE
,
78 LTT_EVENT_SOFT_IRQ_ENTRY
,
79 LTT_EVENT_SOFT_IRQ_EXIT
,
80 LTT_EVENT_SCHED_SCHEDULE
,
81 LTT_EVENT_PROCESS_FORK
,
82 LTT_EVENT_KTHREAD_CREATE
,
83 LTT_EVENT_PROCESS_EXIT
,
84 LTT_EVENT_PROCESS_FREE
,
86 LTT_EVENT_PROCESS_STATE
,
87 LTT_EVENT_STATEDUMP_END
,
88 LTT_EVENT_FUNCTION_ENTRY
,
89 LTT_EVENT_FUNCTION_EXIT
,
90 LTT_EVENT_THREAD_BRAND
,
91 LTT_EVENT_REQUEST_ISSUE
,
92 LTT_EVENT_REQUEST_COMPLETE
,
93 LTT_EVENT_LIST_INTERRUPT
,
94 LTT_EVENT_SYS_CALL_TABLE
,
95 LTT_EVENT_SOFTIRQ_VEC
;
100 LTT_FIELD_SYSCALL_ID
,
103 LTT_FIELD_SOFT_IRQ_ID
,
106 LTT_FIELD_PREV_STATE
,
107 LTT_FIELD_PARENT_PID
,
111 LTT_FIELD_CHILD_TGID
,
129 LTTV_STATE_MODE_UNKNOWN
,
130 LTTV_STATE_USER_MODE
,
137 LTTV_STATE_SUBMODE_UNKNOWN
,
138 LTTV_STATE_SUBMODE_NONE
;
142 LTTV_STATE_WAIT_FORK
,
151 LTTV_STATE_UNBRANDED
;
154 LTTV_STATE_USER_THREAD
,
155 LTTV_STATE_KERNEL_THREAD
;
173 LTTV_BDEV_BUSY_READING
,
174 LTTV_BDEV_BUSY_WRITING
;
177 LTTV_STATE_TRACEFILES
,
178 LTTV_STATE_PROCESSES
,
180 LTTV_STATE_RUNNING_PROCESS
,
182 LTTV_STATE_SAVED_STATES
,
183 LTTV_STATE_SAVED_STATES_TIME
,
186 LTTV_STATE_NAME_TABLES
,
187 LTTV_STATE_TRACE_STATE_USE_COUNT
,
188 LTTV_STATE_RESOURCE_CPUS
,
189 LTTV_STATE_RESOURCE_CPUS_COUNT
,
190 LTTV_STATE_RESOURCE_IRQS
,
191 LTTV_STATE_RESOURCE_SOFT_IRQS
,
192 LTTV_STATE_RESOURCE_TRAPS
,
193 LTTV_STATE_RESOURCE_BLKDEVS
;
195 static void create_max_time(LttvTraceState
*tcs
);
197 static void get_max_time(LttvTraceState
*tcs
);
199 static void free_max_time(LttvTraceState
*tcs
);
201 static void create_name_tables(LttvTraceState
*tcs
);
203 static void get_name_tables(LttvTraceState
*tcs
);
205 static void free_name_tables(LttvTraceState
*tcs
);
207 static void free_saved_state(LttvTraceState
*tcs
);
209 static void lttv_state_free_process_table(GHashTable
*processes
);
211 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
212 GPtrArray
*quarktable
);
214 /* Resource function prototypes */
215 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
216 static LttvBdevState
*bdevstate_new(void);
217 static void bdevstate_free(LttvBdevState
*);
218 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
219 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
222 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
224 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
228 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
230 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
234 void lttv_state_state_saved_free(LttvTraceState
*self
,
235 LttvAttribute
*container
)
237 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
241 guint
process_hash(gconstpointer key
)
243 guint pid
= ((const LttvProcessState
*)key
)->pid
;
244 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
248 /* If the hash table hash function is well distributed,
249 * the process_equal should compare different pid */
250 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
252 const LttvProcessState
*process_a
, *process_b
;
255 process_a
= (const LttvProcessState
*)a
;
256 process_b
= (const LttvProcessState
*)b
;
258 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
259 else if(likely(process_a
->pid
== 0 &&
260 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
265 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
267 g_tree_destroy((GTree
*)value
);
270 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
272 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
273 g_hash_table_destroy(usertraces
);
276 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
281 static guint
check_expand(nb
, id
)
286 return max(id
+ 1, nb
* 2);
289 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
290 guint nb
, guint new_nb
)
292 /* Expand an incomplete table */
293 GQuark
*old_table
= *table
;
294 *table
= g_new(GQuark
, new_nb
);
295 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
298 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
299 guint new_nb
, const char *def_string
)
302 GString
*fe_name
= g_string_new("");
303 for(i
= nb
; i
< new_nb
; i
++) {
304 g_string_printf(fe_name
, "%s %d", def_string
, i
);
305 table
[i
] = g_quark_from_string(fe_name
->str
);
307 g_string_free(fe_name
, TRUE
);
310 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
312 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
313 if(likely(new_nb
== ts
->nb_syscalls
))
315 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
316 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
317 /* Update the table size */
318 ts
->nb_syscalls
= new_nb
;
321 static void expand_trap_table(LttvTraceState
*ts
, int id
)
323 guint new_nb
= check_expand(ts
->nb_traps
, id
);
325 if(likely(new_nb
== ts
->nb_traps
))
327 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
328 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
329 /* Update the table size */
330 ts
->nb_traps
= new_nb
;
332 LttvTrapState
*old_table
= ts
->trap_states
;
333 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
334 memcpy(ts
->trap_states
, old_table
,
335 ts
->nb_traps
* sizeof(LttvTrapState
));
336 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
337 ts
->trap_states
[i
].running
= 0;
340 static void expand_irq_table(LttvTraceState
*ts
, int id
)
342 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
344 if(likely(new_nb
== ts
->nb_irqs
))
346 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
347 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
349 LttvIRQState
*old_table
= ts
->irq_states
;
350 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
351 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
352 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
353 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
356 /* Update the table size */
357 ts
->nb_irqs
= new_nb
;
360 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
362 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
364 if(likely(new_nb
== ts
->nb_soft_irqs
))
366 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
367 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
369 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
370 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
371 memcpy(ts
->soft_irq_states
, old_table
,
372 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
373 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
374 ts
->soft_irq_states
[i
].running
= 0;
376 /* Update the table size */
377 ts
->nb_soft_irqs
= new_nb
;
381 restore_init_state(LttvTraceState
*self
)
383 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
385 //LttvTracefileState *tfcs;
387 LttTime start_time
, end_time
;
389 /* Free the process tables */
390 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
391 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
392 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
393 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
396 /* Seek time to beginning */
397 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
398 // closest. It's the tracecontext job to seek the trace to the beginning
399 // anyway : the init state might be used at the middle of the trace as well...
400 //g_tree_destroy(self->parent.ts_context->pqueue);
401 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
403 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
405 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
407 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
408 nb_irqs
= self
->nb_irqs
;
409 nb_soft_irqs
= self
->nb_soft_irqs
;
410 nb_traps
= self
->nb_traps
;
412 /* Put the per cpu running_process to beginning state : process 0. */
413 for(i
=0; i
< nb_cpus
; i
++) {
414 LttvExecutionState
*es
;
415 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
416 LTTV_STATE_UNNAMED
, &start_time
);
417 /* We are not sure is it's a kernel thread or normal thread, put the
418 * bottom stack state to unknown */
419 self
->running_process
[i
]->execution_stack
=
420 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
421 es
= self
->running_process
[i
]->state
=
422 &g_array_index(self
->running_process
[i
]->execution_stack
,
423 LttvExecutionState
, 0);
424 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
425 es
->s
= LTTV_STATE_UNNAMED
;
427 //self->running_process[i]->state->s = LTTV_STATE_RUN;
428 self
->running_process
[i
]->cpu
= i
;
430 /* reset cpu states */
431 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
432 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
433 self
->cpu_states
[i
].last_irq
= -1;
434 self
->cpu_states
[i
].last_soft_irq
= -1;
435 self
->cpu_states
[i
].last_trap
= -1;
439 /* reset irq states */
440 for(i
=0; i
<nb_irqs
; i
++) {
441 if(self
->irq_states
[i
].mode_stack
->len
> 0)
442 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
445 /* reset softirq states */
446 for(i
=0; i
<nb_soft_irqs
; i
++) {
447 self
->soft_irq_states
[i
].pending
= 0;
448 self
->soft_irq_states
[i
].running
= 0;
451 /* reset trap states */
452 for(i
=0; i
<nb_traps
; i
++) {
453 self
->trap_states
[i
].running
= 0;
456 /* reset bdev states */
457 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
458 //g_hash_table_steal_all(self->bdev_states);
459 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
462 nb_tracefile
= self
->parent
.tracefiles
->len
;
464 for(i
= 0 ; i
< nb_tracefile
; i
++) {
466 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
467 LttvTracefileContext
*, i
));
468 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
469 // tfcs->saved_position = 0;
470 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
471 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
472 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
473 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
478 //static LttTime time_zero = {0,0};
480 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
483 const LttTime
*t1
= (const LttTime
*)a
;
484 const LttTime
*t2
= (const LttTime
*)b
;
486 return ltt_time_compare(*t1
, *t2
);
489 static void free_usertrace_key(gpointer data
)
494 #define MAX_STRING_LEN 4096
497 state_load_saved_states(LttvTraceState
*tcs
)
500 GPtrArray
*quarktable
;
501 const char *trace_path
;
505 tcs
->has_precomputed_states
= FALSE
;
509 gchar buf
[MAX_STRING_LEN
];
512 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
513 strncpy(path
, trace_path
, PATH_MAX
-1);
514 count
= strnlen(trace_path
, PATH_MAX
-1);
515 // quarktable : open, test
516 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
517 fp
= fopen(path
, "r");
519 quarktable
= g_ptr_array_sized_new(4096);
521 /* Index 0 is null */
523 if(hdr
== EOF
) return;
524 g_assert(hdr
== HDR_QUARKS
);
528 if(hdr
== EOF
) break;
529 g_assert(hdr
== HDR_QUARK
);
530 g_ptr_array_set_size(quarktable
, q
+1);
533 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
534 if(buf
[i
] == '\0' || feof(fp
)) break;
537 len
= strnlen(buf
, MAX_STRING_LEN
-1);
538 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
539 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
545 // saved_states : open, test
546 strncpy(path
, trace_path
, PATH_MAX
-1);
547 count
= strnlen(trace_path
, PATH_MAX
-1);
548 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
549 fp
= fopen(path
, "r");
553 if(hdr
!= HDR_TRACE
) goto end
;
555 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
557 tcs
->has_precomputed_states
= TRUE
;
562 /* Free the quarktable */
563 for(i
=0; i
<quarktable
->len
; i
++) {
564 string
= g_ptr_array_index (quarktable
, i
);
567 g_ptr_array_free(quarktable
, TRUE
);
572 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
574 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
577 LttvTraceContext
*tc
;
581 LttvTracefileState
*tfcs
;
583 LttvAttributeValue v
;
585 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
586 init((LttvTracesetContext
*)self
, ts
);
588 nb_trace
= lttv_traceset_number(ts
);
589 for(i
= 0 ; i
< nb_trace
; i
++) {
590 tc
= self
->parent
.traces
[i
];
591 tcs
= LTTV_TRACE_STATE(tc
);
592 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
593 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
597 if(*(v
.v_uint
) == 1) {
598 create_name_tables(tcs
);
599 create_max_time(tcs
);
601 get_name_tables(tcs
);
604 nb_tracefile
= tc
->tracefiles
->len
;
605 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
606 nb_irq
= tcs
->nb_irqs
;
607 tcs
->processes
= NULL
;
608 tcs
->usertraces
= NULL
;
609 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
611 /* init cpu resource stuff */
612 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
613 for(j
= 0; j
<nb_cpu
; j
++) {
614 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
615 tcs
->cpu_states
[j
].last_irq
= -1;
616 tcs
->cpu_states
[j
].last_soft_irq
= -1;
617 tcs
->cpu_states
[j
].last_trap
= -1;
618 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
621 /* init irq resource stuff */
622 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
623 for(j
= 0; j
<nb_irq
; j
++) {
624 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
625 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
628 /* init soft irq stuff */
629 /* the kernel has a statically fixed max of 32 softirqs */
630 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
632 /* init trap stuff */
633 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
635 /* init bdev resource stuff */
636 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
638 restore_init_state(tcs
);
639 for(j
= 0 ; j
< nb_tracefile
; j
++) {
641 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
642 LttvTracefileContext
*, j
));
643 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
644 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
645 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
646 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
647 /* It's a Usertrace */
648 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
649 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
650 GUINT_TO_POINTER(tid
));
651 if(!usertrace_tree
) {
652 usertrace_tree
= g_tree_new_full(compare_usertraces
,
653 NULL
, free_usertrace_key
, NULL
);
654 g_hash_table_insert(tcs
->usertraces
,
655 GUINT_TO_POINTER(tid
), usertrace_tree
);
657 LttTime
*timestamp
= g_new(LttTime
, 1);
658 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
659 ltt_tracefile_creation(tfcs
->parent
.tf
));
660 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
664 /* See if the trace has saved states */
665 state_load_saved_states(tcs
);
670 fini(LttvTracesetState
*self
)
676 //LttvTracefileState *tfcs;
678 LttvAttributeValue v
;
680 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
681 for(i
= 0 ; i
< nb_trace
; i
++) {
682 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
683 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
686 g_assert(*(v
.v_uint
) != 0);
689 if(*(v
.v_uint
) == 0) {
690 free_name_tables(tcs
);
692 free_saved_state(tcs
);
694 g_free(tcs
->running_process
);
695 tcs
->running_process
= NULL
;
696 lttv_state_free_process_table(tcs
->processes
);
697 lttv_state_free_usertraces(tcs
->usertraces
);
698 tcs
->processes
= NULL
;
699 tcs
->usertraces
= NULL
;
701 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
702 fini((LttvTracesetContext
*)self
);
706 static LttvTracesetContext
*
707 new_traceset_context(LttvTracesetContext
*self
)
709 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
713 static LttvTraceContext
*
714 new_trace_context(LttvTracesetContext
*self
)
716 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
720 static LttvTracefileContext
*
721 new_tracefile_context(LttvTracesetContext
*self
)
723 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
727 /* Write the process state of the trace */
729 static void write_process_state(gpointer key
, gpointer value
,
732 LttvProcessState
*process
;
734 LttvExecutionState
*es
;
736 FILE *fp
= (FILE *)user_data
;
741 process
= (LttvProcessState
*)value
;
743 " <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",
744 process
, process
->pid
, process
->tgid
, process
->ppid
,
745 g_quark_to_string(process
->type
),
746 process
->creation_time
.tv_sec
,
747 process
->creation_time
.tv_nsec
,
748 process
->insertion_time
.tv_sec
,
749 process
->insertion_time
.tv_nsec
,
750 g_quark_to_string(process
->name
),
751 g_quark_to_string(process
->brand
),
752 process
->cpu
, process
->free_events
);
754 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
755 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
756 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
757 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
758 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
759 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
760 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
763 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
764 address
= g_array_index(process
->user_stack
, guint64
, i
);
765 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n",
769 if(process
->usertrace
) {
770 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
771 g_quark_to_string(process
->usertrace
->tracefile_name
),
772 process
->usertrace
->cpu
);
776 fprintf(fp
, " </PROCESS>\n");
780 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
782 guint i
, nb_tracefile
, nb_block
, offset
;
785 LttvTracefileState
*tfcs
;
789 LttEventPosition
*ep
;
793 ep
= ltt_event_position_new();
795 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
797 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
799 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
800 for(i
=0;i
<nb_cpus
;i
++) {
801 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
802 i
, self
->running_process
[i
]->pid
);
805 nb_tracefile
= self
->parent
.tracefiles
->len
;
807 for(i
= 0 ; i
< nb_tracefile
; i
++) {
809 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
810 LttvTracefileContext
*, i
));
811 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
812 tfcs
->parent
.timestamp
.tv_sec
,
813 tfcs
->parent
.timestamp
.tv_nsec
);
814 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
815 if(e
== NULL
) fprintf(fp
,"/>\n");
817 ltt_event_position(e
, ep
);
818 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
819 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
824 fprintf(fp
,"</PROCESS_STATE>\n");
828 static void write_process_state_raw(gpointer key
, gpointer value
,
831 LttvProcessState
*process
;
833 LttvExecutionState
*es
;
835 FILE *fp
= (FILE *)user_data
;
840 process
= (LttvProcessState
*)value
;
841 fputc(HDR_PROCESS
, fp
);
842 //fwrite(&header, sizeof(header), 1, fp);
843 //fprintf(fp, "%s", g_quark_to_string(process->type));
845 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
846 //fprintf(fp, "%s", g_quark_to_string(process->name));
848 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
849 //fprintf(fp, "%s", g_quark_to_string(process->brand));
851 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
852 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
853 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
854 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
855 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
856 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
857 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
858 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
862 " <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",
863 process
, process
->pid
, process
->tgid
, process
->ppid
,
864 g_quark_to_string(process
->type
),
865 process
->creation_time
.tv_sec
,
866 process
->creation_time
.tv_nsec
,
867 process
->insertion_time
.tv_sec
,
868 process
->insertion_time
.tv_nsec
,
869 g_quark_to_string(process
->name
),
870 g_quark_to_string(process
->brand
),
874 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
875 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
878 //fprintf(fp, "%s", g_quark_to_string(es->t));
880 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
881 //fprintf(fp, "%s", g_quark_to_string(es->n));
883 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
884 //fprintf(fp, "%s", g_quark_to_string(es->s));
886 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
887 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
888 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
889 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
891 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
892 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
893 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
894 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
895 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
899 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
900 address
= g_array_index(process
->user_stack
, guint64
, i
);
901 fputc(HDR_USER_STACK
, fp
);
902 fwrite(&address
, sizeof(address
), 1, fp
);
904 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
909 if(process
->usertrace
) {
910 fputc(HDR_USERTRACE
, fp
);
911 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
913 fwrite(&process
->usertrace
->tracefile_name
,
914 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
915 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
917 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
918 g_quark_to_string(process
->usertrace
->tracefile_name
),
919 process
->usertrace
->cpu
);
926 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
928 guint i
, nb_tracefile
, nb_block
, offset
;
931 LttvTracefileState
*tfcs
;
935 LttEventPosition
*ep
;
939 ep
= ltt_event_position_new();
941 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
942 fputc(HDR_PROCESS_STATE
, fp
);
943 fwrite(&t
, sizeof(t
), 1, fp
);
945 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
947 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
948 for(i
=0;i
<nb_cpus
;i
++) {
950 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
951 fwrite(&self
->running_process
[i
]->pid
,
952 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
953 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
954 // i, self->running_process[i]->pid);
957 nb_tracefile
= self
->parent
.tracefiles
->len
;
959 for(i
= 0 ; i
< nb_tracefile
; i
++) {
961 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
962 LttvTracefileContext
*, i
));
963 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
964 // tfcs->parent.timestamp.tv_sec,
965 // tfcs->parent.timestamp.tv_nsec);
966 fputc(HDR_TRACEFILE
, fp
);
967 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
968 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
969 * position following : end of trace */
970 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
972 ltt_event_position(e
, ep
);
973 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
974 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
976 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
977 fwrite(&offset
, sizeof(offset
), 1, fp
);
978 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
985 /* Read process state from a file */
987 /* Called because a HDR_PROCESS was found */
988 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
989 GPtrArray
*quarktable
)
991 LttvExecutionState
*es
;
992 LttvProcessState
*process
, *parent_process
;
993 LttvProcessState tmp
;
998 /* TODO : check return value */
999 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1000 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1001 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1002 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1003 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1004 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1005 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1006 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1007 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1008 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1011 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1013 /* We must link to the parent */
1014 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1016 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1017 if(process
== NULL
) {
1018 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1020 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1021 &tmp
.creation_time
);
1024 process
->insertion_time
= tmp
.insertion_time
;
1025 process
->creation_time
= tmp
.creation_time
;
1026 process
->type
= g_quark_from_string(
1027 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1028 process
->tgid
= tmp
.tgid
;
1029 process
->ppid
= tmp
.ppid
;
1030 process
->brand
= g_quark_from_string(
1031 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1033 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1034 process
->free_events
= tmp
.free_events
;
1037 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1039 gint hdr
= fgetc(fp
);
1040 if(hdr
== EOF
) goto end_loop
;
1044 process
->execution_stack
=
1045 g_array_set_size(process
->execution_stack
,
1046 process
->execution_stack
->len
+ 1);
1047 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1048 process
->execution_stack
->len
-1);
1049 process
->state
= es
;
1051 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1052 es
->t
= g_quark_from_string(
1053 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1054 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1055 es
->n
= g_quark_from_string(
1056 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1057 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1058 es
->s
= g_quark_from_string(
1059 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1060 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1061 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1062 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1064 case HDR_USER_STACK
:
1065 process
->user_stack
= g_array_set_size(process
->user_stack
,
1066 process
->user_stack
->len
+ 1);
1067 address
= &g_array_index(process
->user_stack
, guint64
,
1068 process
->user_stack
->len
-1);
1069 fread(address
, sizeof(address
), 1, fp
);
1070 process
->current_function
= *address
;
1073 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1074 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1086 /* Called because a HDR_PROCESS_STATE was found */
1087 /* Append a saved state to the trace states */
1088 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1090 guint i
, nb_tracefile
, nb_block
, offset
;
1092 LttvTracefileState
*tfcs
;
1094 LttEventPosition
*ep
;
1102 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1104 LttvAttributeValue value
;
1105 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1106 ep
= ltt_event_position_new();
1108 restore_init_state(self
);
1110 fread(&t
, sizeof(t
), 1, fp
);
1113 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1115 if(hdr
== EOF
) goto end_loop
;
1119 /* Call read_process_state_raw */
1120 read_process_state_raw(self
, fp
, quarktable
);
1128 case HDR_USER_STACK
:
1130 case HDR_PROCESS_STATE
:
1136 g_error("Error while parsing saved state file : unknown data header %d",
1142 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1143 for(i
=0;i
<nb_cpus
;i
++) {
1146 g_assert(hdr
== HDR_CPU
);
1147 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1148 g_assert(i
== cpu_num
);
1149 fread(&self
->running_process
[i
]->pid
,
1150 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1153 nb_tracefile
= self
->parent
.tracefiles
->len
;
1155 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1157 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1158 LttvTracefileContext
*, i
));
1159 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1160 // tfcs->parent.timestamp.tv_sec,
1161 // tfcs->parent.timestamp.tv_nsec);
1162 g_tree_remove(pqueue
, &tfcs
->parent
);
1164 g_assert(hdr
== HDR_TRACEFILE
);
1165 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1166 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1167 * position following : end of trace */
1168 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1169 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1170 fread(&offset
, sizeof(offset
), 1, fp
);
1171 fread(&tsc
, sizeof(tsc
), 1, fp
);
1172 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1173 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1175 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1180 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1181 LTTV_STATE_SAVED_STATES
);
1182 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1183 value
= lttv_attribute_add(saved_states_tree
,
1184 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1185 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1186 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1187 *(value
.v_time
) = t
;
1188 lttv_state_save(self
, saved_state_tree
);
1189 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1192 *(self
->max_time_state_recomputed_in_seek
) = t
;
1196 /* Called when a HDR_TRACE is found */
1197 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1198 GPtrArray
*quarktable
)
1203 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1205 if(hdr
== EOF
) goto end_loop
;
1208 case HDR_PROCESS_STATE
:
1209 /* Call read_process_state_raw */
1210 lttv_state_read_raw(tcs
, fp
, quarktable
);
1218 case HDR_USER_STACK
:
1222 g_error("Error while parsing saved state file :"
1223 " unexpected data header %d",
1227 g_error("Error while parsing saved state file : unknown data header %d",
1232 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1233 restore_init_state(tcs
);
1234 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1240 /* Copy each process from an existing hash table to a new one */
1242 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1244 LttvProcessState
*process
, *new_process
;
1246 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1250 process
= (LttvProcessState
*)value
;
1251 new_process
= g_new(LttvProcessState
, 1);
1252 *new_process
= *process
;
1253 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1254 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1255 new_process
->execution_stack
=
1256 g_array_set_size(new_process
->execution_stack
,
1257 process
->execution_stack
->len
);
1258 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1259 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1260 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1262 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1263 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1264 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1265 sizeof(guint64
), 0);
1266 new_process
->user_stack
=
1267 g_array_set_size(new_process
->user_stack
,
1268 process
->user_stack
->len
);
1269 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1270 g_array_index(new_process
->user_stack
, guint64
, i
) =
1271 g_array_index(process
->user_stack
, guint64
, i
);
1273 new_process
->current_function
= process
->current_function
;
1274 g_hash_table_insert(new_processes
, new_process
, new_process
);
1278 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1280 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1282 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1283 return new_processes
;
1286 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1289 LttvCPUState
*retval
;
1291 retval
= g_new(LttvCPUState
, n
);
1293 for(i
=0; i
<n
; i
++) {
1294 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1295 retval
[i
].last_irq
= states
[i
].last_irq
;
1296 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1297 retval
[i
].last_trap
= states
[i
].last_trap
;
1298 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1299 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1300 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1307 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1311 for(i
=0; i
<n
; i
++) {
1312 g_array_free(states
[i
].mode_stack
, TRUE
);
1318 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1321 LttvIRQState
*retval
;
1323 retval
= g_new(LttvIRQState
, n
);
1325 for(i
=0; i
<n
; i
++) {
1326 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1327 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1328 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1329 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1336 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1340 for(i
=0; i
<n
; i
++) {
1341 g_array_free(states
[i
].mode_stack
, TRUE
);
1347 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1350 LttvSoftIRQState
*retval
;
1352 retval
= g_new(LttvSoftIRQState
, n
);
1354 for(i
=0; i
<n
; i
++) {
1355 retval
[i
].pending
= states
[i
].pending
;
1356 retval
[i
].running
= states
[i
].running
;
1362 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1367 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1370 LttvTrapState
*retval
;
1372 retval
= g_new(LttvTrapState
, n
);
1374 for(i
=0; i
<n
; i
++) {
1375 retval
[i
].running
= states
[i
].running
;
1381 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1386 /* bdevstate stuff */
1388 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1390 gint devcode_gint
= devcode
;
1391 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1393 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1394 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1396 gint
* key
= g_new(gint
, 1);
1398 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1406 static LttvBdevState
*bdevstate_new(void)
1408 LttvBdevState
*retval
;
1409 retval
= g_new(LttvBdevState
, 1);
1410 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1415 static void bdevstate_free(LttvBdevState
*bds
)
1417 g_array_free(bds
->mode_stack
, TRUE
);
1421 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1423 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1425 bdevstate_free(bds
);
1428 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1430 LttvBdevState
*retval
;
1432 retval
= bdevstate_new();
1433 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1438 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1440 //GHashTable *ht = (GHashTable *)u;
1441 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1442 LttvBdevState
*newbds
;
1444 newbds
= bdevstate_copy(bds
);
1446 g_hash_table_insert(u
, k
, newbds
);
1449 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1453 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1455 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1460 /* Free a hashtable and the LttvBdevState structures its values
1463 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1465 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1466 g_hash_table_destroy(ht
);
1469 /* The saved state for each trace contains a member "processes", which
1470 stores a copy of the process table, and a member "tracefiles" with
1471 one entry per tracefile. Each tracefile has a "process" member pointing
1472 to the current process and a "position" member storing the tracefile
1473 position (needed to seek to the current "next" event. */
1475 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1477 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1479 LttvTracefileState
*tfcs
;
1481 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1483 guint
*running_process
;
1485 LttvAttributeValue value
;
1487 LttEventPosition
*ep
;
1489 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1490 LTTV_STATE_TRACEFILES
);
1492 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1494 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1496 /* Add the currently running processes array */
1497 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1498 running_process
= g_new(guint
, nb_cpus
);
1499 for(i
=0;i
<nb_cpus
;i
++) {
1500 running_process
[i
] = self
->running_process
[i
]->pid
;
1502 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1504 *(value
.v_pointer
) = running_process
;
1506 g_info("State save");
1508 nb_tracefile
= self
->parent
.tracefiles
->len
;
1510 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1512 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1513 LttvTracefileContext
*, i
));
1514 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1515 value
= lttv_attribute_add(tracefiles_tree
, i
,
1517 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1519 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1521 *(value
.v_uint
) = tfcs
->process
->pid
;
1523 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1525 /* Only save the position if the tfs has not infinite time. */
1526 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1527 // && current_tfcs != tfcs) {
1528 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1529 *(value
.v_pointer
) = NULL
;
1531 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1532 ep
= ltt_event_position_new();
1533 ltt_event_position(e
, ep
);
1534 *(value
.v_pointer
) = ep
;
1536 guint nb_block
, offset
;
1539 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1540 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
, offset
,
1542 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1546 /* save the cpu state */
1548 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1550 *(value
.v_uint
) = nb_cpus
;
1552 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1554 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1557 /* save the irq state */
1558 nb_irqs
= self
->nb_irqs
;
1560 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1562 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1565 /* save the soft irq state */
1566 nb_soft_irqs
= self
->nb_soft_irqs
;
1568 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1570 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1573 /* save the trap state */
1574 nb_traps
= self
->nb_traps
;
1576 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1578 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1581 /* save the blkdev states */
1582 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1584 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1588 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1590 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1592 LttvTracefileState
*tfcs
;
1594 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1596 guint
*running_process
;
1598 LttvAttributeType type
;
1600 LttvAttributeValue value
;
1602 LttvAttributeName name
;
1606 LttEventPosition
*ep
;
1608 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1610 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1611 LTTV_STATE_TRACEFILES
);
1613 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1615 g_assert(type
== LTTV_POINTER
);
1616 lttv_state_free_process_table(self
->processes
);
1617 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1619 /* Add the currently running processes array */
1620 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1621 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1623 g_assert(type
== LTTV_POINTER
);
1624 running_process
= *(value
.v_pointer
);
1625 for(i
=0;i
<nb_cpus
;i
++) {
1626 pid
= running_process
[i
];
1627 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1628 g_assert(self
->running_process
[i
] != NULL
);
1631 nb_tracefile
= self
->parent
.tracefiles
->len
;
1633 //g_tree_destroy(tsc->pqueue);
1634 //tsc->pqueue = g_tree_new(compare_tracefile);
1636 /* restore cpu resource states */
1637 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1638 g_assert(type
== LTTV_POINTER
);
1639 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1640 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1642 /* restore irq resource states */
1643 nb_irqs
= self
->nb_irqs
;
1644 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1645 g_assert(type
== LTTV_POINTER
);
1646 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1647 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1649 /* restore soft irq resource states */
1650 nb_soft_irqs
= self
->nb_soft_irqs
;
1651 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1652 g_assert(type
== LTTV_POINTER
);
1653 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1654 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1656 /* restore trap resource states */
1657 nb_traps
= self
->nb_traps
;
1658 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1659 g_assert(type
== LTTV_POINTER
);
1660 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1661 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1663 /* restore the blkdev states */
1664 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1665 g_assert(type
== LTTV_POINTER
);
1666 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1667 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1669 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1671 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1672 LttvTracefileContext
*, i
));
1673 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1674 g_assert(type
== LTTV_GOBJECT
);
1675 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1677 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1679 g_assert(type
== LTTV_UINT
);
1680 pid
= *(value
.v_uint
);
1681 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1683 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1685 g_assert(type
== LTTV_POINTER
);
1686 //g_assert(*(value.v_pointer) != NULL);
1687 ep
= *(value
.v_pointer
);
1688 g_assert(tfcs
->parent
.t_context
!= NULL
);
1690 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1692 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1693 g_tree_remove(tsc
->pqueue
, tfc
);
1696 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1697 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1698 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1699 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1700 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1702 tfc
->timestamp
= ltt_time_infinite
;
1708 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1710 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1712 LttvTracefileState
*tfcs
;
1714 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1716 guint
*running_process
;
1718 LttvAttributeType type
;
1720 LttvAttributeValue value
;
1722 LttvAttributeName name
;
1726 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1727 LTTV_STATE_TRACEFILES
);
1728 g_object_ref(G_OBJECT(tracefiles_tree
));
1729 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1731 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1733 g_assert(type
== LTTV_POINTER
);
1734 lttv_state_free_process_table(*(value
.v_pointer
));
1735 *(value
.v_pointer
) = NULL
;
1736 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1738 /* Free running processes array */
1739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1741 g_assert(type
== LTTV_POINTER
);
1742 running_process
= *(value
.v_pointer
);
1743 g_free(running_process
);
1745 /* free cpu resource states */
1746 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1747 g_assert(type
== LTTV_UINT
);
1748 nb_cpus
= *value
.v_uint
;
1749 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1750 g_assert(type
== LTTV_POINTER
);
1751 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1753 /* free irq resource states */
1754 nb_irqs
= self
->nb_irqs
;
1755 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1756 g_assert(type
== LTTV_POINTER
);
1757 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1759 /* free softirq resource states */
1760 nb_softirqs
= self
->nb_irqs
;
1761 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1762 g_assert(type
== LTTV_POINTER
);
1763 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1765 /* free the blkdev states */
1766 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1767 g_assert(type
== LTTV_POINTER
);
1768 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1770 nb_tracefile
= self
->parent
.tracefiles
->len
;
1772 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1774 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1775 LttvTracefileContext
*, i
));
1776 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1777 g_assert(type
== LTTV_GOBJECT
);
1778 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1780 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1782 g_assert(type
== LTTV_POINTER
);
1783 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1785 g_object_unref(G_OBJECT(tracefiles_tree
));
1789 static void free_saved_state(LttvTraceState
*self
)
1793 LttvAttributeType type
;
1795 LttvAttributeValue value
;
1797 LttvAttributeName name
;
1801 LttvAttribute
*saved_states
;
1803 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1804 LTTV_STATE_SAVED_STATES
);
1806 nb
= lttv_attribute_get_number(saved_states
);
1807 for(i
= 0 ; i
< nb
; i
++) {
1808 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1809 g_assert(type
== LTTV_GOBJECT
);
1810 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1813 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1818 create_max_time(LttvTraceState
*tcs
)
1820 LttvAttributeValue v
;
1822 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1824 g_assert(*(v
.v_pointer
) == NULL
);
1825 *(v
.v_pointer
) = g_new(LttTime
,1);
1826 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1831 get_max_time(LttvTraceState
*tcs
)
1833 LttvAttributeValue v
;
1835 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1837 g_assert(*(v
.v_pointer
) != NULL
);
1838 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1843 free_max_time(LttvTraceState
*tcs
)
1845 LttvAttributeValue v
;
1847 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1849 g_free(*(v
.v_pointer
));
1850 *(v
.v_pointer
) = NULL
;
1854 typedef struct _LttvNameTables
{
1855 // FIXME GQuark *eventtype_names;
1856 GQuark
*syscall_names
;
1862 GQuark
*soft_irq_names
;
1868 create_name_tables(LttvTraceState
*tcs
)
1872 GString
*fe_name
= g_string_new("");
1874 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1876 LttvAttributeValue v
;
1880 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1882 g_assert(*(v
.v_pointer
) == NULL
);
1883 *(v
.v_pointer
) = name_tables
;
1885 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1887 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1889 LTT_EVENT_SYSCALL_ENTRY
,
1890 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1891 NULL
, NULL
, &hooks
)) {
1893 // th = lttv_trace_hook_get_first(&th);
1895 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1896 // nb = ltt_type_element_number(t);
1898 // name_tables->syscall_names = g_new(GQuark, nb);
1899 // name_tables->nb_syscalls = nb;
1901 // for(i = 0 ; i < nb ; i++) {
1902 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1903 // if(!name_tables->syscall_names[i]) {
1904 // GString *string = g_string_new("");
1905 // g_string_printf(string, "syscall %u", i);
1906 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1907 // g_string_free(string, TRUE);
1911 name_tables
->nb_syscalls
= 256;
1912 name_tables
->syscall_names
= g_new(GQuark
, 256);
1913 for(i
= 0 ; i
< 256 ; i
++) {
1914 g_string_printf(fe_name
, "syscall %d", i
);
1915 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1918 name_tables
->syscall_names
= NULL
;
1919 name_tables
->nb_syscalls
= 0;
1921 lttv_trace_hook_remove_all(&hooks
);
1923 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1925 LTT_EVENT_TRAP_ENTRY
,
1926 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1927 NULL
, NULL
, &hooks
)) {
1929 // th = lttv_trace_hook_get_first(&th);
1931 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1932 // //nb = ltt_type_element_number(t);
1934 // name_tables->trap_names = g_new(GQuark, nb);
1935 // for(i = 0 ; i < nb ; i++) {
1936 // name_tables->trap_names[i] = g_quark_from_string(
1937 // ltt_enum_string_get(t, i));
1940 name_tables
->nb_traps
= 256;
1941 name_tables
->trap_names
= g_new(GQuark
, 256);
1942 for(i
= 0 ; i
< 256 ; i
++) {
1943 g_string_printf(fe_name
, "trap %d", i
);
1944 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1947 name_tables
->trap_names
= NULL
;
1948 name_tables
->nb_traps
= 0;
1950 lttv_trace_hook_remove_all(&hooks
);
1952 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1954 LTT_EVENT_IRQ_ENTRY
,
1955 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1956 NULL
, NULL
, &hooks
)) {
1959 name_tables->irq_names = g_new(GQuark, nb);
1960 for(i = 0 ; i < nb ; i++) {
1961 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1965 name_tables
->nb_irqs
= 256;
1966 name_tables
->irq_names
= g_new(GQuark
, 256);
1967 for(i
= 0 ; i
< 256 ; i
++) {
1968 g_string_printf(fe_name
, "irq %d", i
);
1969 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1972 name_tables
->nb_irqs
= 0;
1973 name_tables
->irq_names
= NULL
;
1975 lttv_trace_hook_remove_all(&hooks
);
1977 name_tables->soft_irq_names = g_new(GQuark, nb);
1978 for(i = 0 ; i < nb ; i++) {
1979 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1983 /* the kernel is limited to 32 statically defined softirqs */
1984 name_tables
->nb_softirqs
= 32;
1985 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1986 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1987 g_string_printf(fe_name
, "softirq %d", i
);
1988 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1990 g_array_free(hooks
, TRUE
);
1992 g_string_free(fe_name
, TRUE
);
1997 get_name_tables(LttvTraceState
*tcs
)
1999 LttvNameTables
*name_tables
;
2001 LttvAttributeValue v
;
2003 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2005 g_assert(*(v
.v_pointer
) != NULL
);
2006 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2007 //tcs->eventtype_names = name_tables->eventtype_names;
2008 tcs
->syscall_names
= name_tables
->syscall_names
;
2009 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2010 tcs
->trap_names
= name_tables
->trap_names
;
2011 tcs
->nb_traps
= name_tables
->nb_traps
;
2012 tcs
->irq_names
= name_tables
->irq_names
;
2013 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2014 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2015 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2020 free_name_tables(LttvTraceState
*tcs
)
2022 LttvNameTables
*name_tables
;
2024 LttvAttributeValue v
;
2026 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2028 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2029 *(v
.v_pointer
) = NULL
;
2031 // g_free(name_tables->eventtype_names);
2032 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2033 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2034 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2035 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2036 if(name_tables
) g_free(name_tables
);
2039 #ifdef HASH_TABLE_DEBUG
2041 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2043 LttvProcessState
*process
= (LttvProcessState
*)value
;
2045 /* Test for process corruption */
2046 guint stack_len
= process
->execution_stack
->len
;
2049 static void hash_table_check(GHashTable
*table
)
2051 g_hash_table_foreach(table
, test_process
, NULL
);
2057 /* clears the stack and sets the state passed as argument */
2058 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2060 g_array_set_size(cpust
->mode_stack
, 1);
2061 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2064 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2066 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2067 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2070 static void cpu_pop_mode(LttvCPUState
*cpust
)
2072 if(cpust
->mode_stack
->len
<= 1)
2073 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2075 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2078 /* clears the stack and sets the state passed as argument */
2079 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2081 g_array_set_size(bdevst
->mode_stack
, 1);
2082 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2085 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2087 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2088 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2091 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2093 if(bdevst
->mode_stack
->len
<= 1)
2094 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2096 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2099 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2101 g_array_set_size(irqst
->mode_stack
, 1);
2102 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2105 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2107 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2108 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2111 static void irq_pop_mode(LttvIRQState
*irqst
)
2113 if(irqst
->mode_stack
->len
<= 1)
2114 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2116 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2119 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2122 LttvExecutionState
*es
;
2124 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2125 guint cpu
= tfs
->cpu
;
2127 #ifdef HASH_TABLE_DEBUG
2128 hash_table_check(ts
->processes
);
2130 LttvProcessState
*process
= ts
->running_process
[cpu
];
2132 guint depth
= process
->execution_stack
->len
;
2134 process
->execution_stack
=
2135 g_array_set_size(process
->execution_stack
, depth
+ 1);
2138 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2140 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2143 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2144 es
->cum_cpu_time
= ltt_time_zero
;
2145 es
->s
= process
->state
->s
;
2146 process
->state
= es
;
2150 * return 1 when empty, else 0 */
2151 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2152 LttvTracefileState
*tfs
)
2154 guint depth
= process
->execution_stack
->len
;
2160 process
->execution_stack
=
2161 g_array_set_size(process
->execution_stack
, depth
- 1);
2162 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2164 process
->state
->change
= tfs
->parent
.timestamp
;
2169 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2171 guint cpu
= tfs
->cpu
;
2172 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2173 LttvProcessState
*process
= ts
->running_process
[cpu
];
2175 guint depth
= process
->execution_stack
->len
;
2177 if(process
->state
->t
!= t
){
2178 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2179 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2180 g_info("process state has %s when pop_int is %s\n",
2181 g_quark_to_string(process
->state
->t
),
2182 g_quark_to_string(t
));
2183 g_info("{ %u, %u, %s, %s, %s }\n",
2186 g_quark_to_string(process
->name
),
2187 g_quark_to_string(process
->brand
),
2188 g_quark_to_string(process
->state
->s
));
2193 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2194 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2198 process
->execution_stack
=
2199 g_array_set_size(process
->execution_stack
, depth
- 1);
2200 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2202 process
->state
->change
= tfs
->parent
.timestamp
;
2205 struct search_result
{
2206 const LttTime
*time
; /* Requested time */
2207 LttTime
*best
; /* Best result */
2210 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2212 const LttTime
*elem_time
= (const LttTime
*)a
;
2213 /* Explicit non const cast */
2214 struct search_result
*res
= (struct search_result
*)b
;
2216 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2217 /* The usertrace was created before the schedchange */
2218 /* Get larger keys */
2220 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2221 /* The usertrace was created after the schedchange time */
2222 /* Get smaller keys */
2224 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2225 res
->best
= (LttTime
*)elem_time
;
2228 res
->best
= (LttTime
*)elem_time
;
2235 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2236 guint pid
, const LttTime
*timestamp
)
2238 LttvTracefileState
*tfs
= NULL
;
2239 struct search_result res
;
2240 /* Find the usertrace associated with a pid and time interval.
2241 * Search in the usertraces by PID (within a hash) and then, for each
2242 * corresponding element of the array, find the first one with creation
2243 * timestamp the lowest, but higher or equal to "timestamp". */
2244 res
.time
= timestamp
;
2246 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2247 GUINT_TO_POINTER(pid
));
2248 if(usertrace_tree
) {
2249 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2251 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2259 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2260 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2262 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2264 LttvExecutionState
*es
;
2269 process
->tgid
= tgid
;
2271 process
->name
= name
;
2272 process
->brand
= LTTV_STATE_UNBRANDED
;
2273 //process->last_cpu = tfs->cpu_name;
2274 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2275 process
->type
= LTTV_STATE_USER_THREAD
;
2276 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2277 process
->current_function
= 0; //function 0x0 by default.
2279 g_info("Process %u, core %p", process
->pid
, process
);
2280 g_hash_table_insert(tcs
->processes
, process
, process
);
2283 process
->ppid
= parent
->pid
;
2284 process
->creation_time
= *timestamp
;
2287 /* No parent. This process exists but we are missing all information about
2288 its creation. The birth time is set to zero but we remember the time of
2293 process
->creation_time
= ltt_time_zero
;
2296 process
->insertion_time
= *timestamp
;
2297 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2298 process
->creation_time
.tv_nsec
);
2299 process
->pid_time
= g_quark_from_string(buffer
);
2301 process
->free_events
= 0;
2302 //process->last_cpu = tfs->cpu_name;
2303 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2304 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2305 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2306 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2307 es
= process
->state
= &g_array_index(process
->execution_stack
,
2308 LttvExecutionState
, 0);
2309 es
->t
= LTTV_STATE_USER_MODE
;
2310 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2311 es
->entry
= *timestamp
;
2312 //g_assert(timestamp->tv_sec != 0);
2313 es
->change
= *timestamp
;
2314 es
->cum_cpu_time
= ltt_time_zero
;
2315 es
->s
= LTTV_STATE_RUN
;
2317 es
= process
->state
= &g_array_index(process
->execution_stack
,
2318 LttvExecutionState
, 1);
2319 es
->t
= LTTV_STATE_SYSCALL
;
2320 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2321 es
->entry
= *timestamp
;
2322 //g_assert(timestamp->tv_sec != 0);
2323 es
->change
= *timestamp
;
2324 es
->cum_cpu_time
= ltt_time_zero
;
2325 es
->s
= LTTV_STATE_WAIT_FORK
;
2327 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2328 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2329 sizeof(guint64
), 0);
2334 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2337 LttvProcessState key
;
2338 LttvProcessState
*process
;
2342 process
= g_hash_table_lookup(ts
->processes
, &key
);
2347 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2348 const LttTime
*timestamp
)
2350 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2351 LttvExecutionState
*es
;
2353 /* Put ltt_time_zero creation time for unexisting processes */
2354 if(unlikely(process
== NULL
)) {
2355 process
= lttv_state_create_process(ts
,
2356 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2357 /* We are not sure is it's a kernel thread or normal thread, put the
2358 * bottom stack state to unknown */
2359 process
->execution_stack
=
2360 g_array_set_size(process
->execution_stack
, 1);
2361 process
->state
= es
=
2362 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2363 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2364 es
->s
= LTTV_STATE_UNNAMED
;
2369 /* FIXME : this function should be called when we receive an event telling that
2370 * release_task has been called in the kernel. In happens generally when
2371 * the parent waits for its child terminaison, but may also happen in special
2372 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2373 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2374 * of a killed thread group, but isn't the leader.
2376 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2378 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2379 LttvProcessState key
;
2381 /* Wait for both schedule with exit dead and process free to happen.
2382 * They can happen in any order. */
2383 if (++(process
->free_events
) < 2)
2386 key
.pid
= process
->pid
;
2387 key
.cpu
= process
->cpu
;
2388 g_hash_table_remove(ts
->processes
, &key
);
2389 g_array_free(process
->execution_stack
, TRUE
);
2390 g_array_free(process
->user_stack
, TRUE
);
2396 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2398 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2399 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2404 static void lttv_state_free_process_table(GHashTable
*processes
)
2406 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2407 g_hash_table_destroy(processes
);
2411 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2413 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2415 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2416 LttvProcessState
*process
= ts
->running_process
[cpu
];
2417 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2418 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2419 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2420 LttvExecutionSubmode submode
;
2422 guint syscall
= ltt_event_get_unsigned(e
, f
);
2423 expand_syscall_table(ts
, syscall
);
2424 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2425 /* There can be no system call from PID 0 : unknown state */
2426 if(process
->pid
!= 0)
2427 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2432 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2436 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2437 LttvProcessState
*process
= ts
->running_process
[cpu
];
2439 /* There can be no system call from PID 0 : unknown state */
2440 if(process
->pid
!= 0)
2441 pop_state(s
, LTTV_STATE_SYSCALL
);
2446 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2448 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2449 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2450 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2451 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2452 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2454 LttvExecutionSubmode submode
;
2456 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2458 expand_trap_table(ts
, trap
);
2460 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2462 push_state(s
, LTTV_STATE_TRAP
, submode
);
2464 /* update cpu status */
2465 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2467 /* update trap status */
2468 s
->cpu_state
->last_trap
= trap
;
2469 ts
->trap_states
[trap
].running
++;
2474 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2476 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2477 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2478 gint trap
= s
->cpu_state
->last_trap
;
2480 pop_state(s
, LTTV_STATE_TRAP
);
2482 /* update cpu status */
2483 cpu_pop_mode(s
->cpu_state
);
2485 /* update trap status */
2487 if(ts
->trap_states
[trap
].running
)
2488 ts
->trap_states
[trap
].running
--;
2493 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2495 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2496 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2497 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2498 //guint8 ev_id = ltt_event_eventtype_id(e);
2499 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2500 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2502 LttvExecutionSubmode submode
;
2503 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2505 expand_irq_table(ts
, irq
);
2507 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2509 /* Do something with the info about being in user or system mode when int? */
2510 push_state(s
, LTTV_STATE_IRQ
, submode
);
2512 /* update cpu status */
2513 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2515 /* update irq status */
2516 s
->cpu_state
->last_irq
= irq
;
2517 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2522 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2524 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2525 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2526 gint softirq
= s
->cpu_state
->last_soft_irq
;
2528 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2530 /* update softirq status */
2532 if(ts
->soft_irq_states
[softirq
].running
)
2533 ts
->soft_irq_states
[softirq
].running
--;
2535 /* update cpu status */
2536 cpu_pop_mode(s
->cpu_state
);
2541 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2543 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2544 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2546 pop_state(s
, LTTV_STATE_IRQ
);
2548 /* update cpu status */
2549 cpu_pop_mode(s
->cpu_state
);
2551 /* update irq status */
2552 if (s
->cpu_state
->last_irq
!= -1)
2553 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2558 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2560 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2561 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2562 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2563 //guint8 ev_id = ltt_event_eventtype_id(e);
2564 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2565 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2567 LttvExecutionSubmode submode
;
2568 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2569 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2571 if(softirq
< nb_softirqs
) {
2572 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2574 /* Fixup an incomplete irq table */
2575 GString
*string
= g_string_new("");
2576 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2577 submode
= g_quark_from_string(string
->str
);
2578 g_string_free(string
, TRUE
);
2581 /* update softirq status */
2582 /* a soft irq raises are not cumulative */
2583 ts
->soft_irq_states
[softirq
].pending
=1;
2588 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2590 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2591 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2592 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2593 //guint8 ev_id = ltt_event_eventtype_id(e);
2594 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2595 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2596 LttvExecutionSubmode submode
;
2597 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2598 expand_soft_irq_table(ts
, softirq
);
2599 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2601 /* Do something with the info about being in user or system mode when int? */
2602 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2604 /* update cpu status */
2605 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2607 /* update softirq status */
2608 s
->cpu_state
->last_soft_irq
= softirq
;
2609 if(ts
->soft_irq_states
[softirq
].pending
)
2610 ts
->soft_irq_states
[softirq
].pending
--;
2611 ts
->soft_irq_states
[softirq
].running
++;
2616 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2618 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2619 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2620 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2621 //guint8 ev_id = ltt_event_eventtype_id(e);
2622 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2624 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2625 lttv_trace_get_hook_field(th
, 0)));
2626 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2628 expand_irq_table(ts
, irq
);
2629 ts
->irq_names
[irq
] = action
;
2635 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2637 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2638 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2639 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2640 //guint8 ev_id = ltt_event_eventtype_id(e);
2641 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2643 guint major
= ltt_event_get_long_unsigned(e
,
2644 lttv_trace_get_hook_field(th
, 0));
2645 guint minor
= ltt_event_get_long_unsigned(e
,
2646 lttv_trace_get_hook_field(th
, 1));
2647 guint oper
= ltt_event_get_long_unsigned(e
,
2648 lttv_trace_get_hook_field(th
, 2));
2649 guint16 devcode
= MKDEV(major
,minor
);
2651 /* have we seen this block device before? */
2652 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2655 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2657 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2662 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2664 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2665 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2666 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2667 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2669 guint major
= ltt_event_get_long_unsigned(e
,
2670 lttv_trace_get_hook_field(th
, 0));
2671 guint minor
= ltt_event_get_long_unsigned(e
,
2672 lttv_trace_get_hook_field(th
, 1));
2673 //guint oper = ltt_event_get_long_unsigned(e,
2674 // lttv_trace_get_hook_field(th, 2));
2675 guint16 devcode
= MKDEV(major
,minor
);
2677 /* have we seen this block device before? */
2678 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2680 /* update block device */
2681 bdev_pop_mode(bdev
);
2686 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2690 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2691 guint cpu
= tfs
->cpu
;
2692 LttvProcessState
*process
= ts
->running_process
[cpu
];
2694 guint depth
= process
->user_stack
->len
;
2696 process
->user_stack
=
2697 g_array_set_size(process
->user_stack
, depth
+ 1);
2699 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2700 *new_func
= funcptr
;
2701 process
->current_function
= funcptr
;
2704 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2706 guint cpu
= tfs
->cpu
;
2707 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2708 LttvProcessState
*process
= ts
->running_process
[cpu
];
2710 if(process
->current_function
!= funcptr
){
2711 g_info("Different functions (%lu.%09lu): ignore it\n",
2712 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2713 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2714 process
->current_function
, funcptr
);
2715 g_info("{ %u, %u, %s, %s, %s }\n",
2718 g_quark_to_string(process
->name
),
2719 g_quark_to_string(process
->brand
),
2720 g_quark_to_string(process
->state
->s
));
2723 guint depth
= process
->user_stack
->len
;
2726 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2727 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2731 process
->user_stack
=
2732 g_array_set_size(process
->user_stack
, depth
- 1);
2733 process
->current_function
=
2734 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2738 static gboolean
function_entry(void *hook_data
, void *call_data
)
2740 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2741 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2742 //guint8 ev_id = ltt_event_eventtype_id(e);
2743 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2744 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2745 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2747 push_function(s
, funcptr
);
2751 static gboolean
function_exit(void *hook_data
, void *call_data
)
2753 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2754 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2755 //guint8 ev_id = ltt_event_eventtype_id(e);
2756 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2757 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2758 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2760 pop_function(s
, funcptr
);
2764 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2766 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2767 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2768 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2769 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2774 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2775 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2776 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2778 expand_syscall_table(ts
, id
);
2779 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2784 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2786 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2787 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2788 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2789 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2794 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2795 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2796 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2798 expand_soft_irq_table(ts
, id
);
2799 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2804 static gboolean
schedchange(void *hook_data
, void *call_data
)
2806 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2808 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2809 LttvProcessState
*process
= ts
->running_process
[cpu
];
2810 //LttvProcessState *old_process = ts->running_process[cpu];
2812 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2813 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2814 guint pid_in
, pid_out
;
2817 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2818 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2819 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2821 if(likely(process
!= NULL
)) {
2823 /* We could not know but it was not the idle process executing.
2824 This should only happen at the beginning, before the first schedule
2825 event, and when the initial information (current process for each CPU)
2826 is missing. It is not obvious how we could, after the fact, compensate
2827 the wrongly attributed statistics. */
2829 //This test only makes sense once the state is known and if there is no
2830 //missing events. We need to silently ignore schedchange coming after a
2831 //process_free, or it causes glitches. (FIXME)
2832 //if(unlikely(process->pid != pid_out)) {
2833 // g_assert(process->pid == 0);
2835 if(process
->pid
== 0
2836 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2838 /* Scheduling out of pid 0 at beginning of the trace :
2839 * we know for sure it is in syscall mode at this point. */
2840 g_assert(process
->execution_stack
->len
== 1);
2841 process
->state
->t
= LTTV_STATE_SYSCALL
;
2842 process
->state
->s
= LTTV_STATE_WAIT
;
2843 process
->state
->change
= s
->parent
.timestamp
;
2844 process
->state
->entry
= s
->parent
.timestamp
;
2847 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2848 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2849 process
->state
->change
= s
->parent
.timestamp
;
2851 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2852 else process
->state
->s
= LTTV_STATE_WAIT
;
2853 process
->state
->change
= s
->parent
.timestamp
;
2856 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2857 /* see sched.h for states */
2858 if (!exit_process(s
, process
)) {
2859 process
->state
->s
= LTTV_STATE_DEAD
;
2860 process
->state
->change
= s
->parent
.timestamp
;
2865 process
= ts
->running_process
[cpu
] =
2866 lttv_state_find_process_or_create(
2867 (LttvTraceState
*)s
->parent
.t_context
,
2869 &s
->parent
.timestamp
);
2870 process
->state
->s
= LTTV_STATE_RUN
;
2872 if(process
->usertrace
)
2873 process
->usertrace
->cpu
= cpu
;
2874 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2875 process
->state
->change
= s
->parent
.timestamp
;
2877 /* update cpu status */
2879 /* going to idle task */
2880 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2882 /* scheduling a real task.
2883 * we must be careful here:
2884 * if we just schedule()'ed to a process that is
2885 * in a trap, we must put the cpu in trap mode
2887 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2888 if(process
->state
->t
== LTTV_STATE_TRAP
)
2889 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2895 static gboolean
process_fork(void *hook_data
, void *call_data
)
2897 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2898 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2899 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2901 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2902 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2903 //LttvProcessState *zombie_process;
2905 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2906 LttvProcessState
*process
= ts
->running_process
[cpu
];
2907 LttvProcessState
*child_process
;
2908 struct marker_field
*f
;
2911 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2914 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2915 s
->parent
.target_pid
= child_pid
;
2918 f
= lttv_trace_get_hook_field(th
, 2);
2920 child_tgid
= ltt_event_get_unsigned(e
, f
);
2924 /* Mathieu : it seems like the process might have been scheduled in before the
2925 * fork, and, in a rare case, might be the current process. This might happen
2926 * in a SMP case where we don't have enough precision on the clocks.
2928 * Test reenabled after precision fixes on time. (Mathieu) */
2930 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2932 if(unlikely(zombie_process
!= NULL
)) {
2933 /* Reutilisation of PID. Only now we are sure that the old PID
2934 * has been released. FIXME : should know when release_task happens instead.
2936 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2938 for(i
=0; i
< num_cpus
; i
++) {
2939 g_assert(zombie_process
!= ts
->running_process
[i
]);
2942 exit_process(s
, zombie_process
);
2945 g_assert(process
->pid
!= child_pid
);
2946 // FIXME : Add this test in the "known state" section
2947 // g_assert(process->pid == parent_pid);
2948 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2949 if(child_process
== NULL
) {
2950 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2951 child_pid
, child_tgid
,
2952 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2954 /* The process has already been created : due to time imprecision between
2955 * multiple CPUs : it has been scheduled in before creation. Note that we
2956 * shouldn't have this kind of imprecision.
2958 * Simply put a correct parent.
2960 g_error("Process %u has been created at [%lu.%09lu] "
2961 "and inserted at [%lu.%09lu] before \n"
2962 "fork on cpu %u[%lu.%09lu].\n"
2963 "Probably an unsynchronized TSC problem on the traced machine.",
2965 child_process
->creation_time
.tv_sec
,
2966 child_process
->creation_time
.tv_nsec
,
2967 child_process
->insertion_time
.tv_sec
,
2968 child_process
->insertion_time
.tv_nsec
,
2969 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
2970 //g_assert(0); /* This is a problematic case : the process has been created
2971 // before the fork event */
2972 child_process
->ppid
= process
->pid
;
2973 child_process
->tgid
= child_tgid
;
2975 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2976 child_process
->name
= process
->name
;
2977 child_process
->brand
= process
->brand
;
2982 /* We stamp a newly created process as kernel_thread.
2983 * The thread should not be running yet. */
2984 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2986 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2987 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2988 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2990 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2991 LttvProcessState
*process
;
2992 LttvExecutionState
*es
;
2995 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2996 s
->parent
.target_pid
= pid
;
2998 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3000 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3001 process
->execution_stack
=
3002 g_array_set_size(process
->execution_stack
, 1);
3003 es
= process
->state
=
3004 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3005 es
->t
= LTTV_STATE_SYSCALL
;
3007 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3012 static gboolean
process_exit(void *hook_data
, void *call_data
)
3014 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3015 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3016 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3018 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3019 LttvProcessState
*process
; // = ts->running_process[cpu];
3021 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3022 s
->parent
.target_pid
= pid
;
3024 // FIXME : Add this test in the "known state" section
3025 // g_assert(process->pid == pid);
3027 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3028 if(likely(process
!= NULL
)) {
3029 process
->state
->s
= LTTV_STATE_EXIT
;
3034 static gboolean
process_free(void *hook_data
, void *call_data
)
3036 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3037 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3038 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3039 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3041 LttvProcessState
*process
;
3043 /* PID of the process to release */
3044 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3045 s
->parent
.target_pid
= release_pid
;
3047 g_assert(release_pid
!= 0);
3049 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3050 if(likely(process
!= NULL
))
3051 exit_process(s
, process
);
3054 if(likely(process
!= NULL
)) {
3055 /* release_task is happening at kernel level : we can now safely release
3056 * the data structure of the process */
3057 //This test is fun, though, as it may happen that
3058 //at time t : CPU 0 : process_free
3059 //at time t+150ns : CPU 1 : schedule out
3060 //Clearly due to time imprecision, we disable it. (Mathieu)
3061 //If this weird case happen, we have no choice but to put the
3062 //Currently running process on the cpu to 0.
3063 //I re-enable it following time precision fixes. (Mathieu)
3064 //Well, in the case where an process is freed by a process on another CPU
3065 //and still scheduled, it happens that this is the schedchange that will
3066 //drop the last reference count. Do not free it here!
3067 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3069 for(i
=0; i
< num_cpus
; i
++) {
3070 //g_assert(process != ts->running_process[i]);
3071 if(process
== ts
->running_process
[i
]) {
3072 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3076 if(i
== num_cpus
) /* process is not scheduled */
3077 exit_process(s
, process
);
3084 static gboolean
process_exec(void *hook_data
, void *call_data
)
3086 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3087 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3088 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3089 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3092 LttvProcessState
*process
= ts
->running_process
[cpu
];
3094 #if 0//how to use a sequence that must be transformed in a string
3095 /* PID of the process to release */
3096 guint64 name_len
= ltt_event_field_element_number(e
,
3097 lttv_trace_get_hook_field(th
, 0));
3098 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3099 LttField
*child
= ltt_event_field_element_select(e
,
3100 lttv_trace_get_hook_field(th
, 0), 0);
3102 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3103 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3104 memcpy(null_term_name
, name_begin
, name_len
);
3105 null_term_name
[name_len
] = '\0';
3106 process
->name
= g_quark_from_string(null_term_name
);
3109 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3110 lttv_trace_get_hook_field(th
, 0)));
3111 process
->brand
= LTTV_STATE_UNBRANDED
;
3112 //g_free(null_term_name);
3116 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3118 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3119 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3120 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3121 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3124 LttvProcessState
*process
= ts
->running_process
[cpu
];
3126 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3127 process
->brand
= g_quark_from_string(name
);
3132 static void fix_process(gpointer key
, gpointer value
,
3135 LttvProcessState
*process
;
3136 LttvExecutionState
*es
;
3137 process
= (LttvProcessState
*)value
;
3138 LttTime
*timestamp
= (LttTime
*)user_data
;
3140 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3141 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3142 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3143 es
->t
= LTTV_STATE_SYSCALL
;
3144 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3145 es
->entry
= *timestamp
;
3146 es
->change
= *timestamp
;
3147 es
->cum_cpu_time
= ltt_time_zero
;
3148 if(es
->s
== LTTV_STATE_UNNAMED
)
3149 es
->s
= LTTV_STATE_WAIT
;
3152 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3153 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3154 es
->t
= LTTV_STATE_USER_MODE
;
3155 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3156 es
->entry
= *timestamp
;
3157 //g_assert(timestamp->tv_sec != 0);
3158 es
->change
= *timestamp
;
3159 es
->cum_cpu_time
= ltt_time_zero
;
3160 if(es
->s
== LTTV_STATE_UNNAMED
)
3161 es
->s
= LTTV_STATE_RUN
;
3163 if(process
->execution_stack
->len
== 1) {
3164 /* Still in bottom unknown mode, means never did a system call
3165 * May be either in user mode, syscall mode, running or waiting.*/
3166 /* FIXME : we may be tagging syscall mode when being user mode */
3167 process
->execution_stack
=
3168 g_array_set_size(process
->execution_stack
, 2);
3169 es
= process
->state
= &g_array_index(process
->execution_stack
,
3170 LttvExecutionState
, 1);
3171 es
->t
= LTTV_STATE_SYSCALL
;
3172 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3173 es
->entry
= *timestamp
;
3174 //g_assert(timestamp->tv_sec != 0);
3175 es
->change
= *timestamp
;
3176 es
->cum_cpu_time
= ltt_time_zero
;
3177 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3178 es
->s
= LTTV_STATE_WAIT
;
3184 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3186 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3187 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3188 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3189 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3190 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3192 /* For all processes */
3193 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3194 /* else, if stack[0] is unknown, set to user mode, running */
3196 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3201 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3203 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3204 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3205 //It's slow : optimise later by doing this before reading trace.
3206 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3212 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3213 LttvProcessState
*process
= ts
->running_process
[cpu
];
3214 LttvProcessState
*parent_process
;
3215 struct marker_field
*f
;
3216 GQuark type
, mode
, submode
, status
;
3217 LttvExecutionState
*es
;
3221 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3222 s
->parent
.target_pid
= pid
;
3225 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3228 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3231 f
= lttv_trace_get_hook_field(th
, 3);
3232 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3234 //FIXME: type is rarely used, enum must match possible types.
3237 f
= lttv_trace_get_hook_field(th
, 4);
3238 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3241 f
= lttv_trace_get_hook_field(th
, 5);
3242 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3245 f
= lttv_trace_get_hook_field(th
, 6);
3246 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3249 f
= lttv_trace_get_hook_field(th
, 7);
3251 tgid
= ltt_event_get_unsigned(e
, f
);
3256 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3257 for(i
=0; i
<nb_cpus
; i
++) {
3258 process
= lttv_state_find_process(ts
, i
, pid
);
3259 g_assert(process
!= NULL
);
3261 process
->ppid
= parent_pid
;
3262 process
->tgid
= tgid
;
3263 process
->name
= g_quark_from_string(command
);
3265 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3266 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3270 /* The process might exist if a process was forked while performing the
3272 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3273 if(process
== NULL
) {
3274 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3275 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3276 pid
, tgid
, g_quark_from_string(command
),
3277 &s
->parent
.timestamp
);
3279 /* Keep the stack bottom : a running user mode */
3280 /* Disabled because of inconsistencies in the current statedump states. */
3281 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3282 /* Only keep the bottom
3283 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3284 /* Will cause expected trap when in fact being syscall (even after end of
3286 * Will cause expected interrupt when being syscall. (only before end of
3287 * statedump event) */
3288 // This will cause a "popping last state on stack, ignoring it."
3289 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3290 es
= process
->state
= &g_array_index(process
->execution_stack
,
3291 LttvExecutionState
, 0);
3292 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3293 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3294 es
->s
= LTTV_STATE_UNNAMED
;
3295 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3297 es
->t
= LTTV_STATE_SYSCALL
;
3302 /* User space process :
3303 * bottom : user mode
3304 * either currently running or scheduled out.
3305 * can be scheduled out because interrupted in (user mode or in syscall)
3306 * or because of an explicit call to the scheduler in syscall. Note that
3307 * the scheduler call comes after the irq_exit, so never in interrupt
3309 // temp workaround : set size to 1 : only have user mode bottom of stack.
3310 // will cause g_info message of expected syscall mode when in fact being
3311 // in user mode. Can also cause expected trap when in fact being user
3312 // mode in the event of a page fault reenabling interrupts in the handler.
3313 // Expected syscall and trap can also happen after the end of statedump
3314 // This will cause a "popping last state on stack, ignoring it."
3315 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3316 es
= process
->state
= &g_array_index(process
->execution_stack
,
3317 LttvExecutionState
, 0);
3318 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3319 es
->s
= LTTV_STATE_UNNAMED
;
3320 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3322 es
->t
= LTTV_STATE_USER_MODE
;
3330 es
= process
->state
= &g_array_index(process
->execution_stack
,
3331 LttvExecutionState
, 1);
3332 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3333 es
->s
= LTTV_STATE_UNNAMED
;
3334 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3338 /* The process has already been created :
3339 * Probably was forked while dumping the process state or
3340 * was simply scheduled in prior to get the state dump event.
3342 process
->ppid
= parent_pid
;
3343 process
->tgid
= tgid
;
3344 process
->name
= g_quark_from_string(command
);
3345 process
->type
= type
;
3347 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3349 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3350 if(type
== LTTV_STATE_KERNEL_THREAD
)
3351 es
->t
= LTTV_STATE_SYSCALL
;
3353 es
->t
= LTTV_STATE_USER_MODE
;
3356 /* Don't mess around with the stack, it will eventually become
3357 * ok after the end of state dump. */
3364 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3366 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3368 lttv_state_add_event_hooks(tss
);
3373 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3375 LttvTraceset
*traceset
= self
->parent
.ts
;
3377 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3381 LttvTracefileState
*tfs
;
3387 LttvAttributeValue val
;
3389 nb_trace
= lttv_traceset_number(traceset
);
3390 for(i
= 0 ; i
< nb_trace
; i
++) {
3391 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3393 /* Find the eventtype id for the following events and register the
3394 associated by id hooks. */
3396 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3397 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3400 lttv_trace_find_hook(ts
->parent
.t
,
3402 LTT_EVENT_SYSCALL_ENTRY
,
3403 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3404 syscall_entry
, NULL
, &hooks
);
3406 lttv_trace_find_hook(ts
->parent
.t
,
3408 LTT_EVENT_SYSCALL_EXIT
,
3410 syscall_exit
, NULL
, &hooks
);
3412 lttv_trace_find_hook(ts
->parent
.t
,
3414 LTT_EVENT_TRAP_ENTRY
,
3415 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3416 trap_entry
, NULL
, &hooks
);
3418 lttv_trace_find_hook(ts
->parent
.t
,
3420 LTT_EVENT_TRAP_EXIT
,
3422 trap_exit
, NULL
, &hooks
);
3424 lttv_trace_find_hook(ts
->parent
.t
,
3426 LTT_EVENT_IRQ_ENTRY
,
3427 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3428 irq_entry
, NULL
, &hooks
);
3430 lttv_trace_find_hook(ts
->parent
.t
,
3434 irq_exit
, NULL
, &hooks
);
3436 lttv_trace_find_hook(ts
->parent
.t
,
3438 LTT_EVENT_SOFT_IRQ_RAISE
,
3439 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3440 soft_irq_raise
, NULL
, &hooks
);
3442 lttv_trace_find_hook(ts
->parent
.t
,
3444 LTT_EVENT_SOFT_IRQ_ENTRY
,
3445 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3446 soft_irq_entry
, NULL
, &hooks
);
3448 lttv_trace_find_hook(ts
->parent
.t
,
3450 LTT_EVENT_SOFT_IRQ_EXIT
,
3452 soft_irq_exit
, NULL
, &hooks
);
3454 lttv_trace_find_hook(ts
->parent
.t
,
3456 LTT_EVENT_SCHED_SCHEDULE
,
3457 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3458 LTT_FIELD_PREV_STATE
),
3459 schedchange
, NULL
, &hooks
);
3461 lttv_trace_find_hook(ts
->parent
.t
,
3463 LTT_EVENT_PROCESS_FORK
,
3464 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3465 LTT_FIELD_CHILD_TGID
),
3466 process_fork
, NULL
, &hooks
);
3468 lttv_trace_find_hook(ts
->parent
.t
,
3470 LTT_EVENT_KTHREAD_CREATE
,
3471 FIELD_ARRAY(LTT_FIELD_PID
),
3472 process_kernel_thread
, NULL
, &hooks
);
3474 lttv_trace_find_hook(ts
->parent
.t
,
3476 LTT_EVENT_PROCESS_EXIT
,
3477 FIELD_ARRAY(LTT_FIELD_PID
),
3478 process_exit
, NULL
, &hooks
);
3480 lttv_trace_find_hook(ts
->parent
.t
,
3482 LTT_EVENT_PROCESS_FREE
,
3483 FIELD_ARRAY(LTT_FIELD_PID
),
3484 process_free
, NULL
, &hooks
);
3486 lttv_trace_find_hook(ts
->parent
.t
,
3489 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3490 process_exec
, NULL
, &hooks
);
3492 lttv_trace_find_hook(ts
->parent
.t
,
3493 LTT_CHANNEL_USERSPACE
,
3494 LTT_EVENT_THREAD_BRAND
,
3495 FIELD_ARRAY(LTT_FIELD_NAME
),
3496 thread_brand
, NULL
, &hooks
);
3498 /* statedump-related hooks */
3499 lttv_trace_find_hook(ts
->parent
.t
,
3500 LTT_CHANNEL_TASK_STATE
,
3501 LTT_EVENT_PROCESS_STATE
,
3502 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3503 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3504 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3505 enum_process_state
, NULL
, &hooks
);
3507 lttv_trace_find_hook(ts
->parent
.t
,
3508 LTT_CHANNEL_GLOBAL_STATE
,
3509 LTT_EVENT_STATEDUMP_END
,
3511 statedump_end
, NULL
, &hooks
);
3513 lttv_trace_find_hook(ts
->parent
.t
,
3514 LTT_CHANNEL_IRQ_STATE
,
3515 LTT_EVENT_LIST_INTERRUPT
,
3516 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3517 enum_interrupt
, NULL
, &hooks
);
3519 lttv_trace_find_hook(ts
->parent
.t
,
3521 LTT_EVENT_REQUEST_ISSUE
,
3522 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3523 bdev_request_issue
, NULL
, &hooks
);
3525 lttv_trace_find_hook(ts
->parent
.t
,
3527 LTT_EVENT_REQUEST_COMPLETE
,
3528 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3529 bdev_request_complete
, NULL
, &hooks
);
3531 lttv_trace_find_hook(ts
->parent
.t
,
3532 LTT_CHANNEL_USERSPACE
,
3533 LTT_EVENT_FUNCTION_ENTRY
,
3534 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3535 function_entry
, NULL
, &hooks
);
3537 lttv_trace_find_hook(ts
->parent
.t
,
3538 LTT_CHANNEL_USERSPACE
,
3539 LTT_EVENT_FUNCTION_EXIT
,
3540 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3541 function_exit
, NULL
, &hooks
);
3543 lttv_trace_find_hook(ts
->parent
.t
,
3544 LTT_CHANNEL_SYSCALL_STATE
,
3545 LTT_EVENT_SYS_CALL_TABLE
,
3546 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3547 dump_syscall
, NULL
, &hooks
);
3549 lttv_trace_find_hook(ts
->parent
.t
,
3550 LTT_CHANNEL_SOFTIRQ_STATE
,
3551 LTT_EVENT_SOFTIRQ_VEC
,
3552 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3553 dump_softirq
, NULL
, &hooks
);
3555 /* Add these hooks to each event_by_id hooks list */
3557 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3559 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3561 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3562 LttvTracefileContext
*, j
));
3564 for(k
= 0 ; k
< hooks
->len
; k
++) {
3565 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3566 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3568 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3574 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3575 *(val
.v_pointer
) = hooks
;
3579 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3581 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3583 lttv_state_remove_event_hooks(tss
);
3588 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3590 LttvTraceset
*traceset
= self
->parent
.ts
;
3592 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3596 LttvTracefileState
*tfs
;
3602 LttvAttributeValue val
;
3604 nb_trace
= lttv_traceset_number(traceset
);
3605 for(i
= 0 ; i
< nb_trace
; i
++) {
3606 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3608 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3609 hooks
= *(val
.v_pointer
);
3611 /* Remove these hooks from each event_by_id hooks list */
3613 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3615 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3617 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3618 LttvTracefileContext
*, j
));
3620 for(k
= 0 ; k
< hooks
->len
; k
++) {
3621 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3622 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3623 lttv_hooks_remove_data(
3624 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3629 lttv_trace_hook_remove_all(&hooks
);
3630 g_array_free(hooks
, TRUE
);
3634 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3636 guint
*event_count
= (guint
*)hook_data
;
3638 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3639 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3644 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3646 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3648 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3650 LttvAttributeValue value
;
3652 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3653 LTTV_STATE_SAVED_STATES
);
3654 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3655 value
= lttv_attribute_add(saved_states_tree
,
3656 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3657 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3658 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3659 *(value
.v_time
) = self
->parent
.timestamp
;
3660 lttv_state_save(tcs
, saved_state_tree
);
3661 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3662 self
->parent
.timestamp
.tv_nsec
);
3664 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3669 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3671 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3673 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3678 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3686 static gboolean
block_start(void *hook_data
, void *call_data
)
3688 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3690 LttvTracefileState
*tfcs
;
3692 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3694 LttEventPosition
*ep
;
3696 guint i
, nb_block
, nb_event
, nb_tracefile
;
3700 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3702 LttvAttributeValue value
;
3704 ep
= ltt_event_position_new();
3706 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3708 /* Count the number of events added since the last block end in any
3711 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3713 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3714 LttvTracefileContext
, i
));
3715 ltt_event_position(tfcs
->parent
.e
, ep
);
3716 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3717 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3718 tfcs
->saved_position
= nb_event
;
3722 if(tcs
->nb_event
>= tcs
->save_interval
) {
3723 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3724 LTTV_STATE_SAVED_STATES
);
3725 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3726 value
= lttv_attribute_add(saved_states_tree
,
3727 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3728 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3729 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3730 *(value
.v_time
) = self
->parent
.timestamp
;
3731 lttv_state_save(tcs
, saved_state_tree
);
3733 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3734 self
->parent
.timestamp
.tv_nsec
);
3736 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3742 static gboolean
block_end(void *hook_data
, void *call_data
)
3744 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3746 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3750 LttEventPosition
*ep
;
3752 guint nb_block
, nb_event
;
3754 ep
= ltt_event_position_new();
3755 ltt_event_position(self
->parent
.e
, ep
);
3756 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3757 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3758 self
->saved_position
= 0;
3759 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3766 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3768 LttvTraceset
*traceset
= self
->parent
.ts
;
3770 guint i
, j
, nb_trace
, nb_tracefile
;
3774 LttvTracefileState
*tfs
;
3776 LttvTraceHook hook_start
, hook_end
;
3778 nb_trace
= lttv_traceset_number(traceset
);
3779 for(i
= 0 ; i
< nb_trace
; i
++) {
3780 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3782 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3783 NULL
, NULL
, block_start
, &hook_start
);
3784 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3785 NULL
, NULL
, block_end
, &hook_end
);
3787 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3789 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3791 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3792 LttvTracefileContext
, j
));
3793 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3794 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3795 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3796 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3802 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3804 LttvTraceset
*traceset
= self
->parent
.ts
;
3806 guint i
, j
, nb_trace
, nb_tracefile
;
3810 LttvTracefileState
*tfs
;
3813 nb_trace
= lttv_traceset_number(traceset
);
3814 for(i
= 0 ; i
< nb_trace
; i
++) {
3816 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3817 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3819 if(ts
->has_precomputed_states
) continue;
3821 guint
*event_count
= g_new(guint
, 1);
3824 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3826 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3827 LttvTracefileContext
*, j
));
3828 lttv_hooks_add(tfs
->parent
.event
,
3829 state_save_event_hook
,
3836 lttv_process_traceset_begin(&self
->parent
,
3837 NULL
, NULL
, NULL
, NULL
, NULL
);
3841 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3843 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3845 lttv_state_save_add_event_hooks(tss
);
3852 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3854 LttvTraceset
*traceset
= self
->parent
.ts
;
3856 guint i
, j
, nb_trace
, nb_tracefile
;
3860 LttvTracefileState
*tfs
;
3862 LttvTraceHook hook_start
, hook_end
;
3864 nb_trace
= lttv_traceset_number(traceset
);
3865 for(i
= 0 ; i
< nb_trace
; i
++) {
3866 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3868 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3869 NULL
, NULL
, block_start
, &hook_start
);
3871 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3872 NULL
, NULL
, block_end
, &hook_end
);
3874 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3876 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3878 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3879 LttvTracefileContext
, j
));
3880 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3881 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3882 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3883 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3889 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3891 LttvTraceset
*traceset
= self
->parent
.ts
;
3893 guint i
, j
, nb_trace
, nb_tracefile
;
3897 LttvTracefileState
*tfs
;
3899 LttvHooks
*after_trace
= lttv_hooks_new();
3901 lttv_hooks_add(after_trace
,
3902 state_save_after_trace_hook
,
3907 lttv_process_traceset_end(&self
->parent
,
3908 NULL
, after_trace
, NULL
, NULL
, NULL
);
3910 lttv_hooks_destroy(after_trace
);
3912 nb_trace
= lttv_traceset_number(traceset
);
3913 for(i
= 0 ; i
< nb_trace
; i
++) {
3915 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3916 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3918 if(ts
->has_precomputed_states
) continue;
3920 guint
*event_count
= NULL
;
3922 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3924 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3925 LttvTracefileContext
*, j
));
3926 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3927 state_save_event_hook
);
3929 if(event_count
) g_free(event_count
);
3933 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3935 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3937 lttv_state_save_remove_event_hooks(tss
);
3942 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3944 LttvTraceset
*traceset
= self
->parent
.ts
;
3948 int min_pos
, mid_pos
, max_pos
;
3950 guint call_rest
= 0;
3952 LttvTraceState
*tcs
;
3954 LttvAttributeValue value
;
3956 LttvAttributeType type
;
3958 LttvAttributeName name
;
3962 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
3964 //g_tree_destroy(self->parent.pqueue);
3965 //self->parent.pqueue = g_tree_new(compare_tracefile);
3967 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3969 nb_trace
= lttv_traceset_number(traceset
);
3970 for(i
= 0 ; i
< nb_trace
; i
++) {
3971 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3973 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3974 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3975 LTTV_STATE_SAVED_STATES
);
3978 if(saved_states_tree
) {
3979 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3980 mid_pos
= max_pos
/ 2;
3981 while(min_pos
< max_pos
) {
3982 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3984 g_assert(type
== LTTV_GOBJECT
);
3985 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3986 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3988 g_assert(type
== LTTV_TIME
);
3989 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3991 closest_tree
= saved_state_tree
;
3993 else max_pos
= mid_pos
- 1;
3995 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3999 /* restore the closest earlier saved state */
4001 lttv_state_restore(tcs
, closest_tree
);
4005 /* There is no saved state, yet we want to have it. Restart at T0 */
4007 restore_init_state(tcs
);
4008 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4011 /* We want to seek quickly without restoring/updating the state */
4013 restore_init_state(tcs
);
4014 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4017 if(!call_rest
) g_info("NOT Calling restore");
4022 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4028 traceset_state_finalize (LttvTracesetState
*self
)
4030 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4031 finalize(G_OBJECT(self
));
4036 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4038 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4040 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4041 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4042 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4043 klass
->new_traceset_context
= new_traceset_context
;
4044 klass
->new_trace_context
= new_trace_context
;
4045 klass
->new_tracefile_context
= new_tracefile_context
;
4050 lttv_traceset_state_get_type(void)
4052 static GType type
= 0;
4054 static const GTypeInfo info
= {
4055 sizeof (LttvTracesetStateClass
),
4056 NULL
, /* base_init */
4057 NULL
, /* base_finalize */
4058 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4059 NULL
, /* class_finalize */
4060 NULL
, /* class_data */
4061 sizeof (LttvTracesetState
),
4062 0, /* n_preallocs */
4063 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4064 NULL
/* value handling */
4067 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4075 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4081 trace_state_finalize (LttvTraceState
*self
)
4083 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4084 finalize(G_OBJECT(self
));
4089 trace_state_class_init (LttvTraceStateClass
*klass
)
4091 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4093 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4094 klass
->state_save
= state_save
;
4095 klass
->state_restore
= state_restore
;
4096 klass
->state_saved_free
= state_saved_free
;
4101 lttv_trace_state_get_type(void)
4103 static GType type
= 0;
4105 static const GTypeInfo info
= {
4106 sizeof (LttvTraceStateClass
),
4107 NULL
, /* base_init */
4108 NULL
, /* base_finalize */
4109 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4110 NULL
, /* class_finalize */
4111 NULL
, /* class_data */
4112 sizeof (LttvTraceState
),
4113 0, /* n_preallocs */
4114 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4115 NULL
/* value handling */
4118 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4119 "LttvTraceStateType", &info
, 0);
4126 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4132 tracefile_state_finalize (LttvTracefileState
*self
)
4134 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4135 finalize(G_OBJECT(self
));
4140 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4142 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4144 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4149 lttv_tracefile_state_get_type(void)
4151 static GType type
= 0;
4153 static const GTypeInfo info
= {
4154 sizeof (LttvTracefileStateClass
),
4155 NULL
, /* base_init */
4156 NULL
, /* base_finalize */
4157 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4158 NULL
, /* class_finalize */
4159 NULL
, /* class_data */
4160 sizeof (LttvTracefileState
),
4161 0, /* n_preallocs */
4162 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4163 NULL
/* value handling */
4166 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4167 "LttvTracefileStateType", &info
, 0);
4173 static void module_init()
4175 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4176 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4177 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4178 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4179 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4180 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4181 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4182 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4183 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4184 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4185 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4186 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4187 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4188 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4189 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4190 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4191 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4192 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4193 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4194 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4195 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4196 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4197 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4198 LTTV_STATE_EVENT
= g_quark_from_string("event");
4199 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4200 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4201 LTTV_STATE_TIME
= g_quark_from_string("time");
4202 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4203 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4204 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4205 g_quark_from_string("trace_state_use_count");
4206 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4207 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4208 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4209 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4210 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4211 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4213 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4214 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4215 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4216 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4217 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4218 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4219 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4220 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4221 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4222 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4223 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4224 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4225 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4226 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4227 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4229 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4230 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4231 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4232 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4233 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4234 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4235 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4236 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4237 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4238 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4239 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4240 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4241 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4242 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4243 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4244 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4245 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4246 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4247 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4248 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4249 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4250 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4251 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4252 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4253 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4255 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4256 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4257 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4258 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4259 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4260 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4261 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4262 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4263 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4264 LTT_FIELD_PID
= g_quark_from_string("pid");
4265 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4266 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4267 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4268 LTT_FIELD_NAME
= g_quark_from_string("name");
4269 LTT_FIELD_TYPE
= g_quark_from_string("type");
4270 LTT_FIELD_MODE
= g_quark_from_string("mode");
4271 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4272 LTT_FIELD_STATUS
= g_quark_from_string("status");
4273 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4274 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4275 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4276 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4277 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4278 LTT_FIELD_ACTION
= g_quark_from_string("action");
4279 LTT_FIELD_ID
= g_quark_from_string("id");
4280 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4281 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4283 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4284 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4285 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4286 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4287 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4288 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4290 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4291 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4292 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4294 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4295 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4296 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4297 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4300 static void module_destroy()
4305 LTTV_MODULE("state", "State computation", \
4306 "Update the system state, possibly saving it at intervals", \
4307 module_init
, module_destroy
)