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>
38 * usertrace is there only to be able to update the current CPU of the
39 * usertraces when there is a schedchange. it is a way to link the ProcessState
40 * to the associated usertrace. Link only created upon thread creation.
42 * The cpu id is necessary : it gives us back the current ProcessState when we
43 * are considering data from the usertrace.
46 #define PREALLOCATED_EXECUTION_STACK 10
52 LTT_CHANNEL_GLOBAL_STATE
,
53 LTT_CHANNEL_IRQ_STATE
,
54 LTT_CHANNEL_MODULE_STATE
,
55 LTT_CHANNEL_NETIF_STATE
,
56 LTT_CHANNEL_SOFTIRQ_STATE
,
57 LTT_CHANNEL_SWAP_STATE
,
58 LTT_CHANNEL_SYSCALL_STATE
,
59 LTT_CHANNEL_TASK_STATE
,
64 LTT_CHANNEL_USERSPACE
,
70 LTT_EVENT_SYSCALL_ENTRY
,
71 LTT_EVENT_SYSCALL_EXIT
,
76 LTT_EVENT_SOFT_IRQ_RAISE
,
77 LTT_EVENT_SOFT_IRQ_ENTRY
,
78 LTT_EVENT_SOFT_IRQ_EXIT
,
79 LTT_EVENT_SCHED_SCHEDULE
,
80 LTT_EVENT_PROCESS_FORK
,
81 LTT_EVENT_KTHREAD_CREATE
,
82 LTT_EVENT_PROCESS_EXIT
,
83 LTT_EVENT_PROCESS_FREE
,
85 LTT_EVENT_PROCESS_STATE
,
86 LTT_EVENT_STATEDUMP_END
,
87 LTT_EVENT_FUNCTION_ENTRY
,
88 LTT_EVENT_FUNCTION_EXIT
,
89 LTT_EVENT_THREAD_BRAND
,
90 LTT_EVENT_REQUEST_ISSUE
,
91 LTT_EVENT_REQUEST_COMPLETE
,
92 LTT_EVENT_LIST_INTERRUPT
,
93 LTT_EVENT_SYS_CALL_TABLE
,
94 LTT_EVENT_SOFTIRQ_VEC
;
102 LTT_FIELD_SOFT_IRQ_ID
,
105 LTT_FIELD_PREV_STATE
,
106 LTT_FIELD_PARENT_PID
,
110 LTT_FIELD_CHILD_TGID
,
128 LTTV_STATE_MODE_UNKNOWN
,
129 LTTV_STATE_USER_MODE
,
136 LTTV_STATE_SUBMODE_UNKNOWN
,
137 LTTV_STATE_SUBMODE_NONE
;
141 LTTV_STATE_WAIT_FORK
,
150 LTTV_STATE_UNBRANDED
;
153 LTTV_STATE_USER_THREAD
,
154 LTTV_STATE_KERNEL_THREAD
;
172 LTTV_BDEV_BUSY_READING
,
173 LTTV_BDEV_BUSY_WRITING
;
176 LTTV_STATE_TRACEFILES
,
177 LTTV_STATE_PROCESSES
,
179 LTTV_STATE_RUNNING_PROCESS
,
181 LTTV_STATE_SAVED_STATES
,
182 LTTV_STATE_SAVED_STATES_TIME
,
185 LTTV_STATE_NAME_TABLES
,
186 LTTV_STATE_TRACE_STATE_USE_COUNT
,
187 LTTV_STATE_RESOURCE_CPUS
,
188 LTTV_STATE_RESOURCE_CPUS_COUNT
,
189 LTTV_STATE_RESOURCE_IRQS
,
190 LTTV_STATE_RESOURCE_SOFT_IRQS
,
191 LTTV_STATE_RESOURCE_TRAPS
,
192 LTTV_STATE_RESOURCE_BLKDEVS
;
194 static void create_max_time(LttvTraceState
*tcs
);
196 static void get_max_time(LttvTraceState
*tcs
);
198 static void free_max_time(LttvTraceState
*tcs
);
200 static void create_name_tables(LttvTraceState
*tcs
);
202 static void get_name_tables(LttvTraceState
*tcs
);
204 static void free_name_tables(LttvTraceState
*tcs
);
206 static void free_saved_state(LttvTraceState
*tcs
);
208 static void lttv_state_free_process_table(GHashTable
*processes
);
210 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
211 GPtrArray
*quarktable
);
213 /* Resource function prototypes */
214 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
215 static LttvBdevState
*bdevstate_new(void);
216 static void bdevstate_free(LttvBdevState
*);
217 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
218 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
221 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
223 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
227 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
229 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
233 void lttv_state_state_saved_free(LttvTraceState
*self
,
234 LttvAttribute
*container
)
236 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
240 guint
process_hash(gconstpointer key
)
242 guint pid
= ((const LttvProcessState
*)key
)->pid
;
243 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
247 /* If the hash table hash function is well distributed,
248 * the process_equal should compare different pid */
249 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
251 const LttvProcessState
*process_a
, *process_b
;
254 process_a
= (const LttvProcessState
*)a
;
255 process_b
= (const LttvProcessState
*)b
;
257 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
258 else if(likely(process_a
->pid
== 0 &&
259 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
264 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
266 g_tree_destroy((GTree
*)value
);
269 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
271 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
272 g_hash_table_destroy(usertraces
);
275 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
280 static guint
check_expand(nb
, id
)
285 return max(id
+ 1, nb
* 2);
288 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
289 guint nb
, guint new_nb
)
291 /* Expand an incomplete table */
292 GQuark
*old_table
= *table
;
293 *table
= g_new(GQuark
, new_nb
);
294 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
297 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
298 guint new_nb
, const char *def_string
)
301 GString
*fe_name
= g_string_new("");
302 for(i
= nb
; i
< new_nb
; i
++) {
303 g_string_printf(fe_name
, "%s %d", def_string
, i
);
304 table
[i
] = g_quark_from_string(fe_name
->str
);
306 g_string_free(fe_name
, TRUE
);
309 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
311 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
312 if(likely(new_nb
== ts
->nb_syscalls
))
314 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
315 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
316 /* Update the table size */
317 ts
->nb_syscalls
= new_nb
;
320 static void expand_trap_table(LttvTraceState
*ts
, int id
)
322 guint new_nb
= check_expand(ts
->nb_traps
, id
);
324 if(likely(new_nb
== ts
->nb_traps
))
326 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
327 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
328 /* Update the table size */
329 ts
->nb_traps
= new_nb
;
331 LttvTrapState
*old_table
= ts
->trap_states
;
332 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
333 memcpy(ts
->trap_states
, old_table
,
334 ts
->nb_traps
* sizeof(LttvTrapState
));
335 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
336 ts
->trap_states
[i
].running
= 0;
339 static void expand_irq_table(LttvTraceState
*ts
, int id
)
341 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
343 if(likely(new_nb
== ts
->nb_irqs
))
345 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
346 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
348 LttvIRQState
*old_table
= ts
->irq_states
;
349 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
350 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
351 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
352 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
355 /* Update the table size */
356 ts
->nb_irqs
= new_nb
;
359 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
361 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
363 if(likely(new_nb
== ts
->nb_soft_irqs
))
365 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
366 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
368 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
369 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
370 memcpy(ts
->soft_irq_states
, old_table
,
371 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
372 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
373 ts
->soft_irq_states
[i
].running
= 0;
375 /* Update the table size */
376 ts
->nb_soft_irqs
= new_nb
;
380 restore_init_state(LttvTraceState
*self
)
382 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
384 //LttvTracefileState *tfcs;
386 LttTime start_time
, end_time
;
388 /* Free the process tables */
389 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
390 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
391 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
392 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
395 /* Seek time to beginning */
396 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
397 // closest. It's the tracecontext job to seek the trace to the beginning
398 // anyway : the init state might be used at the middle of the trace as well...
399 //g_tree_destroy(self->parent.ts_context->pqueue);
400 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
402 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
404 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
406 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
407 nb_irqs
= self
->nb_irqs
;
408 nb_soft_irqs
= self
->nb_soft_irqs
;
409 nb_traps
= self
->nb_traps
;
411 /* Put the per cpu running_process to beginning state : process 0. */
412 for(i
=0; i
< nb_cpus
; i
++) {
413 LttvExecutionState
*es
;
414 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
415 LTTV_STATE_UNNAMED
, &start_time
);
416 /* We are not sure is it's a kernel thread or normal thread, put the
417 * bottom stack state to unknown */
418 self
->running_process
[i
]->execution_stack
=
419 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
420 es
= self
->running_process
[i
]->state
=
421 &g_array_index(self
->running_process
[i
]->execution_stack
,
422 LttvExecutionState
, 0);
423 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
424 es
->s
= LTTV_STATE_UNNAMED
;
426 //self->running_process[i]->state->s = LTTV_STATE_RUN;
427 self
->running_process
[i
]->cpu
= i
;
429 /* reset cpu states */
430 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
431 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
432 self
->cpu_states
[i
].last_irq
= -1;
433 self
->cpu_states
[i
].last_soft_irq
= -1;
434 self
->cpu_states
[i
].last_trap
= -1;
438 /* reset irq states */
439 for(i
=0; i
<nb_irqs
; i
++) {
440 if(self
->irq_states
[i
].mode_stack
->len
> 0)
441 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
444 /* reset softirq states */
445 for(i
=0; i
<nb_soft_irqs
; i
++) {
446 self
->soft_irq_states
[i
].pending
= 0;
447 self
->soft_irq_states
[i
].running
= 0;
450 /* reset trap states */
451 for(i
=0; i
<nb_traps
; i
++) {
452 self
->trap_states
[i
].running
= 0;
455 /* reset bdev states */
456 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
457 //g_hash_table_steal_all(self->bdev_states);
458 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
461 nb_tracefile
= self
->parent
.tracefiles
->len
;
463 for(i
= 0 ; i
< nb_tracefile
; i
++) {
465 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
466 LttvTracefileContext
*, i
));
467 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
468 // tfcs->saved_position = 0;
469 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
470 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
471 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
472 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
477 //static LttTime time_zero = {0,0};
479 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
482 const LttTime
*t1
= (const LttTime
*)a
;
483 const LttTime
*t2
= (const LttTime
*)b
;
485 return ltt_time_compare(*t1
, *t2
);
488 static void free_usertrace_key(gpointer data
)
493 #define MAX_STRING_LEN 4096
496 state_load_saved_states(LttvTraceState
*tcs
)
499 GPtrArray
*quarktable
;
500 const char *trace_path
;
504 tcs
->has_precomputed_states
= FALSE
;
508 gchar buf
[MAX_STRING_LEN
];
511 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
512 strncpy(path
, trace_path
, PATH_MAX
-1);
513 count
= strnlen(trace_path
, PATH_MAX
-1);
514 // quarktable : open, test
515 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
516 fp
= fopen(path
, "r");
518 quarktable
= g_ptr_array_sized_new(4096);
520 /* Index 0 is null */
522 if(hdr
== EOF
) return;
523 g_assert(hdr
== HDR_QUARKS
);
527 if(hdr
== EOF
) break;
528 g_assert(hdr
== HDR_QUARK
);
529 g_ptr_array_set_size(quarktable
, q
+1);
532 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
533 if(buf
[i
] == '\0' || feof(fp
)) break;
536 len
= strnlen(buf
, MAX_STRING_LEN
-1);
537 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
538 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
544 // saved_states : open, test
545 strncpy(path
, trace_path
, PATH_MAX
-1);
546 count
= strnlen(trace_path
, PATH_MAX
-1);
547 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
548 fp
= fopen(path
, "r");
552 if(hdr
!= HDR_TRACE
) goto end
;
554 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
556 tcs
->has_precomputed_states
= TRUE
;
561 /* Free the quarktable */
562 for(i
=0; i
<quarktable
->len
; i
++) {
563 string
= g_ptr_array_index (quarktable
, i
);
566 g_ptr_array_free(quarktable
, TRUE
);
571 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
573 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
576 LttvTraceContext
*tc
;
580 LttvTracefileState
*tfcs
;
582 LttvAttributeValue v
;
584 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
585 init((LttvTracesetContext
*)self
, ts
);
587 nb_trace
= lttv_traceset_number(ts
);
588 for(i
= 0 ; i
< nb_trace
; i
++) {
589 tc
= self
->parent
.traces
[i
];
590 tcs
= LTTV_TRACE_STATE(tc
);
591 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
592 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
596 if(*(v
.v_uint
) == 1) {
597 create_name_tables(tcs
);
598 create_max_time(tcs
);
600 get_name_tables(tcs
);
603 nb_tracefile
= tc
->tracefiles
->len
;
604 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
605 nb_irq
= tcs
->nb_irqs
;
606 tcs
->processes
= NULL
;
607 tcs
->usertraces
= NULL
;
608 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
610 /* init cpu resource stuff */
611 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
612 for(j
= 0; j
<nb_cpu
; j
++) {
613 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
614 tcs
->cpu_states
[j
].last_irq
= -1;
615 tcs
->cpu_states
[j
].last_soft_irq
= -1;
616 tcs
->cpu_states
[j
].last_trap
= -1;
617 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
620 /* init irq resource stuff */
621 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
622 for(j
= 0; j
<nb_irq
; j
++) {
623 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
624 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
627 /* init soft irq stuff */
628 /* the kernel has a statically fixed max of 32 softirqs */
629 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
631 /* init trap stuff */
632 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
634 /* init bdev resource stuff */
635 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
637 restore_init_state(tcs
);
638 for(j
= 0 ; j
< nb_tracefile
; j
++) {
640 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
641 LttvTracefileContext
*, j
));
642 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
643 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
644 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
645 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
646 /* It's a Usertrace */
647 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
648 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
650 if(!usertrace_tree
) {
651 usertrace_tree
= g_tree_new_full(compare_usertraces
,
652 NULL
, free_usertrace_key
, NULL
);
653 g_hash_table_insert(tcs
->usertraces
,
654 (gpointer
)tid
, usertrace_tree
);
656 LttTime
*timestamp
= g_new(LttTime
, 1);
657 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
658 ltt_tracefile_creation(tfcs
->parent
.tf
));
659 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
663 /* See if the trace has saved states */
664 state_load_saved_states(tcs
);
669 fini(LttvTracesetState
*self
)
675 //LttvTracefileState *tfcs;
677 LttvAttributeValue v
;
679 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
680 for(i
= 0 ; i
< nb_trace
; i
++) {
681 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
682 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
685 g_assert(*(v
.v_uint
) != 0);
688 if(*(v
.v_uint
) == 0) {
689 free_name_tables(tcs
);
691 free_saved_state(tcs
);
693 g_free(tcs
->running_process
);
694 tcs
->running_process
= NULL
;
695 lttv_state_free_process_table(tcs
->processes
);
696 lttv_state_free_usertraces(tcs
->usertraces
);
697 tcs
->processes
= NULL
;
698 tcs
->usertraces
= NULL
;
700 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
701 fini((LttvTracesetContext
*)self
);
705 static LttvTracesetContext
*
706 new_traceset_context(LttvTracesetContext
*self
)
708 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
712 static LttvTraceContext
*
713 new_trace_context(LttvTracesetContext
*self
)
715 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
719 static LttvTracefileContext
*
720 new_tracefile_context(LttvTracesetContext
*self
)
722 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
726 /* Write the process state of the trace */
728 static void write_process_state(gpointer key
, gpointer value
,
731 LttvProcessState
*process
;
733 LttvExecutionState
*es
;
735 FILE *fp
= (FILE *)user_data
;
740 process
= (LttvProcessState
*)value
;
742 " <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",
743 process
, process
->pid
, process
->tgid
, process
->ppid
,
744 g_quark_to_string(process
->type
),
745 process
->creation_time
.tv_sec
,
746 process
->creation_time
.tv_nsec
,
747 process
->insertion_time
.tv_sec
,
748 process
->insertion_time
.tv_nsec
,
749 g_quark_to_string(process
->name
),
750 g_quark_to_string(process
->brand
),
751 process
->cpu
, process
->free_events
);
753 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
754 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
755 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
756 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
757 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
758 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
759 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
762 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
763 address
= g_array_index(process
->user_stack
, guint64
, i
);
764 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
768 if(process
->usertrace
) {
769 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
770 g_quark_to_string(process
->usertrace
->tracefile_name
),
771 process
->usertrace
->cpu
);
775 fprintf(fp
, " </PROCESS>\n");
779 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
781 guint i
, nb_tracefile
, nb_block
, offset
;
784 LttvTracefileState
*tfcs
;
788 LttEventPosition
*ep
;
792 ep
= ltt_event_position_new();
794 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
796 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
798 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
799 for(i
=0;i
<nb_cpus
;i
++) {
800 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
801 i
, self
->running_process
[i
]->pid
);
804 nb_tracefile
= self
->parent
.tracefiles
->len
;
806 for(i
= 0 ; i
< nb_tracefile
; i
++) {
808 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
809 LttvTracefileContext
*, i
));
810 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
811 tfcs
->parent
.timestamp
.tv_sec
,
812 tfcs
->parent
.timestamp
.tv_nsec
);
813 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
814 if(e
== NULL
) fprintf(fp
,"/>\n");
816 ltt_event_position(e
, ep
);
817 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
818 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
823 fprintf(fp
,"</PROCESS_STATE>\n");
827 static void write_process_state_raw(gpointer key
, gpointer value
,
830 LttvProcessState
*process
;
832 LttvExecutionState
*es
;
834 FILE *fp
= (FILE *)user_data
;
839 process
= (LttvProcessState
*)value
;
840 fputc(HDR_PROCESS
, fp
);
841 //fwrite(&header, sizeof(header), 1, fp);
842 //fprintf(fp, "%s", g_quark_to_string(process->type));
844 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
845 //fprintf(fp, "%s", g_quark_to_string(process->name));
847 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
848 //fprintf(fp, "%s", g_quark_to_string(process->brand));
850 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
851 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
852 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
853 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
854 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
855 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
856 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
857 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
861 " <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",
862 process
, process
->pid
, process
->tgid
, process
->ppid
,
863 g_quark_to_string(process
->type
),
864 process
->creation_time
.tv_sec
,
865 process
->creation_time
.tv_nsec
,
866 process
->insertion_time
.tv_sec
,
867 process
->insertion_time
.tv_nsec
,
868 g_quark_to_string(process
->name
),
869 g_quark_to_string(process
->brand
),
873 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
874 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
877 //fprintf(fp, "%s", g_quark_to_string(es->t));
879 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
880 //fprintf(fp, "%s", g_quark_to_string(es->n));
882 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
883 //fprintf(fp, "%s", g_quark_to_string(es->s));
885 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
886 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
887 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
888 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
890 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
891 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
892 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
893 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
894 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
898 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
899 address
= g_array_index(process
->user_stack
, guint64
, i
);
900 fputc(HDR_USER_STACK
, fp
);
901 fwrite(&address
, sizeof(address
), 1, fp
);
903 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
908 if(process
->usertrace
) {
909 fputc(HDR_USERTRACE
, fp
);
910 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
912 fwrite(&process
->usertrace
->tracefile_name
,
913 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
914 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
916 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
917 g_quark_to_string(process
->usertrace
->tracefile_name
),
918 process
->usertrace
->cpu
);
925 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
927 guint i
, nb_tracefile
, nb_block
, offset
;
930 LttvTracefileState
*tfcs
;
934 LttEventPosition
*ep
;
938 ep
= ltt_event_position_new();
940 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
941 fputc(HDR_PROCESS_STATE
, fp
);
942 fwrite(&t
, sizeof(t
), 1, fp
);
944 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
946 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
947 for(i
=0;i
<nb_cpus
;i
++) {
949 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
950 fwrite(&self
->running_process
[i
]->pid
,
951 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
952 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
953 // i, self->running_process[i]->pid);
956 nb_tracefile
= self
->parent
.tracefiles
->len
;
958 for(i
= 0 ; i
< nb_tracefile
; i
++) {
960 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
961 LttvTracefileContext
*, i
));
962 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
963 // tfcs->parent.timestamp.tv_sec,
964 // tfcs->parent.timestamp.tv_nsec);
965 fputc(HDR_TRACEFILE
, fp
);
966 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
967 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
968 * position following : end of trace */
969 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
971 ltt_event_position(e
, ep
);
972 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
973 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
975 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
976 fwrite(&offset
, sizeof(offset
), 1, fp
);
977 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
984 /* Read process state from a file */
986 /* Called because a HDR_PROCESS was found */
987 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
988 GPtrArray
*quarktable
)
990 LttvExecutionState
*es
;
991 LttvProcessState
*process
, *parent_process
;
992 LttvProcessState tmp
;
997 /* TODO : check return value */
998 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
999 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1000 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1001 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1002 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1003 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1004 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1005 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1006 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1007 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1010 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1012 /* We must link to the parent */
1013 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1015 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1016 if(process
== NULL
) {
1017 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1019 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1020 &tmp
.creation_time
);
1023 process
->insertion_time
= tmp
.insertion_time
;
1024 process
->creation_time
= tmp
.creation_time
;
1025 process
->type
= g_quark_from_string(
1026 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1027 process
->tgid
= tmp
.tgid
;
1028 process
->ppid
= tmp
.ppid
;
1029 process
->brand
= g_quark_from_string(
1030 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1032 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1033 process
->free_events
= tmp
.free_events
;
1036 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1038 gint hdr
= fgetc(fp
);
1039 if(hdr
== EOF
) goto end_loop
;
1043 process
->execution_stack
=
1044 g_array_set_size(process
->execution_stack
,
1045 process
->execution_stack
->len
+ 1);
1046 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1047 process
->execution_stack
->len
-1);
1048 process
->state
= es
;
1050 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1051 es
->t
= g_quark_from_string(
1052 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1053 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1054 es
->n
= g_quark_from_string(
1055 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1056 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1057 es
->s
= g_quark_from_string(
1058 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1059 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1060 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1061 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1063 case HDR_USER_STACK
:
1064 process
->user_stack
= g_array_set_size(process
->user_stack
,
1065 process
->user_stack
->len
+ 1);
1066 address
= &g_array_index(process
->user_stack
, guint64
,
1067 process
->user_stack
->len
-1);
1068 fread(address
, sizeof(address
), 1, fp
);
1069 process
->current_function
= *address
;
1072 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1073 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1085 /* Called because a HDR_PROCESS_STATE was found */
1086 /* Append a saved state to the trace states */
1087 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1089 guint i
, nb_tracefile
, nb_block
, offset
;
1091 LttvTracefileState
*tfcs
;
1093 LttEventPosition
*ep
;
1101 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1103 LttvAttributeValue value
;
1104 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1105 ep
= ltt_event_position_new();
1107 restore_init_state(self
);
1109 fread(&t
, sizeof(t
), 1, fp
);
1112 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1114 if(hdr
== EOF
) goto end_loop
;
1118 /* Call read_process_state_raw */
1119 read_process_state_raw(self
, fp
, quarktable
);
1127 case HDR_USER_STACK
:
1129 case HDR_PROCESS_STATE
:
1135 g_error("Error while parsing saved state file : unknown data header %d",
1141 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1142 for(i
=0;i
<nb_cpus
;i
++) {
1145 g_assert(hdr
== HDR_CPU
);
1146 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1147 g_assert(i
== cpu_num
);
1148 fread(&self
->running_process
[i
]->pid
,
1149 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1152 nb_tracefile
= self
->parent
.tracefiles
->len
;
1154 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1156 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1157 LttvTracefileContext
*, i
));
1158 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1159 // tfcs->parent.timestamp.tv_sec,
1160 // tfcs->parent.timestamp.tv_nsec);
1161 g_tree_remove(pqueue
, &tfcs
->parent
);
1163 g_assert(hdr
== HDR_TRACEFILE
);
1164 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1165 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1166 * position following : end of trace */
1167 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1168 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1169 fread(&offset
, sizeof(offset
), 1, fp
);
1170 fread(&tsc
, sizeof(tsc
), 1, fp
);
1171 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1172 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1174 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1179 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1180 LTTV_STATE_SAVED_STATES
);
1181 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1182 value
= lttv_attribute_add(saved_states_tree
,
1183 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1184 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1185 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1186 *(value
.v_time
) = t
;
1187 lttv_state_save(self
, saved_state_tree
);
1188 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1191 *(self
->max_time_state_recomputed_in_seek
) = t
;
1195 /* Called when a HDR_TRACE is found */
1196 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1197 GPtrArray
*quarktable
)
1202 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1204 if(hdr
== EOF
) goto end_loop
;
1207 case HDR_PROCESS_STATE
:
1208 /* Call read_process_state_raw */
1209 lttv_state_read_raw(tcs
, fp
, quarktable
);
1217 case HDR_USER_STACK
:
1221 g_error("Error while parsing saved state file :"
1222 " unexpected data header %d",
1226 g_error("Error while parsing saved state file : unknown data header %d",
1231 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1232 restore_init_state(tcs
);
1233 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1239 /* Copy each process from an existing hash table to a new one */
1241 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1243 LttvProcessState
*process
, *new_process
;
1245 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1249 process
= (LttvProcessState
*)value
;
1250 new_process
= g_new(LttvProcessState
, 1);
1251 *new_process
= *process
;
1252 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1253 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1254 new_process
->execution_stack
=
1255 g_array_set_size(new_process
->execution_stack
,
1256 process
->execution_stack
->len
);
1257 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1258 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1259 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1261 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1262 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1263 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1264 sizeof(guint64
), 0);
1265 new_process
->user_stack
=
1266 g_array_set_size(new_process
->user_stack
,
1267 process
->user_stack
->len
);
1268 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1269 g_array_index(new_process
->user_stack
, guint64
, i
) =
1270 g_array_index(process
->user_stack
, guint64
, i
);
1272 new_process
->current_function
= process
->current_function
;
1273 g_hash_table_insert(new_processes
, new_process
, new_process
);
1277 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1279 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1281 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1282 return new_processes
;
1285 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1288 LttvCPUState
*retval
;
1290 retval
= g_new(LttvCPUState
, n
);
1292 for(i
=0; i
<n
; i
++) {
1293 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1294 retval
[i
].last_irq
= states
[i
].last_irq
;
1295 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1296 retval
[i
].last_trap
= states
[i
].last_trap
;
1297 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1298 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1299 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1306 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1310 for(i
=0; i
<n
; i
++) {
1311 g_array_free(states
[i
].mode_stack
, TRUE
);
1317 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1320 LttvIRQState
*retval
;
1322 retval
= g_new(LttvIRQState
, n
);
1324 for(i
=0; i
<n
; i
++) {
1325 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1326 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1327 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1328 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1335 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1339 for(i
=0; i
<n
; i
++) {
1340 g_array_free(states
[i
].mode_stack
, TRUE
);
1346 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1349 LttvSoftIRQState
*retval
;
1351 retval
= g_new(LttvSoftIRQState
, n
);
1353 for(i
=0; i
<n
; i
++) {
1354 retval
[i
].pending
= states
[i
].pending
;
1355 retval
[i
].running
= states
[i
].running
;
1361 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1366 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1369 LttvTrapState
*retval
;
1371 retval
= g_new(LttvTrapState
, n
);
1373 for(i
=0; i
<n
; i
++) {
1374 retval
[i
].running
= states
[i
].running
;
1380 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1385 /* bdevstate stuff */
1387 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1389 gint devcode_gint
= devcode
;
1390 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1392 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1393 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1395 gint
* key
= g_new(gint
, 1);
1397 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1405 static LttvBdevState
*bdevstate_new(void)
1407 LttvBdevState
*retval
;
1408 retval
= g_new(LttvBdevState
, 1);
1409 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1414 static void bdevstate_free(LttvBdevState
*bds
)
1416 g_array_free(bds
->mode_stack
, TRUE
);
1420 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1422 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1424 bdevstate_free(bds
);
1427 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1429 LttvBdevState
*retval
;
1431 retval
= bdevstate_new();
1432 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1437 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1439 //GHashTable *ht = (GHashTable *)u;
1440 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1441 LttvBdevState
*newbds
;
1443 newbds
= bdevstate_copy(bds
);
1445 g_hash_table_insert(u
, k
, newbds
);
1448 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1452 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1454 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1459 /* Free a hashtable and the LttvBdevState structures its values
1462 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1464 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1465 g_hash_table_destroy(ht
);
1468 /* The saved state for each trace contains a member "processes", which
1469 stores a copy of the process table, and a member "tracefiles" with
1470 one entry per tracefile. Each tracefile has a "process" member pointing
1471 to the current process and a "position" member storing the tracefile
1472 position (needed to seek to the current "next" event. */
1474 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1476 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1478 LttvTracefileState
*tfcs
;
1480 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1482 guint
*running_process
;
1484 LttvAttributeValue value
;
1486 LttEventPosition
*ep
;
1488 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1489 LTTV_STATE_TRACEFILES
);
1491 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1493 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1495 /* Add the currently running processes array */
1496 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1497 running_process
= g_new(guint
, nb_cpus
);
1498 for(i
=0;i
<nb_cpus
;i
++) {
1499 running_process
[i
] = self
->running_process
[i
]->pid
;
1501 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1503 *(value
.v_pointer
) = running_process
;
1505 g_info("State save");
1507 nb_tracefile
= self
->parent
.tracefiles
->len
;
1509 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1511 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1512 LttvTracefileContext
*, i
));
1513 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1514 value
= lttv_attribute_add(tracefiles_tree
, i
,
1516 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1518 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1520 *(value
.v_uint
) = tfcs
->process
->pid
;
1522 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1524 /* Only save the position if the tfs has not infinite time. */
1525 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1526 // && current_tfcs != tfcs) {
1527 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1528 *(value
.v_pointer
) = NULL
;
1530 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1531 ep
= ltt_event_position_new();
1532 ltt_event_position(e
, ep
);
1533 *(value
.v_pointer
) = ep
;
1535 guint nb_block
, offset
;
1538 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1539 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1541 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1545 /* save the cpu state */
1547 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1549 *(value
.v_uint
) = nb_cpus
;
1551 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1553 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1556 /* save the irq state */
1557 nb_irqs
= self
->nb_irqs
;
1559 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1561 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1564 /* save the soft irq state */
1565 nb_soft_irqs
= self
->nb_soft_irqs
;
1567 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1569 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1572 /* save the trap state */
1573 nb_traps
= self
->nb_traps
;
1575 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1577 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1580 /* save the blkdev states */
1581 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1583 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1587 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1589 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1591 LttvTracefileState
*tfcs
;
1593 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1595 guint
*running_process
;
1597 LttvAttributeType type
;
1599 LttvAttributeValue value
;
1601 LttvAttributeName name
;
1605 LttEventPosition
*ep
;
1607 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1609 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1610 LTTV_STATE_TRACEFILES
);
1612 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1614 g_assert(type
== LTTV_POINTER
);
1615 lttv_state_free_process_table(self
->processes
);
1616 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1618 /* Add the currently running processes array */
1619 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1620 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1622 g_assert(type
== LTTV_POINTER
);
1623 running_process
= *(value
.v_pointer
);
1624 for(i
=0;i
<nb_cpus
;i
++) {
1625 pid
= running_process
[i
];
1626 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1627 g_assert(self
->running_process
[i
] != NULL
);
1630 nb_tracefile
= self
->parent
.tracefiles
->len
;
1632 //g_tree_destroy(tsc->pqueue);
1633 //tsc->pqueue = g_tree_new(compare_tracefile);
1635 /* restore cpu resource states */
1636 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1637 g_assert(type
== LTTV_POINTER
);
1638 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1639 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1641 /* restore irq resource states */
1642 nb_irqs
= self
->nb_irqs
;
1643 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1644 g_assert(type
== LTTV_POINTER
);
1645 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1646 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1648 /* restore soft irq resource states */
1649 nb_soft_irqs
= self
->nb_soft_irqs
;
1650 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1651 g_assert(type
== LTTV_POINTER
);
1652 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1653 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1655 /* restore trap resource states */
1656 nb_traps
= self
->nb_traps
;
1657 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1658 g_assert(type
== LTTV_POINTER
);
1659 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1660 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1662 /* restore the blkdev states */
1663 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1664 g_assert(type
== LTTV_POINTER
);
1665 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1666 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1668 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1670 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1671 LttvTracefileContext
*, i
));
1672 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1673 g_assert(type
== LTTV_GOBJECT
);
1674 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1676 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1678 g_assert(type
== LTTV_UINT
);
1679 pid
= *(value
.v_uint
);
1680 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1682 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1684 g_assert(type
== LTTV_POINTER
);
1685 //g_assert(*(value.v_pointer) != NULL);
1686 ep
= *(value
.v_pointer
);
1687 g_assert(tfcs
->parent
.t_context
!= NULL
);
1689 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1691 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1692 g_tree_remove(tsc
->pqueue
, tfc
);
1695 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1696 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1697 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1698 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1699 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1701 tfc
->timestamp
= ltt_time_infinite
;
1707 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1709 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1711 LttvTracefileState
*tfcs
;
1713 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1715 guint
*running_process
;
1717 LttvAttributeType type
;
1719 LttvAttributeValue value
;
1721 LttvAttributeName name
;
1725 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1726 LTTV_STATE_TRACEFILES
);
1727 g_object_ref(G_OBJECT(tracefiles_tree
));
1728 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1732 g_assert(type
== LTTV_POINTER
);
1733 lttv_state_free_process_table(*(value
.v_pointer
));
1734 *(value
.v_pointer
) = NULL
;
1735 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1737 /* Free running processes array */
1738 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1740 g_assert(type
== LTTV_POINTER
);
1741 running_process
= *(value
.v_pointer
);
1742 g_free(running_process
);
1744 /* free cpu resource states */
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1746 g_assert(type
== LTTV_UINT
);
1747 nb_cpus
= *value
.v_uint
;
1748 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1749 g_assert(type
== LTTV_POINTER
);
1750 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1752 /* free irq resource states */
1753 nb_irqs
= self
->nb_irqs
;
1754 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1755 g_assert(type
== LTTV_POINTER
);
1756 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1758 /* free softirq resource states */
1759 nb_softirqs
= self
->nb_irqs
;
1760 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1761 g_assert(type
== LTTV_POINTER
);
1762 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1764 /* free the blkdev states */
1765 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1766 g_assert(type
== LTTV_POINTER
);
1767 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1769 nb_tracefile
= self
->parent
.tracefiles
->len
;
1771 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1773 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1774 LttvTracefileContext
*, i
));
1775 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1776 g_assert(type
== LTTV_GOBJECT
);
1777 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1779 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1781 g_assert(type
== LTTV_POINTER
);
1782 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1784 g_object_unref(G_OBJECT(tracefiles_tree
));
1788 static void free_saved_state(LttvTraceState
*self
)
1792 LttvAttributeType type
;
1794 LttvAttributeValue value
;
1796 LttvAttributeName name
;
1800 LttvAttribute
*saved_states
;
1802 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1803 LTTV_STATE_SAVED_STATES
);
1805 nb
= lttv_attribute_get_number(saved_states
);
1806 for(i
= 0 ; i
< nb
; i
++) {
1807 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1808 g_assert(type
== LTTV_GOBJECT
);
1809 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1812 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1817 create_max_time(LttvTraceState
*tcs
)
1819 LttvAttributeValue v
;
1821 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1823 g_assert(*(v
.v_pointer
) == NULL
);
1824 *(v
.v_pointer
) = g_new(LttTime
,1);
1825 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1830 get_max_time(LttvTraceState
*tcs
)
1832 LttvAttributeValue v
;
1834 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1836 g_assert(*(v
.v_pointer
) != NULL
);
1837 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1842 free_max_time(LttvTraceState
*tcs
)
1844 LttvAttributeValue v
;
1846 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1848 g_free(*(v
.v_pointer
));
1849 *(v
.v_pointer
) = NULL
;
1853 typedef struct _LttvNameTables
{
1854 // FIXME GQuark *eventtype_names;
1855 GQuark
*syscall_names
;
1861 GQuark
*soft_irq_names
;
1867 create_name_tables(LttvTraceState
*tcs
)
1871 GString
*fe_name
= g_string_new("");
1873 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1875 LttvAttributeValue v
;
1879 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1881 g_assert(*(v
.v_pointer
) == NULL
);
1882 *(v
.v_pointer
) = name_tables
;
1884 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1886 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1888 LTT_EVENT_SYSCALL_ENTRY
,
1889 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1890 NULL
, NULL
, &hooks
)) {
1892 // th = lttv_trace_hook_get_first(&th);
1894 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1895 // nb = ltt_type_element_number(t);
1897 // name_tables->syscall_names = g_new(GQuark, nb);
1898 // name_tables->nb_syscalls = nb;
1900 // for(i = 0 ; i < nb ; i++) {
1901 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1902 // if(!name_tables->syscall_names[i]) {
1903 // GString *string = g_string_new("");
1904 // g_string_printf(string, "syscall %u", i);
1905 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1906 // g_string_free(string, TRUE);
1910 name_tables
->nb_syscalls
= 256;
1911 name_tables
->syscall_names
= g_new(GQuark
, 256);
1912 for(i
= 0 ; i
< 256 ; i
++) {
1913 g_string_printf(fe_name
, "syscall %d", i
);
1914 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1917 name_tables
->syscall_names
= NULL
;
1918 name_tables
->nb_syscalls
= 0;
1920 lttv_trace_hook_remove_all(&hooks
);
1922 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1924 LTT_EVENT_TRAP_ENTRY
,
1925 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1926 NULL
, NULL
, &hooks
)) {
1928 // th = lttv_trace_hook_get_first(&th);
1930 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1931 // //nb = ltt_type_element_number(t);
1933 // name_tables->trap_names = g_new(GQuark, nb);
1934 // for(i = 0 ; i < nb ; i++) {
1935 // name_tables->trap_names[i] = g_quark_from_string(
1936 // ltt_enum_string_get(t, i));
1939 name_tables
->nb_traps
= 256;
1940 name_tables
->trap_names
= g_new(GQuark
, 256);
1941 for(i
= 0 ; i
< 256 ; i
++) {
1942 g_string_printf(fe_name
, "trap %d", i
);
1943 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1946 name_tables
->trap_names
= NULL
;
1947 name_tables
->nb_traps
= 0;
1949 lttv_trace_hook_remove_all(&hooks
);
1951 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1953 LTT_EVENT_IRQ_ENTRY
,
1954 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1955 NULL
, NULL
, &hooks
)) {
1958 name_tables->irq_names = g_new(GQuark, nb);
1959 for(i = 0 ; i < nb ; i++) {
1960 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1964 name_tables
->nb_irqs
= 256;
1965 name_tables
->irq_names
= g_new(GQuark
, 256);
1966 for(i
= 0 ; i
< 256 ; i
++) {
1967 g_string_printf(fe_name
, "irq %d", i
);
1968 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1971 name_tables
->nb_irqs
= 0;
1972 name_tables
->irq_names
= NULL
;
1974 lttv_trace_hook_remove_all(&hooks
);
1976 name_tables->soft_irq_names = g_new(GQuark, nb);
1977 for(i = 0 ; i < nb ; i++) {
1978 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1982 /* the kernel is limited to 32 statically defined softirqs */
1983 name_tables
->nb_softirqs
= 32;
1984 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1985 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1986 g_string_printf(fe_name
, "softirq %d", i
);
1987 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1989 g_array_free(hooks
, TRUE
);
1991 g_string_free(fe_name
, TRUE
);
1996 get_name_tables(LttvTraceState
*tcs
)
1998 LttvNameTables
*name_tables
;
2000 LttvAttributeValue v
;
2002 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2004 g_assert(*(v
.v_pointer
) != NULL
);
2005 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2006 //tcs->eventtype_names = name_tables->eventtype_names;
2007 tcs
->syscall_names
= name_tables
->syscall_names
;
2008 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2009 tcs
->trap_names
= name_tables
->trap_names
;
2010 tcs
->nb_traps
= name_tables
->nb_traps
;
2011 tcs
->irq_names
= name_tables
->irq_names
;
2012 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2013 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2014 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2019 free_name_tables(LttvTraceState
*tcs
)
2021 LttvNameTables
*name_tables
;
2023 LttvAttributeValue v
;
2025 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2027 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2028 *(v
.v_pointer
) = NULL
;
2030 // g_free(name_tables->eventtype_names);
2031 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2032 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2033 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2034 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2035 if(name_tables
) g_free(name_tables
);
2038 #ifdef HASH_TABLE_DEBUG
2040 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2042 LttvProcessState
*process
= (LttvProcessState
*)value
;
2044 /* Test for process corruption */
2045 guint stack_len
= process
->execution_stack
->len
;
2048 static void hash_table_check(GHashTable
*table
)
2050 g_hash_table_foreach(table
, test_process
, NULL
);
2056 /* clears the stack and sets the state passed as argument */
2057 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2059 g_array_set_size(cpust
->mode_stack
, 1);
2060 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2063 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2065 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2066 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2069 static void cpu_pop_mode(LttvCPUState
*cpust
)
2071 if(cpust
->mode_stack
->len
<= 1)
2072 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2074 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2077 /* clears the stack and sets the state passed as argument */
2078 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2080 g_array_set_size(bdevst
->mode_stack
, 1);
2081 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2084 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2086 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2087 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2090 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2092 if(bdevst
->mode_stack
->len
<= 1)
2093 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2095 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2098 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2100 g_array_set_size(irqst
->mode_stack
, 1);
2101 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2104 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2106 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2107 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2110 static void irq_pop_mode(LttvIRQState
*irqst
)
2112 if(irqst
->mode_stack
->len
<= 1)
2113 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2115 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2118 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2121 LttvExecutionState
*es
;
2123 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2124 guint cpu
= tfs
->cpu
;
2126 #ifdef HASH_TABLE_DEBUG
2127 hash_table_check(ts
->processes
);
2129 LttvProcessState
*process
= ts
->running_process
[cpu
];
2131 guint depth
= process
->execution_stack
->len
;
2133 process
->execution_stack
=
2134 g_array_set_size(process
->execution_stack
, depth
+ 1);
2137 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2139 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2142 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2143 es
->cum_cpu_time
= ltt_time_zero
;
2144 es
->s
= process
->state
->s
;
2145 process
->state
= es
;
2149 * return 1 when empty, else 0 */
2150 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2151 LttvTracefileState
*tfs
)
2153 guint depth
= process
->execution_stack
->len
;
2159 process
->execution_stack
=
2160 g_array_set_size(process
->execution_stack
, depth
- 1);
2161 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2163 process
->state
->change
= tfs
->parent
.timestamp
;
2168 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2170 guint cpu
= tfs
->cpu
;
2171 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2172 LttvProcessState
*process
= ts
->running_process
[cpu
];
2174 guint depth
= process
->execution_stack
->len
;
2176 if(process
->state
->t
!= t
){
2177 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2178 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2179 g_info("process state has %s when pop_int is %s\n",
2180 g_quark_to_string(process
->state
->t
),
2181 g_quark_to_string(t
));
2182 g_info("{ %u, %u, %s, %s, %s }\n",
2185 g_quark_to_string(process
->name
),
2186 g_quark_to_string(process
->brand
),
2187 g_quark_to_string(process
->state
->s
));
2192 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2193 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2197 process
->execution_stack
=
2198 g_array_set_size(process
->execution_stack
, depth
- 1);
2199 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2201 process
->state
->change
= tfs
->parent
.timestamp
;
2204 struct search_result
{
2205 const LttTime
*time
; /* Requested time */
2206 LttTime
*best
; /* Best result */
2209 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2211 const LttTime
*elem_time
= (const LttTime
*)a
;
2212 /* Explicit non const cast */
2213 struct search_result
*res
= (struct search_result
*)b
;
2215 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2216 /* The usertrace was created before the schedchange */
2217 /* Get larger keys */
2219 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2220 /* The usertrace was created after the schedchange time */
2221 /* Get smaller keys */
2223 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2224 res
->best
= (LttTime
*)elem_time
;
2227 res
->best
= (LttTime
*)elem_time
;
2234 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2235 guint pid
, const LttTime
*timestamp
)
2237 LttvTracefileState
*tfs
= NULL
;
2238 struct search_result res
;
2239 /* Find the usertrace associated with a pid and time interval.
2240 * Search in the usertraces by PID (within a hash) and then, for each
2241 * corresponding element of the array, find the first one with creation
2242 * timestamp the lowest, but higher or equal to "timestamp". */
2243 res
.time
= timestamp
;
2245 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2246 if(usertrace_tree
) {
2247 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2249 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2257 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2258 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2260 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2262 LttvExecutionState
*es
;
2267 process
->tgid
= tgid
;
2269 process
->name
= name
;
2270 process
->brand
= LTTV_STATE_UNBRANDED
;
2271 //process->last_cpu = tfs->cpu_name;
2272 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2273 process
->type
= LTTV_STATE_USER_THREAD
;
2274 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2275 process
->current_function
= 0; //function 0x0 by default.
2277 g_info("Process %u, core %p", process
->pid
, process
);
2278 g_hash_table_insert(tcs
->processes
, process
, process
);
2281 process
->ppid
= parent
->pid
;
2282 process
->creation_time
= *timestamp
;
2285 /* No parent. This process exists but we are missing all information about
2286 its creation. The birth time is set to zero but we remember the time of
2291 process
->creation_time
= ltt_time_zero
;
2294 process
->insertion_time
= *timestamp
;
2295 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2296 process
->creation_time
.tv_nsec
);
2297 process
->pid_time
= g_quark_from_string(buffer
);
2299 process
->free_events
= 0;
2300 //process->last_cpu = tfs->cpu_name;
2301 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2302 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2303 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2304 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2305 es
= process
->state
= &g_array_index(process
->execution_stack
,
2306 LttvExecutionState
, 0);
2307 es
->t
= LTTV_STATE_USER_MODE
;
2308 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2309 es
->entry
= *timestamp
;
2310 //g_assert(timestamp->tv_sec != 0);
2311 es
->change
= *timestamp
;
2312 es
->cum_cpu_time
= ltt_time_zero
;
2313 es
->s
= LTTV_STATE_RUN
;
2315 es
= process
->state
= &g_array_index(process
->execution_stack
,
2316 LttvExecutionState
, 1);
2317 es
->t
= LTTV_STATE_SYSCALL
;
2318 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2319 es
->entry
= *timestamp
;
2320 //g_assert(timestamp->tv_sec != 0);
2321 es
->change
= *timestamp
;
2322 es
->cum_cpu_time
= ltt_time_zero
;
2323 es
->s
= LTTV_STATE_WAIT_FORK
;
2325 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2326 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2327 sizeof(guint64
), 0);
2332 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2335 LttvProcessState key
;
2336 LttvProcessState
*process
;
2340 process
= g_hash_table_lookup(ts
->processes
, &key
);
2345 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2346 const LttTime
*timestamp
)
2348 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2349 LttvExecutionState
*es
;
2351 /* Put ltt_time_zero creation time for unexisting processes */
2352 if(unlikely(process
== NULL
)) {
2353 process
= lttv_state_create_process(ts
,
2354 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2355 /* We are not sure is it's a kernel thread or normal thread, put the
2356 * bottom stack state to unknown */
2357 process
->execution_stack
=
2358 g_array_set_size(process
->execution_stack
, 1);
2359 process
->state
= es
=
2360 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2361 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2362 es
->s
= LTTV_STATE_UNNAMED
;
2367 /* FIXME : this function should be called when we receive an event telling that
2368 * release_task has been called in the kernel. In happens generally when
2369 * the parent waits for its child terminaison, but may also happen in special
2370 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2371 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2372 * of a killed thread group, but isn't the leader.
2374 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2376 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2377 LttvProcessState key
;
2379 /* Wait for both schedule with exit dead and process free to happen.
2380 * They can happen in any order. */
2381 if (++(process
->free_events
) < 2)
2384 key
.pid
= process
->pid
;
2385 key
.cpu
= process
->cpu
;
2386 g_hash_table_remove(ts
->processes
, &key
);
2387 g_array_free(process
->execution_stack
, TRUE
);
2388 g_array_free(process
->user_stack
, TRUE
);
2394 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2396 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2397 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2402 static void lttv_state_free_process_table(GHashTable
*processes
)
2404 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2405 g_hash_table_destroy(processes
);
2409 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2411 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2413 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2414 LttvProcessState
*process
= ts
->running_process
[cpu
];
2415 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2416 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2417 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2418 LttvExecutionSubmode submode
;
2420 guint syscall
= ltt_event_get_unsigned(e
, f
);
2421 expand_syscall_table(ts
, syscall
);
2422 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2423 /* There can be no system call from PID 0 : unknown state */
2424 if(process
->pid
!= 0)
2425 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2430 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2432 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2434 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2435 LttvProcessState
*process
= ts
->running_process
[cpu
];
2437 /* There can be no system call from PID 0 : unknown state */
2438 if(process
->pid
!= 0)
2439 pop_state(s
, LTTV_STATE_SYSCALL
);
2444 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2446 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2447 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2448 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2449 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2450 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2452 LttvExecutionSubmode submode
;
2454 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2456 expand_trap_table(ts
, trap
);
2458 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2460 push_state(s
, LTTV_STATE_TRAP
, submode
);
2462 /* update cpu status */
2463 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2465 /* update trap status */
2466 s
->cpu_state
->last_trap
= trap
;
2467 ts
->trap_states
[trap
].running
++;
2472 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2474 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2475 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2476 gint trap
= s
->cpu_state
->last_trap
;
2478 pop_state(s
, LTTV_STATE_TRAP
);
2480 /* update cpu status */
2481 cpu_pop_mode(s
->cpu_state
);
2483 /* update trap status */
2485 if(ts
->trap_states
[trap
].running
)
2486 ts
->trap_states
[trap
].running
--;
2491 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2493 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2494 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2495 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2496 //guint8 ev_id = ltt_event_eventtype_id(e);
2497 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2498 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2500 LttvExecutionSubmode submode
;
2501 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2503 expand_irq_table(ts
, irq
);
2505 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2507 /* Do something with the info about being in user or system mode when int? */
2508 push_state(s
, LTTV_STATE_IRQ
, submode
);
2510 /* update cpu status */
2511 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2513 /* update irq status */
2514 s
->cpu_state
->last_irq
= irq
;
2515 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2520 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2522 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2523 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2524 gint softirq
= s
->cpu_state
->last_soft_irq
;
2526 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2528 /* update softirq status */
2530 if(ts
->soft_irq_states
[softirq
].running
)
2531 ts
->soft_irq_states
[softirq
].running
--;
2533 /* update cpu status */
2534 cpu_pop_mode(s
->cpu_state
);
2539 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2541 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2542 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2544 pop_state(s
, LTTV_STATE_IRQ
);
2546 /* update cpu status */
2547 cpu_pop_mode(s
->cpu_state
);
2549 /* update irq status */
2550 if (s
->cpu_state
->last_irq
!= -1)
2551 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2556 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2558 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2559 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2560 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2561 //guint8 ev_id = ltt_event_eventtype_id(e);
2562 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2563 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2565 LttvExecutionSubmode submode
;
2566 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2567 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2569 if(softirq
< nb_softirqs
) {
2570 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2572 /* Fixup an incomplete irq table */
2573 GString
*string
= g_string_new("");
2574 g_string_printf(string
, "softirq %llu", softirq
);
2575 submode
= g_quark_from_string(string
->str
);
2576 g_string_free(string
, TRUE
);
2579 /* update softirq status */
2580 /* a soft irq raises are not cumulative */
2581 ts
->soft_irq_states
[softirq
].pending
=1;
2586 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2588 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2589 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2590 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2591 //guint8 ev_id = ltt_event_eventtype_id(e);
2592 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2593 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2594 LttvExecutionSubmode submode
;
2595 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2596 expand_soft_irq_table(ts
, softirq
);
2597 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2599 /* Do something with the info about being in user or system mode when int? */
2600 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2602 /* update cpu status */
2603 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2605 /* update softirq status */
2606 s
->cpu_state
->last_soft_irq
= softirq
;
2607 if(ts
->soft_irq_states
[softirq
].pending
)
2608 ts
->soft_irq_states
[softirq
].pending
--;
2609 ts
->soft_irq_states
[softirq
].running
++;
2614 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2616 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2617 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2618 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2619 //guint8 ev_id = ltt_event_eventtype_id(e);
2620 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2622 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2623 lttv_trace_get_hook_field(th
, 0)));
2624 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2626 expand_irq_table(ts
, irq
);
2627 ts
->irq_names
[irq
] = action
;
2633 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2635 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2636 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2637 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2638 //guint8 ev_id = ltt_event_eventtype_id(e);
2639 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2641 guint major
= ltt_event_get_long_unsigned(e
,
2642 lttv_trace_get_hook_field(th
, 0));
2643 guint minor
= ltt_event_get_long_unsigned(e
,
2644 lttv_trace_get_hook_field(th
, 1));
2645 guint oper
= ltt_event_get_long_unsigned(e
,
2646 lttv_trace_get_hook_field(th
, 2));
2647 guint16 devcode
= MKDEV(major
,minor
);
2649 /* have we seen this block device before? */
2650 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2653 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2655 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2660 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2662 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2663 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2664 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2665 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2667 guint major
= ltt_event_get_long_unsigned(e
,
2668 lttv_trace_get_hook_field(th
, 0));
2669 guint minor
= ltt_event_get_long_unsigned(e
,
2670 lttv_trace_get_hook_field(th
, 1));
2671 //guint oper = ltt_event_get_long_unsigned(e,
2672 // lttv_trace_get_hook_field(th, 2));
2673 guint16 devcode
= MKDEV(major
,minor
);
2675 /* have we seen this block device before? */
2676 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2678 /* update block device */
2679 bdev_pop_mode(bdev
);
2684 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2688 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2689 guint cpu
= tfs
->cpu
;
2690 LttvProcessState
*process
= ts
->running_process
[cpu
];
2692 guint depth
= process
->user_stack
->len
;
2694 process
->user_stack
=
2695 g_array_set_size(process
->user_stack
, depth
+ 1);
2697 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2698 *new_func
= funcptr
;
2699 process
->current_function
= funcptr
;
2702 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2704 guint cpu
= tfs
->cpu
;
2705 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2706 LttvProcessState
*process
= ts
->running_process
[cpu
];
2708 if(process
->current_function
!= funcptr
){
2709 g_info("Different functions (%lu.%09lu): ignore it\n",
2710 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2711 g_info("process state has %llu when pop_function is %llu\n",
2712 process
->current_function
, funcptr
);
2713 g_info("{ %u, %u, %s, %s, %s }\n",
2716 g_quark_to_string(process
->name
),
2717 g_quark_to_string(process
->brand
),
2718 g_quark_to_string(process
->state
->s
));
2721 guint depth
= process
->user_stack
->len
;
2724 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2725 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2729 process
->user_stack
=
2730 g_array_set_size(process
->user_stack
, depth
- 1);
2731 process
->current_function
=
2732 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2736 static gboolean
function_entry(void *hook_data
, void *call_data
)
2738 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2739 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2740 //guint8 ev_id = ltt_event_eventtype_id(e);
2741 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2742 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2743 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2745 push_function(s
, funcptr
);
2749 static gboolean
function_exit(void *hook_data
, void *call_data
)
2751 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2752 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2753 //guint8 ev_id = ltt_event_eventtype_id(e);
2754 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2755 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2756 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2758 pop_function(s
, funcptr
);
2762 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2765 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2767 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2772 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2773 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2774 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2776 expand_syscall_table(ts
, id
);
2777 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2782 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2784 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2785 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2786 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2787 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2792 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2793 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2794 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2796 expand_soft_irq_table(ts
, id
);
2797 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2802 static gboolean
schedchange(void *hook_data
, void *call_data
)
2804 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2806 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2807 LttvProcessState
*process
= ts
->running_process
[cpu
];
2808 //LttvProcessState *old_process = ts->running_process[cpu];
2810 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2811 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2812 guint pid_in
, pid_out
;
2815 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2816 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2817 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2819 if(likely(process
!= NULL
)) {
2821 /* We could not know but it was not the idle process executing.
2822 This should only happen at the beginning, before the first schedule
2823 event, and when the initial information (current process for each CPU)
2824 is missing. It is not obvious how we could, after the fact, compensate
2825 the wrongly attributed statistics. */
2827 //This test only makes sense once the state is known and if there is no
2828 //missing events. We need to silently ignore schedchange coming after a
2829 //process_free, or it causes glitches. (FIXME)
2830 //if(unlikely(process->pid != pid_out)) {
2831 // g_assert(process->pid == 0);
2833 if(process
->pid
== 0
2834 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2836 /* Scheduling out of pid 0 at beginning of the trace :
2837 * we know for sure it is in syscall mode at this point. */
2838 g_assert(process
->execution_stack
->len
== 1);
2839 process
->state
->t
= LTTV_STATE_SYSCALL
;
2840 process
->state
->s
= LTTV_STATE_WAIT
;
2841 process
->state
->change
= s
->parent
.timestamp
;
2842 process
->state
->entry
= s
->parent
.timestamp
;
2845 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2846 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2847 process
->state
->change
= s
->parent
.timestamp
;
2849 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2850 else process
->state
->s
= LTTV_STATE_WAIT
;
2851 process
->state
->change
= s
->parent
.timestamp
;
2854 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2855 /* see sched.h for states */
2856 if (!exit_process(s
, process
)) {
2857 process
->state
->s
= LTTV_STATE_DEAD
;
2858 process
->state
->change
= s
->parent
.timestamp
;
2863 process
= ts
->running_process
[cpu
] =
2864 lttv_state_find_process_or_create(
2865 (LttvTraceState
*)s
->parent
.t_context
,
2867 &s
->parent
.timestamp
);
2868 process
->state
->s
= LTTV_STATE_RUN
;
2870 if(process
->usertrace
)
2871 process
->usertrace
->cpu
= cpu
;
2872 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2873 process
->state
->change
= s
->parent
.timestamp
;
2875 /* update cpu status */
2877 /* going to idle task */
2878 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2880 /* scheduling a real task.
2881 * we must be careful here:
2882 * if we just schedule()'ed to a process that is
2883 * in a trap, we must put the cpu in trap mode
2885 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2886 if(process
->state
->t
== LTTV_STATE_TRAP
)
2887 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2893 static gboolean
process_fork(void *hook_data
, void *call_data
)
2895 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2896 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2897 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2899 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2900 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2901 //LttvProcessState *zombie_process;
2903 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2904 LttvProcessState
*process
= ts
->running_process
[cpu
];
2905 LttvProcessState
*child_process
;
2906 struct marker_field
*f
;
2909 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2912 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2913 s
->parent
.target_pid
= child_pid
;
2916 f
= lttv_trace_get_hook_field(th
, 2);
2918 child_tgid
= ltt_event_get_unsigned(e
, f
);
2922 /* Mathieu : it seems like the process might have been scheduled in before the
2923 * fork, and, in a rare case, might be the current process. This might happen
2924 * in a SMP case where we don't have enough precision on the clocks.
2926 * Test reenabled after precision fixes on time. (Mathieu) */
2928 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2930 if(unlikely(zombie_process
!= NULL
)) {
2931 /* Reutilisation of PID. Only now we are sure that the old PID
2932 * has been released. FIXME : should know when release_task happens instead.
2934 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2936 for(i
=0; i
< num_cpus
; i
++) {
2937 g_assert(zombie_process
!= ts
->running_process
[i
]);
2940 exit_process(s
, zombie_process
);
2943 g_assert(process
->pid
!= child_pid
);
2944 // FIXME : Add this test in the "known state" section
2945 // g_assert(process->pid == parent_pid);
2946 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2947 if(child_process
== NULL
) {
2948 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2949 child_pid
, child_tgid
,
2950 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2952 /* The process has already been created : due to time imprecision between
2953 * multiple CPUs : it has been scheduled in before creation. Note that we
2954 * shouldn't have this kind of imprecision.
2956 * Simply put a correct parent.
2958 g_error("Process %u has been created at [%lu.%09lu] "
2959 "and inserted at [%lu.%09lu] before \n"
2960 "fork on cpu %u[%lu.%09lu].\n"
2961 "Probably an unsynchronized TSC problem on the traced machine.",
2963 child_process
->creation_time
.tv_sec
,
2964 child_process
->creation_time
.tv_nsec
,
2965 child_process
->insertion_time
.tv_sec
,
2966 child_process
->insertion_time
.tv_nsec
,
2967 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
2968 //g_assert(0); /* This is a problematic case : the process has been created
2969 // before the fork event */
2970 child_process
->ppid
= process
->pid
;
2971 child_process
->tgid
= child_tgid
;
2973 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2974 child_process
->name
= process
->name
;
2975 child_process
->brand
= process
->brand
;
2980 /* We stamp a newly created process as kernel_thread.
2981 * The thread should not be running yet. */
2982 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2984 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2985 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2986 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2988 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2989 LttvProcessState
*process
;
2990 LttvExecutionState
*es
;
2993 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2994 s
->parent
.target_pid
= pid
;
2996 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2998 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2999 process
->execution_stack
=
3000 g_array_set_size(process
->execution_stack
, 1);
3001 es
= process
->state
=
3002 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3003 es
->t
= LTTV_STATE_SYSCALL
;
3005 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3010 static gboolean
process_exit(void *hook_data
, void *call_data
)
3012 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3013 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3014 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3016 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3017 LttvProcessState
*process
; // = ts->running_process[cpu];
3019 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3020 s
->parent
.target_pid
= pid
;
3022 // FIXME : Add this test in the "known state" section
3023 // g_assert(process->pid == pid);
3025 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3026 if(likely(process
!= NULL
)) {
3027 process
->state
->s
= LTTV_STATE_EXIT
;
3032 static gboolean
process_free(void *hook_data
, void *call_data
)
3034 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3035 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3036 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3037 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3039 LttvProcessState
*process
;
3041 /* PID of the process to release */
3042 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3043 s
->parent
.target_pid
= release_pid
;
3045 g_assert(release_pid
!= 0);
3047 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3048 if(likely(process
!= NULL
))
3049 exit_process(s
, process
);
3052 if(likely(process
!= NULL
)) {
3053 /* release_task is happening at kernel level : we can now safely release
3054 * the data structure of the process */
3055 //This test is fun, though, as it may happen that
3056 //at time t : CPU 0 : process_free
3057 //at time t+150ns : CPU 1 : schedule out
3058 //Clearly due to time imprecision, we disable it. (Mathieu)
3059 //If this weird case happen, we have no choice but to put the
3060 //Currently running process on the cpu to 0.
3061 //I re-enable it following time precision fixes. (Mathieu)
3062 //Well, in the case where an process is freed by a process on another CPU
3063 //and still scheduled, it happens that this is the schedchange that will
3064 //drop the last reference count. Do not free it here!
3065 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3067 for(i
=0; i
< num_cpus
; i
++) {
3068 //g_assert(process != ts->running_process[i]);
3069 if(process
== ts
->running_process
[i
]) {
3070 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3074 if(i
== num_cpus
) /* process is not scheduled */
3075 exit_process(s
, process
);
3082 static gboolean
process_exec(void *hook_data
, void *call_data
)
3084 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3085 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3086 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3087 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3090 LttvProcessState
*process
= ts
->running_process
[cpu
];
3092 #if 0//how to use a sequence that must be transformed in a string
3093 /* PID of the process to release */
3094 guint64 name_len
= ltt_event_field_element_number(e
,
3095 lttv_trace_get_hook_field(th
, 0));
3096 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3097 LttField
*child
= ltt_event_field_element_select(e
,
3098 lttv_trace_get_hook_field(th
, 0), 0);
3100 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3101 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3102 memcpy(null_term_name
, name_begin
, name_len
);
3103 null_term_name
[name_len
] = '\0';
3104 process
->name
= g_quark_from_string(null_term_name
);
3107 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3108 lttv_trace_get_hook_field(th
, 0)));
3109 process
->brand
= LTTV_STATE_UNBRANDED
;
3110 //g_free(null_term_name);
3114 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3116 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3117 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3118 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3119 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3122 LttvProcessState
*process
= ts
->running_process
[cpu
];
3124 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3125 process
->brand
= g_quark_from_string(name
);
3130 static void fix_process(gpointer key
, gpointer value
,
3133 LttvProcessState
*process
;
3134 LttvExecutionState
*es
;
3135 process
= (LttvProcessState
*)value
;
3136 LttTime
*timestamp
= (LttTime
*)user_data
;
3138 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3139 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3140 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3141 es
->t
= LTTV_STATE_SYSCALL
;
3142 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3143 es
->entry
= *timestamp
;
3144 es
->change
= *timestamp
;
3145 es
->cum_cpu_time
= ltt_time_zero
;
3146 if(es
->s
== LTTV_STATE_UNNAMED
)
3147 es
->s
= LTTV_STATE_WAIT
;
3150 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3151 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3152 es
->t
= LTTV_STATE_USER_MODE
;
3153 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3154 es
->entry
= *timestamp
;
3155 //g_assert(timestamp->tv_sec != 0);
3156 es
->change
= *timestamp
;
3157 es
->cum_cpu_time
= ltt_time_zero
;
3158 if(es
->s
== LTTV_STATE_UNNAMED
)
3159 es
->s
= LTTV_STATE_RUN
;
3161 if(process
->execution_stack
->len
== 1) {
3162 /* Still in bottom unknown mode, means never did a system call
3163 * May be either in user mode, syscall mode, running or waiting.*/
3164 /* FIXME : we may be tagging syscall mode when being user mode */
3165 process
->execution_stack
=
3166 g_array_set_size(process
->execution_stack
, 2);
3167 es
= process
->state
= &g_array_index(process
->execution_stack
,
3168 LttvExecutionState
, 1);
3169 es
->t
= LTTV_STATE_SYSCALL
;
3170 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3171 es
->entry
= *timestamp
;
3172 //g_assert(timestamp->tv_sec != 0);
3173 es
->change
= *timestamp
;
3174 es
->cum_cpu_time
= ltt_time_zero
;
3175 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3176 es
->s
= LTTV_STATE_WAIT
;
3182 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3184 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3185 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3186 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3187 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3188 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3190 /* For all processes */
3191 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3192 /* else, if stack[0] is unknown, set to user mode, running */
3194 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3199 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3201 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3202 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3203 //It's slow : optimise later by doing this before reading trace.
3204 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3210 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3211 LttvProcessState
*process
= ts
->running_process
[cpu
];
3212 LttvProcessState
*parent_process
;
3213 struct marker_field
*f
;
3214 GQuark type
, mode
, submode
, status
;
3215 LttvExecutionState
*es
;
3219 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3220 s
->parent
.target_pid
= pid
;
3223 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3226 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3229 f
= lttv_trace_get_hook_field(th
, 3);
3230 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3232 //FIXME: type is rarely used, enum must match possible types.
3235 f
= lttv_trace_get_hook_field(th
, 4);
3236 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3239 f
= lttv_trace_get_hook_field(th
, 5);
3240 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3243 f
= lttv_trace_get_hook_field(th
, 6);
3244 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3247 f
= lttv_trace_get_hook_field(th
, 7);
3249 tgid
= ltt_event_get_unsigned(e
, f
);
3254 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3255 for(i
=0; i
<nb_cpus
; i
++) {
3256 process
= lttv_state_find_process(ts
, i
, pid
);
3257 g_assert(process
!= NULL
);
3259 process
->ppid
= parent_pid
;
3260 process
->tgid
= tgid
;
3261 process
->name
= g_quark_from_string(command
);
3263 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3264 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3268 /* The process might exist if a process was forked while performing the
3270 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3271 if(process
== NULL
) {
3272 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3273 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3274 pid
, tgid
, g_quark_from_string(command
),
3275 &s
->parent
.timestamp
);
3277 /* Keep the stack bottom : a running user mode */
3278 /* Disabled because of inconsistencies in the current statedump states. */
3279 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3280 /* Only keep the bottom
3281 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3282 /* Will cause expected trap when in fact being syscall (even after end of
3284 * Will cause expected interrupt when being syscall. (only before end of
3285 * statedump event) */
3286 // This will cause a "popping last state on stack, ignoring it."
3287 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3288 es
= process
->state
= &g_array_index(process
->execution_stack
,
3289 LttvExecutionState
, 0);
3290 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3291 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3292 es
->s
= LTTV_STATE_UNNAMED
;
3293 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3295 es
->t
= LTTV_STATE_SYSCALL
;
3300 /* User space process :
3301 * bottom : user mode
3302 * either currently running or scheduled out.
3303 * can be scheduled out because interrupted in (user mode or in syscall)
3304 * or because of an explicit call to the scheduler in syscall. Note that
3305 * the scheduler call comes after the irq_exit, so never in interrupt
3307 // temp workaround : set size to 1 : only have user mode bottom of stack.
3308 // will cause g_info message of expected syscall mode when in fact being
3309 // in user mode. Can also cause expected trap when in fact being user
3310 // mode in the event of a page fault reenabling interrupts in the handler.
3311 // Expected syscall and trap can also happen after the end of statedump
3312 // This will cause a "popping last state on stack, ignoring it."
3313 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3314 es
= process
->state
= &g_array_index(process
->execution_stack
,
3315 LttvExecutionState
, 0);
3316 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3317 es
->s
= LTTV_STATE_UNNAMED
;
3318 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3320 es
->t
= LTTV_STATE_USER_MODE
;
3328 es
= process
->state
= &g_array_index(process
->execution_stack
,
3329 LttvExecutionState
, 1);
3330 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3331 es
->s
= LTTV_STATE_UNNAMED
;
3332 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3336 /* The process has already been created :
3337 * Probably was forked while dumping the process state or
3338 * was simply scheduled in prior to get the state dump event.
3340 process
->ppid
= parent_pid
;
3341 process
->tgid
= tgid
;
3342 process
->name
= g_quark_from_string(command
);
3343 process
->type
= type
;
3345 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3347 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3348 if(type
== LTTV_STATE_KERNEL_THREAD
)
3349 es
->t
= LTTV_STATE_SYSCALL
;
3351 es
->t
= LTTV_STATE_USER_MODE
;
3354 /* Don't mess around with the stack, it will eventually become
3355 * ok after the end of state dump. */
3362 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3364 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3366 lttv_state_add_event_hooks(tss
);
3371 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3373 LttvTraceset
*traceset
= self
->parent
.ts
;
3375 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3379 LttvTracefileState
*tfs
;
3385 LttvAttributeValue val
;
3387 nb_trace
= lttv_traceset_number(traceset
);
3388 for(i
= 0 ; i
< nb_trace
; i
++) {
3389 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3391 /* Find the eventtype id for the following events and register the
3392 associated by id hooks. */
3394 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3395 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3398 lttv_trace_find_hook(ts
->parent
.t
,
3400 LTT_EVENT_SYSCALL_ENTRY
,
3401 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3402 syscall_entry
, NULL
, &hooks
);
3404 lttv_trace_find_hook(ts
->parent
.t
,
3406 LTT_EVENT_SYSCALL_EXIT
,
3408 syscall_exit
, NULL
, &hooks
);
3410 lttv_trace_find_hook(ts
->parent
.t
,
3412 LTT_EVENT_TRAP_ENTRY
,
3413 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3414 trap_entry
, NULL
, &hooks
);
3416 lttv_trace_find_hook(ts
->parent
.t
,
3418 LTT_EVENT_TRAP_EXIT
,
3420 trap_exit
, NULL
, &hooks
);
3422 lttv_trace_find_hook(ts
->parent
.t
,
3424 LTT_EVENT_IRQ_ENTRY
,
3425 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3426 irq_entry
, NULL
, &hooks
);
3428 lttv_trace_find_hook(ts
->parent
.t
,
3432 irq_exit
, NULL
, &hooks
);
3434 lttv_trace_find_hook(ts
->parent
.t
,
3436 LTT_EVENT_SOFT_IRQ_RAISE
,
3437 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3438 soft_irq_raise
, NULL
, &hooks
);
3440 lttv_trace_find_hook(ts
->parent
.t
,
3442 LTT_EVENT_SOFT_IRQ_ENTRY
,
3443 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3444 soft_irq_entry
, NULL
, &hooks
);
3446 lttv_trace_find_hook(ts
->parent
.t
,
3448 LTT_EVENT_SOFT_IRQ_EXIT
,
3450 soft_irq_exit
, NULL
, &hooks
);
3452 lttv_trace_find_hook(ts
->parent
.t
,
3454 LTT_EVENT_SCHED_SCHEDULE
,
3455 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3456 LTT_FIELD_PREV_STATE
),
3457 schedchange
, NULL
, &hooks
);
3459 lttv_trace_find_hook(ts
->parent
.t
,
3461 LTT_EVENT_PROCESS_FORK
,
3462 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3463 LTT_FIELD_CHILD_TGID
),
3464 process_fork
, NULL
, &hooks
);
3466 lttv_trace_find_hook(ts
->parent
.t
,
3468 LTT_EVENT_KTHREAD_CREATE
,
3469 FIELD_ARRAY(LTT_FIELD_PID
),
3470 process_kernel_thread
, NULL
, &hooks
);
3472 lttv_trace_find_hook(ts
->parent
.t
,
3474 LTT_EVENT_PROCESS_EXIT
,
3475 FIELD_ARRAY(LTT_FIELD_PID
),
3476 process_exit
, NULL
, &hooks
);
3478 lttv_trace_find_hook(ts
->parent
.t
,
3480 LTT_EVENT_PROCESS_FREE
,
3481 FIELD_ARRAY(LTT_FIELD_PID
),
3482 process_free
, NULL
, &hooks
);
3484 lttv_trace_find_hook(ts
->parent
.t
,
3487 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3488 process_exec
, NULL
, &hooks
);
3490 lttv_trace_find_hook(ts
->parent
.t
,
3491 LTT_CHANNEL_USERSPACE
,
3492 LTT_EVENT_THREAD_BRAND
,
3493 FIELD_ARRAY(LTT_FIELD_NAME
),
3494 thread_brand
, NULL
, &hooks
);
3496 /* statedump-related hooks */
3497 lttv_trace_find_hook(ts
->parent
.t
,
3498 LTT_CHANNEL_TASK_STATE
,
3499 LTT_EVENT_PROCESS_STATE
,
3500 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3501 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3502 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3503 enum_process_state
, NULL
, &hooks
);
3505 lttv_trace_find_hook(ts
->parent
.t
,
3506 LTT_CHANNEL_GLOBAL_STATE
,
3507 LTT_EVENT_STATEDUMP_END
,
3509 statedump_end
, NULL
, &hooks
);
3511 lttv_trace_find_hook(ts
->parent
.t
,
3512 LTT_CHANNEL_IRQ_STATE
,
3513 LTT_EVENT_LIST_INTERRUPT
,
3514 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3515 enum_interrupt
, NULL
, &hooks
);
3517 lttv_trace_find_hook(ts
->parent
.t
,
3519 LTT_EVENT_REQUEST_ISSUE
,
3520 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3521 bdev_request_issue
, NULL
, &hooks
);
3523 lttv_trace_find_hook(ts
->parent
.t
,
3525 LTT_EVENT_REQUEST_COMPLETE
,
3526 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3527 bdev_request_complete
, NULL
, &hooks
);
3529 lttv_trace_find_hook(ts
->parent
.t
,
3530 LTT_CHANNEL_USERSPACE
,
3531 LTT_EVENT_FUNCTION_ENTRY
,
3532 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3533 function_entry
, NULL
, &hooks
);
3535 lttv_trace_find_hook(ts
->parent
.t
,
3536 LTT_CHANNEL_USERSPACE
,
3537 LTT_EVENT_FUNCTION_EXIT
,
3538 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3539 function_exit
, NULL
, &hooks
);
3541 lttv_trace_find_hook(ts
->parent
.t
,
3542 LTT_CHANNEL_SYSCALL_STATE
,
3543 LTT_EVENT_SYS_CALL_TABLE
,
3544 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3545 dump_syscall
, NULL
, &hooks
);
3547 lttv_trace_find_hook(ts
->parent
.t
,
3548 LTT_CHANNEL_SOFTIRQ_STATE
,
3549 LTT_EVENT_SOFTIRQ_VEC
,
3550 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3551 dump_softirq
, NULL
, &hooks
);
3553 /* Add these hooks to each event_by_id hooks list */
3555 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3557 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3559 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3560 LttvTracefileContext
*, j
));
3562 for(k
= 0 ; k
< hooks
->len
; k
++) {
3563 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3564 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3566 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3572 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3573 *(val
.v_pointer
) = hooks
;
3577 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3579 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3581 lttv_state_remove_event_hooks(tss
);
3586 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3588 LttvTraceset
*traceset
= self
->parent
.ts
;
3590 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3594 LttvTracefileState
*tfs
;
3600 LttvAttributeValue val
;
3602 nb_trace
= lttv_traceset_number(traceset
);
3603 for(i
= 0 ; i
< nb_trace
; i
++) {
3604 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3606 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3607 hooks
= *(val
.v_pointer
);
3609 /* Remove these hooks from each event_by_id hooks list */
3611 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3613 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3615 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3616 LttvTracefileContext
*, j
));
3618 for(k
= 0 ; k
< hooks
->len
; k
++) {
3619 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3620 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3621 lttv_hooks_remove_data(
3622 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3627 lttv_trace_hook_remove_all(&hooks
);
3628 g_array_free(hooks
, TRUE
);
3632 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3634 guint
*event_count
= (guint
*)hook_data
;
3636 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3637 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3642 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3644 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3646 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3648 LttvAttributeValue value
;
3650 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3651 LTTV_STATE_SAVED_STATES
);
3652 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3653 value
= lttv_attribute_add(saved_states_tree
,
3654 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3655 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3656 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3657 *(value
.v_time
) = self
->parent
.timestamp
;
3658 lttv_state_save(tcs
, saved_state_tree
);
3659 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3660 self
->parent
.timestamp
.tv_nsec
);
3662 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3667 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3669 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3671 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3676 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3684 static gboolean
block_start(void *hook_data
, void *call_data
)
3686 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3688 LttvTracefileState
*tfcs
;
3690 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3692 LttEventPosition
*ep
;
3694 guint i
, nb_block
, nb_event
, nb_tracefile
;
3698 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3700 LttvAttributeValue value
;
3702 ep
= ltt_event_position_new();
3704 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3706 /* Count the number of events added since the last block end in any
3709 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3711 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3712 LttvTracefileContext
, i
));
3713 ltt_event_position(tfcs
->parent
.e
, ep
);
3714 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3715 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3716 tfcs
->saved_position
= nb_event
;
3720 if(tcs
->nb_event
>= tcs
->save_interval
) {
3721 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3722 LTTV_STATE_SAVED_STATES
);
3723 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3724 value
= lttv_attribute_add(saved_states_tree
,
3725 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3726 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3727 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3728 *(value
.v_time
) = self
->parent
.timestamp
;
3729 lttv_state_save(tcs
, saved_state_tree
);
3731 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3732 self
->parent
.timestamp
.tv_nsec
);
3734 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3740 static gboolean
block_end(void *hook_data
, void *call_data
)
3742 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3744 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3748 LttEventPosition
*ep
;
3750 guint nb_block
, nb_event
;
3752 ep
= ltt_event_position_new();
3753 ltt_event_position(self
->parent
.e
, ep
);
3754 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3755 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3756 self
->saved_position
= 0;
3757 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3764 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3766 LttvTraceset
*traceset
= self
->parent
.ts
;
3768 guint i
, j
, nb_trace
, nb_tracefile
;
3772 LttvTracefileState
*tfs
;
3774 LttvTraceHook hook_start
, hook_end
;
3776 nb_trace
= lttv_traceset_number(traceset
);
3777 for(i
= 0 ; i
< nb_trace
; i
++) {
3778 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3780 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3781 NULL
, NULL
, block_start
, &hook_start
);
3782 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3783 NULL
, NULL
, block_end
, &hook_end
);
3785 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3787 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3789 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3790 LttvTracefileContext
, j
));
3791 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3792 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3793 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3794 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3800 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3802 LttvTraceset
*traceset
= self
->parent
.ts
;
3804 guint i
, j
, nb_trace
, nb_tracefile
;
3808 LttvTracefileState
*tfs
;
3811 nb_trace
= lttv_traceset_number(traceset
);
3812 for(i
= 0 ; i
< nb_trace
; i
++) {
3814 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3815 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3817 if(ts
->has_precomputed_states
) continue;
3819 guint
*event_count
= g_new(guint
, 1);
3822 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3824 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3825 LttvTracefileContext
*, j
));
3826 lttv_hooks_add(tfs
->parent
.event
,
3827 state_save_event_hook
,
3834 lttv_process_traceset_begin(&self
->parent
,
3835 NULL
, NULL
, NULL
, NULL
, NULL
);
3839 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3841 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3843 lttv_state_save_add_event_hooks(tss
);
3850 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3852 LttvTraceset
*traceset
= self
->parent
.ts
;
3854 guint i
, j
, nb_trace
, nb_tracefile
;
3858 LttvTracefileState
*tfs
;
3860 LttvTraceHook hook_start
, hook_end
;
3862 nb_trace
= lttv_traceset_number(traceset
);
3863 for(i
= 0 ; i
< nb_trace
; i
++) {
3864 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3866 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3867 NULL
, NULL
, block_start
, &hook_start
);
3869 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3870 NULL
, NULL
, block_end
, &hook_end
);
3872 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3874 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3876 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3877 LttvTracefileContext
, j
));
3878 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3879 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3880 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3881 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3887 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3889 LttvTraceset
*traceset
= self
->parent
.ts
;
3891 guint i
, j
, nb_trace
, nb_tracefile
;
3895 LttvTracefileState
*tfs
;
3897 LttvHooks
*after_trace
= lttv_hooks_new();
3899 lttv_hooks_add(after_trace
,
3900 state_save_after_trace_hook
,
3905 lttv_process_traceset_end(&self
->parent
,
3906 NULL
, after_trace
, NULL
, NULL
, NULL
);
3908 lttv_hooks_destroy(after_trace
);
3910 nb_trace
= lttv_traceset_number(traceset
);
3911 for(i
= 0 ; i
< nb_trace
; i
++) {
3913 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3914 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3916 if(ts
->has_precomputed_states
) continue;
3918 guint
*event_count
= NULL
;
3920 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3922 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3923 LttvTracefileContext
*, j
));
3924 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3925 state_save_event_hook
);
3927 if(event_count
) g_free(event_count
);
3931 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3933 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3935 lttv_state_save_remove_event_hooks(tss
);
3940 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3942 LttvTraceset
*traceset
= self
->parent
.ts
;
3946 int min_pos
, mid_pos
, max_pos
;
3948 guint call_rest
= 0;
3950 LttvTraceState
*tcs
;
3952 LttvAttributeValue value
;
3954 LttvAttributeType type
;
3956 LttvAttributeName name
;
3960 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3962 //g_tree_destroy(self->parent.pqueue);
3963 //self->parent.pqueue = g_tree_new(compare_tracefile);
3965 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3967 nb_trace
= lttv_traceset_number(traceset
);
3968 for(i
= 0 ; i
< nb_trace
; i
++) {
3969 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3971 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3972 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3973 LTTV_STATE_SAVED_STATES
);
3976 if(saved_states_tree
) {
3977 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3978 mid_pos
= max_pos
/ 2;
3979 while(min_pos
< max_pos
) {
3980 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3982 g_assert(type
== LTTV_GOBJECT
);
3983 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3984 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3986 g_assert(type
== LTTV_TIME
);
3987 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3989 closest_tree
= saved_state_tree
;
3991 else max_pos
= mid_pos
- 1;
3993 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3997 /* restore the closest earlier saved state */
3999 lttv_state_restore(tcs
, closest_tree
);
4003 /* There is no saved state, yet we want to have it. Restart at T0 */
4005 restore_init_state(tcs
);
4006 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4009 /* We want to seek quickly without restoring/updating the state */
4011 restore_init_state(tcs
);
4012 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4015 if(!call_rest
) g_info("NOT Calling restore");
4020 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4026 traceset_state_finalize (LttvTracesetState
*self
)
4028 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4029 finalize(G_OBJECT(self
));
4034 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4036 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4038 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4039 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4040 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4041 klass
->new_traceset_context
= new_traceset_context
;
4042 klass
->new_trace_context
= new_trace_context
;
4043 klass
->new_tracefile_context
= new_tracefile_context
;
4048 lttv_traceset_state_get_type(void)
4050 static GType type
= 0;
4052 static const GTypeInfo info
= {
4053 sizeof (LttvTracesetStateClass
),
4054 NULL
, /* base_init */
4055 NULL
, /* base_finalize */
4056 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4057 NULL
, /* class_finalize */
4058 NULL
, /* class_data */
4059 sizeof (LttvTracesetState
),
4060 0, /* n_preallocs */
4061 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4062 NULL
/* value handling */
4065 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4073 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4079 trace_state_finalize (LttvTraceState
*self
)
4081 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4082 finalize(G_OBJECT(self
));
4087 trace_state_class_init (LttvTraceStateClass
*klass
)
4089 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4091 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4092 klass
->state_save
= state_save
;
4093 klass
->state_restore
= state_restore
;
4094 klass
->state_saved_free
= state_saved_free
;
4099 lttv_trace_state_get_type(void)
4101 static GType type
= 0;
4103 static const GTypeInfo info
= {
4104 sizeof (LttvTraceStateClass
),
4105 NULL
, /* base_init */
4106 NULL
, /* base_finalize */
4107 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4108 NULL
, /* class_finalize */
4109 NULL
, /* class_data */
4110 sizeof (LttvTraceState
),
4111 0, /* n_preallocs */
4112 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4113 NULL
/* value handling */
4116 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4117 "LttvTraceStateType", &info
, 0);
4124 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4130 tracefile_state_finalize (LttvTracefileState
*self
)
4132 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4133 finalize(G_OBJECT(self
));
4138 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4140 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4142 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4147 lttv_tracefile_state_get_type(void)
4149 static GType type
= 0;
4151 static const GTypeInfo info
= {
4152 sizeof (LttvTracefileStateClass
),
4153 NULL
, /* base_init */
4154 NULL
, /* base_finalize */
4155 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4156 NULL
, /* class_finalize */
4157 NULL
, /* class_data */
4158 sizeof (LttvTracefileState
),
4159 0, /* n_preallocs */
4160 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4161 NULL
/* value handling */
4164 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4165 "LttvTracefileStateType", &info
, 0);
4171 static void module_init()
4173 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4174 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4175 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4176 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4177 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4178 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4179 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4180 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4181 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4182 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4183 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4184 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4185 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4186 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4187 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4188 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4189 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4190 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4191 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4192 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4193 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4194 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4195 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4196 LTTV_STATE_EVENT
= g_quark_from_string("event");
4197 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4198 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4199 LTTV_STATE_TIME
= g_quark_from_string("time");
4200 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4201 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4202 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4203 g_quark_from_string("trace_state_use_count");
4204 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4205 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4206 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4207 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4208 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4209 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4211 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4212 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4213 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4214 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4215 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4216 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4217 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4218 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4219 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4220 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4221 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4222 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4223 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4224 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4225 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4227 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4228 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4229 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4230 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4231 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4232 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4233 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4234 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4235 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4236 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4237 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4238 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4239 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4240 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4241 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4242 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4243 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4244 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4245 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4246 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4247 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4248 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4249 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4250 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4251 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4253 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4254 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4255 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4256 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4257 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4258 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4259 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4260 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4261 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4262 LTT_FIELD_PID
= g_quark_from_string("pid");
4263 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4264 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4265 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4266 LTT_FIELD_NAME
= g_quark_from_string("name");
4267 LTT_FIELD_TYPE
= g_quark_from_string("type");
4268 LTT_FIELD_MODE
= g_quark_from_string("mode");
4269 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4270 LTT_FIELD_STATUS
= g_quark_from_string("status");
4271 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4272 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4273 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4274 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4275 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4276 LTT_FIELD_ACTION
= g_quark_from_string("action");
4277 LTT_FIELD_ID
= g_quark_from_string("id");
4278 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4279 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4281 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4282 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4283 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4284 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4285 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4286 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4288 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4289 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4290 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4292 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4293 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4294 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4295 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4298 static void module_destroy()
4303 LTTV_MODULE("state", "State computation", \
4304 "Update the system state, possibly saving it at intervals", \
4305 module_init
, module_destroy
)