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
48 /* Facilities Quarks */
52 LTT_FACILITY_KERNEL_ARCH
,
55 LTT_FACILITY_USER_GENERIC
,
57 LTT_FACILITY_STATEDUMP
;
62 LTT_EVENT_SYSCALL_ENTRY
,
63 LTT_EVENT_SYSCALL_EXIT
,
68 LTT_EVENT_SOFT_IRQ_RAISE
,
69 LTT_EVENT_SOFT_IRQ_ENTRY
,
70 LTT_EVENT_SOFT_IRQ_EXIT
,
71 LTT_EVENT_SCHED_SCHEDULE
,
72 LTT_EVENT_PROCESS_FORK
,
73 LTT_EVENT_KTHREAD_CREATE
,
74 LTT_EVENT_PROCESS_EXIT
,
75 LTT_EVENT_PROCESS_FREE
,
77 LTT_EVENT_PROCESS_STATE
,
78 LTT_EVENT_STATEDUMP_END
,
79 LTT_EVENT_FUNCTION_ENTRY
,
80 LTT_EVENT_FUNCTION_EXIT
,
81 LTT_EVENT_THREAD_BRAND
,
82 LTT_EVENT_REQUEST_ISSUE
,
83 LTT_EVENT_REQUEST_COMPLETE
,
84 LTT_EVENT_LIST_INTERRUPT
,
85 LTT_EVENT_SYS_CALL_TABLE
,
86 LTT_EVENT_SOFTIRQ_VEC
;
94 LTT_FIELD_SOFT_IRQ_ID
,
102 LTT_FIELD_CHILD_TGID
,
120 LTTV_STATE_MODE_UNKNOWN
,
121 LTTV_STATE_USER_MODE
,
128 LTTV_STATE_SUBMODE_UNKNOWN
,
129 LTTV_STATE_SUBMODE_NONE
;
133 LTTV_STATE_WAIT_FORK
,
142 LTTV_STATE_UNBRANDED
;
145 LTTV_STATE_USER_THREAD
,
146 LTTV_STATE_KERNEL_THREAD
;
164 LTTV_BDEV_BUSY_READING
,
165 LTTV_BDEV_BUSY_WRITING
;
168 LTTV_STATE_TRACEFILES
,
169 LTTV_STATE_PROCESSES
,
171 LTTV_STATE_RUNNING_PROCESS
,
173 LTTV_STATE_SAVED_STATES
,
174 LTTV_STATE_SAVED_STATES_TIME
,
177 LTTV_STATE_NAME_TABLES
,
178 LTTV_STATE_TRACE_STATE_USE_COUNT
,
179 LTTV_STATE_RESOURCE_CPUS
,
180 LTTV_STATE_RESOURCE_CPUS_COUNT
,
181 LTTV_STATE_RESOURCE_IRQS
,
182 LTTV_STATE_RESOURCE_SOFT_IRQS
,
183 LTTV_STATE_RESOURCE_TRAPS
,
184 LTTV_STATE_RESOURCE_BLKDEVS
;
186 static void create_max_time(LttvTraceState
*tcs
);
188 static void get_max_time(LttvTraceState
*tcs
);
190 static void free_max_time(LttvTraceState
*tcs
);
192 static void create_name_tables(LttvTraceState
*tcs
);
194 static void get_name_tables(LttvTraceState
*tcs
);
196 static void free_name_tables(LttvTraceState
*tcs
);
198 static void free_saved_state(LttvTraceState
*tcs
);
200 static void lttv_state_free_process_table(GHashTable
*processes
);
202 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
203 GPtrArray
*quarktable
);
205 /* Resource function prototypes */
206 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
207 static LttvBdevState
*bdevstate_new(void);
208 static void bdevstate_free(LttvBdevState
*);
209 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
210 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
213 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
215 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
219 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
221 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
225 void lttv_state_state_saved_free(LttvTraceState
*self
,
226 LttvAttribute
*container
)
228 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
232 guint
process_hash(gconstpointer key
)
234 guint pid
= ((const LttvProcessState
*)key
)->pid
;
235 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
239 /* If the hash table hash function is well distributed,
240 * the process_equal should compare different pid */
241 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
243 const LttvProcessState
*process_a
, *process_b
;
246 process_a
= (const LttvProcessState
*)a
;
247 process_b
= (const LttvProcessState
*)b
;
249 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
250 else if(likely(process_a
->pid
== 0 &&
251 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
256 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
258 g_tree_destroy((GTree
*)value
);
261 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
263 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
264 g_hash_table_destroy(usertraces
);
267 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
272 static guint
check_expand(nb
, id
)
277 return max(id
+ 1, nb
* 2);
280 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
281 guint nb
, guint new_nb
)
283 /* Expand an incomplete table */
284 GQuark
*old_table
= *table
;
285 *table
= g_new(GQuark
, new_nb
);
286 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
289 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
290 guint new_nb
, const char *def_string
)
293 GString
*fe_name
= g_string_new("");
294 for(i
= nb
; i
< new_nb
; i
++) {
295 g_string_printf(fe_name
, "%s %d", def_string
, i
);
296 table
[i
] = g_quark_from_string(fe_name
->str
);
298 g_string_free(fe_name
, TRUE
);
301 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
303 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
304 if(likely(new_nb
== ts
->nb_syscalls
))
306 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
307 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
308 /* Update the table size */
309 ts
->nb_syscalls
= new_nb
;
312 static void expand_trap_table(LttvTraceState
*ts
, int id
)
314 guint new_nb
= check_expand(ts
->nb_traps
, id
);
316 if(likely(new_nb
== ts
->nb_traps
))
318 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
319 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
320 /* Update the table size */
321 ts
->nb_traps
= new_nb
;
323 LttvTrapState
*old_table
= ts
->trap_states
;
324 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
325 memcpy(ts
->trap_states
, old_table
,
326 ts
->nb_traps
* sizeof(LttvTrapState
));
327 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
328 ts
->trap_states
[i
].running
= 0;
331 static void expand_irq_table(LttvTraceState
*ts
, int id
)
333 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
335 if(likely(new_nb
== ts
->nb_irqs
))
337 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
338 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
340 LttvIRQState
*old_table
= ts
->irq_states
;
341 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
342 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
343 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
344 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
347 /* Update the table size */
348 ts
->nb_irqs
= new_nb
;
351 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
353 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
355 if(likely(new_nb
== ts
->nb_soft_irqs
))
357 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
358 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
360 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
361 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
362 memcpy(ts
->soft_irq_states
, old_table
,
363 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
364 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
365 ts
->soft_irq_states
[i
].running
= 0;
367 /* Update the table size */
368 ts
->nb_soft_irqs
= new_nb
;
372 restore_init_state(LttvTraceState
*self
)
374 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
376 //LttvTracefileState *tfcs;
378 LttTime start_time
, end_time
;
380 /* Free the process tables */
381 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
382 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
383 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
384 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
387 /* Seek time to beginning */
388 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
389 // closest. It's the tracecontext job to seek the trace to the beginning
390 // anyway : the init state might be used at the middle of the trace as well...
391 //g_tree_destroy(self->parent.ts_context->pqueue);
392 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
394 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
396 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
398 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
399 nb_irqs
= self
->nb_irqs
;
400 nb_soft_irqs
= self
->nb_soft_irqs
;
401 nb_traps
= self
->nb_traps
;
403 /* Put the per cpu running_process to beginning state : process 0. */
404 for(i
=0; i
< nb_cpus
; i
++) {
405 LttvExecutionState
*es
;
406 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
407 LTTV_STATE_UNNAMED
, &start_time
);
408 /* We are not sure is it's a kernel thread or normal thread, put the
409 * bottom stack state to unknown */
410 self
->running_process
[i
]->execution_stack
=
411 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
412 es
= self
->running_process
[i
]->state
=
413 &g_array_index(self
->running_process
[i
]->execution_stack
,
414 LttvExecutionState
, 0);
415 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
416 es
->s
= LTTV_STATE_UNNAMED
;
418 //self->running_process[i]->state->s = LTTV_STATE_RUN;
419 self
->running_process
[i
]->cpu
= i
;
421 /* reset cpu states */
422 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
423 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
424 self
->cpu_states
[i
].last_irq
= -1;
425 self
->cpu_states
[i
].last_soft_irq
= -1;
426 self
->cpu_states
[i
].last_trap
= -1;
430 /* reset irq states */
431 for(i
=0; i
<nb_irqs
; i
++) {
432 if(self
->irq_states
[i
].mode_stack
->len
> 0)
433 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
436 /* reset softirq states */
437 for(i
=0; i
<nb_soft_irqs
; i
++) {
438 self
->soft_irq_states
[i
].pending
= 0;
439 self
->soft_irq_states
[i
].running
= 0;
442 /* reset trap states */
443 for(i
=0; i
<nb_traps
; i
++) {
444 self
->trap_states
[i
].running
= 0;
447 /* reset bdev states */
448 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
449 //g_hash_table_steal_all(self->bdev_states);
450 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
453 nb_tracefile
= self
->parent
.tracefiles
->len
;
455 for(i
= 0 ; i
< nb_tracefile
; i
++) {
457 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
458 LttvTracefileContext
*, i
));
459 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
460 // tfcs->saved_position = 0;
461 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
462 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
463 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
464 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
469 //static LttTime time_zero = {0,0};
471 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
474 const LttTime
*t1
= (const LttTime
*)a
;
475 const LttTime
*t2
= (const LttTime
*)b
;
477 return ltt_time_compare(*t1
, *t2
);
480 static void free_usertrace_key(gpointer data
)
485 #define MAX_STRING_LEN 4096
488 state_load_saved_states(LttvTraceState
*tcs
)
491 GPtrArray
*quarktable
;
492 const char *trace_path
;
496 tcs
->has_precomputed_states
= FALSE
;
500 gchar buf
[MAX_STRING_LEN
];
503 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
504 strncpy(path
, trace_path
, PATH_MAX
-1);
505 count
= strnlen(trace_path
, PATH_MAX
-1);
506 // quarktable : open, test
507 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
508 fp
= fopen(path
, "r");
510 quarktable
= g_ptr_array_sized_new(4096);
512 /* Index 0 is null */
514 if(hdr
== EOF
) return;
515 g_assert(hdr
== HDR_QUARKS
);
519 if(hdr
== EOF
) break;
520 g_assert(hdr
== HDR_QUARK
);
521 g_ptr_array_set_size(quarktable
, q
+1);
524 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
525 if(buf
[i
] == '\0' || feof(fp
)) break;
528 len
= strnlen(buf
, MAX_STRING_LEN
-1);
529 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
530 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
536 // saved_states : open, test
537 strncpy(path
, trace_path
, PATH_MAX
-1);
538 count
= strnlen(trace_path
, PATH_MAX
-1);
539 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
540 fp
= fopen(path
, "r");
544 if(hdr
!= HDR_TRACE
) goto end
;
546 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
548 tcs
->has_precomputed_states
= TRUE
;
553 /* Free the quarktable */
554 for(i
=0; i
<quarktable
->len
; i
++) {
555 string
= g_ptr_array_index (quarktable
, i
);
558 g_ptr_array_free(quarktable
, TRUE
);
563 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
565 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
568 LttvTraceContext
*tc
;
572 LttvTracefileState
*tfcs
;
574 LttvAttributeValue v
;
576 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
577 init((LttvTracesetContext
*)self
, ts
);
579 nb_trace
= lttv_traceset_number(ts
);
580 for(i
= 0 ; i
< nb_trace
; i
++) {
581 tc
= self
->parent
.traces
[i
];
582 tcs
= LTTV_TRACE_STATE(tc
);
583 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
584 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
588 if(*(v
.v_uint
) == 1) {
589 create_name_tables(tcs
);
590 create_max_time(tcs
);
592 get_name_tables(tcs
);
595 nb_tracefile
= tc
->tracefiles
->len
;
596 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
597 nb_irq
= tcs
->nb_irqs
;
598 tcs
->processes
= NULL
;
599 tcs
->usertraces
= NULL
;
600 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
602 /* init cpu resource stuff */
603 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
604 for(j
= 0; j
<nb_cpu
; j
++) {
605 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
606 tcs
->cpu_states
[j
].last_irq
= -1;
607 tcs
->cpu_states
[j
].last_soft_irq
= -1;
608 tcs
->cpu_states
[j
].last_trap
= -1;
609 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
612 /* init irq resource stuff */
613 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
614 for(j
= 0; j
<nb_irq
; j
++) {
615 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
616 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
619 /* init soft irq stuff */
620 /* the kernel has a statically fixed max of 32 softirqs */
621 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
623 /* init trap stuff */
624 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
626 /* init bdev resource stuff */
627 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
629 restore_init_state(tcs
);
630 for(j
= 0 ; j
< nb_tracefile
; j
++) {
632 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
633 LttvTracefileContext
*, j
));
634 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
635 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
636 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
637 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
638 /* It's a Usertrace */
639 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
640 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
642 if(!usertrace_tree
) {
643 usertrace_tree
= g_tree_new_full(compare_usertraces
,
644 NULL
, free_usertrace_key
, NULL
);
645 g_hash_table_insert(tcs
->usertraces
,
646 (gpointer
)tid
, usertrace_tree
);
648 LttTime
*timestamp
= g_new(LttTime
, 1);
649 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
650 ltt_tracefile_creation(tfcs
->parent
.tf
));
651 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
655 /* See if the trace has saved states */
656 state_load_saved_states(tcs
);
661 fini(LttvTracesetState
*self
)
667 //LttvTracefileState *tfcs;
669 LttvAttributeValue v
;
671 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
672 for(i
= 0 ; i
< nb_trace
; i
++) {
673 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
674 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
677 g_assert(*(v
.v_uint
) != 0);
680 if(*(v
.v_uint
) == 0) {
681 free_name_tables(tcs
);
683 free_saved_state(tcs
);
685 g_free(tcs
->running_process
);
686 tcs
->running_process
= NULL
;
687 lttv_state_free_process_table(tcs
->processes
);
688 lttv_state_free_usertraces(tcs
->usertraces
);
689 tcs
->processes
= NULL
;
690 tcs
->usertraces
= NULL
;
692 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
693 fini((LttvTracesetContext
*)self
);
697 static LttvTracesetContext
*
698 new_traceset_context(LttvTracesetContext
*self
)
700 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
704 static LttvTraceContext
*
705 new_trace_context(LttvTracesetContext
*self
)
707 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
711 static LttvTracefileContext
*
712 new_tracefile_context(LttvTracesetContext
*self
)
714 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
718 /* Write the process state of the trace */
720 static void write_process_state(gpointer key
, gpointer value
,
723 LttvProcessState
*process
;
725 LttvExecutionState
*es
;
727 FILE *fp
= (FILE *)user_data
;
732 process
= (LttvProcessState
*)value
;
734 " <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",
735 process
, process
->pid
, process
->tgid
, process
->ppid
,
736 g_quark_to_string(process
->type
),
737 process
->creation_time
.tv_sec
,
738 process
->creation_time
.tv_nsec
,
739 process
->insertion_time
.tv_sec
,
740 process
->insertion_time
.tv_nsec
,
741 g_quark_to_string(process
->name
),
742 g_quark_to_string(process
->brand
),
743 process
->cpu
, process
->free_events
);
745 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
746 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
747 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
748 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
749 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
750 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
751 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
754 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
755 address
= g_array_index(process
->user_stack
, guint64
, i
);
756 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
760 if(process
->usertrace
) {
761 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
762 g_quark_to_string(process
->usertrace
->tracefile_name
),
763 process
->usertrace
->cpu
);
767 fprintf(fp
, " </PROCESS>\n");
771 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
773 guint i
, nb_tracefile
, nb_block
, offset
;
776 LttvTracefileState
*tfcs
;
780 LttEventPosition
*ep
;
784 ep
= ltt_event_position_new();
786 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
788 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
790 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
791 for(i
=0;i
<nb_cpus
;i
++) {
792 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
793 i
, self
->running_process
[i
]->pid
);
796 nb_tracefile
= self
->parent
.tracefiles
->len
;
798 for(i
= 0 ; i
< nb_tracefile
; i
++) {
800 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
801 LttvTracefileContext
*, i
));
802 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
803 tfcs
->parent
.timestamp
.tv_sec
,
804 tfcs
->parent
.timestamp
.tv_nsec
);
805 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
806 if(e
== NULL
) fprintf(fp
,"/>\n");
808 ltt_event_position(e
, ep
);
809 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
810 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
815 fprintf(fp
,"</PROCESS_STATE>\n");
819 static void write_process_state_raw(gpointer key
, gpointer value
,
822 LttvProcessState
*process
;
824 LttvExecutionState
*es
;
826 FILE *fp
= (FILE *)user_data
;
831 process
= (LttvProcessState
*)value
;
832 fputc(HDR_PROCESS
, fp
);
833 //fwrite(&header, sizeof(header), 1, fp);
834 //fprintf(fp, "%s", g_quark_to_string(process->type));
836 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
837 //fprintf(fp, "%s", g_quark_to_string(process->name));
839 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
840 //fprintf(fp, "%s", g_quark_to_string(process->brand));
842 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
843 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
844 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
845 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
846 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
847 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
848 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
849 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
853 " <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",
854 process
, process
->pid
, process
->tgid
, process
->ppid
,
855 g_quark_to_string(process
->type
),
856 process
->creation_time
.tv_sec
,
857 process
->creation_time
.tv_nsec
,
858 process
->insertion_time
.tv_sec
,
859 process
->insertion_time
.tv_nsec
,
860 g_quark_to_string(process
->name
),
861 g_quark_to_string(process
->brand
),
865 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
866 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
869 //fprintf(fp, "%s", g_quark_to_string(es->t));
871 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
872 //fprintf(fp, "%s", g_quark_to_string(es->n));
874 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
875 //fprintf(fp, "%s", g_quark_to_string(es->s));
877 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
878 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
879 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
880 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
882 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
883 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
884 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
885 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
886 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
890 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
891 address
= g_array_index(process
->user_stack
, guint64
, i
);
892 fputc(HDR_USER_STACK
, fp
);
893 fwrite(&address
, sizeof(address
), 1, fp
);
895 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
900 if(process
->usertrace
) {
901 fputc(HDR_USERTRACE
, fp
);
902 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
904 fwrite(&process
->usertrace
->tracefile_name
,
905 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
906 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
908 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
909 g_quark_to_string(process
->usertrace
->tracefile_name
),
910 process
->usertrace
->cpu
);
917 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
919 guint i
, nb_tracefile
, nb_block
, offset
;
922 LttvTracefileState
*tfcs
;
926 LttEventPosition
*ep
;
930 ep
= ltt_event_position_new();
932 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
933 fputc(HDR_PROCESS_STATE
, fp
);
934 fwrite(&t
, sizeof(t
), 1, fp
);
936 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
938 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
939 for(i
=0;i
<nb_cpus
;i
++) {
941 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
942 fwrite(&self
->running_process
[i
]->pid
,
943 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
944 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
945 // i, self->running_process[i]->pid);
948 nb_tracefile
= self
->parent
.tracefiles
->len
;
950 for(i
= 0 ; i
< nb_tracefile
; i
++) {
952 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
953 LttvTracefileContext
*, i
));
954 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
955 // tfcs->parent.timestamp.tv_sec,
956 // tfcs->parent.timestamp.tv_nsec);
957 fputc(HDR_TRACEFILE
, fp
);
958 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
959 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
960 * position following : end of trace */
961 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
963 ltt_event_position(e
, ep
);
964 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
965 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
967 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
968 fwrite(&offset
, sizeof(offset
), 1, fp
);
969 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
976 /* Read process state from a file */
978 /* Called because a HDR_PROCESS was found */
979 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
980 GPtrArray
*quarktable
)
982 LttvExecutionState
*es
;
983 LttvProcessState
*process
, *parent_process
;
984 LttvProcessState tmp
;
989 /* TODO : check return value */
990 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
991 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
992 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
993 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
994 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
995 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
996 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
997 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
998 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
999 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1002 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1004 /* We must link to the parent */
1005 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1007 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1008 if(process
== NULL
) {
1009 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1011 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1012 &tmp
.creation_time
);
1015 process
->insertion_time
= tmp
.insertion_time
;
1016 process
->creation_time
= tmp
.creation_time
;
1017 process
->type
= g_quark_from_string(
1018 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1019 process
->tgid
= tmp
.tgid
;
1020 process
->ppid
= tmp
.ppid
;
1021 process
->brand
= g_quark_from_string(
1022 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1024 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1025 process
->free_events
= tmp
.free_events
;
1028 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1030 gint hdr
= fgetc(fp
);
1031 if(hdr
== EOF
) goto end_loop
;
1035 process
->execution_stack
=
1036 g_array_set_size(process
->execution_stack
,
1037 process
->execution_stack
->len
+ 1);
1038 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1039 process
->execution_stack
->len
-1);
1040 process
->state
= es
;
1042 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1043 es
->t
= g_quark_from_string(
1044 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1045 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1046 es
->n
= g_quark_from_string(
1047 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1048 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1049 es
->s
= g_quark_from_string(
1050 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1051 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1052 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1053 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1055 case HDR_USER_STACK
:
1056 process
->user_stack
= g_array_set_size(process
->user_stack
,
1057 process
->user_stack
->len
+ 1);
1058 address
= &g_array_index(process
->user_stack
, guint64
,
1059 process
->user_stack
->len
-1);
1060 fread(address
, sizeof(address
), 1, fp
);
1061 process
->current_function
= *address
;
1064 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1065 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1077 /* Called because a HDR_PROCESS_STATE was found */
1078 /* Append a saved state to the trace states */
1079 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1081 guint i
, nb_tracefile
, nb_block
, offset
;
1083 LttvTracefileState
*tfcs
;
1085 LttEventPosition
*ep
;
1093 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1095 LttvAttributeValue value
;
1096 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1097 ep
= ltt_event_position_new();
1099 restore_init_state(self
);
1101 fread(&t
, sizeof(t
), 1, fp
);
1104 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1106 if(hdr
== EOF
) goto end_loop
;
1110 /* Call read_process_state_raw */
1111 read_process_state_raw(self
, fp
, quarktable
);
1119 case HDR_USER_STACK
:
1121 case HDR_PROCESS_STATE
:
1127 g_error("Error while parsing saved state file : unknown data header %d",
1133 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1134 for(i
=0;i
<nb_cpus
;i
++) {
1137 g_assert(hdr
== HDR_CPU
);
1138 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1139 g_assert(i
== cpu_num
);
1140 fread(&self
->running_process
[i
]->pid
,
1141 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1144 nb_tracefile
= self
->parent
.tracefiles
->len
;
1146 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1148 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1149 LttvTracefileContext
*, i
));
1150 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1151 // tfcs->parent.timestamp.tv_sec,
1152 // tfcs->parent.timestamp.tv_nsec);
1153 g_tree_remove(pqueue
, &tfcs
->parent
);
1155 g_assert(hdr
== HDR_TRACEFILE
);
1156 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1157 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1158 * position following : end of trace */
1159 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1160 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1161 fread(&offset
, sizeof(offset
), 1, fp
);
1162 fread(&tsc
, sizeof(tsc
), 1, fp
);
1163 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1164 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1166 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1171 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1172 LTTV_STATE_SAVED_STATES
);
1173 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1174 value
= lttv_attribute_add(saved_states_tree
,
1175 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1176 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1177 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1178 *(value
.v_time
) = t
;
1179 lttv_state_save(self
, saved_state_tree
);
1180 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1183 *(self
->max_time_state_recomputed_in_seek
) = t
;
1187 /* Called when a HDR_TRACE is found */
1188 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1189 GPtrArray
*quarktable
)
1194 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1196 if(hdr
== EOF
) goto end_loop
;
1199 case HDR_PROCESS_STATE
:
1200 /* Call read_process_state_raw */
1201 lttv_state_read_raw(tcs
, fp
, quarktable
);
1209 case HDR_USER_STACK
:
1213 g_error("Error while parsing saved state file :"
1214 " unexpected data header %d",
1218 g_error("Error while parsing saved state file : unknown data header %d",
1223 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1224 restore_init_state(tcs
);
1225 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1231 /* Copy each process from an existing hash table to a new one */
1233 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1235 LttvProcessState
*process
, *new_process
;
1237 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1241 process
= (LttvProcessState
*)value
;
1242 new_process
= g_new(LttvProcessState
, 1);
1243 *new_process
= *process
;
1244 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1245 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1246 new_process
->execution_stack
=
1247 g_array_set_size(new_process
->execution_stack
,
1248 process
->execution_stack
->len
);
1249 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1250 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1251 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1253 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1254 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1255 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1256 sizeof(guint64
), 0);
1257 new_process
->user_stack
=
1258 g_array_set_size(new_process
->user_stack
,
1259 process
->user_stack
->len
);
1260 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1261 g_array_index(new_process
->user_stack
, guint64
, i
) =
1262 g_array_index(process
->user_stack
, guint64
, i
);
1264 new_process
->current_function
= process
->current_function
;
1265 g_hash_table_insert(new_processes
, new_process
, new_process
);
1269 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1271 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1273 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1274 return new_processes
;
1277 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1280 LttvCPUState
*retval
;
1282 retval
= g_new(LttvCPUState
, n
);
1284 for(i
=0; i
<n
; i
++) {
1285 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1286 retval
[i
].last_irq
= states
[i
].last_irq
;
1287 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1288 retval
[i
].last_trap
= states
[i
].last_trap
;
1289 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1290 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1291 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1298 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1302 for(i
=0; i
<n
; i
++) {
1303 g_array_free(states
[i
].mode_stack
, TRUE
);
1309 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1312 LttvIRQState
*retval
;
1314 retval
= g_new(LttvIRQState
, n
);
1316 for(i
=0; i
<n
; i
++) {
1317 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1318 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1319 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1320 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1327 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1331 for(i
=0; i
<n
; i
++) {
1332 g_array_free(states
[i
].mode_stack
, TRUE
);
1338 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1341 LttvSoftIRQState
*retval
;
1343 retval
= g_new(LttvSoftIRQState
, n
);
1345 for(i
=0; i
<n
; i
++) {
1346 retval
[i
].pending
= states
[i
].pending
;
1347 retval
[i
].running
= states
[i
].running
;
1353 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1358 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1361 LttvTrapState
*retval
;
1363 retval
= g_new(LttvTrapState
, n
);
1365 for(i
=0; i
<n
; i
++) {
1366 retval
[i
].running
= states
[i
].running
;
1372 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1377 /* bdevstate stuff */
1379 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1381 gint devcode_gint
= devcode
;
1382 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1384 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1385 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1387 gint
* key
= g_new(gint
, 1);
1389 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1397 static LttvBdevState
*bdevstate_new(void)
1399 LttvBdevState
*retval
;
1400 retval
= g_new(LttvBdevState
, 1);
1401 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1406 static void bdevstate_free(LttvBdevState
*bds
)
1408 g_array_free(bds
->mode_stack
, TRUE
);
1412 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1414 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1416 bdevstate_free(bds
);
1419 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1421 LttvBdevState
*retval
;
1423 retval
= bdevstate_new();
1424 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1429 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1431 //GHashTable *ht = (GHashTable *)u;
1432 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1433 LttvBdevState
*newbds
;
1435 newbds
= bdevstate_copy(bds
);
1437 g_hash_table_insert(u
, k
, newbds
);
1440 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1444 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1446 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1451 /* Free a hashtable and the LttvBdevState structures its values
1454 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1456 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1457 g_hash_table_destroy(ht
);
1460 /* The saved state for each trace contains a member "processes", which
1461 stores a copy of the process table, and a member "tracefiles" with
1462 one entry per tracefile. Each tracefile has a "process" member pointing
1463 to the current process and a "position" member storing the tracefile
1464 position (needed to seek to the current "next" event. */
1466 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1468 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1470 LttvTracefileState
*tfcs
;
1472 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1474 guint
*running_process
;
1476 LttvAttributeValue value
;
1478 LttEventPosition
*ep
;
1480 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1481 LTTV_STATE_TRACEFILES
);
1483 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1485 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1487 /* Add the currently running processes array */
1488 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1489 running_process
= g_new(guint
, nb_cpus
);
1490 for(i
=0;i
<nb_cpus
;i
++) {
1491 running_process
[i
] = self
->running_process
[i
]->pid
;
1493 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1495 *(value
.v_pointer
) = running_process
;
1497 g_info("State save");
1499 nb_tracefile
= self
->parent
.tracefiles
->len
;
1501 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1503 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1504 LttvTracefileContext
*, i
));
1505 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1506 value
= lttv_attribute_add(tracefiles_tree
, i
,
1508 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1510 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1512 *(value
.v_uint
) = tfcs
->process
->pid
;
1514 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1516 /* Only save the position if the tfs has not infinite time. */
1517 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1518 // && current_tfcs != tfcs) {
1519 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1520 *(value
.v_pointer
) = NULL
;
1522 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1523 ep
= ltt_event_position_new();
1524 ltt_event_position(e
, ep
);
1525 *(value
.v_pointer
) = ep
;
1527 guint nb_block
, offset
;
1530 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1531 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1533 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1537 /* save the cpu state */
1539 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1541 *(value
.v_uint
) = nb_cpus
;
1543 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1545 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1548 /* save the irq state */
1549 nb_irqs
= self
->nb_irqs
;
1551 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1553 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1556 /* save the soft irq state */
1557 nb_soft_irqs
= self
->nb_soft_irqs
;
1559 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1561 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1564 /* save the trap state */
1565 nb_traps
= self
->nb_traps
;
1567 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1569 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1572 /* save the blkdev states */
1573 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1575 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1579 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1581 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1583 LttvTracefileState
*tfcs
;
1585 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1587 guint
*running_process
;
1589 LttvAttributeType type
;
1591 LttvAttributeValue value
;
1593 LttvAttributeName name
;
1597 LttEventPosition
*ep
;
1599 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1601 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1602 LTTV_STATE_TRACEFILES
);
1604 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1606 g_assert(type
== LTTV_POINTER
);
1607 lttv_state_free_process_table(self
->processes
);
1608 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1610 /* Add the currently running processes array */
1611 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1612 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1614 g_assert(type
== LTTV_POINTER
);
1615 running_process
= *(value
.v_pointer
);
1616 for(i
=0;i
<nb_cpus
;i
++) {
1617 pid
= running_process
[i
];
1618 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1619 g_assert(self
->running_process
[i
] != NULL
);
1622 nb_tracefile
= self
->parent
.tracefiles
->len
;
1624 //g_tree_destroy(tsc->pqueue);
1625 //tsc->pqueue = g_tree_new(compare_tracefile);
1627 /* restore cpu resource states */
1628 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1629 g_assert(type
== LTTV_POINTER
);
1630 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1631 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1633 /* restore irq resource states */
1634 nb_irqs
= self
->nb_irqs
;
1635 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1636 g_assert(type
== LTTV_POINTER
);
1637 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1638 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1640 /* restore soft irq resource states */
1641 nb_soft_irqs
= self
->nb_soft_irqs
;
1642 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1643 g_assert(type
== LTTV_POINTER
);
1644 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1645 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1647 /* restore trap resource states */
1648 nb_traps
= self
->nb_traps
;
1649 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1650 g_assert(type
== LTTV_POINTER
);
1651 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1652 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1654 /* restore the blkdev states */
1655 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1656 g_assert(type
== LTTV_POINTER
);
1657 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1658 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1660 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1662 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1663 LttvTracefileContext
*, i
));
1664 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1665 g_assert(type
== LTTV_GOBJECT
);
1666 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1668 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1670 g_assert(type
== LTTV_UINT
);
1671 pid
= *(value
.v_uint
);
1672 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1674 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1676 g_assert(type
== LTTV_POINTER
);
1677 //g_assert(*(value.v_pointer) != NULL);
1678 ep
= *(value
.v_pointer
);
1679 g_assert(tfcs
->parent
.t_context
!= NULL
);
1681 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1683 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1684 g_tree_remove(tsc
->pqueue
, tfc
);
1687 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1688 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1689 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1690 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1691 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1693 tfc
->timestamp
= ltt_time_infinite
;
1699 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1701 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1703 LttvTracefileState
*tfcs
;
1705 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1707 guint
*running_process
;
1709 LttvAttributeType type
;
1711 LttvAttributeValue value
;
1713 LttvAttributeName name
;
1717 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1718 LTTV_STATE_TRACEFILES
);
1719 g_object_ref(G_OBJECT(tracefiles_tree
));
1720 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1722 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1724 g_assert(type
== LTTV_POINTER
);
1725 lttv_state_free_process_table(*(value
.v_pointer
));
1726 *(value
.v_pointer
) = NULL
;
1727 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1729 /* Free running processes array */
1730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1732 g_assert(type
== LTTV_POINTER
);
1733 running_process
= *(value
.v_pointer
);
1734 g_free(running_process
);
1736 /* free cpu resource states */
1737 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1738 g_assert(type
== LTTV_UINT
);
1739 nb_cpus
= *value
.v_uint
;
1740 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1741 g_assert(type
== LTTV_POINTER
);
1742 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1744 /* free irq resource states */
1745 nb_irqs
= self
->nb_irqs
;
1746 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1747 g_assert(type
== LTTV_POINTER
);
1748 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1750 /* free softirq resource states */
1751 nb_softirqs
= self
->nb_irqs
;
1752 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1753 g_assert(type
== LTTV_POINTER
);
1754 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1756 /* free the blkdev states */
1757 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1758 g_assert(type
== LTTV_POINTER
);
1759 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1761 nb_tracefile
= self
->parent
.tracefiles
->len
;
1763 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1765 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1766 LttvTracefileContext
*, i
));
1767 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1768 g_assert(type
== LTTV_GOBJECT
);
1769 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1771 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1773 g_assert(type
== LTTV_POINTER
);
1774 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1776 g_object_unref(G_OBJECT(tracefiles_tree
));
1780 static void free_saved_state(LttvTraceState
*self
)
1784 LttvAttributeType type
;
1786 LttvAttributeValue value
;
1788 LttvAttributeName name
;
1792 LttvAttribute
*saved_states
;
1794 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1795 LTTV_STATE_SAVED_STATES
);
1797 nb
= lttv_attribute_get_number(saved_states
);
1798 for(i
= 0 ; i
< nb
; i
++) {
1799 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1800 g_assert(type
== LTTV_GOBJECT
);
1801 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1804 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1809 create_max_time(LttvTraceState
*tcs
)
1811 LttvAttributeValue v
;
1813 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1815 g_assert(*(v
.v_pointer
) == NULL
);
1816 *(v
.v_pointer
) = g_new(LttTime
,1);
1817 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1822 get_max_time(LttvTraceState
*tcs
)
1824 LttvAttributeValue v
;
1826 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1828 g_assert(*(v
.v_pointer
) != NULL
);
1829 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1834 free_max_time(LttvTraceState
*tcs
)
1836 LttvAttributeValue v
;
1838 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1840 g_free(*(v
.v_pointer
));
1841 *(v
.v_pointer
) = NULL
;
1845 typedef struct _LttvNameTables
{
1846 // FIXME GQuark *eventtype_names;
1847 GQuark
*syscall_names
;
1853 GQuark
*soft_irq_names
;
1859 create_name_tables(LttvTraceState
*tcs
)
1863 GString
*fe_name
= g_string_new("");
1865 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1867 LttvAttributeValue v
;
1871 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1873 g_assert(*(v
.v_pointer
) == NULL
);
1874 *(v
.v_pointer
) = name_tables
;
1876 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1878 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1879 LTT_FACILITY_KERNEL_ARCH
,
1880 LTT_EVENT_SYSCALL_ENTRY
,
1881 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1882 NULL
, NULL
, &hooks
)) {
1884 // th = lttv_trace_hook_get_first(&th);
1886 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1887 // nb = ltt_type_element_number(t);
1889 // name_tables->syscall_names = g_new(GQuark, nb);
1890 // name_tables->nb_syscalls = nb;
1892 // for(i = 0 ; i < nb ; i++) {
1893 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1894 // if(!name_tables->syscall_names[i]) {
1895 // GString *string = g_string_new("");
1896 // g_string_printf(string, "syscall %u", i);
1897 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1898 // g_string_free(string, TRUE);
1902 name_tables
->nb_syscalls
= 256;
1903 name_tables
->syscall_names
= g_new(GQuark
, 256);
1904 for(i
= 0 ; i
< 256 ; i
++) {
1905 g_string_printf(fe_name
, "syscall %d", i
);
1906 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1909 name_tables
->syscall_names
= NULL
;
1910 name_tables
->nb_syscalls
= 0;
1912 lttv_trace_hook_remove_all(&hooks
);
1914 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1915 LTT_FACILITY_KERNEL_ARCH
,
1916 LTT_EVENT_TRAP_ENTRY
,
1917 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1918 NULL
, NULL
, &hooks
)) {
1920 // th = lttv_trace_hook_get_first(&th);
1922 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1923 // //nb = ltt_type_element_number(t);
1925 // name_tables->trap_names = g_new(GQuark, nb);
1926 // for(i = 0 ; i < nb ; i++) {
1927 // name_tables->trap_names[i] = g_quark_from_string(
1928 // ltt_enum_string_get(t, i));
1931 name_tables
->nb_traps
= 256;
1932 name_tables
->trap_names
= g_new(GQuark
, 256);
1933 for(i
= 0 ; i
< 256 ; i
++) {
1934 g_string_printf(fe_name
, "trap %d", i
);
1935 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1938 name_tables
->trap_names
= NULL
;
1939 name_tables
->nb_traps
= 0;
1941 lttv_trace_hook_remove_all(&hooks
);
1943 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1944 LTT_FACILITY_KERNEL
,
1945 LTT_EVENT_IRQ_ENTRY
,
1946 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1947 NULL
, NULL
, &hooks
)) {
1950 name_tables->irq_names = g_new(GQuark, nb);
1951 for(i = 0 ; i < nb ; i++) {
1952 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1956 name_tables
->nb_irqs
= 256;
1957 name_tables
->irq_names
= g_new(GQuark
, 256);
1958 for(i
= 0 ; i
< 256 ; i
++) {
1959 g_string_printf(fe_name
, "irq %d", i
);
1960 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1963 name_tables
->nb_irqs
= 0;
1964 name_tables
->irq_names
= NULL
;
1966 lttv_trace_hook_remove_all(&hooks
);
1968 name_tables->soft_irq_names = g_new(GQuark, nb);
1969 for(i = 0 ; i < nb ; i++) {
1970 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1974 /* the kernel is limited to 32 statically defined softirqs */
1975 name_tables
->nb_softirqs
= 32;
1976 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1977 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1978 g_string_printf(fe_name
, "softirq %d", i
);
1979 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1981 g_array_free(hooks
, TRUE
);
1983 g_string_free(fe_name
, TRUE
);
1988 get_name_tables(LttvTraceState
*tcs
)
1990 LttvNameTables
*name_tables
;
1992 LttvAttributeValue v
;
1994 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1996 g_assert(*(v
.v_pointer
) != NULL
);
1997 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1998 //tcs->eventtype_names = name_tables->eventtype_names;
1999 tcs
->syscall_names
= name_tables
->syscall_names
;
2000 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2001 tcs
->trap_names
= name_tables
->trap_names
;
2002 tcs
->nb_traps
= name_tables
->nb_traps
;
2003 tcs
->irq_names
= name_tables
->irq_names
;
2004 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2005 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2006 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2011 free_name_tables(LttvTraceState
*tcs
)
2013 LttvNameTables
*name_tables
;
2015 LttvAttributeValue v
;
2017 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2019 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2020 *(v
.v_pointer
) = NULL
;
2022 // g_free(name_tables->eventtype_names);
2023 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2024 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2025 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2026 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2027 if(name_tables
) g_free(name_tables
);
2030 #ifdef HASH_TABLE_DEBUG
2032 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2034 LttvProcessState
*process
= (LttvProcessState
*)value
;
2036 /* Test for process corruption */
2037 guint stack_len
= process
->execution_stack
->len
;
2040 static void hash_table_check(GHashTable
*table
)
2042 g_hash_table_foreach(table
, test_process
, NULL
);
2048 /* clears the stack and sets the state passed as argument */
2049 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2051 g_array_set_size(cpust
->mode_stack
, 1);
2052 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2055 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2057 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2058 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2061 static void cpu_pop_mode(LttvCPUState
*cpust
)
2063 if(cpust
->mode_stack
->len
<= 1)
2064 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2066 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2069 /* clears the stack and sets the state passed as argument */
2070 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2072 g_array_set_size(bdevst
->mode_stack
, 1);
2073 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2076 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2078 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2079 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2082 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2084 if(bdevst
->mode_stack
->len
<= 1)
2085 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2087 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2090 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2092 g_array_set_size(irqst
->mode_stack
, 1);
2093 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2096 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2098 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2099 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2102 static void irq_pop_mode(LttvIRQState
*irqst
)
2104 if(irqst
->mode_stack
->len
<= 1)
2105 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2107 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2110 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2113 LttvExecutionState
*es
;
2115 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2116 guint cpu
= tfs
->cpu
;
2118 #ifdef HASH_TABLE_DEBUG
2119 hash_table_check(ts
->processes
);
2121 LttvProcessState
*process
= ts
->running_process
[cpu
];
2123 guint depth
= process
->execution_stack
->len
;
2125 process
->execution_stack
=
2126 g_array_set_size(process
->execution_stack
, depth
+ 1);
2129 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2131 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2134 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2135 es
->cum_cpu_time
= ltt_time_zero
;
2136 es
->s
= process
->state
->s
;
2137 process
->state
= es
;
2141 * return 1 when empty, else 0 */
2142 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2143 LttvTracefileState
*tfs
)
2145 guint depth
= process
->execution_stack
->len
;
2151 process
->execution_stack
=
2152 g_array_set_size(process
->execution_stack
, depth
- 1);
2153 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2155 process
->state
->change
= tfs
->parent
.timestamp
;
2160 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2162 guint cpu
= tfs
->cpu
;
2163 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2164 LttvProcessState
*process
= ts
->running_process
[cpu
];
2166 guint depth
= process
->execution_stack
->len
;
2168 if(process
->state
->t
!= t
){
2169 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2170 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2171 g_info("process state has %s when pop_int is %s\n",
2172 g_quark_to_string(process
->state
->t
),
2173 g_quark_to_string(t
));
2174 g_info("{ %u, %u, %s, %s, %s }\n",
2177 g_quark_to_string(process
->name
),
2178 g_quark_to_string(process
->brand
),
2179 g_quark_to_string(process
->state
->s
));
2184 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2185 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2189 process
->execution_stack
=
2190 g_array_set_size(process
->execution_stack
, depth
- 1);
2191 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2193 process
->state
->change
= tfs
->parent
.timestamp
;
2196 struct search_result
{
2197 const LttTime
*time
; /* Requested time */
2198 LttTime
*best
; /* Best result */
2201 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2203 const LttTime
*elem_time
= (const LttTime
*)a
;
2204 /* Explicit non const cast */
2205 struct search_result
*res
= (struct search_result
*)b
;
2207 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2208 /* The usertrace was created before the schedchange */
2209 /* Get larger keys */
2211 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2212 /* The usertrace was created after the schedchange time */
2213 /* Get smaller keys */
2215 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2216 res
->best
= (LttTime
*)elem_time
;
2219 res
->best
= (LttTime
*)elem_time
;
2226 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2227 guint pid
, const LttTime
*timestamp
)
2229 LttvTracefileState
*tfs
= NULL
;
2230 struct search_result res
;
2231 /* Find the usertrace associated with a pid and time interval.
2232 * Search in the usertraces by PID (within a hash) and then, for each
2233 * corresponding element of the array, find the first one with creation
2234 * timestamp the lowest, but higher or equal to "timestamp". */
2235 res
.time
= timestamp
;
2237 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2238 if(usertrace_tree
) {
2239 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2241 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2249 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2250 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2252 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2254 LttvExecutionState
*es
;
2259 process
->tgid
= tgid
;
2261 process
->name
= name
;
2262 process
->brand
= LTTV_STATE_UNBRANDED
;
2263 //process->last_cpu = tfs->cpu_name;
2264 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2265 process
->type
= LTTV_STATE_USER_THREAD
;
2266 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2267 process
->current_function
= 0; //function 0x0 by default.
2269 g_info("Process %u, core %p", process
->pid
, process
);
2270 g_hash_table_insert(tcs
->processes
, process
, process
);
2273 process
->ppid
= parent
->pid
;
2274 process
->creation_time
= *timestamp
;
2277 /* No parent. This process exists but we are missing all information about
2278 its creation. The birth time is set to zero but we remember the time of
2283 process
->creation_time
= ltt_time_zero
;
2286 process
->insertion_time
= *timestamp
;
2287 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2288 process
->creation_time
.tv_nsec
);
2289 process
->pid_time
= g_quark_from_string(buffer
);
2291 process
->free_events
= 0;
2292 //process->last_cpu = tfs->cpu_name;
2293 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2294 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2295 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2296 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2297 es
= process
->state
= &g_array_index(process
->execution_stack
,
2298 LttvExecutionState
, 0);
2299 es
->t
= LTTV_STATE_USER_MODE
;
2300 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2301 es
->entry
= *timestamp
;
2302 //g_assert(timestamp->tv_sec != 0);
2303 es
->change
= *timestamp
;
2304 es
->cum_cpu_time
= ltt_time_zero
;
2305 es
->s
= LTTV_STATE_RUN
;
2307 es
= process
->state
= &g_array_index(process
->execution_stack
,
2308 LttvExecutionState
, 1);
2309 es
->t
= LTTV_STATE_SYSCALL
;
2310 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2311 es
->entry
= *timestamp
;
2312 //g_assert(timestamp->tv_sec != 0);
2313 es
->change
= *timestamp
;
2314 es
->cum_cpu_time
= ltt_time_zero
;
2315 es
->s
= LTTV_STATE_WAIT_FORK
;
2317 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2318 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2319 sizeof(guint64
), 0);
2324 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2327 LttvProcessState key
;
2328 LttvProcessState
*process
;
2332 process
= g_hash_table_lookup(ts
->processes
, &key
);
2337 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2338 const LttTime
*timestamp
)
2340 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2341 LttvExecutionState
*es
;
2343 /* Put ltt_time_zero creation time for unexisting processes */
2344 if(unlikely(process
== NULL
)) {
2345 process
= lttv_state_create_process(ts
,
2346 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2347 /* We are not sure is it's a kernel thread or normal thread, put the
2348 * bottom stack state to unknown */
2349 process
->execution_stack
=
2350 g_array_set_size(process
->execution_stack
, 1);
2351 process
->state
= es
=
2352 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2353 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2354 es
->s
= LTTV_STATE_UNNAMED
;
2359 /* FIXME : this function should be called when we receive an event telling that
2360 * release_task has been called in the kernel. In happens generally when
2361 * the parent waits for its child terminaison, but may also happen in special
2362 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2363 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2364 * of a killed thread group, but isn't the leader.
2366 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2368 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2369 LttvProcessState key
;
2371 /* Wait for both schedule with exit dead and process free to happen.
2372 * They can happen in any order. */
2373 if (++(process
->free_events
) < 2)
2376 key
.pid
= process
->pid
;
2377 key
.cpu
= process
->cpu
;
2378 g_hash_table_remove(ts
->processes
, &key
);
2379 g_array_free(process
->execution_stack
, TRUE
);
2380 g_array_free(process
->user_stack
, TRUE
);
2386 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2388 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2389 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2394 static void lttv_state_free_process_table(GHashTable
*processes
)
2396 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2397 g_hash_table_destroy(processes
);
2401 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2403 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2405 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2406 LttvProcessState
*process
= ts
->running_process
[cpu
];
2407 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2408 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2409 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2410 LttvExecutionSubmode submode
;
2412 guint syscall
= ltt_event_get_unsigned(e
, f
);
2413 expand_syscall_table(ts
, syscall
);
2414 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2415 /* There can be no system call from PID 0 : unknown state */
2416 if(process
->pid
!= 0)
2417 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2422 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2424 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2426 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2427 LttvProcessState
*process
= ts
->running_process
[cpu
];
2429 /* There can be no system call from PID 0 : unknown state */
2430 if(process
->pid
!= 0)
2431 pop_state(s
, LTTV_STATE_SYSCALL
);
2436 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2438 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2439 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2440 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2441 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2442 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2444 LttvExecutionSubmode submode
;
2446 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2448 expand_trap_table(ts
, trap
);
2450 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2452 push_state(s
, LTTV_STATE_TRAP
, submode
);
2454 /* update cpu status */
2455 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2457 /* update trap status */
2458 s
->cpu_state
->last_trap
= trap
;
2459 ts
->trap_states
[trap
].running
++;
2464 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2466 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2467 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2468 gint trap
= s
->cpu_state
->last_trap
;
2470 pop_state(s
, LTTV_STATE_TRAP
);
2472 /* update cpu status */
2473 cpu_pop_mode(s
->cpu_state
);
2475 /* update trap status */
2477 if(ts
->trap_states
[trap
].running
)
2478 ts
->trap_states
[trap
].running
--;
2483 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2485 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2486 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2487 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2488 //guint8 ev_id = ltt_event_eventtype_id(e);
2489 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2490 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2492 LttvExecutionSubmode submode
;
2493 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2495 expand_irq_table(ts
, irq
);
2497 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2499 /* Do something with the info about being in user or system mode when int? */
2500 push_state(s
, LTTV_STATE_IRQ
, submode
);
2502 /* update cpu status */
2503 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2505 /* update irq status */
2506 s
->cpu_state
->last_irq
= irq
;
2507 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2512 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2514 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2515 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2516 gint softirq
= s
->cpu_state
->last_soft_irq
;
2518 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2520 /* update softirq status */
2522 if(ts
->soft_irq_states
[softirq
].running
)
2523 ts
->soft_irq_states
[softirq
].running
--;
2525 /* update cpu status */
2526 cpu_pop_mode(s
->cpu_state
);
2531 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2533 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2534 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2536 pop_state(s
, LTTV_STATE_IRQ
);
2538 /* update cpu status */
2539 cpu_pop_mode(s
->cpu_state
);
2541 /* update irq status */
2542 if (s
->cpu_state
->last_irq
!= -1)
2543 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2548 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2550 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2551 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2552 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2553 //guint8 ev_id = ltt_event_eventtype_id(e);
2554 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2555 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2557 LttvExecutionSubmode submode
;
2558 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2559 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2561 if(softirq
< nb_softirqs
) {
2562 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2564 /* Fixup an incomplete irq table */
2565 GString
*string
= g_string_new("");
2566 g_string_printf(string
, "softirq %llu", softirq
);
2567 submode
= g_quark_from_string(string
->str
);
2568 g_string_free(string
, TRUE
);
2571 /* update softirq status */
2572 /* a soft irq raises are not cumulative */
2573 ts
->soft_irq_states
[softirq
].pending
=1;
2578 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2580 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2581 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2582 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2583 //guint8 ev_id = ltt_event_eventtype_id(e);
2584 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2585 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2586 LttvExecutionSubmode submode
;
2587 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2588 expand_soft_irq_table(ts
, softirq
);
2589 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2591 /* Do something with the info about being in user or system mode when int? */
2592 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2594 /* update cpu status */
2595 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2597 /* update softirq status */
2598 s
->cpu_state
->last_soft_irq
= softirq
;
2599 if(ts
->soft_irq_states
[softirq
].pending
)
2600 ts
->soft_irq_states
[softirq
].pending
--;
2601 ts
->soft_irq_states
[softirq
].running
++;
2606 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2608 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2609 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2610 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2611 //guint8 ev_id = ltt_event_eventtype_id(e);
2612 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2614 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2615 lttv_trace_get_hook_field(th
, 0)));
2616 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2618 expand_irq_table(ts
, irq
);
2619 ts
->irq_names
[irq
] = action
;
2625 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2627 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2628 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2629 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2630 //guint8 ev_id = ltt_event_eventtype_id(e);
2631 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2633 guint major
= ltt_event_get_long_unsigned(e
,
2634 lttv_trace_get_hook_field(th
, 0));
2635 guint minor
= ltt_event_get_long_unsigned(e
,
2636 lttv_trace_get_hook_field(th
, 1));
2637 guint oper
= ltt_event_get_long_unsigned(e
,
2638 lttv_trace_get_hook_field(th
, 2));
2639 guint16 devcode
= MKDEV(major
,minor
);
2641 /* have we seen this block device before? */
2642 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2645 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2647 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2652 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2654 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2655 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2656 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2657 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2659 guint major
= ltt_event_get_long_unsigned(e
,
2660 lttv_trace_get_hook_field(th
, 0));
2661 guint minor
= ltt_event_get_long_unsigned(e
,
2662 lttv_trace_get_hook_field(th
, 1));
2663 //guint oper = ltt_event_get_long_unsigned(e,
2664 // lttv_trace_get_hook_field(th, 2));
2665 guint16 devcode
= MKDEV(major
,minor
);
2667 /* have we seen this block device before? */
2668 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2670 /* update block device */
2671 bdev_pop_mode(bdev
);
2676 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2680 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2681 guint cpu
= tfs
->cpu
;
2682 LttvProcessState
*process
= ts
->running_process
[cpu
];
2684 guint depth
= process
->user_stack
->len
;
2686 process
->user_stack
=
2687 g_array_set_size(process
->user_stack
, depth
+ 1);
2689 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2690 *new_func
= funcptr
;
2691 process
->current_function
= funcptr
;
2694 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2696 guint cpu
= tfs
->cpu
;
2697 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2698 LttvProcessState
*process
= ts
->running_process
[cpu
];
2700 if(process
->current_function
!= funcptr
){
2701 g_info("Different functions (%lu.%09lu): ignore it\n",
2702 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2703 g_info("process state has %llu when pop_function is %llu\n",
2704 process
->current_function
, funcptr
);
2705 g_info("{ %u, %u, %s, %s, %s }\n",
2708 g_quark_to_string(process
->name
),
2709 g_quark_to_string(process
->brand
),
2710 g_quark_to_string(process
->state
->s
));
2713 guint depth
= process
->user_stack
->len
;
2716 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2717 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2721 process
->user_stack
=
2722 g_array_set_size(process
->user_stack
, depth
- 1);
2723 process
->current_function
=
2724 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2728 static gboolean
function_entry(void *hook_data
, void *call_data
)
2730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2731 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2732 //guint8 ev_id = ltt_event_eventtype_id(e);
2733 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2734 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2735 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2737 push_function(s
, funcptr
);
2741 static gboolean
function_exit(void *hook_data
, void *call_data
)
2743 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2744 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2745 //guint8 ev_id = ltt_event_eventtype_id(e);
2746 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2747 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2748 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2750 pop_function(s
, funcptr
);
2754 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2756 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2757 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2758 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2759 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2764 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2765 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2766 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2768 expand_syscall_table(ts
, id
);
2769 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2774 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2776 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2777 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2778 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2779 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2784 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2785 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2786 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2788 expand_soft_irq_table(ts
, id
);
2789 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2794 static gboolean
schedchange(void *hook_data
, void *call_data
)
2796 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2798 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2799 LttvProcessState
*process
= ts
->running_process
[cpu
];
2800 //LttvProcessState *old_process = ts->running_process[cpu];
2802 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2803 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2804 guint pid_in
, pid_out
;
2807 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2808 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2809 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2811 if(likely(process
!= NULL
)) {
2813 /* We could not know but it was not the idle process executing.
2814 This should only happen at the beginning, before the first schedule
2815 event, and when the initial information (current process for each CPU)
2816 is missing. It is not obvious how we could, after the fact, compensate
2817 the wrongly attributed statistics. */
2819 //This test only makes sense once the state is known and if there is no
2820 //missing events. We need to silently ignore schedchange coming after a
2821 //process_free, or it causes glitches. (FIXME)
2822 //if(unlikely(process->pid != pid_out)) {
2823 // g_assert(process->pid == 0);
2825 if(process
->pid
== 0
2826 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2828 /* Scheduling out of pid 0 at beginning of the trace :
2829 * we know for sure it is in syscall mode at this point. */
2830 g_assert(process
->execution_stack
->len
== 1);
2831 process
->state
->t
= LTTV_STATE_SYSCALL
;
2832 process
->state
->s
= LTTV_STATE_WAIT
;
2833 process
->state
->change
= s
->parent
.timestamp
;
2834 process
->state
->entry
= s
->parent
.timestamp
;
2837 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2838 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2839 process
->state
->change
= s
->parent
.timestamp
;
2841 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2842 else process
->state
->s
= LTTV_STATE_WAIT
;
2843 process
->state
->change
= s
->parent
.timestamp
;
2846 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2847 /* see sched.h for states */
2848 if (!exit_process(s
, process
)) {
2849 process
->state
->s
= LTTV_STATE_DEAD
;
2850 process
->state
->change
= s
->parent
.timestamp
;
2855 process
= ts
->running_process
[cpu
] =
2856 lttv_state_find_process_or_create(
2857 (LttvTraceState
*)s
->parent
.t_context
,
2859 &s
->parent
.timestamp
);
2860 process
->state
->s
= LTTV_STATE_RUN
;
2862 if(process
->usertrace
)
2863 process
->usertrace
->cpu
= cpu
;
2864 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2865 process
->state
->change
= s
->parent
.timestamp
;
2867 /* update cpu status */
2869 /* going to idle task */
2870 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2872 /* scheduling a real task.
2873 * we must be careful here:
2874 * if we just schedule()'ed to a process that is
2875 * in a trap, we must put the cpu in trap mode
2877 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2878 if(process
->state
->t
== LTTV_STATE_TRAP
)
2879 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2885 static gboolean
process_fork(void *hook_data
, void *call_data
)
2887 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2888 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2889 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2891 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2892 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2893 //LttvProcessState *zombie_process;
2895 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2896 LttvProcessState
*process
= ts
->running_process
[cpu
];
2897 LttvProcessState
*child_process
;
2898 struct marker_field
*f
;
2901 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2904 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2905 s
->parent
.target_pid
= child_pid
;
2908 f
= lttv_trace_get_hook_field(th
, 2);
2910 child_tgid
= ltt_event_get_unsigned(e
, f
);
2914 /* Mathieu : it seems like the process might have been scheduled in before the
2915 * fork, and, in a rare case, might be the current process. This might happen
2916 * in a SMP case where we don't have enough precision on the clocks.
2918 * Test reenabled after precision fixes on time. (Mathieu) */
2920 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2922 if(unlikely(zombie_process
!= NULL
)) {
2923 /* Reutilisation of PID. Only now we are sure that the old PID
2924 * has been released. FIXME : should know when release_task happens instead.
2926 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2928 for(i
=0; i
< num_cpus
; i
++) {
2929 g_assert(zombie_process
!= ts
->running_process
[i
]);
2932 exit_process(s
, zombie_process
);
2935 g_assert(process
->pid
!= child_pid
);
2936 // FIXME : Add this test in the "known state" section
2937 // g_assert(process->pid == parent_pid);
2938 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2939 if(child_process
== NULL
) {
2940 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2941 child_pid
, child_tgid
,
2942 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2944 /* The process has already been created : due to time imprecision between
2945 * multiple CPUs : it has been scheduled in before creation. Note that we
2946 * shouldn't have this kind of imprecision.
2948 * Simply put a correct parent.
2950 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2951 //g_assert(0); /* This is a problematic case : the process has been created
2952 // before the fork event */
2953 child_process
->ppid
= process
->pid
;
2954 child_process
->tgid
= child_tgid
;
2956 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2957 child_process
->name
= process
->name
;
2958 child_process
->brand
= process
->brand
;
2963 /* We stamp a newly created process as kernel_thread.
2964 * The thread should not be running yet. */
2965 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2967 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2968 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2969 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2971 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2972 LttvProcessState
*process
;
2973 LttvExecutionState
*es
;
2976 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2977 s
->parent
.target_pid
= pid
;
2979 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2981 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2982 process
->execution_stack
=
2983 g_array_set_size(process
->execution_stack
, 1);
2984 es
= process
->state
=
2985 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2986 es
->t
= LTTV_STATE_SYSCALL
;
2988 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2993 static gboolean
process_exit(void *hook_data
, void *call_data
)
2995 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2996 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2997 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2999 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3000 LttvProcessState
*process
; // = ts->running_process[cpu];
3002 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3003 s
->parent
.target_pid
= pid
;
3005 // FIXME : Add this test in the "known state" section
3006 // g_assert(process->pid == pid);
3008 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3009 if(likely(process
!= NULL
)) {
3010 process
->state
->s
= LTTV_STATE_EXIT
;
3015 static gboolean
process_free(void *hook_data
, void *call_data
)
3017 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3018 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3019 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3020 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3022 LttvProcessState
*process
;
3024 /* PID of the process to release */
3025 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3026 s
->parent
.target_pid
= release_pid
;
3028 g_assert(release_pid
!= 0);
3030 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3031 if(likely(process
!= NULL
))
3032 exit_process(s
, process
);
3035 if(likely(process
!= NULL
)) {
3036 /* release_task is happening at kernel level : we can now safely release
3037 * the data structure of the process */
3038 //This test is fun, though, as it may happen that
3039 //at time t : CPU 0 : process_free
3040 //at time t+150ns : CPU 1 : schedule out
3041 //Clearly due to time imprecision, we disable it. (Mathieu)
3042 //If this weird case happen, we have no choice but to put the
3043 //Currently running process on the cpu to 0.
3044 //I re-enable it following time precision fixes. (Mathieu)
3045 //Well, in the case where an process is freed by a process on another CPU
3046 //and still scheduled, it happens that this is the schedchange that will
3047 //drop the last reference count. Do not free it here!
3048 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3050 for(i
=0; i
< num_cpus
; i
++) {
3051 //g_assert(process != ts->running_process[i]);
3052 if(process
== ts
->running_process
[i
]) {
3053 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3057 if(i
== num_cpus
) /* process is not scheduled */
3058 exit_process(s
, process
);
3065 static gboolean
process_exec(void *hook_data
, void *call_data
)
3067 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3068 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3069 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3070 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3073 LttvProcessState
*process
= ts
->running_process
[cpu
];
3075 #if 0//how to use a sequence that must be transformed in a string
3076 /* PID of the process to release */
3077 guint64 name_len
= ltt_event_field_element_number(e
,
3078 lttv_trace_get_hook_field(th
, 0));
3079 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3080 LttField
*child
= ltt_event_field_element_select(e
,
3081 lttv_trace_get_hook_field(th
, 0), 0);
3083 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3084 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3085 memcpy(null_term_name
, name_begin
, name_len
);
3086 null_term_name
[name_len
] = '\0';
3087 process
->name
= g_quark_from_string(null_term_name
);
3090 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3091 lttv_trace_get_hook_field(th
, 0)));
3092 process
->brand
= LTTV_STATE_UNBRANDED
;
3093 //g_free(null_term_name);
3097 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3099 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3100 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3101 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3102 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3105 LttvProcessState
*process
= ts
->running_process
[cpu
];
3107 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3108 process
->brand
= g_quark_from_string(name
);
3113 static void fix_process(gpointer key
, gpointer value
,
3116 LttvProcessState
*process
;
3117 LttvExecutionState
*es
;
3118 process
= (LttvProcessState
*)value
;
3119 LttTime
*timestamp
= (LttTime
*)user_data
;
3121 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3122 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3123 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3124 es
->t
= LTTV_STATE_SYSCALL
;
3125 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3126 es
->entry
= *timestamp
;
3127 es
->change
= *timestamp
;
3128 es
->cum_cpu_time
= ltt_time_zero
;
3129 if(es
->s
== LTTV_STATE_UNNAMED
)
3130 es
->s
= LTTV_STATE_WAIT
;
3133 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3134 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3135 es
->t
= LTTV_STATE_USER_MODE
;
3136 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3137 es
->entry
= *timestamp
;
3138 //g_assert(timestamp->tv_sec != 0);
3139 es
->change
= *timestamp
;
3140 es
->cum_cpu_time
= ltt_time_zero
;
3141 if(es
->s
== LTTV_STATE_UNNAMED
)
3142 es
->s
= LTTV_STATE_RUN
;
3144 if(process
->execution_stack
->len
== 1) {
3145 /* Still in bottom unknown mode, means never did a system call
3146 * May be either in user mode, syscall mode, running or waiting.*/
3147 /* FIXME : we may be tagging syscall mode when being user mode */
3148 process
->execution_stack
=
3149 g_array_set_size(process
->execution_stack
, 2);
3150 es
= process
->state
= &g_array_index(process
->execution_stack
,
3151 LttvExecutionState
, 1);
3152 es
->t
= LTTV_STATE_SYSCALL
;
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_WAIT_FORK
)
3159 es
->s
= LTTV_STATE_WAIT
;
3165 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3167 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3168 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3169 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3170 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3171 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3173 /* For all processes */
3174 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3175 /* else, if stack[0] is unknown, set to user mode, running */
3177 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3182 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3184 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3185 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3186 //It's slow : optimise later by doing this before reading trace.
3187 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3193 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3194 LttvProcessState
*process
= ts
->running_process
[cpu
];
3195 LttvProcessState
*parent_process
;
3196 struct marker_field
*f
;
3197 GQuark type
, mode
, submode
, status
;
3198 LttvExecutionState
*es
;
3202 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3203 s
->parent
.target_pid
= pid
;
3206 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3209 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3212 f
= lttv_trace_get_hook_field(th
, 3);
3213 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3215 //FIXME: type is rarely used, enum must match possible types.
3218 f
= lttv_trace_get_hook_field(th
, 4);
3219 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3222 f
= lttv_trace_get_hook_field(th
, 5);
3223 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3226 f
= lttv_trace_get_hook_field(th
, 6);
3227 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3230 f
= lttv_trace_get_hook_field(th
, 7);
3232 tgid
= ltt_event_get_unsigned(e
, f
);
3237 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3238 for(i
=0; i
<nb_cpus
; i
++) {
3239 process
= lttv_state_find_process(ts
, i
, pid
);
3240 g_assert(process
!= NULL
);
3242 process
->ppid
= parent_pid
;
3243 process
->tgid
= tgid
;
3244 process
->name
= g_quark_from_string(command
);
3246 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3247 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3251 /* The process might exist if a process was forked while performing the
3253 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3254 if(process
== NULL
) {
3255 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3256 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3257 pid
, tgid
, g_quark_from_string(command
),
3258 &s
->parent
.timestamp
);
3260 /* Keep the stack bottom : a running user mode */
3261 /* Disabled because of inconsistencies in the current statedump states. */
3262 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3263 /* Only keep the bottom
3264 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3265 /* Will cause expected trap when in fact being syscall (even after end of
3267 * Will cause expected interrupt when being syscall. (only before end of
3268 * statedump event) */
3269 // This will cause a "popping last state on stack, ignoring it."
3270 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3271 es
= process
->state
= &g_array_index(process
->execution_stack
,
3272 LttvExecutionState
, 0);
3273 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3274 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3275 es
->s
= LTTV_STATE_UNNAMED
;
3276 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3278 es
->t
= LTTV_STATE_SYSCALL
;
3283 /* User space process :
3284 * bottom : user mode
3285 * either currently running or scheduled out.
3286 * can be scheduled out because interrupted in (user mode or in syscall)
3287 * or because of an explicit call to the scheduler in syscall. Note that
3288 * the scheduler call comes after the irq_exit, so never in interrupt
3290 // temp workaround : set size to 1 : only have user mode bottom of stack.
3291 // will cause g_info message of expected syscall mode when in fact being
3292 // in user mode. Can also cause expected trap when in fact being user
3293 // mode in the event of a page fault reenabling interrupts in the handler.
3294 // Expected syscall and trap can also happen after the end of statedump
3295 // This will cause a "popping last state on stack, ignoring it."
3296 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3297 es
= process
->state
= &g_array_index(process
->execution_stack
,
3298 LttvExecutionState
, 0);
3299 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3300 es
->s
= LTTV_STATE_UNNAMED
;
3301 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3303 es
->t
= LTTV_STATE_USER_MODE
;
3311 es
= process
->state
= &g_array_index(process
->execution_stack
,
3312 LttvExecutionState
, 1);
3313 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3314 es
->s
= LTTV_STATE_UNNAMED
;
3315 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3319 /* The process has already been created :
3320 * Probably was forked while dumping the process state or
3321 * was simply scheduled in prior to get the state dump event.
3323 process
->ppid
= parent_pid
;
3324 process
->tgid
= tgid
;
3325 process
->name
= g_quark_from_string(command
);
3326 process
->type
= type
;
3328 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3330 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3331 if(type
== LTTV_STATE_KERNEL_THREAD
)
3332 es
->t
= LTTV_STATE_SYSCALL
;
3334 es
->t
= LTTV_STATE_USER_MODE
;
3337 /* Don't mess around with the stack, it will eventually become
3338 * ok after the end of state dump. */
3345 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3347 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3349 lttv_state_add_event_hooks(tss
);
3354 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3356 LttvTraceset
*traceset
= self
->parent
.ts
;
3358 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3362 LttvTracefileState
*tfs
;
3368 LttvAttributeValue val
;
3370 nb_trace
= lttv_traceset_number(traceset
);
3371 for(i
= 0 ; i
< nb_trace
; i
++) {
3372 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3374 /* Find the eventtype id for the following events and register the
3375 associated by id hooks. */
3377 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3378 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3381 lttv_trace_find_hook(ts
->parent
.t
,
3382 LTT_FACILITY_KERNEL_ARCH
,
3383 LTT_EVENT_SYSCALL_ENTRY
,
3384 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3385 syscall_entry
, NULL
, &hooks
);
3387 lttv_trace_find_hook(ts
->parent
.t
,
3388 LTT_FACILITY_KERNEL_ARCH
,
3389 LTT_EVENT_SYSCALL_EXIT
,
3391 syscall_exit
, NULL
, &hooks
);
3393 lttv_trace_find_hook(ts
->parent
.t
,
3394 LTT_FACILITY_KERNEL_ARCH
,
3395 LTT_EVENT_TRAP_ENTRY
,
3396 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3397 trap_entry
, NULL
, &hooks
);
3399 lttv_trace_find_hook(ts
->parent
.t
,
3400 LTT_FACILITY_KERNEL_ARCH
,
3401 LTT_EVENT_TRAP_EXIT
,
3403 trap_exit
, NULL
, &hooks
);
3405 lttv_trace_find_hook(ts
->parent
.t
,
3406 LTT_FACILITY_KERNEL
,
3407 LTT_EVENT_IRQ_ENTRY
,
3408 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3409 irq_entry
, NULL
, &hooks
);
3411 lttv_trace_find_hook(ts
->parent
.t
,
3412 LTT_FACILITY_KERNEL
,
3415 irq_exit
, NULL
, &hooks
);
3417 lttv_trace_find_hook(ts
->parent
.t
,
3418 LTT_FACILITY_KERNEL
,
3419 LTT_EVENT_SOFT_IRQ_RAISE
,
3420 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3421 soft_irq_raise
, NULL
, &hooks
);
3423 lttv_trace_find_hook(ts
->parent
.t
,
3424 LTT_FACILITY_KERNEL
,
3425 LTT_EVENT_SOFT_IRQ_ENTRY
,
3426 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3427 soft_irq_entry
, NULL
, &hooks
);
3429 lttv_trace_find_hook(ts
->parent
.t
,
3430 LTT_FACILITY_KERNEL
,
3431 LTT_EVENT_SOFT_IRQ_EXIT
,
3433 soft_irq_exit
, NULL
, &hooks
);
3435 lttv_trace_find_hook(ts
->parent
.t
,
3436 LTT_FACILITY_KERNEL
,
3437 LTT_EVENT_SCHED_SCHEDULE
,
3438 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3439 LTT_FIELD_PREV_STATE
),
3440 schedchange
, NULL
, &hooks
);
3442 lttv_trace_find_hook(ts
->parent
.t
,
3443 LTT_FACILITY_KERNEL
,
3444 LTT_EVENT_PROCESS_FORK
,
3445 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3446 LTT_FIELD_CHILD_TGID
),
3447 process_fork
, NULL
, &hooks
);
3449 lttv_trace_find_hook(ts
->parent
.t
,
3450 LTT_FACILITY_KERNEL_ARCH
,
3451 LTT_EVENT_KTHREAD_CREATE
,
3452 FIELD_ARRAY(LTT_FIELD_PID
),
3453 process_kernel_thread
, NULL
, &hooks
);
3455 lttv_trace_find_hook(ts
->parent
.t
,
3456 LTT_FACILITY_KERNEL
,
3457 LTT_EVENT_PROCESS_EXIT
,
3458 FIELD_ARRAY(LTT_FIELD_PID
),
3459 process_exit
, NULL
, &hooks
);
3461 lttv_trace_find_hook(ts
->parent
.t
,
3462 LTT_FACILITY_KERNEL
,
3463 LTT_EVENT_PROCESS_FREE
,
3464 FIELD_ARRAY(LTT_FIELD_PID
),
3465 process_free
, NULL
, &hooks
);
3467 lttv_trace_find_hook(ts
->parent
.t
,
3470 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3471 process_exec
, NULL
, &hooks
);
3473 lttv_trace_find_hook(ts
->parent
.t
,
3474 LTT_FACILITY_USER_GENERIC
,
3475 LTT_EVENT_THREAD_BRAND
,
3476 FIELD_ARRAY(LTT_FIELD_NAME
),
3477 thread_brand
, NULL
, &hooks
);
3479 /* statedump-related hooks */
3480 lttv_trace_find_hook(ts
->parent
.t
,
3482 LTT_EVENT_PROCESS_STATE
,
3483 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3484 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3485 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3486 enum_process_state
, NULL
, &hooks
);
3488 lttv_trace_find_hook(ts
->parent
.t
,
3490 LTT_EVENT_STATEDUMP_END
,
3492 statedump_end
, NULL
, &hooks
);
3494 lttv_trace_find_hook(ts
->parent
.t
,
3496 LTT_EVENT_LIST_INTERRUPT
,
3497 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3498 enum_interrupt
, NULL
, &hooks
);
3500 lttv_trace_find_hook(ts
->parent
.t
,
3502 LTT_EVENT_REQUEST_ISSUE
,
3503 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3504 bdev_request_issue
, NULL
, &hooks
);
3506 lttv_trace_find_hook(ts
->parent
.t
,
3508 LTT_EVENT_REQUEST_COMPLETE
,
3509 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3510 bdev_request_complete
, NULL
, &hooks
);
3512 lttv_trace_find_hook(ts
->parent
.t
,
3513 LTT_FACILITY_USER_GENERIC
,
3514 LTT_EVENT_FUNCTION_ENTRY
,
3515 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3516 function_entry
, NULL
, &hooks
);
3518 lttv_trace_find_hook(ts
->parent
.t
,
3519 LTT_FACILITY_USER_GENERIC
,
3520 LTT_EVENT_FUNCTION_EXIT
,
3521 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3522 function_exit
, NULL
, &hooks
);
3524 lttv_trace_find_hook(ts
->parent
.t
,
3525 LTT_FACILITY_STATEDUMP
,
3526 LTT_EVENT_SYS_CALL_TABLE
,
3527 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3528 dump_syscall
, NULL
, &hooks
);
3530 lttv_trace_find_hook(ts
->parent
.t
,
3531 LTT_FACILITY_STATEDUMP
,
3532 LTT_EVENT_SOFTIRQ_VEC
,
3533 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3534 dump_softirq
, NULL
, &hooks
);
3536 /* Add these hooks to each event_by_id hooks list */
3538 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3540 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3542 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3543 LttvTracefileContext
*, j
));
3545 for(k
= 0 ; k
< hooks
->len
; k
++) {
3546 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3548 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3554 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3555 *(val
.v_pointer
) = hooks
;
3559 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3561 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3563 lttv_state_remove_event_hooks(tss
);
3568 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3570 LttvTraceset
*traceset
= self
->parent
.ts
;
3572 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3576 LttvTracefileState
*tfs
;
3582 LttvAttributeValue val
;
3584 nb_trace
= lttv_traceset_number(traceset
);
3585 for(i
= 0 ; i
< nb_trace
; i
++) {
3586 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3588 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3589 hooks
= *(val
.v_pointer
);
3591 /* Remove these hooks from each event_by_id hooks list */
3593 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3595 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3597 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3598 LttvTracefileContext
*, j
));
3600 for(k
= 0 ; k
< hooks
->len
; k
++) {
3601 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3602 lttv_hooks_remove_data(
3603 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3608 lttv_trace_hook_remove_all(&hooks
);
3609 g_array_free(hooks
, TRUE
);
3613 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3615 guint
*event_count
= (guint
*)hook_data
;
3617 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3618 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3623 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3625 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3627 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3629 LttvAttributeValue value
;
3631 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3632 LTTV_STATE_SAVED_STATES
);
3633 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3634 value
= lttv_attribute_add(saved_states_tree
,
3635 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3636 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3637 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3638 *(value
.v_time
) = self
->parent
.timestamp
;
3639 lttv_state_save(tcs
, saved_state_tree
);
3640 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3641 self
->parent
.timestamp
.tv_nsec
);
3643 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3648 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3650 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3652 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3657 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3665 static gboolean
block_start(void *hook_data
, void *call_data
)
3667 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3669 LttvTracefileState
*tfcs
;
3671 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3673 LttEventPosition
*ep
;
3675 guint i
, nb_block
, nb_event
, nb_tracefile
;
3679 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3681 LttvAttributeValue value
;
3683 ep
= ltt_event_position_new();
3685 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3687 /* Count the number of events added since the last block end in any
3690 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3692 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3693 LttvTracefileContext
, i
));
3694 ltt_event_position(tfcs
->parent
.e
, ep
);
3695 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3696 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3697 tfcs
->saved_position
= nb_event
;
3701 if(tcs
->nb_event
>= tcs
->save_interval
) {
3702 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3703 LTTV_STATE_SAVED_STATES
);
3704 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3705 value
= lttv_attribute_add(saved_states_tree
,
3706 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3707 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3708 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3709 *(value
.v_time
) = self
->parent
.timestamp
;
3710 lttv_state_save(tcs
, saved_state_tree
);
3712 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3713 self
->parent
.timestamp
.tv_nsec
);
3715 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3721 static gboolean
block_end(void *hook_data
, void *call_data
)
3723 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3725 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3729 LttEventPosition
*ep
;
3731 guint nb_block
, nb_event
;
3733 ep
= ltt_event_position_new();
3734 ltt_event_position(self
->parent
.e
, ep
);
3735 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3736 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3737 self
->saved_position
= 0;
3738 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3745 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3747 LttvTraceset
*traceset
= self
->parent
.ts
;
3749 guint i
, j
, nb_trace
, nb_tracefile
;
3753 LttvTracefileState
*tfs
;
3755 LttvTraceHook hook_start
, hook_end
;
3757 nb_trace
= lttv_traceset_number(traceset
);
3758 for(i
= 0 ; i
< nb_trace
; i
++) {
3759 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3761 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3762 NULL
, NULL
, block_start
, &hook_start
);
3763 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3764 NULL
, NULL
, block_end
, &hook_end
);
3766 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3768 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3770 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3771 LttvTracefileContext
, j
));
3772 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3773 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3774 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3775 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3781 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3783 LttvTraceset
*traceset
= self
->parent
.ts
;
3785 guint i
, j
, nb_trace
, nb_tracefile
;
3789 LttvTracefileState
*tfs
;
3792 nb_trace
= lttv_traceset_number(traceset
);
3793 for(i
= 0 ; i
< nb_trace
; i
++) {
3795 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3796 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3798 if(ts
->has_precomputed_states
) continue;
3800 guint
*event_count
= g_new(guint
, 1);
3803 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3805 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3806 LttvTracefileContext
*, j
));
3807 lttv_hooks_add(tfs
->parent
.event
,
3808 state_save_event_hook
,
3815 lttv_process_traceset_begin(&self
->parent
,
3816 NULL
, NULL
, NULL
, NULL
, NULL
);
3820 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3822 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3824 lttv_state_save_add_event_hooks(tss
);
3831 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3833 LttvTraceset
*traceset
= self
->parent
.ts
;
3835 guint i
, j
, nb_trace
, nb_tracefile
;
3839 LttvTracefileState
*tfs
;
3841 LttvTraceHook hook_start
, hook_end
;
3843 nb_trace
= lttv_traceset_number(traceset
);
3844 for(i
= 0 ; i
< nb_trace
; i
++) {
3845 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3847 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3848 NULL
, NULL
, block_start
, &hook_start
);
3850 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3851 NULL
, NULL
, block_end
, &hook_end
);
3853 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3855 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3857 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3858 LttvTracefileContext
, j
));
3859 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3860 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3861 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3862 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3868 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3870 LttvTraceset
*traceset
= self
->parent
.ts
;
3872 guint i
, j
, nb_trace
, nb_tracefile
;
3876 LttvTracefileState
*tfs
;
3878 LttvHooks
*after_trace
= lttv_hooks_new();
3880 lttv_hooks_add(after_trace
,
3881 state_save_after_trace_hook
,
3886 lttv_process_traceset_end(&self
->parent
,
3887 NULL
, after_trace
, NULL
, NULL
, NULL
);
3889 lttv_hooks_destroy(after_trace
);
3891 nb_trace
= lttv_traceset_number(traceset
);
3892 for(i
= 0 ; i
< nb_trace
; i
++) {
3894 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3895 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3897 if(ts
->has_precomputed_states
) continue;
3899 guint
*event_count
= NULL
;
3901 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3903 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3904 LttvTracefileContext
*, j
));
3905 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3906 state_save_event_hook
);
3908 if(event_count
) g_free(event_count
);
3912 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3914 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3916 lttv_state_save_remove_event_hooks(tss
);
3921 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3923 LttvTraceset
*traceset
= self
->parent
.ts
;
3927 int min_pos
, mid_pos
, max_pos
;
3929 guint call_rest
= 0;
3931 LttvTraceState
*tcs
;
3933 LttvAttributeValue value
;
3935 LttvAttributeType type
;
3937 LttvAttributeName name
;
3941 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3943 //g_tree_destroy(self->parent.pqueue);
3944 //self->parent.pqueue = g_tree_new(compare_tracefile);
3946 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3948 nb_trace
= lttv_traceset_number(traceset
);
3949 for(i
= 0 ; i
< nb_trace
; i
++) {
3950 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3952 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3953 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3954 LTTV_STATE_SAVED_STATES
);
3957 if(saved_states_tree
) {
3958 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3959 mid_pos
= max_pos
/ 2;
3960 while(min_pos
< max_pos
) {
3961 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3963 g_assert(type
== LTTV_GOBJECT
);
3964 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3965 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3967 g_assert(type
== LTTV_TIME
);
3968 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3970 closest_tree
= saved_state_tree
;
3972 else max_pos
= mid_pos
- 1;
3974 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3978 /* restore the closest earlier saved state */
3980 lttv_state_restore(tcs
, closest_tree
);
3984 /* There is no saved state, yet we want to have it. Restart at T0 */
3986 restore_init_state(tcs
);
3987 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3990 /* We want to seek quickly without restoring/updating the state */
3992 restore_init_state(tcs
);
3993 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3996 if(!call_rest
) g_info("NOT Calling restore");
4001 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4007 traceset_state_finalize (LttvTracesetState
*self
)
4009 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4010 finalize(G_OBJECT(self
));
4015 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4017 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4019 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4020 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4021 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4022 klass
->new_traceset_context
= new_traceset_context
;
4023 klass
->new_trace_context
= new_trace_context
;
4024 klass
->new_tracefile_context
= new_tracefile_context
;
4029 lttv_traceset_state_get_type(void)
4031 static GType type
= 0;
4033 static const GTypeInfo info
= {
4034 sizeof (LttvTracesetStateClass
),
4035 NULL
, /* base_init */
4036 NULL
, /* base_finalize */
4037 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4038 NULL
, /* class_finalize */
4039 NULL
, /* class_data */
4040 sizeof (LttvTracesetState
),
4041 0, /* n_preallocs */
4042 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4043 NULL
/* value handling */
4046 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4054 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4060 trace_state_finalize (LttvTraceState
*self
)
4062 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4063 finalize(G_OBJECT(self
));
4068 trace_state_class_init (LttvTraceStateClass
*klass
)
4070 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4072 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4073 klass
->state_save
= state_save
;
4074 klass
->state_restore
= state_restore
;
4075 klass
->state_saved_free
= state_saved_free
;
4080 lttv_trace_state_get_type(void)
4082 static GType type
= 0;
4084 static const GTypeInfo info
= {
4085 sizeof (LttvTraceStateClass
),
4086 NULL
, /* base_init */
4087 NULL
, /* base_finalize */
4088 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4089 NULL
, /* class_finalize */
4090 NULL
, /* class_data */
4091 sizeof (LttvTraceState
),
4092 0, /* n_preallocs */
4093 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4094 NULL
/* value handling */
4097 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4098 "LttvTraceStateType", &info
, 0);
4105 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4111 tracefile_state_finalize (LttvTracefileState
*self
)
4113 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4114 finalize(G_OBJECT(self
));
4119 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4121 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4123 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4128 lttv_tracefile_state_get_type(void)
4130 static GType type
= 0;
4132 static const GTypeInfo info
= {
4133 sizeof (LttvTracefileStateClass
),
4134 NULL
, /* base_init */
4135 NULL
, /* base_finalize */
4136 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4137 NULL
, /* class_finalize */
4138 NULL
, /* class_data */
4139 sizeof (LttvTracefileState
),
4140 0, /* n_preallocs */
4141 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4142 NULL
/* value handling */
4145 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4146 "LttvTracefileStateType", &info
, 0);
4152 static void module_init()
4154 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4155 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4156 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4157 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4158 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4159 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4160 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4161 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4162 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4163 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4164 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4165 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4166 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4167 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4168 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4169 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4170 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4171 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4172 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4173 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4174 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4175 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4176 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4177 LTTV_STATE_EVENT
= g_quark_from_string("event");
4178 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4179 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4180 LTTV_STATE_TIME
= g_quark_from_string("time");
4181 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4182 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4183 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4184 g_quark_from_string("trace_state_use_count");
4185 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4186 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4187 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4188 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4189 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4190 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4193 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4194 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4195 LTT_FACILITY_FS
= g_quark_from_string("fs");
4196 LTT_FACILITY_LIST
= g_quark_from_string("list");
4197 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4198 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4199 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4201 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4202 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4203 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4204 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4205 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4206 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4207 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4208 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4209 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4210 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4211 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4212 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4213 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4214 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4215 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4216 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4217 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4218 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4219 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4220 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4221 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4222 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4223 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4224 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4225 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4227 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4228 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4229 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4230 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4231 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4232 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4233 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4234 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4235 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4236 LTT_FIELD_PID
= g_quark_from_string("pid");
4237 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4238 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4239 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4240 LTT_FIELD_NAME
= g_quark_from_string("name");
4241 LTT_FIELD_TYPE
= g_quark_from_string("type");
4242 LTT_FIELD_MODE
= g_quark_from_string("mode");
4243 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4244 LTT_FIELD_STATUS
= g_quark_from_string("status");
4245 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4246 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4247 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4248 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4249 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4250 LTT_FIELD_ACTION
= g_quark_from_string("action");
4251 LTT_FIELD_ID
= g_quark_from_string("id");
4252 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4253 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4255 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4256 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4257 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4258 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4259 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4260 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4262 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4263 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4264 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4266 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4267 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4268 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4269 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4272 static void module_destroy()
4277 LTTV_MODULE("state", "State computation", \
4278 "Update the system state, possibly saving it at intervals", \
4279 module_init
, module_destroy
)