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>
36 guint64 nr_states
= 0;
40 * usertrace is there only to be able to update the current CPU of the
41 * usertraces when there is a schedchange. it is a way to link the ProcessState
42 * to the associated usertrace. Link only created upon thread creation.
44 * The cpu id is necessary : it gives us back the current ProcessState when we
45 * are considering data from the usertrace.
48 #define PREALLOCATED_EXECUTION_STACK 10
50 /* Facilities Quarks */
54 LTT_FACILITY_KERNEL_ARCH
,
57 LTT_FACILITY_USER_GENERIC
,
59 LTT_FACILITY_STATEDUMP
;
64 LTT_EVENT_SYSCALL_ENTRY
,
65 LTT_EVENT_SYSCALL_EXIT
,
70 LTT_EVENT_SOFT_IRQ_RAISE
,
71 LTT_EVENT_SOFT_IRQ_ENTRY
,
72 LTT_EVENT_SOFT_IRQ_EXIT
,
73 LTT_EVENT_SCHED_SCHEDULE
,
74 LTT_EVENT_PROCESS_FORK
,
75 LTT_EVENT_KTHREAD_CREATE
,
76 LTT_EVENT_PROCESS_EXIT
,
77 LTT_EVENT_PROCESS_FREE
,
79 LTT_EVENT_PROCESS_STATE
,
80 LTT_EVENT_STATEDUMP_END
,
81 LTT_EVENT_FUNCTION_ENTRY
,
82 LTT_EVENT_FUNCTION_EXIT
,
83 LTT_EVENT_THREAD_BRAND
,
84 LTT_EVENT_REQUEST_ISSUE
,
85 LTT_EVENT_REQUEST_COMPLETE
,
86 LTT_EVENT_LIST_INTERRUPT
,
87 LTT_EVENT_SYS_CALL_TABLE
,
88 LTT_EVENT_SOFTIRQ_VEC
;
96 LTT_FIELD_SOFT_IRQ_ID
,
100 LTT_FIELD_PARENT_PID
,
104 LTT_FIELD_CHILD_TGID
,
122 LTTV_STATE_MODE_UNKNOWN
,
123 LTTV_STATE_USER_MODE
,
130 LTTV_STATE_SUBMODE_UNKNOWN
,
131 LTTV_STATE_SUBMODE_NONE
;
135 LTTV_STATE_WAIT_FORK
,
144 LTTV_STATE_UNBRANDED
;
147 LTTV_STATE_USER_THREAD
,
148 LTTV_STATE_KERNEL_THREAD
;
166 LTTV_BDEV_BUSY_READING
,
167 LTTV_BDEV_BUSY_WRITING
;
170 LTTV_STATE_TRACEFILES
,
171 LTTV_STATE_PROCESSES
,
173 LTTV_STATE_RUNNING_PROCESS
,
175 LTTV_STATE_SAVED_STATES
,
176 LTTV_STATE_SAVED_STATES_TIME
,
179 LTTV_STATE_NAME_TABLES
,
180 LTTV_STATE_TRACE_STATE_USE_COUNT
,
181 LTTV_STATE_RESOURCE_CPUS
,
182 LTTV_STATE_RESOURCE_CPUS_COUNT
,
183 LTTV_STATE_RESOURCE_IRQS
,
184 LTTV_STATE_RESOURCE_SOFT_IRQS
,
185 LTTV_STATE_RESOURCE_TRAPS
,
186 LTTV_STATE_RESOURCE_BLKDEVS
;
188 static void create_max_time(LttvTraceState
*tcs
);
190 static void get_max_time(LttvTraceState
*tcs
);
192 static void free_max_time(LttvTraceState
*tcs
);
194 static void create_name_tables(LttvTraceState
*tcs
);
196 static void get_name_tables(LttvTraceState
*tcs
);
198 static void free_name_tables(LttvTraceState
*tcs
);
200 static void free_saved_state(LttvTraceState
*tcs
);
202 static void lttv_state_free_process_table(GHashTable
*processes
);
204 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
205 GPtrArray
*quarktable
);
207 /* Resource function prototypes */
208 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
209 static LttvBdevState
*bdevstate_new(void);
210 static void bdevstate_free(LttvBdevState
*);
211 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
212 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
215 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
217 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
221 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
223 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
227 void lttv_state_state_saved_free(LttvTraceState
*self
,
228 LttvAttribute
*container
)
230 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
234 guint
process_hash(gconstpointer key
)
236 guint pid
= ((const LttvProcessState
*)key
)->pid
;
237 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
241 /* If the hash table hash function is well distributed,
242 * the process_equal should compare different pid */
243 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
245 const LttvProcessState
*process_a
, *process_b
;
248 process_a
= (const LttvProcessState
*)a
;
249 process_b
= (const LttvProcessState
*)b
;
251 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
252 else if(likely(process_a
->pid
== 0 &&
253 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
258 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
260 g_tree_destroy((GTree
*)value
);
263 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
265 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
266 g_hash_table_destroy(usertraces
);
269 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
274 static guint
check_expand(nb
, id
)
279 return max(id
+ 1, nb
* 2);
282 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
283 guint nb
, guint new_nb
)
285 /* Expand an incomplete table */
286 GQuark
*old_table
= *table
;
287 *table
= g_new(GQuark
, new_nb
);
288 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
291 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
292 guint new_nb
, const char *def_string
)
295 GString
*fe_name
= g_string_new("");
296 for(i
= nb
; i
< new_nb
; i
++) {
297 g_string_printf(fe_name
, "%s %d", def_string
, i
);
298 table
[i
] = g_quark_from_string(fe_name
->str
);
300 g_string_free(fe_name
, TRUE
);
303 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
305 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
306 if(likely(new_nb
== ts
->nb_syscalls
))
308 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
309 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
310 /* Update the table size */
311 ts
->nb_syscalls
= new_nb
;
314 static void expand_trap_table(LttvTraceState
*ts
, int id
)
316 guint new_nb
= check_expand(ts
->nb_traps
, id
);
318 if(likely(new_nb
== ts
->nb_traps
))
320 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
321 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
322 /* Update the table size */
323 ts
->nb_traps
= new_nb
;
325 LttvTrapState
*old_table
= ts
->trap_states
;
326 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
327 memcpy(ts
->trap_states
, old_table
,
328 ts
->nb_traps
* sizeof(LttvTrapState
));
329 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
330 ts
->trap_states
[i
].running
= 0;
333 static void expand_irq_table(LttvTraceState
*ts
, int id
)
335 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
337 if(likely(new_nb
== ts
->nb_irqs
))
339 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
340 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
342 LttvIRQState
*old_table
= ts
->irq_states
;
343 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
344 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
345 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
346 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
349 /* Update the table size */
350 ts
->nb_irqs
= new_nb
;
353 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
355 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
357 if(likely(new_nb
== ts
->nb_soft_irqs
))
359 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
360 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
362 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
363 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
364 memcpy(ts
->soft_irq_states
, old_table
,
365 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
366 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
367 ts
->soft_irq_states
[i
].running
= 0;
369 /* Update the table size */
370 ts
->nb_soft_irqs
= new_nb
;
374 restore_init_state(LttvTraceState
*self
)
376 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
378 //LttvTracefileState *tfcs;
380 LttTime start_time
, end_time
;
382 /* Free the process tables */
383 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
384 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
385 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
386 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
389 /* Seek time to beginning */
390 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
391 // closest. It's the tracecontext job to seek the trace to the beginning
392 // anyway : the init state might be used at the middle of the trace as well...
393 //g_tree_destroy(self->parent.ts_context->pqueue);
394 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
396 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
398 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
400 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
401 nb_irqs
= self
->nb_irqs
;
402 nb_soft_irqs
= self
->nb_soft_irqs
;
403 nb_traps
= self
->nb_traps
;
405 /* Put the per cpu running_process to beginning state : process 0. */
406 for(i
=0; i
< nb_cpus
; i
++) {
407 LttvExecutionState
*es
;
408 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
409 LTTV_STATE_UNNAMED
, &start_time
);
410 /* We are not sure is it's a kernel thread or normal thread, put the
411 * bottom stack state to unknown */
412 self
->running_process
[i
]->execution_stack
=
413 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
414 es
= self
->running_process
[i
]->state
=
415 &g_array_index(self
->running_process
[i
]->execution_stack
,
416 LttvExecutionState
, 0);
417 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
418 es
->s
= LTTV_STATE_UNNAMED
;
420 //self->running_process[i]->state->s = LTTV_STATE_RUN;
421 self
->running_process
[i
]->cpu
= i
;
423 /* reset cpu states */
424 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
425 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
428 /* reset irq states */
429 for(i
=0; i
<nb_irqs
; i
++) {
430 if(self
->irq_states
[i
].mode_stack
->len
> 0)
431 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
434 /* reset softirq states */
435 for(i
=0; i
<nb_soft_irqs
; i
++) {
436 self
->soft_irq_states
[i
].pending
= 0;
437 self
->soft_irq_states
[i
].running
= 0;
440 /* reset trap states */
441 for(i
=0; i
<nb_traps
; i
++) {
442 self
->trap_states
[i
].running
= 0;
445 /* reset bdev states */
446 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
447 //g_hash_table_steal_all(self->bdev_states);
448 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
451 nb_tracefile
= self
->parent
.tracefiles
->len
;
453 for(i
= 0 ; i
< nb_tracefile
; i
++) {
455 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
456 LttvTracefileContext
*, i
));
457 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
458 // tfcs->saved_position = 0;
459 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
460 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
461 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
462 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
467 //static LttTime time_zero = {0,0};
469 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
472 const LttTime
*t1
= (const LttTime
*)a
;
473 const LttTime
*t2
= (const LttTime
*)b
;
475 return ltt_time_compare(*t1
, *t2
);
478 static void free_usertrace_key(gpointer data
)
483 #define MAX_STRING_LEN 4096
486 state_load_saved_states(LttvTraceState
*tcs
)
489 GPtrArray
*quarktable
;
490 const char *trace_path
;
494 tcs
->has_precomputed_states
= FALSE
;
498 gchar buf
[MAX_STRING_LEN
];
501 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
502 strncpy(path
, trace_path
, PATH_MAX
-1);
503 count
= strnlen(trace_path
, PATH_MAX
-1);
504 // quarktable : open, test
505 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
506 fp
= fopen(path
, "r");
508 quarktable
= g_ptr_array_sized_new(4096);
510 /* Index 0 is null */
512 if(hdr
== EOF
) return;
513 g_assert(hdr
== HDR_QUARKS
);
517 if(hdr
== EOF
) break;
518 g_assert(hdr
== HDR_QUARK
);
519 g_ptr_array_set_size(quarktable
, q
+1);
522 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
523 if(buf
[i
] == '\0' || feof(fp
)) break;
526 len
= strnlen(buf
, MAX_STRING_LEN
-1);
527 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
528 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
534 // saved_states : open, test
535 strncpy(path
, trace_path
, PATH_MAX
-1);
536 count
= strnlen(trace_path
, PATH_MAX
-1);
537 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
538 fp
= fopen(path
, "r");
542 if(hdr
!= HDR_TRACE
) goto end
;
544 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
546 tcs
->has_precomputed_states
= TRUE
;
551 /* Free the quarktable */
552 for(i
=0; i
<quarktable
->len
; i
++) {
553 string
= g_ptr_array_index (quarktable
, i
);
556 g_ptr_array_free(quarktable
, TRUE
);
561 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
563 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
566 LttvTraceContext
*tc
;
570 LttvTracefileState
*tfcs
;
572 LttvAttributeValue v
;
574 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
575 init((LttvTracesetContext
*)self
, ts
);
577 nb_trace
= lttv_traceset_number(ts
);
578 for(i
= 0 ; i
< nb_trace
; i
++) {
579 tc
= self
->parent
.traces
[i
];
580 tcs
= LTTV_TRACE_STATE(tc
);
581 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
582 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
586 if(*(v
.v_uint
) == 1) {
587 create_name_tables(tcs
);
588 create_max_time(tcs
);
590 get_name_tables(tcs
);
593 nb_tracefile
= tc
->tracefiles
->len
;
594 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
595 nb_irq
= tcs
->nb_irqs
;
596 tcs
->processes
= NULL
;
597 tcs
->usertraces
= NULL
;
598 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
600 /* init cpu resource stuff */
601 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
602 for(j
= 0; j
<nb_cpu
; j
++) {
603 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
604 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
607 /* init irq resource stuff */
608 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
609 for(j
= 0; j
<nb_irq
; j
++) {
610 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
611 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
614 /* init soft irq stuff */
615 /* the kernel has a statically fixed max of 32 softirqs */
616 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
618 /* init trap stuff */
619 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
621 /* init bdev resource stuff */
622 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
624 restore_init_state(tcs
);
625 for(j
= 0 ; j
< nb_tracefile
; j
++) {
627 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
628 LttvTracefileContext
*, j
));
629 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
630 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
631 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
632 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
633 /* It's a Usertrace */
634 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
635 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
637 if(!usertrace_tree
) {
638 usertrace_tree
= g_tree_new_full(compare_usertraces
,
639 NULL
, free_usertrace_key
, NULL
);
640 g_hash_table_insert(tcs
->usertraces
,
641 (gpointer
)tid
, usertrace_tree
);
643 LttTime
*timestamp
= g_new(LttTime
, 1);
644 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
645 ltt_tracefile_creation(tfcs
->parent
.tf
));
646 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
650 /* See if the trace has saved states */
651 state_load_saved_states(tcs
);
656 fini(LttvTracesetState
*self
)
662 //LttvTracefileState *tfcs;
664 LttvAttributeValue v
;
666 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
667 for(i
= 0 ; i
< nb_trace
; i
++) {
668 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
669 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
672 g_assert(*(v
.v_uint
) != 0);
675 if(*(v
.v_uint
) == 0) {
676 free_name_tables(tcs
);
678 free_saved_state(tcs
);
680 g_free(tcs
->running_process
);
681 tcs
->running_process
= NULL
;
682 lttv_state_free_process_table(tcs
->processes
);
683 lttv_state_free_usertraces(tcs
->usertraces
);
684 tcs
->processes
= NULL
;
685 tcs
->usertraces
= NULL
;
687 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
688 fini((LttvTracesetContext
*)self
);
692 static LttvTracesetContext
*
693 new_traceset_context(LttvTracesetContext
*self
)
695 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
699 static LttvTraceContext
*
700 new_trace_context(LttvTracesetContext
*self
)
702 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
706 static LttvTracefileContext
*
707 new_tracefile_context(LttvTracesetContext
*self
)
709 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
713 /* Write the process state of the trace */
715 static void write_process_state(gpointer key
, gpointer value
,
718 LttvProcessState
*process
;
720 LttvExecutionState
*es
;
722 FILE *fp
= (FILE *)user_data
;
727 process
= (LttvProcessState
*)value
;
729 " <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",
730 process
, process
->pid
, process
->tgid
, process
->ppid
,
731 g_quark_to_string(process
->type
),
732 process
->creation_time
.tv_sec
,
733 process
->creation_time
.tv_nsec
,
734 process
->insertion_time
.tv_sec
,
735 process
->insertion_time
.tv_nsec
,
736 g_quark_to_string(process
->name
),
737 g_quark_to_string(process
->brand
),
738 process
->cpu
, process
->free_events
);
740 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
741 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
742 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
743 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
744 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
745 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
746 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
749 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
750 address
= g_array_index(process
->user_stack
, guint64
, i
);
751 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
755 if(process
->usertrace
) {
756 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
757 g_quark_to_string(process
->usertrace
->tracefile_name
),
758 process
->usertrace
->cpu
);
762 fprintf(fp
, " </PROCESS>\n");
766 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
768 guint i
, nb_tracefile
, nb_block
, offset
;
771 LttvTracefileState
*tfcs
;
775 LttEventPosition
*ep
;
779 ep
= ltt_event_position_new();
781 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
783 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
785 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
786 for(i
=0;i
<nb_cpus
;i
++) {
787 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
788 i
, self
->running_process
[i
]->pid
);
791 nb_tracefile
= self
->parent
.tracefiles
->len
;
793 for(i
= 0 ; i
< nb_tracefile
; i
++) {
795 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
796 LttvTracefileContext
*, i
));
797 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
798 tfcs
->parent
.timestamp
.tv_sec
,
799 tfcs
->parent
.timestamp
.tv_nsec
);
800 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
801 if(e
== NULL
) fprintf(fp
,"/>\n");
803 ltt_event_position(e
, ep
);
804 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
805 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
810 fprintf(fp
,"</PROCESS_STATE>\n");
814 static void write_process_state_raw(gpointer key
, gpointer value
,
817 LttvProcessState
*process
;
819 LttvExecutionState
*es
;
821 FILE *fp
= (FILE *)user_data
;
826 process
= (LttvProcessState
*)value
;
827 fputc(HDR_PROCESS
, fp
);
828 //fwrite(&header, sizeof(header), 1, fp);
829 //fprintf(fp, "%s", g_quark_to_string(process->type));
831 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
832 //fprintf(fp, "%s", g_quark_to_string(process->name));
834 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
835 //fprintf(fp, "%s", g_quark_to_string(process->brand));
837 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
838 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
839 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
840 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
841 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
842 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
843 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
844 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
848 " <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",
849 process
, process
->pid
, process
->tgid
, process
->ppid
,
850 g_quark_to_string(process
->type
),
851 process
->creation_time
.tv_sec
,
852 process
->creation_time
.tv_nsec
,
853 process
->insertion_time
.tv_sec
,
854 process
->insertion_time
.tv_nsec
,
855 g_quark_to_string(process
->name
),
856 g_quark_to_string(process
->brand
),
860 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
861 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
864 //fprintf(fp, "%s", g_quark_to_string(es->t));
866 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
867 //fprintf(fp, "%s", g_quark_to_string(es->n));
869 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
870 //fprintf(fp, "%s", g_quark_to_string(es->s));
872 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
873 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
874 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
875 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
877 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
878 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
879 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
880 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
881 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
885 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
886 address
= g_array_index(process
->user_stack
, guint64
, i
);
887 fputc(HDR_USER_STACK
, fp
);
888 fwrite(&address
, sizeof(address
), 1, fp
);
890 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
895 if(process
->usertrace
) {
896 fputc(HDR_USERTRACE
, fp
);
897 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
899 fwrite(&process
->usertrace
->tracefile_name
,
900 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
901 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
903 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
904 g_quark_to_string(process
->usertrace
->tracefile_name
),
905 process
->usertrace
->cpu
);
912 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
914 guint i
, nb_tracefile
, nb_block
, offset
;
917 LttvTracefileState
*tfcs
;
921 LttEventPosition
*ep
;
925 ep
= ltt_event_position_new();
927 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
928 fputc(HDR_PROCESS_STATE
, fp
);
929 fwrite(&t
, sizeof(t
), 1, fp
);
931 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
933 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
934 for(i
=0;i
<nb_cpus
;i
++) {
936 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
937 fwrite(&self
->running_process
[i
]->pid
,
938 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
939 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
940 // i, self->running_process[i]->pid);
943 nb_tracefile
= self
->parent
.tracefiles
->len
;
945 for(i
= 0 ; i
< nb_tracefile
; i
++) {
947 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
948 LttvTracefileContext
*, i
));
949 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
950 // tfcs->parent.timestamp.tv_sec,
951 // tfcs->parent.timestamp.tv_nsec);
952 fputc(HDR_TRACEFILE
, fp
);
953 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
954 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
955 * position following : end of trace */
956 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
958 ltt_event_position(e
, ep
);
959 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
960 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
962 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
963 fwrite(&offset
, sizeof(offset
), 1, fp
);
964 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
971 /* Read process state from a file */
973 /* Called because a HDR_PROCESS was found */
974 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
975 GPtrArray
*quarktable
)
977 LttvExecutionState
*es
;
978 LttvProcessState
*process
, *parent_process
;
979 LttvProcessState tmp
;
984 /* TODO : check return value */
985 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
986 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
987 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
988 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
989 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
990 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
991 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
992 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
993 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
994 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
997 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
999 /* We must link to the parent */
1000 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1002 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1003 if(process
== NULL
) {
1004 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1006 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1007 &tmp
.creation_time
);
1010 process
->insertion_time
= tmp
.insertion_time
;
1011 process
->creation_time
= tmp
.creation_time
;
1012 process
->type
= g_quark_from_string(
1013 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1014 process
->tgid
= tmp
.tgid
;
1015 process
->ppid
= tmp
.ppid
;
1016 process
->brand
= g_quark_from_string(
1017 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1019 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1020 process
->free_events
= tmp
.free_events
;
1023 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1025 gint hdr
= fgetc(fp
);
1026 if(hdr
== EOF
) goto end_loop
;
1030 process
->execution_stack
=
1031 g_array_set_size(process
->execution_stack
,
1032 process
->execution_stack
->len
+ 1);
1033 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1034 process
->execution_stack
->len
-1);
1035 process
->state
= es
;
1037 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1038 es
->t
= g_quark_from_string(
1039 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1040 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1041 es
->n
= g_quark_from_string(
1042 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1043 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1044 es
->s
= g_quark_from_string(
1045 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1046 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1047 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1048 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1050 case HDR_USER_STACK
:
1051 process
->user_stack
= g_array_set_size(process
->user_stack
,
1052 process
->user_stack
->len
+ 1);
1053 address
= &g_array_index(process
->user_stack
, guint64
,
1054 process
->user_stack
->len
-1);
1055 fread(address
, sizeof(address
), 1, fp
);
1056 process
->current_function
= *address
;
1059 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1060 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1072 /* Called because a HDR_PROCESS_STATE was found */
1073 /* Append a saved state to the trace states */
1074 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1076 guint i
, nb_tracefile
, nb_block
, offset
;
1078 LttvTracefileState
*tfcs
;
1080 LttEventPosition
*ep
;
1088 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1090 LttvAttributeValue value
;
1091 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1092 ep
= ltt_event_position_new();
1094 restore_init_state(self
);
1096 fread(&t
, sizeof(t
), 1, fp
);
1099 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1101 if(hdr
== EOF
) goto end_loop
;
1105 /* Call read_process_state_raw */
1106 read_process_state_raw(self
, fp
, quarktable
);
1114 case HDR_USER_STACK
:
1116 case HDR_PROCESS_STATE
:
1122 g_error("Error while parsing saved state file : unknown data header %d",
1128 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1129 for(i
=0;i
<nb_cpus
;i
++) {
1132 g_assert(hdr
== HDR_CPU
);
1133 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1134 g_assert(i
== cpu_num
);
1135 fread(&self
->running_process
[i
]->pid
,
1136 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1139 nb_tracefile
= self
->parent
.tracefiles
->len
;
1141 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1143 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1144 LttvTracefileContext
*, i
));
1145 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1146 // tfcs->parent.timestamp.tv_sec,
1147 // tfcs->parent.timestamp.tv_nsec);
1148 g_tree_remove(pqueue
, &tfcs
->parent
);
1150 g_assert(hdr
== HDR_TRACEFILE
);
1151 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1152 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1153 * position following : end of trace */
1154 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1155 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1156 fread(&offset
, sizeof(offset
), 1, fp
);
1157 fread(&tsc
, sizeof(tsc
), 1, fp
);
1158 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1159 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1161 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1166 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1167 LTTV_STATE_SAVED_STATES
);
1168 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1169 value
= lttv_attribute_add(saved_states_tree
,
1170 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1171 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1172 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1173 *(value
.v_time
) = t
;
1174 lttv_state_save(self
, saved_state_tree
);
1175 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1178 *(self
->max_time_state_recomputed_in_seek
) = t
;
1182 /* Called when a HDR_TRACE is found */
1183 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1184 GPtrArray
*quarktable
)
1189 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1191 if(hdr
== EOF
) goto end_loop
;
1194 case HDR_PROCESS_STATE
:
1195 /* Call read_process_state_raw */
1196 lttv_state_read_raw(tcs
, fp
, quarktable
);
1204 case HDR_USER_STACK
:
1208 g_error("Error while parsing saved state file :"
1209 " unexpected data header %d",
1213 g_error("Error while parsing saved state file : unknown data header %d",
1218 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1219 restore_init_state(tcs
);
1220 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1226 /* Copy each process from an existing hash table to a new one */
1228 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1230 LttvProcessState
*process
, *new_process
;
1232 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1236 process
= (LttvProcessState
*)value
;
1237 new_process
= g_new(LttvProcessState
, 1);
1238 *new_process
= *process
;
1239 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1240 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1241 new_process
->execution_stack
=
1242 g_array_set_size(new_process
->execution_stack
,
1243 process
->execution_stack
->len
);
1244 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1245 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1246 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1248 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1249 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1250 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1251 sizeof(guint64
), 0);
1252 new_process
->user_stack
=
1253 g_array_set_size(new_process
->user_stack
,
1254 process
->user_stack
->len
);
1255 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1256 g_array_index(new_process
->user_stack
, guint64
, i
) =
1257 g_array_index(process
->user_stack
, guint64
, i
);
1259 new_process
->current_function
= process
->current_function
;
1260 g_hash_table_insert(new_processes
, new_process
, new_process
);
1264 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1266 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1268 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1269 return new_processes
;
1272 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1275 LttvCPUState
*retval
;
1277 retval
= g_new(LttvCPUState
, n
);
1279 for(i
=0; i
<n
; i
++) {
1280 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1281 retval
[i
].last_irq
= states
[i
].last_irq
;
1282 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1283 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1284 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1291 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1295 for(i
=0; i
<n
; i
++) {
1296 g_array_free(states
[i
].mode_stack
, TRUE
);
1302 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1305 LttvIRQState
*retval
;
1307 retval
= g_new(LttvIRQState
, n
);
1309 for(i
=0; i
<n
; i
++) {
1310 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1311 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1312 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1313 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1320 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1324 for(i
=0; i
<n
; i
++) {
1325 g_array_free(states
[i
].mode_stack
, TRUE
);
1331 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1334 LttvSoftIRQState
*retval
;
1336 retval
= g_new(LttvSoftIRQState
, n
);
1338 for(i
=0; i
<n
; i
++) {
1339 retval
[i
].pending
= states
[i
].pending
;
1340 retval
[i
].running
= states
[i
].running
;
1346 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1351 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1354 LttvTrapState
*retval
;
1356 retval
= g_new(LttvTrapState
, n
);
1358 for(i
=0; i
<n
; i
++) {
1359 retval
[i
].running
= states
[i
].running
;
1365 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1370 /* bdevstate stuff */
1372 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1374 gint devcode_gint
= devcode
;
1375 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1377 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1378 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1380 gint
* key
= g_new(gint
, 1);
1382 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1390 static LttvBdevState
*bdevstate_new(void)
1392 LttvBdevState
*retval
;
1393 retval
= g_new(LttvBdevState
, 1);
1394 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1399 static void bdevstate_free(LttvBdevState
*bds
)
1401 g_array_free(bds
->mode_stack
, TRUE
);
1405 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1407 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1409 bdevstate_free(bds
);
1412 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1414 LttvBdevState
*retval
;
1416 retval
= bdevstate_new();
1417 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1422 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1424 //GHashTable *ht = (GHashTable *)u;
1425 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1426 LttvBdevState
*newbds
;
1428 newbds
= bdevstate_copy(bds
);
1430 g_hash_table_insert(u
, k
, newbds
);
1433 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1437 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1439 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1444 /* Free a hashtable and the LttvBdevState structures its values
1447 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1449 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1450 g_hash_table_destroy(ht
);
1453 /* The saved state for each trace contains a member "processes", which
1454 stores a copy of the process table, and a member "tracefiles" with
1455 one entry per tracefile. Each tracefile has a "process" member pointing
1456 to the current process and a "position" member storing the tracefile
1457 position (needed to seek to the current "next" event. */
1459 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1461 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1463 LttvTracefileState
*tfcs
;
1465 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1467 guint
*running_process
;
1469 LttvAttributeValue value
;
1471 LttEventPosition
*ep
;
1473 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1474 LTTV_STATE_TRACEFILES
);
1476 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1478 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1480 /* Add the currently running processes array */
1481 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1482 running_process
= g_new(guint
, nb_cpus
);
1483 for(i
=0;i
<nb_cpus
;i
++) {
1484 running_process
[i
] = self
->running_process
[i
]->pid
;
1486 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1488 *(value
.v_pointer
) = running_process
;
1490 g_info("State save");
1492 nb_tracefile
= self
->parent
.tracefiles
->len
;
1494 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1496 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1497 LttvTracefileContext
*, i
));
1498 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1499 value
= lttv_attribute_add(tracefiles_tree
, i
,
1501 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1503 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1505 *(value
.v_uint
) = tfcs
->process
->pid
;
1507 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1509 /* Only save the position if the tfs has not infinite time. */
1510 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1511 // && current_tfcs != tfcs) {
1512 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1513 *(value
.v_pointer
) = NULL
;
1515 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1516 ep
= ltt_event_position_new();
1517 ltt_event_position(e
, ep
);
1518 *(value
.v_pointer
) = ep
;
1520 guint nb_block
, offset
;
1523 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1524 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1526 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1530 /* save the cpu state */
1532 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1534 *(value
.v_uint
) = nb_cpus
;
1536 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1538 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1541 /* save the irq state */
1542 nb_irqs
= self
->nb_irqs
;
1544 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1546 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1549 /* save the soft irq state */
1550 nb_soft_irqs
= self
->nb_soft_irqs
;
1552 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1554 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1557 /* save the trap state */
1558 nb_traps
= self
->nb_traps
;
1560 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1562 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1565 /* save the blkdev states */
1566 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1568 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1572 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1574 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1576 LttvTracefileState
*tfcs
;
1578 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1580 guint
*running_process
;
1582 LttvAttributeType type
;
1584 LttvAttributeValue value
;
1586 LttvAttributeName name
;
1590 LttEventPosition
*ep
;
1592 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1594 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1595 LTTV_STATE_TRACEFILES
);
1597 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1599 g_assert(type
== LTTV_POINTER
);
1600 lttv_state_free_process_table(self
->processes
);
1601 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1603 /* Add the currently running processes array */
1604 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1605 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1607 g_assert(type
== LTTV_POINTER
);
1608 running_process
= *(value
.v_pointer
);
1609 for(i
=0;i
<nb_cpus
;i
++) {
1610 pid
= running_process
[i
];
1611 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1612 g_assert(self
->running_process
[i
] != NULL
);
1615 nb_tracefile
= self
->parent
.tracefiles
->len
;
1617 //g_tree_destroy(tsc->pqueue);
1618 //tsc->pqueue = g_tree_new(compare_tracefile);
1620 /* restore cpu resource states */
1621 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1622 g_assert(type
== LTTV_POINTER
);
1623 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1624 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1626 /* restore irq resource states */
1627 nb_irqs
= self
->nb_irqs
;
1628 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1629 g_assert(type
== LTTV_POINTER
);
1630 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1631 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1633 /* restore soft irq resource states */
1634 nb_soft_irqs
= self
->nb_soft_irqs
;
1635 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1636 g_assert(type
== LTTV_POINTER
);
1637 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1638 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1640 /* restore trap resource states */
1641 nb_traps
= self
->nb_traps
;
1642 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1643 g_assert(type
== LTTV_POINTER
);
1644 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1645 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1647 /* restore the blkdev states */
1648 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1649 g_assert(type
== LTTV_POINTER
);
1650 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1651 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1653 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1655 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1656 LttvTracefileContext
*, i
));
1657 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1658 g_assert(type
== LTTV_GOBJECT
);
1659 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1661 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1663 g_assert(type
== LTTV_UINT
);
1664 pid
= *(value
.v_uint
);
1665 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1667 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1669 g_assert(type
== LTTV_POINTER
);
1670 //g_assert(*(value.v_pointer) != NULL);
1671 ep
= *(value
.v_pointer
);
1672 g_assert(tfcs
->parent
.t_context
!= NULL
);
1674 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1676 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1677 g_tree_remove(tsc
->pqueue
, tfc
);
1680 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1681 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1682 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1683 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1684 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1686 tfc
->timestamp
= ltt_time_infinite
;
1692 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1694 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1696 LttvTracefileState
*tfcs
;
1698 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1700 guint
*running_process
;
1702 LttvAttributeType type
;
1704 LttvAttributeValue value
;
1706 LttvAttributeName name
;
1710 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1711 LTTV_STATE_TRACEFILES
);
1712 g_object_ref(G_OBJECT(tracefiles_tree
));
1713 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1715 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1717 g_assert(type
== LTTV_POINTER
);
1718 lttv_state_free_process_table(*(value
.v_pointer
));
1719 *(value
.v_pointer
) = NULL
;
1720 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1722 /* Free running processes array */
1723 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1725 g_assert(type
== LTTV_POINTER
);
1726 running_process
= *(value
.v_pointer
);
1727 g_free(running_process
);
1729 /* free cpu resource states */
1730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1731 g_assert(type
== LTTV_UINT
);
1732 nb_cpus
= *value
.v_uint
;
1733 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1734 g_assert(type
== LTTV_POINTER
);
1735 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1737 /* free irq resource states */
1738 nb_irqs
= self
->nb_irqs
;
1739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1740 g_assert(type
== LTTV_POINTER
);
1741 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1743 /* free softirq resource states */
1744 nb_softirqs
= self
->nb_irqs
;
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1746 g_assert(type
== LTTV_POINTER
);
1747 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1749 /* free the blkdev states */
1750 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1751 g_assert(type
== LTTV_POINTER
);
1752 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1754 nb_tracefile
= self
->parent
.tracefiles
->len
;
1756 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1758 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1759 LttvTracefileContext
*, i
));
1760 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1761 g_assert(type
== LTTV_GOBJECT
);
1762 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1764 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1766 g_assert(type
== LTTV_POINTER
);
1767 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1769 g_object_unref(G_OBJECT(tracefiles_tree
));
1773 static void free_saved_state(LttvTraceState
*self
)
1777 LttvAttributeType type
;
1779 LttvAttributeValue value
;
1781 LttvAttributeName name
;
1785 LttvAttribute
*saved_states
;
1787 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1788 LTTV_STATE_SAVED_STATES
);
1790 nb
= lttv_attribute_get_number(saved_states
);
1791 for(i
= 0 ; i
< nb
; i
++) {
1792 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1793 g_assert(type
== LTTV_GOBJECT
);
1794 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1797 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1802 create_max_time(LttvTraceState
*tcs
)
1804 LttvAttributeValue v
;
1806 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1808 g_assert(*(v
.v_pointer
) == NULL
);
1809 *(v
.v_pointer
) = g_new(LttTime
,1);
1810 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1815 get_max_time(LttvTraceState
*tcs
)
1817 LttvAttributeValue v
;
1819 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1821 g_assert(*(v
.v_pointer
) != NULL
);
1822 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1827 free_max_time(LttvTraceState
*tcs
)
1829 LttvAttributeValue v
;
1831 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1833 g_free(*(v
.v_pointer
));
1834 *(v
.v_pointer
) = NULL
;
1838 typedef struct _LttvNameTables
{
1839 // FIXME GQuark *eventtype_names;
1840 GQuark
*syscall_names
;
1846 GQuark
*soft_irq_names
;
1852 create_name_tables(LttvTraceState
*tcs
)
1856 GString
*fe_name
= g_string_new("");
1858 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1860 LttvAttributeValue v
;
1864 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1866 g_assert(*(v
.v_pointer
) == NULL
);
1867 *(v
.v_pointer
) = name_tables
;
1869 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1871 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1872 LTT_FACILITY_KERNEL_ARCH
,
1873 LTT_EVENT_SYSCALL_ENTRY
,
1874 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1875 NULL
, NULL
, &hooks
)) {
1877 // th = lttv_trace_hook_get_first(&th);
1879 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1880 // nb = ltt_type_element_number(t);
1882 // name_tables->syscall_names = g_new(GQuark, nb);
1883 // name_tables->nb_syscalls = nb;
1885 // for(i = 0 ; i < nb ; i++) {
1886 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1887 // if(!name_tables->syscall_names[i]) {
1888 // GString *string = g_string_new("");
1889 // g_string_printf(string, "syscall %u", i);
1890 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1891 // g_string_free(string, TRUE);
1895 name_tables
->nb_syscalls
= 256;
1896 name_tables
->syscall_names
= g_new(GQuark
, 256);
1897 for(i
= 0 ; i
< 256 ; i
++) {
1898 g_string_printf(fe_name
, "syscall %d", i
);
1899 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1902 name_tables
->syscall_names
= NULL
;
1903 name_tables
->nb_syscalls
= 0;
1905 lttv_trace_hook_remove_all(&hooks
);
1907 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1908 LTT_FACILITY_KERNEL_ARCH
,
1909 LTT_EVENT_TRAP_ENTRY
,
1910 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1911 NULL
, NULL
, &hooks
)) {
1913 // th = lttv_trace_hook_get_first(&th);
1915 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1916 // //nb = ltt_type_element_number(t);
1918 // name_tables->trap_names = g_new(GQuark, nb);
1919 // for(i = 0 ; i < nb ; i++) {
1920 // name_tables->trap_names[i] = g_quark_from_string(
1921 // ltt_enum_string_get(t, i));
1924 name_tables
->nb_traps
= 256;
1925 name_tables
->trap_names
= g_new(GQuark
, 256);
1926 for(i
= 0 ; i
< 256 ; i
++) {
1927 g_string_printf(fe_name
, "trap %d", i
);
1928 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1931 name_tables
->trap_names
= NULL
;
1932 name_tables
->nb_traps
= 0;
1934 lttv_trace_hook_remove_all(&hooks
);
1936 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1937 LTT_FACILITY_KERNEL
,
1938 LTT_EVENT_IRQ_ENTRY
,
1939 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1940 NULL
, NULL
, &hooks
)) {
1943 name_tables->irq_names = g_new(GQuark, nb);
1944 for(i = 0 ; i < nb ; i++) {
1945 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1949 name_tables
->nb_irqs
= 256;
1950 name_tables
->irq_names
= g_new(GQuark
, 256);
1951 for(i
= 0 ; i
< 256 ; i
++) {
1952 g_string_printf(fe_name
, "irq %d", i
);
1953 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1956 name_tables
->nb_irqs
= 0;
1957 name_tables
->irq_names
= NULL
;
1959 lttv_trace_hook_remove_all(&hooks
);
1961 name_tables->soft_irq_names = g_new(GQuark, nb);
1962 for(i = 0 ; i < nb ; i++) {
1963 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1967 /* the kernel is limited to 32 statically defined softirqs */
1968 name_tables
->nb_softirqs
= 32;
1969 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1970 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1971 g_string_printf(fe_name
, "softirq %d", i
);
1972 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1974 g_array_free(hooks
, TRUE
);
1976 g_string_free(fe_name
, TRUE
);
1981 get_name_tables(LttvTraceState
*tcs
)
1983 LttvNameTables
*name_tables
;
1985 LttvAttributeValue v
;
1987 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1989 g_assert(*(v
.v_pointer
) != NULL
);
1990 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1991 //tcs->eventtype_names = name_tables->eventtype_names;
1992 tcs
->syscall_names
= name_tables
->syscall_names
;
1993 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1994 tcs
->trap_names
= name_tables
->trap_names
;
1995 tcs
->nb_traps
= name_tables
->nb_traps
;
1996 tcs
->irq_names
= name_tables
->irq_names
;
1997 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1998 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1999 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2004 free_name_tables(LttvTraceState
*tcs
)
2006 LttvNameTables
*name_tables
;
2008 LttvAttributeValue v
;
2010 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2012 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2013 *(v
.v_pointer
) = NULL
;
2015 // g_free(name_tables->eventtype_names);
2016 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2017 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2018 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2019 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2020 if(name_tables
) g_free(name_tables
);
2023 #ifdef HASH_TABLE_DEBUG
2025 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2027 LttvProcessState
*process
= (LttvProcessState
*)value
;
2029 /* Test for process corruption */
2030 guint stack_len
= process
->execution_stack
->len
;
2033 static void hash_table_check(GHashTable
*table
)
2035 g_hash_table_foreach(table
, test_process
, NULL
);
2041 /* clears the stack and sets the state passed as argument */
2042 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2044 g_array_set_size(cpust
->mode_stack
, 1);
2045 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2048 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2050 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2051 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2054 static void cpu_pop_mode(LttvCPUState
*cpust
)
2056 if(cpust
->mode_stack
->len
<= 1)
2057 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2059 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2062 /* clears the stack and sets the state passed as argument */
2063 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2065 g_array_set_size(bdevst
->mode_stack
, 1);
2066 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2069 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2071 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2072 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2075 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2077 if(bdevst
->mode_stack
->len
<= 1)
2078 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2080 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2083 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2085 g_array_set_size(irqst
->mode_stack
, 1);
2086 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2089 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2091 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2092 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2095 static void irq_pop_mode(LttvIRQState
*irqst
)
2097 if(irqst
->mode_stack
->len
<= 1)
2098 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2100 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2103 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2106 LttvExecutionState
*es
;
2108 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2109 guint cpu
= tfs
->cpu
;
2111 #ifdef HASH_TABLE_DEBUG
2112 hash_table_check(ts
->processes
);
2114 LttvProcessState
*process
= ts
->running_process
[cpu
];
2116 guint depth
= process
->execution_stack
->len
;
2118 process
->execution_stack
=
2119 g_array_set_size(process
->execution_stack
, depth
+ 1);
2122 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2124 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2127 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2128 es
->cum_cpu_time
= ltt_time_zero
;
2129 es
->s
= process
->state
->s
;
2130 process
->state
= es
;
2134 * return 1 when empty, else 0 */
2135 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2136 LttvTracefileState
*tfs
)
2138 guint depth
= process
->execution_stack
->len
;
2144 process
->execution_stack
=
2145 g_array_set_size(process
->execution_stack
, depth
- 1);
2146 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2148 process
->state
->change
= tfs
->parent
.timestamp
;
2153 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2155 guint cpu
= tfs
->cpu
;
2156 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2157 LttvProcessState
*process
= ts
->running_process
[cpu
];
2159 guint depth
= process
->execution_stack
->len
;
2161 if(process
->state
->t
!= t
){
2162 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2163 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2164 g_info("process state has %s when pop_int is %s\n",
2165 g_quark_to_string(process
->state
->t
),
2166 g_quark_to_string(t
));
2167 g_info("{ %u, %u, %s, %s, %s }\n",
2170 g_quark_to_string(process
->name
),
2171 g_quark_to_string(process
->brand
),
2172 g_quark_to_string(process
->state
->s
));
2177 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2178 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2182 process
->execution_stack
=
2183 g_array_set_size(process
->execution_stack
, depth
- 1);
2184 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2186 process
->state
->change
= tfs
->parent
.timestamp
;
2189 struct search_result
{
2190 const LttTime
*time
; /* Requested time */
2191 LttTime
*best
; /* Best result */
2194 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2196 const LttTime
*elem_time
= (const LttTime
*)a
;
2197 /* Explicit non const cast */
2198 struct search_result
*res
= (struct search_result
*)b
;
2200 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2201 /* The usertrace was created before the schedchange */
2202 /* Get larger keys */
2204 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2205 /* The usertrace was created after the schedchange time */
2206 /* Get smaller keys */
2208 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2209 res
->best
= (LttTime
*)elem_time
;
2212 res
->best
= (LttTime
*)elem_time
;
2219 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2220 guint pid
, const LttTime
*timestamp
)
2222 LttvTracefileState
*tfs
= NULL
;
2223 struct search_result res
;
2224 /* Find the usertrace associated with a pid and time interval.
2225 * Search in the usertraces by PID (within a hash) and then, for each
2226 * corresponding element of the array, find the first one with creation
2227 * timestamp the lowest, but higher or equal to "timestamp". */
2228 res
.time
= timestamp
;
2230 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2231 if(usertrace_tree
) {
2232 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2234 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2242 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2243 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2245 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2247 LttvExecutionState
*es
;
2252 process
->tgid
= tgid
;
2254 process
->name
= name
;
2255 process
->brand
= LTTV_STATE_UNBRANDED
;
2256 //process->last_cpu = tfs->cpu_name;
2257 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2258 process
->type
= LTTV_STATE_USER_THREAD
;
2259 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2260 process
->current_function
= 0; //function 0x0 by default.
2262 g_info("Process %u, core %p", process
->pid
, process
);
2263 g_hash_table_insert(tcs
->processes
, process
, process
);
2266 process
->ppid
= parent
->pid
;
2267 process
->creation_time
= *timestamp
;
2270 /* No parent. This process exists but we are missing all information about
2271 its creation. The birth time is set to zero but we remember the time of
2276 process
->creation_time
= ltt_time_zero
;
2279 process
->insertion_time
= *timestamp
;
2280 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2281 process
->creation_time
.tv_nsec
);
2282 process
->pid_time
= g_quark_from_string(buffer
);
2284 process
->free_events
= 0;
2285 //process->last_cpu = tfs->cpu_name;
2286 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2287 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2288 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2289 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2290 es
= process
->state
= &g_array_index(process
->execution_stack
,
2291 LttvExecutionState
, 0);
2292 es
->t
= LTTV_STATE_USER_MODE
;
2293 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2294 es
->entry
= *timestamp
;
2295 //g_assert(timestamp->tv_sec != 0);
2296 es
->change
= *timestamp
;
2297 es
->cum_cpu_time
= ltt_time_zero
;
2298 es
->s
= LTTV_STATE_RUN
;
2300 es
= process
->state
= &g_array_index(process
->execution_stack
,
2301 LttvExecutionState
, 1);
2302 es
->t
= LTTV_STATE_SYSCALL
;
2303 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2304 es
->entry
= *timestamp
;
2305 //g_assert(timestamp->tv_sec != 0);
2306 es
->change
= *timestamp
;
2307 es
->cum_cpu_time
= ltt_time_zero
;
2308 es
->s
= LTTV_STATE_WAIT_FORK
;
2310 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2311 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2312 sizeof(guint64
), 0);
2317 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2320 LttvProcessState key
;
2321 LttvProcessState
*process
;
2325 process
= g_hash_table_lookup(ts
->processes
, &key
);
2330 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2331 const LttTime
*timestamp
)
2333 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2334 LttvExecutionState
*es
;
2336 /* Put ltt_time_zero creation time for unexisting processes */
2337 if(unlikely(process
== NULL
)) {
2338 process
= lttv_state_create_process(ts
,
2339 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2340 /* We are not sure is it's a kernel thread or normal thread, put the
2341 * bottom stack state to unknown */
2342 process
->execution_stack
=
2343 g_array_set_size(process
->execution_stack
, 1);
2344 process
->state
= es
=
2345 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2346 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2347 es
->s
= LTTV_STATE_UNNAMED
;
2352 /* FIXME : this function should be called when we receive an event telling that
2353 * release_task has been called in the kernel. In happens generally when
2354 * the parent waits for its child terminaison, but may also happen in special
2355 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2356 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2357 * of a killed thread group, but isn't the leader.
2359 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2361 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2362 LttvProcessState key
;
2366 /* Wait for both schedule with exit dead and process free to happen.
2367 * They can happen in any order. */
2368 if (++(process
->free_events
) < 2)
2371 key
.pid
= process
->pid
;
2372 key
.cpu
= process
->cpu
;
2373 g_hash_table_remove(ts
->processes
, &key
);
2374 g_array_free(process
->execution_stack
, TRUE
);
2375 g_array_free(process
->user_stack
, TRUE
);
2381 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2383 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2384 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2389 static void lttv_state_free_process_table(GHashTable
*processes
)
2391 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2392 g_hash_table_destroy(processes
);
2396 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2398 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2400 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2401 LttvProcessState
*process
= ts
->running_process
[cpu
];
2402 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2403 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2404 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2405 LttvExecutionSubmode submode
;
2409 guint syscall
= ltt_event_get_unsigned(e
, f
);
2410 expand_syscall_table(ts
, syscall
);
2411 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2412 /* There can be no system call from PID 0 : unknown state */
2413 if(process
->pid
!= 0)
2414 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2419 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2421 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2423 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2424 LttvProcessState
*process
= ts
->running_process
[cpu
];
2426 /* There can be no system call from PID 0 : unknown state */
2427 if(process
->pid
!= 0)
2428 pop_state(s
, LTTV_STATE_SYSCALL
);
2433 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2435 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2436 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2437 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2438 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2439 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2441 LttvExecutionSubmode submode
;
2444 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2446 expand_trap_table(ts
, trap
);
2448 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2450 push_state(s
, LTTV_STATE_TRAP
, submode
);
2452 /* update cpu status */
2453 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2455 /* update trap status */
2456 s
->cpu_state
->last_trap
= trap
;
2457 ts
->trap_states
[trap
].running
++;
2462 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2464 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2465 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2466 guint trap
= s
->cpu_state
->last_trap
;
2468 pop_state(s
, LTTV_STATE_TRAP
);
2470 /* update cpu status */
2471 cpu_pop_mode(s
->cpu_state
);
2473 /* update trap status */
2474 if(ts
->trap_states
[trap
].running
)
2475 ts
->trap_states
[trap
].running
--;
2480 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2482 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2483 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2484 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2485 //guint8 ev_id = ltt_event_eventtype_id(e);
2486 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2487 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2490 LttvExecutionSubmode submode
;
2491 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2493 expand_irq_table(ts
, irq
);
2495 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2497 /* Do something with the info about being in user or system mode when int? */
2498 push_state(s
, LTTV_STATE_IRQ
, submode
);
2500 /* update cpu status */
2501 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2503 /* update irq status */
2504 s
->cpu_state
->last_irq
= irq
;
2505 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2510 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2512 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2513 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2514 guint softirq
= s
->cpu_state
->last_soft_irq
;
2516 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2518 /* update softirq status */
2519 if(ts
->soft_irq_states
[softirq
].running
)
2520 ts
->soft_irq_states
[softirq
].running
--;
2522 /* update cpu status */
2523 cpu_pop_mode(s
->cpu_state
);
2528 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2530 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2531 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2533 pop_state(s
, LTTV_STATE_IRQ
);
2535 /* update cpu status */
2536 cpu_pop_mode(s
->cpu_state
);
2538 /* update irq status */
2539 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2544 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2546 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2547 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2548 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2549 //guint8 ev_id = ltt_event_eventtype_id(e);
2550 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2551 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2553 LttvExecutionSubmode submode
;
2554 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2555 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2557 if(softirq
< nb_softirqs
) {
2558 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2560 /* Fixup an incomplete irq table */
2561 GString
*string
= g_string_new("");
2562 g_string_printf(string
, "softirq %llu", softirq
);
2563 submode
= g_quark_from_string(string
->str
);
2564 g_string_free(string
, TRUE
);
2567 /* update softirq status */
2568 /* a soft irq raises are not cumulative */
2569 ts
->soft_irq_states
[softirq
].pending
=1;
2574 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2576 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2577 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2578 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2579 //guint8 ev_id = ltt_event_eventtype_id(e);
2580 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2581 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2582 LttvExecutionSubmode submode
;
2583 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2584 expand_soft_irq_table(ts
, softirq
);
2585 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2588 /* Do something with the info about being in user or system mode when int? */
2589 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2591 /* update cpu status */
2592 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2594 /* update softirq status */
2595 s
->cpu_state
->last_soft_irq
= softirq
;
2596 if(ts
->soft_irq_states
[softirq
].pending
)
2597 ts
->soft_irq_states
[softirq
].pending
--;
2598 ts
->soft_irq_states
[softirq
].running
++;
2603 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2605 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2606 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2607 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2608 //guint8 ev_id = ltt_event_eventtype_id(e);
2609 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2611 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2612 lttv_trace_get_hook_field(th
, 0)));
2613 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2615 expand_irq_table(ts
, irq
);
2616 ts
->irq_names
[irq
] = action
;
2622 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2624 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2625 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2626 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2627 //guint8 ev_id = ltt_event_eventtype_id(e);
2628 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2630 guint major
= ltt_event_get_long_unsigned(e
,
2631 lttv_trace_get_hook_field(th
, 0));
2632 guint minor
= ltt_event_get_long_unsigned(e
,
2633 lttv_trace_get_hook_field(th
, 1));
2634 guint oper
= ltt_event_get_long_unsigned(e
,
2635 lttv_trace_get_hook_field(th
, 2));
2636 guint16 devcode
= MKDEV(major
,minor
);
2639 /* have we seen this block device before? */
2640 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2643 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2645 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2650 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2652 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2653 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2654 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2655 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2657 guint major
= ltt_event_get_long_unsigned(e
,
2658 lttv_trace_get_hook_field(th
, 0));
2659 guint minor
= ltt_event_get_long_unsigned(e
,
2660 lttv_trace_get_hook_field(th
, 1));
2661 //guint oper = ltt_event_get_long_unsigned(e,
2662 // lttv_trace_get_hook_field(th, 2));
2663 guint16 devcode
= MKDEV(major
,minor
);
2665 /* have we seen this block device before? */
2666 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2668 /* update block device */
2669 bdev_pop_mode(bdev
);
2674 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2678 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2679 guint cpu
= tfs
->cpu
;
2680 LttvProcessState
*process
= ts
->running_process
[cpu
];
2682 guint depth
= process
->user_stack
->len
;
2684 process
->user_stack
=
2685 g_array_set_size(process
->user_stack
, depth
+ 1);
2687 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2688 *new_func
= funcptr
;
2689 process
->current_function
= funcptr
;
2692 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2694 guint cpu
= tfs
->cpu
;
2695 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2696 LttvProcessState
*process
= ts
->running_process
[cpu
];
2698 if(process
->current_function
!= funcptr
){
2699 g_info("Different functions (%lu.%09lu): ignore it\n",
2700 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2701 g_info("process state has %llu when pop_function is %llu\n",
2702 process
->current_function
, funcptr
);
2703 g_info("{ %u, %u, %s, %s, %s }\n",
2706 g_quark_to_string(process
->name
),
2707 g_quark_to_string(process
->brand
),
2708 g_quark_to_string(process
->state
->s
));
2711 guint depth
= process
->user_stack
->len
;
2714 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2715 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2719 process
->user_stack
=
2720 g_array_set_size(process
->user_stack
, depth
- 1);
2721 process
->current_function
=
2722 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2726 static gboolean
function_entry(void *hook_data
, void *call_data
)
2728 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2729 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2730 //guint8 ev_id = ltt_event_eventtype_id(e);
2731 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2732 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2733 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2735 push_function(s
, funcptr
);
2739 static gboolean
function_exit(void *hook_data
, void *call_data
)
2741 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2742 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2743 //guint8 ev_id = ltt_event_eventtype_id(e);
2744 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2745 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2746 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2748 pop_function(s
, funcptr
);
2752 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2754 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2755 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2756 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2757 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2762 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2763 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2764 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2766 expand_syscall_table(ts
, id
);
2767 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2772 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2774 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2775 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2776 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2777 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2782 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2783 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2784 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2786 expand_soft_irq_table(ts
, id
);
2787 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2792 static gboolean
schedchange(void *hook_data
, void *call_data
)
2794 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2796 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2797 LttvProcessState
*process
= ts
->running_process
[cpu
];
2798 //LttvProcessState *old_process = ts->running_process[cpu];
2800 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2801 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2802 guint pid_in
, pid_out
;
2805 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2806 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2807 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2810 if(likely(process
!= NULL
)) {
2812 /* We could not know but it was not the idle process executing.
2813 This should only happen at the beginning, before the first schedule
2814 event, and when the initial information (current process for each CPU)
2815 is missing. It is not obvious how we could, after the fact, compensate
2816 the wrongly attributed statistics. */
2818 //This test only makes sense once the state is known and if there is no
2819 //missing events. We need to silently ignore schedchange coming after a
2820 //process_free, or it causes glitches. (FIXME)
2821 //if(unlikely(process->pid != pid_out)) {
2822 // g_assert(process->pid == 0);
2824 if(process
->pid
== 0
2825 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2827 /* Scheduling out of pid 0 at beginning of the trace :
2828 * we know for sure it is in syscall mode at this point. */
2829 g_assert(process
->execution_stack
->len
== 1);
2830 process
->state
->t
= LTTV_STATE_SYSCALL
;
2831 process
->state
->s
= LTTV_STATE_WAIT
;
2832 process
->state
->change
= s
->parent
.timestamp
;
2833 process
->state
->entry
= s
->parent
.timestamp
;
2836 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2837 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2838 process
->state
->change
= s
->parent
.timestamp
;
2840 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2841 else process
->state
->s
= LTTV_STATE_WAIT
;
2842 process
->state
->change
= s
->parent
.timestamp
;
2845 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2846 /* see sched.h for states */
2847 if (!exit_process(s
, process
)) {
2848 process
->state
->s
= LTTV_STATE_DEAD
;
2849 process
->state
->change
= s
->parent
.timestamp
;
2854 process
= ts
->running_process
[cpu
] =
2855 lttv_state_find_process_or_create(
2856 (LttvTraceState
*)s
->parent
.t_context
,
2858 &s
->parent
.timestamp
);
2859 process
->state
->s
= LTTV_STATE_RUN
;
2861 if(process
->usertrace
)
2862 process
->usertrace
->cpu
= cpu
;
2863 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2864 process
->state
->change
= s
->parent
.timestamp
;
2866 /* update cpu status */
2868 /* going to idle task */
2869 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2871 /* scheduling a real task.
2872 * we must be careful here:
2873 * if we just schedule()'ed to a process that is
2874 * in a trap, we must put the cpu in trap mode
2876 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2877 if(process
->state
->t
== LTTV_STATE_TRAP
)
2878 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2884 static gboolean
process_fork(void *hook_data
, void *call_data
)
2886 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2887 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2888 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2890 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2891 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2892 //LttvProcessState *zombie_process;
2894 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2895 LttvProcessState
*process
= ts
->running_process
[cpu
];
2896 LttvProcessState
*child_process
;
2897 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
];
3076 #if 0//how to use a sequence that must be transformed in a string
3077 /* PID of the process to release */
3078 guint64 name_len
= ltt_event_field_element_number(e
,
3079 lttv_trace_get_hook_field(th
, 0));
3080 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3081 LttField
*child
= ltt_event_field_element_select(e
,
3082 lttv_trace_get_hook_field(th
, 0), 0);
3084 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3085 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3086 memcpy(null_term_name
, name_begin
, name_len
);
3087 null_term_name
[name_len
] = '\0';
3088 process
->name
= g_quark_from_string(null_term_name
);
3091 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3092 lttv_trace_get_hook_field(th
, 0)));
3093 process
->brand
= LTTV_STATE_UNBRANDED
;
3094 //g_free(null_term_name);
3098 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3100 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3101 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3102 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3103 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3106 LttvProcessState
*process
= ts
->running_process
[cpu
];
3108 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3109 process
->brand
= g_quark_from_string(name
);
3114 static void fix_process(gpointer key
, gpointer value
,
3117 LttvProcessState
*process
;
3118 LttvExecutionState
*es
;
3119 process
= (LttvProcessState
*)value
;
3120 LttTime
*timestamp
= (LttTime
*)user_data
;
3122 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3123 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3124 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3125 es
->t
= LTTV_STATE_SYSCALL
;
3126 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3127 es
->entry
= *timestamp
;
3128 es
->change
= *timestamp
;
3129 es
->cum_cpu_time
= ltt_time_zero
;
3130 if(es
->s
== LTTV_STATE_UNNAMED
)
3131 es
->s
= LTTV_STATE_WAIT
;
3134 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3135 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3136 es
->t
= LTTV_STATE_USER_MODE
;
3137 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3138 es
->entry
= *timestamp
;
3139 //g_assert(timestamp->tv_sec != 0);
3140 es
->change
= *timestamp
;
3141 es
->cum_cpu_time
= ltt_time_zero
;
3142 if(es
->s
== LTTV_STATE_UNNAMED
)
3143 es
->s
= LTTV_STATE_RUN
;
3145 if(process
->execution_stack
->len
== 1) {
3146 /* Still in bottom unknown mode, means never did a system call
3147 * May be either in user mode, syscall mode, running or waiting.*/
3148 /* FIXME : we may be tagging syscall mode when being user mode */
3149 process
->execution_stack
=
3150 g_array_set_size(process
->execution_stack
, 2);
3151 es
= process
->state
= &g_array_index(process
->execution_stack
,
3152 LttvExecutionState
, 1);
3153 es
->t
= LTTV_STATE_SYSCALL
;
3154 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3155 es
->entry
= *timestamp
;
3156 //g_assert(timestamp->tv_sec != 0);
3157 es
->change
= *timestamp
;
3158 es
->cum_cpu_time
= ltt_time_zero
;
3159 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3160 es
->s
= LTTV_STATE_WAIT
;
3166 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3168 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3169 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3170 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3171 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3172 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3174 /* For all processes */
3175 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3176 /* else, if stack[0] is unknown, set to user mode, running */
3178 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3183 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3185 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3186 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3187 //It's slow : optimise later by doing this before reading trace.
3188 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3194 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3195 LttvProcessState
*process
= ts
->running_process
[cpu
];
3196 LttvProcessState
*parent_process
;
3197 struct marker_field
*f
;
3198 GQuark type
, mode
, submode
, status
;
3199 LttvExecutionState
*es
;
3203 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3204 s
->parent
.target_pid
= pid
;
3207 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3210 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3213 f
= lttv_trace_get_hook_field(th
, 3);
3214 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3216 //FIXME: type is rarely used, enum must match possible types.
3219 f
= lttv_trace_get_hook_field(th
, 4);
3220 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3223 f
= lttv_trace_get_hook_field(th
, 5);
3224 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3227 f
= lttv_trace_get_hook_field(th
, 6);
3228 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3231 f
= lttv_trace_get_hook_field(th
, 7);
3233 tgid
= ltt_event_get_unsigned(e
, f
);
3238 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3239 for(i
=0; i
<nb_cpus
; i
++) {
3240 process
= lttv_state_find_process(ts
, i
, pid
);
3241 g_assert(process
!= NULL
);
3243 process
->ppid
= parent_pid
;
3244 process
->tgid
= tgid
;
3245 process
->name
= g_quark_from_string(command
);
3247 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3248 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3252 /* The process might exist if a process was forked while performing the
3254 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3255 if(process
== NULL
) {
3256 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3257 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3258 pid
, tgid
, g_quark_from_string(command
),
3259 &s
->parent
.timestamp
);
3261 /* Keep the stack bottom : a running user mode */
3262 /* Disabled because of inconsistencies in the current statedump states. */
3263 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3264 /* Only keep the bottom
3265 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3266 /* Will cause expected trap when in fact being syscall (even after end of
3268 * Will cause expected interrupt when being syscall. (only before end of
3269 * statedump event) */
3270 // This will cause a "popping last state on stack, ignoring it."
3271 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3272 es
= process
->state
= &g_array_index(process
->execution_stack
,
3273 LttvExecutionState
, 0);
3274 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3275 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3276 es
->s
= LTTV_STATE_UNNAMED
;
3277 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3279 es
->t
= LTTV_STATE_SYSCALL
;
3284 /* User space process :
3285 * bottom : user mode
3286 * either currently running or scheduled out.
3287 * can be scheduled out because interrupted in (user mode or in syscall)
3288 * or because of an explicit call to the scheduler in syscall. Note that
3289 * the scheduler call comes after the irq_exit, so never in interrupt
3291 // temp workaround : set size to 1 : only have user mode bottom of stack.
3292 // will cause g_info message of expected syscall mode when in fact being
3293 // in user mode. Can also cause expected trap when in fact being user
3294 // mode in the event of a page fault reenabling interrupts in the handler.
3295 // Expected syscall and trap can also happen after the end of statedump
3296 // This will cause a "popping last state on stack, ignoring it."
3297 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3298 es
= process
->state
= &g_array_index(process
->execution_stack
,
3299 LttvExecutionState
, 0);
3300 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3301 es
->s
= LTTV_STATE_UNNAMED
;
3302 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3304 es
->t
= LTTV_STATE_USER_MODE
;
3312 es
= process
->state
= &g_array_index(process
->execution_stack
,
3313 LttvExecutionState
, 1);
3314 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3315 es
->s
= LTTV_STATE_UNNAMED
;
3316 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3320 /* The process has already been created :
3321 * Probably was forked while dumping the process state or
3322 * was simply scheduled in prior to get the state dump event.
3324 process
->ppid
= parent_pid
;
3325 process
->tgid
= tgid
;
3326 process
->name
= g_quark_from_string(command
);
3327 process
->type
= type
;
3329 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3331 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3332 if(type
== LTTV_STATE_KERNEL_THREAD
)
3333 es
->t
= LTTV_STATE_SYSCALL
;
3335 es
->t
= LTTV_STATE_USER_MODE
;
3338 /* Don't mess around with the stack, it will eventually become
3339 * ok after the end of state dump. */
3346 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3348 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3350 lttv_state_add_event_hooks(tss
);
3355 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3357 LttvTraceset
*traceset
= self
->parent
.ts
;
3359 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3363 LttvTracefileState
*tfs
;
3369 LttvAttributeValue val
;
3371 nb_trace
= lttv_traceset_number(traceset
);
3372 for(i
= 0 ; i
< nb_trace
; i
++) {
3373 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3375 /* Find the eventtype id for the following events and register the
3376 associated by id hooks. */
3378 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3379 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3382 lttv_trace_find_hook(ts
->parent
.t
,
3383 LTT_FACILITY_KERNEL_ARCH
,
3384 LTT_EVENT_SYSCALL_ENTRY
,
3385 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3386 syscall_entry
, NULL
, &hooks
);
3388 lttv_trace_find_hook(ts
->parent
.t
,
3389 LTT_FACILITY_KERNEL_ARCH
,
3390 LTT_EVENT_SYSCALL_EXIT
,
3392 syscall_exit
, NULL
, &hooks
);
3394 lttv_trace_find_hook(ts
->parent
.t
,
3395 LTT_FACILITY_KERNEL_ARCH
,
3396 LTT_EVENT_TRAP_ENTRY
,
3397 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3398 trap_entry
, NULL
, &hooks
);
3400 lttv_trace_find_hook(ts
->parent
.t
,
3401 LTT_FACILITY_KERNEL_ARCH
,
3402 LTT_EVENT_TRAP_EXIT
,
3404 trap_exit
, NULL
, &hooks
);
3406 lttv_trace_find_hook(ts
->parent
.t
,
3407 LTT_FACILITY_KERNEL
,
3408 LTT_EVENT_IRQ_ENTRY
,
3409 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3410 irq_entry
, NULL
, &hooks
);
3412 lttv_trace_find_hook(ts
->parent
.t
,
3413 LTT_FACILITY_KERNEL
,
3416 irq_exit
, NULL
, &hooks
);
3418 lttv_trace_find_hook(ts
->parent
.t
,
3419 LTT_FACILITY_KERNEL
,
3420 LTT_EVENT_SOFT_IRQ_RAISE
,
3421 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3422 soft_irq_raise
, NULL
, &hooks
);
3424 lttv_trace_find_hook(ts
->parent
.t
,
3425 LTT_FACILITY_KERNEL
,
3426 LTT_EVENT_SOFT_IRQ_ENTRY
,
3427 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3428 soft_irq_entry
, NULL
, &hooks
);
3430 lttv_trace_find_hook(ts
->parent
.t
,
3431 LTT_FACILITY_KERNEL
,
3432 LTT_EVENT_SOFT_IRQ_EXIT
,
3434 soft_irq_exit
, NULL
, &hooks
);
3436 lttv_trace_find_hook(ts
->parent
.t
,
3437 LTT_FACILITY_KERNEL
,
3438 LTT_EVENT_SCHED_SCHEDULE
,
3439 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3440 LTT_FIELD_PREV_STATE
),
3441 schedchange
, NULL
, &hooks
);
3443 lttv_trace_find_hook(ts
->parent
.t
,
3444 LTT_FACILITY_KERNEL
,
3445 LTT_EVENT_PROCESS_FORK
,
3446 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3447 LTT_FIELD_CHILD_TGID
),
3448 process_fork
, NULL
, &hooks
);
3450 lttv_trace_find_hook(ts
->parent
.t
,
3451 LTT_FACILITY_KERNEL_ARCH
,
3452 LTT_EVENT_KTHREAD_CREATE
,
3453 FIELD_ARRAY(LTT_FIELD_PID
),
3454 process_kernel_thread
, NULL
, &hooks
);
3456 lttv_trace_find_hook(ts
->parent
.t
,
3457 LTT_FACILITY_KERNEL
,
3458 LTT_EVENT_PROCESS_EXIT
,
3459 FIELD_ARRAY(LTT_FIELD_PID
),
3460 process_exit
, NULL
, &hooks
);
3462 lttv_trace_find_hook(ts
->parent
.t
,
3463 LTT_FACILITY_KERNEL
,
3464 LTT_EVENT_PROCESS_FREE
,
3465 FIELD_ARRAY(LTT_FIELD_PID
),
3466 process_free
, NULL
, &hooks
);
3468 lttv_trace_find_hook(ts
->parent
.t
,
3471 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3472 process_exec
, NULL
, &hooks
);
3474 lttv_trace_find_hook(ts
->parent
.t
,
3475 LTT_FACILITY_USER_GENERIC
,
3476 LTT_EVENT_THREAD_BRAND
,
3477 FIELD_ARRAY(LTT_FIELD_NAME
),
3478 thread_brand
, NULL
, &hooks
);
3480 /* statedump-related hooks */
3481 lttv_trace_find_hook(ts
->parent
.t
,
3483 LTT_EVENT_PROCESS_STATE
,
3484 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3485 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3486 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3487 enum_process_state
, NULL
, &hooks
);
3489 lttv_trace_find_hook(ts
->parent
.t
,
3491 LTT_EVENT_STATEDUMP_END
,
3493 statedump_end
, NULL
, &hooks
);
3495 lttv_trace_find_hook(ts
->parent
.t
,
3497 LTT_EVENT_LIST_INTERRUPT
,
3498 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3499 enum_interrupt
, NULL
, &hooks
);
3501 lttv_trace_find_hook(ts
->parent
.t
,
3503 LTT_EVENT_REQUEST_ISSUE
,
3504 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3505 bdev_request_issue
, NULL
, &hooks
);
3507 lttv_trace_find_hook(ts
->parent
.t
,
3509 LTT_EVENT_REQUEST_COMPLETE
,
3510 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3511 bdev_request_complete
, NULL
, &hooks
);
3513 lttv_trace_find_hook(ts
->parent
.t
,
3514 LTT_FACILITY_USER_GENERIC
,
3515 LTT_EVENT_FUNCTION_ENTRY
,
3516 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3517 function_entry
, NULL
, &hooks
);
3519 lttv_trace_find_hook(ts
->parent
.t
,
3520 LTT_FACILITY_USER_GENERIC
,
3521 LTT_EVENT_FUNCTION_EXIT
,
3522 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3523 function_exit
, NULL
, &hooks
);
3525 lttv_trace_find_hook(ts
->parent
.t
,
3526 LTT_FACILITY_STATEDUMP
,
3527 LTT_EVENT_SYS_CALL_TABLE
,
3528 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3529 dump_syscall
, NULL
, &hooks
);
3531 lttv_trace_find_hook(ts
->parent
.t
,
3532 LTT_FACILITY_STATEDUMP
,
3533 LTT_EVENT_SOFTIRQ_VEC
,
3534 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3535 dump_softirq
, NULL
, &hooks
);
3537 /* Add these hooks to each event_by_id hooks list */
3539 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3541 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3543 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3544 LttvTracefileContext
*, j
));
3546 for(k
= 0 ; k
< hooks
->len
; k
++) {
3547 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3549 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3555 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3556 *(val
.v_pointer
) = hooks
;
3560 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3562 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3564 lttv_state_remove_event_hooks(tss
);
3569 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3571 LttvTraceset
*traceset
= self
->parent
.ts
;
3573 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3577 LttvTracefileState
*tfs
;
3583 LttvAttributeValue val
;
3585 nb_trace
= lttv_traceset_number(traceset
);
3586 for(i
= 0 ; i
< nb_trace
; i
++) {
3587 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3589 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3590 hooks
= *(val
.v_pointer
);
3592 /* Remove these hooks from each event_by_id hooks list */
3594 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3596 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3598 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3599 LttvTracefileContext
*, j
));
3601 for(k
= 0 ; k
< hooks
->len
; k
++) {
3602 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3603 lttv_hooks_remove_data(
3604 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3609 lttv_trace_hook_remove_all(&hooks
);
3610 g_array_free(hooks
, TRUE
);
3614 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3616 guint
*event_count
= (guint
*)hook_data
;
3618 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3619 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3624 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3626 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3628 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3630 LttvAttributeValue value
;
3632 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3633 LTTV_STATE_SAVED_STATES
);
3634 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3635 value
= lttv_attribute_add(saved_states_tree
,
3636 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3637 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3638 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3639 *(value
.v_time
) = self
->parent
.timestamp
;
3640 lttv_state_save(tcs
, saved_state_tree
);
3641 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3642 self
->parent
.timestamp
.tv_nsec
);
3644 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3649 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3651 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3653 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3658 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3666 static gboolean
block_start(void *hook_data
, void *call_data
)
3668 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3670 LttvTracefileState
*tfcs
;
3672 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3674 LttEventPosition
*ep
;
3676 guint i
, nb_block
, nb_event
, nb_tracefile
;
3680 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3682 LttvAttributeValue value
;
3684 ep
= ltt_event_position_new();
3686 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3688 /* Count the number of events added since the last block end in any
3691 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3693 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3694 LttvTracefileContext
, i
));
3695 ltt_event_position(tfcs
->parent
.e
, ep
);
3696 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3697 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3698 tfcs
->saved_position
= nb_event
;
3702 if(tcs
->nb_event
>= tcs
->save_interval
) {
3703 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3704 LTTV_STATE_SAVED_STATES
);
3705 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3706 value
= lttv_attribute_add(saved_states_tree
,
3707 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3708 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3709 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3710 *(value
.v_time
) = self
->parent
.timestamp
;
3711 lttv_state_save(tcs
, saved_state_tree
);
3713 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3714 self
->parent
.timestamp
.tv_nsec
);
3716 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3722 static gboolean
block_end(void *hook_data
, void *call_data
)
3724 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3726 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3730 LttEventPosition
*ep
;
3732 guint nb_block
, nb_event
;
3734 ep
= ltt_event_position_new();
3735 ltt_event_position(self
->parent
.e
, ep
);
3736 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3737 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3738 self
->saved_position
= 0;
3739 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3746 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3748 LttvTraceset
*traceset
= self
->parent
.ts
;
3750 guint i
, j
, nb_trace
, nb_tracefile
;
3754 LttvTracefileState
*tfs
;
3756 LttvTraceHook hook_start
, hook_end
;
3758 nb_trace
= lttv_traceset_number(traceset
);
3759 for(i
= 0 ; i
< nb_trace
; i
++) {
3760 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3762 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3763 NULL
, NULL
, block_start
, &hook_start
);
3764 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3765 NULL
, NULL
, block_end
, &hook_end
);
3767 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3769 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3771 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3772 LttvTracefileContext
, j
));
3773 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3774 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3775 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3776 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3782 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3784 LttvTraceset
*traceset
= self
->parent
.ts
;
3786 guint i
, j
, nb_trace
, nb_tracefile
;
3790 LttvTracefileState
*tfs
;
3793 nb_trace
= lttv_traceset_number(traceset
);
3794 for(i
= 0 ; i
< nb_trace
; i
++) {
3796 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3797 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3799 if(ts
->has_precomputed_states
) continue;
3801 guint
*event_count
= g_new(guint
, 1);
3804 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3806 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3807 LttvTracefileContext
*, j
));
3808 lttv_hooks_add(tfs
->parent
.event
,
3809 state_save_event_hook
,
3816 lttv_process_traceset_begin(&self
->parent
,
3817 NULL
, NULL
, NULL
, NULL
, NULL
);
3821 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3823 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3825 lttv_state_save_add_event_hooks(tss
);
3832 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3834 LttvTraceset
*traceset
= self
->parent
.ts
;
3836 guint i
, j
, nb_trace
, nb_tracefile
;
3840 LttvTracefileState
*tfs
;
3842 LttvTraceHook hook_start
, hook_end
;
3844 nb_trace
= lttv_traceset_number(traceset
);
3845 for(i
= 0 ; i
< nb_trace
; i
++) {
3846 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3848 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3849 NULL
, NULL
, block_start
, &hook_start
);
3851 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3852 NULL
, NULL
, block_end
, &hook_end
);
3854 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3856 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3858 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3859 LttvTracefileContext
, j
));
3860 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3861 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3862 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3863 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3869 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3871 LttvTraceset
*traceset
= self
->parent
.ts
;
3873 guint i
, j
, nb_trace
, nb_tracefile
;
3877 LttvTracefileState
*tfs
;
3879 LttvHooks
*after_trace
= lttv_hooks_new();
3881 lttv_hooks_add(after_trace
,
3882 state_save_after_trace_hook
,
3887 lttv_process_traceset_end(&self
->parent
,
3888 NULL
, after_trace
, NULL
, NULL
, NULL
);
3890 lttv_hooks_destroy(after_trace
);
3892 nb_trace
= lttv_traceset_number(traceset
);
3893 for(i
= 0 ; i
< nb_trace
; i
++) {
3895 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3896 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3898 if(ts
->has_precomputed_states
) continue;
3900 guint
*event_count
= NULL
;
3902 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3904 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3905 LttvTracefileContext
*, j
));
3906 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3907 state_save_event_hook
);
3909 if(event_count
) g_free(event_count
);
3913 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3915 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3917 lttv_state_save_remove_event_hooks(tss
);
3922 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3924 LttvTraceset
*traceset
= self
->parent
.ts
;
3928 int min_pos
, mid_pos
, max_pos
;
3930 guint call_rest
= 0;
3932 LttvTraceState
*tcs
;
3934 LttvAttributeValue value
;
3936 LttvAttributeType type
;
3938 LttvAttributeName name
;
3942 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3944 //g_tree_destroy(self->parent.pqueue);
3945 //self->parent.pqueue = g_tree_new(compare_tracefile);
3947 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3949 nb_trace
= lttv_traceset_number(traceset
);
3950 for(i
= 0 ; i
< nb_trace
; i
++) {
3951 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3953 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3954 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3955 LTTV_STATE_SAVED_STATES
);
3958 if(saved_states_tree
) {
3959 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3960 mid_pos
= max_pos
/ 2;
3961 while(min_pos
< max_pos
) {
3962 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3964 g_assert(type
== LTTV_GOBJECT
);
3965 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3966 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3968 g_assert(type
== LTTV_TIME
);
3969 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3971 closest_tree
= saved_state_tree
;
3973 else max_pos
= mid_pos
- 1;
3975 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3979 /* restore the closest earlier saved state */
3981 lttv_state_restore(tcs
, closest_tree
);
3985 /* There is no saved state, yet we want to have it. Restart at T0 */
3987 restore_init_state(tcs
);
3988 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3991 /* We want to seek quickly without restoring/updating the state */
3993 restore_init_state(tcs
);
3994 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3997 if(!call_rest
) g_info("NOT Calling restore");
4002 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4008 traceset_state_finalize (LttvTracesetState
*self
)
4010 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4011 finalize(G_OBJECT(self
));
4016 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4018 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4020 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4021 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4022 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4023 klass
->new_traceset_context
= new_traceset_context
;
4024 klass
->new_trace_context
= new_trace_context
;
4025 klass
->new_tracefile_context
= new_tracefile_context
;
4030 lttv_traceset_state_get_type(void)
4032 static GType type
= 0;
4034 static const GTypeInfo info
= {
4035 sizeof (LttvTracesetStateClass
),
4036 NULL
, /* base_init */
4037 NULL
, /* base_finalize */
4038 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4039 NULL
, /* class_finalize */
4040 NULL
, /* class_data */
4041 sizeof (LttvTracesetState
),
4042 0, /* n_preallocs */
4043 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4044 NULL
/* value handling */
4047 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4055 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4061 trace_state_finalize (LttvTraceState
*self
)
4063 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4064 finalize(G_OBJECT(self
));
4069 trace_state_class_init (LttvTraceStateClass
*klass
)
4071 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4073 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4074 klass
->state_save
= state_save
;
4075 klass
->state_restore
= state_restore
;
4076 klass
->state_saved_free
= state_saved_free
;
4081 lttv_trace_state_get_type(void)
4083 static GType type
= 0;
4085 static const GTypeInfo info
= {
4086 sizeof (LttvTraceStateClass
),
4087 NULL
, /* base_init */
4088 NULL
, /* base_finalize */
4089 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4090 NULL
, /* class_finalize */
4091 NULL
, /* class_data */
4092 sizeof (LttvTraceState
),
4093 0, /* n_preallocs */
4094 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4095 NULL
/* value handling */
4098 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4099 "LttvTraceStateType", &info
, 0);
4106 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4112 tracefile_state_finalize (LttvTracefileState
*self
)
4114 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4115 finalize(G_OBJECT(self
));
4120 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4122 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4124 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4129 lttv_tracefile_state_get_type(void)
4131 static GType type
= 0;
4133 static const GTypeInfo info
= {
4134 sizeof (LttvTracefileStateClass
),
4135 NULL
, /* base_init */
4136 NULL
, /* base_finalize */
4137 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4138 NULL
, /* class_finalize */
4139 NULL
, /* class_data */
4140 sizeof (LttvTracefileState
),
4141 0, /* n_preallocs */
4142 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4143 NULL
/* value handling */
4146 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4147 "LttvTracefileStateType", &info
, 0);
4153 static void module_init()
4155 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4156 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4157 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4158 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4159 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4160 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4161 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4162 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4163 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4164 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4165 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4166 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4167 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4168 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4169 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4170 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4171 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4172 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4173 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4174 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4175 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4176 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4177 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4178 LTTV_STATE_EVENT
= g_quark_from_string("event");
4179 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4180 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4181 LTTV_STATE_TIME
= g_quark_from_string("time");
4182 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4183 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4184 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4185 g_quark_from_string("trace_state_use_count");
4186 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4187 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4188 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4189 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4190 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4191 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4194 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4195 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4196 LTT_FACILITY_FS
= g_quark_from_string("fs");
4197 LTT_FACILITY_LIST
= g_quark_from_string("list");
4198 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4199 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4200 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4202 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4203 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4204 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4205 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4206 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4207 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4208 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4209 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4210 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4211 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4212 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4213 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4214 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4215 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4216 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4217 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4218 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4219 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4220 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4221 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4222 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4223 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4224 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4225 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4226 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4228 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4229 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4230 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4231 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4232 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4233 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4234 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4235 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4236 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4237 LTT_FIELD_PID
= g_quark_from_string("pid");
4238 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4239 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4240 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4241 LTT_FIELD_NAME
= g_quark_from_string("name");
4242 LTT_FIELD_TYPE
= g_quark_from_string("type");
4243 LTT_FIELD_MODE
= g_quark_from_string("mode");
4244 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4245 LTT_FIELD_STATUS
= g_quark_from_string("status");
4246 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4247 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4248 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4249 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4250 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4251 LTT_FIELD_ACTION
= g_quark_from_string("action");
4252 LTT_FIELD_ID
= g_quark_from_string("id");
4253 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4254 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4256 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4257 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4258 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4259 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4260 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4261 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4263 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4264 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4265 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4267 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4268 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4269 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4270 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4273 static void module_destroy()
4278 LTTV_MODULE("state", "State computation", \
4279 "Update the system state, possibly saving it at intervals", \
4280 module_init
, module_destroy
)