1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
31 #include <ltt/marker-desc.h>
34 #include <ltt/ltt-private.h>
38 * usertrace is there only to be able to update the current CPU of the
39 * usertraces when there is a schedchange. it is a way to link the ProcessState
40 * to the associated usertrace. Link only created upon thread creation.
42 * The cpu id is necessary : it gives us back the current ProcessState when we
43 * are considering data from the usertrace.
46 #define PREALLOCATED_EXECUTION_STACK 10
48 /* Facilities Quarks */
54 LTT_FACILITY_USER_GENERIC
,
56 LTT_FACILITY_STATEDUMP
;
61 LTT_EVENT_SYSCALL_ENTRY
,
62 LTT_EVENT_SYSCALL_EXIT
,
67 LTT_EVENT_SOFT_IRQ_RAISE
,
68 LTT_EVENT_SOFT_IRQ_ENTRY
,
69 LTT_EVENT_SOFT_IRQ_EXIT
,
70 LTT_EVENT_SCHED_SCHEDULE
,
71 LTT_EVENT_PROCESS_FORK
,
72 LTT_EVENT_KTHREAD_CREATE
,
73 LTT_EVENT_PROCESS_EXIT
,
74 LTT_EVENT_PROCESS_FREE
,
76 LTT_EVENT_PROCESS_STATE
,
77 LTT_EVENT_STATEDUMP_END
,
78 LTT_EVENT_FUNCTION_ENTRY
,
79 LTT_EVENT_FUNCTION_EXIT
,
80 LTT_EVENT_THREAD_BRAND
,
81 LTT_EVENT_REQUEST_ISSUE
,
82 LTT_EVENT_REQUEST_COMPLETE
,
83 LTT_EVENT_LIST_INTERRUPT
,
84 LTT_EVENT_SYS_CALL_TABLE
,
85 LTT_EVENT_SOFTIRQ_VEC
;
93 LTT_FIELD_SOFT_IRQ_ID
,
101 LTT_FIELD_CHILD_TGID
,
119 LTTV_STATE_MODE_UNKNOWN
,
120 LTTV_STATE_USER_MODE
,
127 LTTV_STATE_SUBMODE_UNKNOWN
,
128 LTTV_STATE_SUBMODE_NONE
;
132 LTTV_STATE_WAIT_FORK
,
141 LTTV_STATE_UNBRANDED
;
144 LTTV_STATE_USER_THREAD
,
145 LTTV_STATE_KERNEL_THREAD
;
163 LTTV_BDEV_BUSY_READING
,
164 LTTV_BDEV_BUSY_WRITING
;
167 LTTV_STATE_TRACEFILES
,
168 LTTV_STATE_PROCESSES
,
170 LTTV_STATE_RUNNING_PROCESS
,
172 LTTV_STATE_SAVED_STATES
,
173 LTTV_STATE_SAVED_STATES_TIME
,
176 LTTV_STATE_NAME_TABLES
,
177 LTTV_STATE_TRACE_STATE_USE_COUNT
,
178 LTTV_STATE_RESOURCE_CPUS
,
179 LTTV_STATE_RESOURCE_CPUS_COUNT
,
180 LTTV_STATE_RESOURCE_IRQS
,
181 LTTV_STATE_RESOURCE_SOFT_IRQS
,
182 LTTV_STATE_RESOURCE_TRAPS
,
183 LTTV_STATE_RESOURCE_BLKDEVS
;
185 static void create_max_time(LttvTraceState
*tcs
);
187 static void get_max_time(LttvTraceState
*tcs
);
189 static void free_max_time(LttvTraceState
*tcs
);
191 static void create_name_tables(LttvTraceState
*tcs
);
193 static void get_name_tables(LttvTraceState
*tcs
);
195 static void free_name_tables(LttvTraceState
*tcs
);
197 static void free_saved_state(LttvTraceState
*tcs
);
199 static void lttv_state_free_process_table(GHashTable
*processes
);
201 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
202 GPtrArray
*quarktable
);
204 /* Resource function prototypes */
205 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
206 static LttvBdevState
*bdevstate_new(void);
207 static void bdevstate_free(LttvBdevState
*);
208 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
209 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
212 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
214 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
218 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
220 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
224 void lttv_state_state_saved_free(LttvTraceState
*self
,
225 LttvAttribute
*container
)
227 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
231 guint
process_hash(gconstpointer key
)
233 guint pid
= ((const LttvProcessState
*)key
)->pid
;
234 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
238 /* If the hash table hash function is well distributed,
239 * the process_equal should compare different pid */
240 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
242 const LttvProcessState
*process_a
, *process_b
;
245 process_a
= (const LttvProcessState
*)a
;
246 process_b
= (const LttvProcessState
*)b
;
248 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
249 else if(likely(process_a
->pid
== 0 &&
250 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
255 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
257 g_tree_destroy((GTree
*)value
);
260 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
262 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
263 g_hash_table_destroy(usertraces
);
266 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
271 static guint
check_expand(nb
, id
)
276 return max(id
+ 1, nb
* 2);
279 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
280 guint nb
, guint new_nb
)
282 /* Expand an incomplete table */
283 GQuark
*old_table
= *table
;
284 *table
= g_new(GQuark
, new_nb
);
285 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
288 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
289 guint new_nb
, const char *def_string
)
292 GString
*fe_name
= g_string_new("");
293 for(i
= nb
; i
< new_nb
; i
++) {
294 g_string_printf(fe_name
, "%s %d", def_string
, i
);
295 table
[i
] = g_quark_from_string(fe_name
->str
);
297 g_string_free(fe_name
, TRUE
);
300 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
302 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
303 if(likely(new_nb
== ts
->nb_syscalls
))
305 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
306 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
307 /* Update the table size */
308 ts
->nb_syscalls
= new_nb
;
311 static void expand_trap_table(LttvTraceState
*ts
, int id
)
313 guint new_nb
= check_expand(ts
->nb_traps
, id
);
315 if(likely(new_nb
== ts
->nb_traps
))
317 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
318 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
319 /* Update the table size */
320 ts
->nb_traps
= new_nb
;
322 LttvTrapState
*old_table
= ts
->trap_states
;
323 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
324 memcpy(ts
->trap_states
, old_table
,
325 ts
->nb_traps
* sizeof(LttvTrapState
));
326 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
327 ts
->trap_states
[i
].running
= 0;
330 static void expand_irq_table(LttvTraceState
*ts
, int id
)
332 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
334 if(likely(new_nb
== ts
->nb_irqs
))
336 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
337 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
339 LttvIRQState
*old_table
= ts
->irq_states
;
340 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
341 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
342 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
343 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
346 /* Update the table size */
347 ts
->nb_irqs
= new_nb
;
350 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
352 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
354 if(likely(new_nb
== ts
->nb_soft_irqs
))
356 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
357 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
359 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
360 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
361 memcpy(ts
->soft_irq_states
, old_table
,
362 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
363 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
364 ts
->soft_irq_states
[i
].running
= 0;
366 /* Update the table size */
367 ts
->nb_soft_irqs
= new_nb
;
371 restore_init_state(LttvTraceState
*self
)
373 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
375 //LttvTracefileState *tfcs;
377 LttTime start_time
, end_time
;
379 /* Free the process tables */
380 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
381 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
382 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
383 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
386 /* Seek time to beginning */
387 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
388 // closest. It's the tracecontext job to seek the trace to the beginning
389 // anyway : the init state might be used at the middle of the trace as well...
390 //g_tree_destroy(self->parent.ts_context->pqueue);
391 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
393 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
395 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
397 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
398 nb_irqs
= self
->nb_irqs
;
399 nb_soft_irqs
= self
->nb_soft_irqs
;
400 nb_traps
= self
->nb_traps
;
402 /* Put the per cpu running_process to beginning state : process 0. */
403 for(i
=0; i
< nb_cpus
; i
++) {
404 LttvExecutionState
*es
;
405 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
406 LTTV_STATE_UNNAMED
, &start_time
);
407 /* We are not sure is it's a kernel thread or normal thread, put the
408 * bottom stack state to unknown */
409 self
->running_process
[i
]->execution_stack
=
410 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
411 es
= self
->running_process
[i
]->state
=
412 &g_array_index(self
->running_process
[i
]->execution_stack
,
413 LttvExecutionState
, 0);
414 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
415 es
->s
= LTTV_STATE_UNNAMED
;
417 //self->running_process[i]->state->s = LTTV_STATE_RUN;
418 self
->running_process
[i
]->cpu
= i
;
420 /* reset cpu states */
421 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
422 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
423 self
->cpu_states
[i
].last_irq
= -1;
424 self
->cpu_states
[i
].last_soft_irq
= -1;
425 self
->cpu_states
[i
].last_trap
= -1;
429 /* reset irq states */
430 for(i
=0; i
<nb_irqs
; i
++) {
431 if(self
->irq_states
[i
].mode_stack
->len
> 0)
432 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
435 /* reset softirq states */
436 for(i
=0; i
<nb_soft_irqs
; i
++) {
437 self
->soft_irq_states
[i
].pending
= 0;
438 self
->soft_irq_states
[i
].running
= 0;
441 /* reset trap states */
442 for(i
=0; i
<nb_traps
; i
++) {
443 self
->trap_states
[i
].running
= 0;
446 /* reset bdev states */
447 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
448 //g_hash_table_steal_all(self->bdev_states);
449 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
452 nb_tracefile
= self
->parent
.tracefiles
->len
;
454 for(i
= 0 ; i
< nb_tracefile
; i
++) {
456 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
457 LttvTracefileContext
*, i
));
458 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
459 // tfcs->saved_position = 0;
460 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
461 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
462 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
463 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
468 //static LttTime time_zero = {0,0};
470 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
473 const LttTime
*t1
= (const LttTime
*)a
;
474 const LttTime
*t2
= (const LttTime
*)b
;
476 return ltt_time_compare(*t1
, *t2
);
479 static void free_usertrace_key(gpointer data
)
484 #define MAX_STRING_LEN 4096
487 state_load_saved_states(LttvTraceState
*tcs
)
490 GPtrArray
*quarktable
;
491 const char *trace_path
;
495 tcs
->has_precomputed_states
= FALSE
;
499 gchar buf
[MAX_STRING_LEN
];
502 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
503 strncpy(path
, trace_path
, PATH_MAX
-1);
504 count
= strnlen(trace_path
, PATH_MAX
-1);
505 // quarktable : open, test
506 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
507 fp
= fopen(path
, "r");
509 quarktable
= g_ptr_array_sized_new(4096);
511 /* Index 0 is null */
513 if(hdr
== EOF
) return;
514 g_assert(hdr
== HDR_QUARKS
);
518 if(hdr
== EOF
) break;
519 g_assert(hdr
== HDR_QUARK
);
520 g_ptr_array_set_size(quarktable
, q
+1);
523 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
524 if(buf
[i
] == '\0' || feof(fp
)) break;
527 len
= strnlen(buf
, MAX_STRING_LEN
-1);
528 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
529 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
535 // saved_states : open, test
536 strncpy(path
, trace_path
, PATH_MAX
-1);
537 count
= strnlen(trace_path
, PATH_MAX
-1);
538 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
539 fp
= fopen(path
, "r");
543 if(hdr
!= HDR_TRACE
) goto end
;
545 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
547 tcs
->has_precomputed_states
= TRUE
;
552 /* Free the quarktable */
553 for(i
=0; i
<quarktable
->len
; i
++) {
554 string
= g_ptr_array_index (quarktable
, i
);
557 g_ptr_array_free(quarktable
, TRUE
);
562 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
564 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
567 LttvTraceContext
*tc
;
571 LttvTracefileState
*tfcs
;
573 LttvAttributeValue v
;
575 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
576 init((LttvTracesetContext
*)self
, ts
);
578 nb_trace
= lttv_traceset_number(ts
);
579 for(i
= 0 ; i
< nb_trace
; i
++) {
580 tc
= self
->parent
.traces
[i
];
581 tcs
= LTTV_TRACE_STATE(tc
);
582 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
583 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
587 if(*(v
.v_uint
) == 1) {
588 create_name_tables(tcs
);
589 create_max_time(tcs
);
591 get_name_tables(tcs
);
594 nb_tracefile
= tc
->tracefiles
->len
;
595 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
596 nb_irq
= tcs
->nb_irqs
;
597 tcs
->processes
= NULL
;
598 tcs
->usertraces
= NULL
;
599 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
601 /* init cpu resource stuff */
602 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
603 for(j
= 0; j
<nb_cpu
; j
++) {
604 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
605 tcs
->cpu_states
[j
].last_irq
= -1;
606 tcs
->cpu_states
[j
].last_soft_irq
= -1;
607 tcs
->cpu_states
[j
].last_trap
= -1;
608 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
611 /* init irq resource stuff */
612 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
613 for(j
= 0; j
<nb_irq
; j
++) {
614 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
615 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
618 /* init soft irq stuff */
619 /* the kernel has a statically fixed max of 32 softirqs */
620 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
622 /* init trap stuff */
623 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
625 /* init bdev resource stuff */
626 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
628 restore_init_state(tcs
);
629 for(j
= 0 ; j
< nb_tracefile
; j
++) {
631 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
632 LttvTracefileContext
*, j
));
633 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
634 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
635 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
636 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
637 /* It's a Usertrace */
638 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
639 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
641 if(!usertrace_tree
) {
642 usertrace_tree
= g_tree_new_full(compare_usertraces
,
643 NULL
, free_usertrace_key
, NULL
);
644 g_hash_table_insert(tcs
->usertraces
,
645 (gpointer
)tid
, usertrace_tree
);
647 LttTime
*timestamp
= g_new(LttTime
, 1);
648 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
649 ltt_tracefile_creation(tfcs
->parent
.tf
));
650 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
654 /* See if the trace has saved states */
655 state_load_saved_states(tcs
);
660 fini(LttvTracesetState
*self
)
666 //LttvTracefileState *tfcs;
668 LttvAttributeValue v
;
670 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
671 for(i
= 0 ; i
< nb_trace
; i
++) {
672 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
673 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
676 g_assert(*(v
.v_uint
) != 0);
679 if(*(v
.v_uint
) == 0) {
680 free_name_tables(tcs
);
682 free_saved_state(tcs
);
684 g_free(tcs
->running_process
);
685 tcs
->running_process
= NULL
;
686 lttv_state_free_process_table(tcs
->processes
);
687 lttv_state_free_usertraces(tcs
->usertraces
);
688 tcs
->processes
= NULL
;
689 tcs
->usertraces
= NULL
;
691 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
692 fini((LttvTracesetContext
*)self
);
696 static LttvTracesetContext
*
697 new_traceset_context(LttvTracesetContext
*self
)
699 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
703 static LttvTraceContext
*
704 new_trace_context(LttvTracesetContext
*self
)
706 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
710 static LttvTracefileContext
*
711 new_tracefile_context(LttvTracesetContext
*self
)
713 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
717 /* Write the process state of the trace */
719 static void write_process_state(gpointer key
, gpointer value
,
722 LttvProcessState
*process
;
724 LttvExecutionState
*es
;
726 FILE *fp
= (FILE *)user_data
;
731 process
= (LttvProcessState
*)value
;
733 " <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",
734 process
, process
->pid
, process
->tgid
, process
->ppid
,
735 g_quark_to_string(process
->type
),
736 process
->creation_time
.tv_sec
,
737 process
->creation_time
.tv_nsec
,
738 process
->insertion_time
.tv_sec
,
739 process
->insertion_time
.tv_nsec
,
740 g_quark_to_string(process
->name
),
741 g_quark_to_string(process
->brand
),
742 process
->cpu
, process
->free_events
);
744 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
745 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
746 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
747 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
748 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
749 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
750 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
753 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
754 address
= g_array_index(process
->user_stack
, guint64
, i
);
755 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
759 if(process
->usertrace
) {
760 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
761 g_quark_to_string(process
->usertrace
->tracefile_name
),
762 process
->usertrace
->cpu
);
766 fprintf(fp
, " </PROCESS>\n");
770 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
772 guint i
, nb_tracefile
, nb_block
, offset
;
775 LttvTracefileState
*tfcs
;
779 LttEventPosition
*ep
;
783 ep
= ltt_event_position_new();
785 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
787 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
789 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
790 for(i
=0;i
<nb_cpus
;i
++) {
791 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
792 i
, self
->running_process
[i
]->pid
);
795 nb_tracefile
= self
->parent
.tracefiles
->len
;
797 for(i
= 0 ; i
< nb_tracefile
; i
++) {
799 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
800 LttvTracefileContext
*, i
));
801 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
802 tfcs
->parent
.timestamp
.tv_sec
,
803 tfcs
->parent
.timestamp
.tv_nsec
);
804 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
805 if(e
== NULL
) fprintf(fp
,"/>\n");
807 ltt_event_position(e
, ep
);
808 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
809 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
814 fprintf(fp
,"</PROCESS_STATE>\n");
818 static void write_process_state_raw(gpointer key
, gpointer value
,
821 LttvProcessState
*process
;
823 LttvExecutionState
*es
;
825 FILE *fp
= (FILE *)user_data
;
830 process
= (LttvProcessState
*)value
;
831 fputc(HDR_PROCESS
, fp
);
832 //fwrite(&header, sizeof(header), 1, fp);
833 //fprintf(fp, "%s", g_quark_to_string(process->type));
835 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
836 //fprintf(fp, "%s", g_quark_to_string(process->name));
838 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
839 //fprintf(fp, "%s", g_quark_to_string(process->brand));
841 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
842 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
843 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
844 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
845 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
846 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
847 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
848 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
852 " <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",
853 process
, process
->pid
, process
->tgid
, process
->ppid
,
854 g_quark_to_string(process
->type
),
855 process
->creation_time
.tv_sec
,
856 process
->creation_time
.tv_nsec
,
857 process
->insertion_time
.tv_sec
,
858 process
->insertion_time
.tv_nsec
,
859 g_quark_to_string(process
->name
),
860 g_quark_to_string(process
->brand
),
864 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
865 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
868 //fprintf(fp, "%s", g_quark_to_string(es->t));
870 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
871 //fprintf(fp, "%s", g_quark_to_string(es->n));
873 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
874 //fprintf(fp, "%s", g_quark_to_string(es->s));
876 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
877 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
878 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
879 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
881 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
882 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
883 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
884 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
885 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
889 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
890 address
= g_array_index(process
->user_stack
, guint64
, i
);
891 fputc(HDR_USER_STACK
, fp
);
892 fwrite(&address
, sizeof(address
), 1, fp
);
894 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
899 if(process
->usertrace
) {
900 fputc(HDR_USERTRACE
, fp
);
901 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
903 fwrite(&process
->usertrace
->tracefile_name
,
904 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
905 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
907 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
908 g_quark_to_string(process
->usertrace
->tracefile_name
),
909 process
->usertrace
->cpu
);
916 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
918 guint i
, nb_tracefile
, nb_block
, offset
;
921 LttvTracefileState
*tfcs
;
925 LttEventPosition
*ep
;
929 ep
= ltt_event_position_new();
931 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
932 fputc(HDR_PROCESS_STATE
, fp
);
933 fwrite(&t
, sizeof(t
), 1, fp
);
935 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
937 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
938 for(i
=0;i
<nb_cpus
;i
++) {
940 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
941 fwrite(&self
->running_process
[i
]->pid
,
942 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
943 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
944 // i, self->running_process[i]->pid);
947 nb_tracefile
= self
->parent
.tracefiles
->len
;
949 for(i
= 0 ; i
< nb_tracefile
; i
++) {
951 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
952 LttvTracefileContext
*, i
));
953 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
954 // tfcs->parent.timestamp.tv_sec,
955 // tfcs->parent.timestamp.tv_nsec);
956 fputc(HDR_TRACEFILE
, fp
);
957 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
958 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
959 * position following : end of trace */
960 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
962 ltt_event_position(e
, ep
);
963 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
964 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
966 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
967 fwrite(&offset
, sizeof(offset
), 1, fp
);
968 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
975 /* Read process state from a file */
977 /* Called because a HDR_PROCESS was found */
978 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
979 GPtrArray
*quarktable
)
981 LttvExecutionState
*es
;
982 LttvProcessState
*process
, *parent_process
;
983 LttvProcessState tmp
;
988 /* TODO : check return value */
989 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
990 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
991 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
992 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
993 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
994 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
995 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
996 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
997 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
998 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1001 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1003 /* We must link to the parent */
1004 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1006 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1007 if(process
== NULL
) {
1008 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1010 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1011 &tmp
.creation_time
);
1014 process
->insertion_time
= tmp
.insertion_time
;
1015 process
->creation_time
= tmp
.creation_time
;
1016 process
->type
= g_quark_from_string(
1017 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1018 process
->tgid
= tmp
.tgid
;
1019 process
->ppid
= tmp
.ppid
;
1020 process
->brand
= g_quark_from_string(
1021 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1023 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1024 process
->free_events
= tmp
.free_events
;
1027 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1029 gint hdr
= fgetc(fp
);
1030 if(hdr
== EOF
) goto end_loop
;
1034 process
->execution_stack
=
1035 g_array_set_size(process
->execution_stack
,
1036 process
->execution_stack
->len
+ 1);
1037 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1038 process
->execution_stack
->len
-1);
1039 process
->state
= es
;
1041 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1042 es
->t
= g_quark_from_string(
1043 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1044 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1045 es
->n
= g_quark_from_string(
1046 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1047 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1048 es
->s
= g_quark_from_string(
1049 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1050 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1051 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1052 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1054 case HDR_USER_STACK
:
1055 process
->user_stack
= g_array_set_size(process
->user_stack
,
1056 process
->user_stack
->len
+ 1);
1057 address
= &g_array_index(process
->user_stack
, guint64
,
1058 process
->user_stack
->len
-1);
1059 fread(address
, sizeof(address
), 1, fp
);
1060 process
->current_function
= *address
;
1063 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1064 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1076 /* Called because a HDR_PROCESS_STATE was found */
1077 /* Append a saved state to the trace states */
1078 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1080 guint i
, nb_tracefile
, nb_block
, offset
;
1082 LttvTracefileState
*tfcs
;
1084 LttEventPosition
*ep
;
1092 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1094 LttvAttributeValue value
;
1095 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1096 ep
= ltt_event_position_new();
1098 restore_init_state(self
);
1100 fread(&t
, sizeof(t
), 1, fp
);
1103 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1105 if(hdr
== EOF
) goto end_loop
;
1109 /* Call read_process_state_raw */
1110 read_process_state_raw(self
, fp
, quarktable
);
1118 case HDR_USER_STACK
:
1120 case HDR_PROCESS_STATE
:
1126 g_error("Error while parsing saved state file : unknown data header %d",
1132 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1133 for(i
=0;i
<nb_cpus
;i
++) {
1136 g_assert(hdr
== HDR_CPU
);
1137 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1138 g_assert(i
== cpu_num
);
1139 fread(&self
->running_process
[i
]->pid
,
1140 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1143 nb_tracefile
= self
->parent
.tracefiles
->len
;
1145 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1147 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1148 LttvTracefileContext
*, i
));
1149 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1150 // tfcs->parent.timestamp.tv_sec,
1151 // tfcs->parent.timestamp.tv_nsec);
1152 g_tree_remove(pqueue
, &tfcs
->parent
);
1154 g_assert(hdr
== HDR_TRACEFILE
);
1155 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1156 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1157 * position following : end of trace */
1158 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1159 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1160 fread(&offset
, sizeof(offset
), 1, fp
);
1161 fread(&tsc
, sizeof(tsc
), 1, fp
);
1162 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1163 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1165 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1170 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1171 LTTV_STATE_SAVED_STATES
);
1172 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1173 value
= lttv_attribute_add(saved_states_tree
,
1174 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1175 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1176 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1177 *(value
.v_time
) = t
;
1178 lttv_state_save(self
, saved_state_tree
);
1179 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1182 *(self
->max_time_state_recomputed_in_seek
) = t
;
1186 /* Called when a HDR_TRACE is found */
1187 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1188 GPtrArray
*quarktable
)
1193 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1195 if(hdr
== EOF
) goto end_loop
;
1198 case HDR_PROCESS_STATE
:
1199 /* Call read_process_state_raw */
1200 lttv_state_read_raw(tcs
, fp
, quarktable
);
1208 case HDR_USER_STACK
:
1212 g_error("Error while parsing saved state file :"
1213 " unexpected data header %d",
1217 g_error("Error while parsing saved state file : unknown data header %d",
1222 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1223 restore_init_state(tcs
);
1224 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1230 /* Copy each process from an existing hash table to a new one */
1232 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1234 LttvProcessState
*process
, *new_process
;
1236 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1240 process
= (LttvProcessState
*)value
;
1241 new_process
= g_new(LttvProcessState
, 1);
1242 *new_process
= *process
;
1243 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1244 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1245 new_process
->execution_stack
=
1246 g_array_set_size(new_process
->execution_stack
,
1247 process
->execution_stack
->len
);
1248 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1249 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1250 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1252 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1253 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1254 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1255 sizeof(guint64
), 0);
1256 new_process
->user_stack
=
1257 g_array_set_size(new_process
->user_stack
,
1258 process
->user_stack
->len
);
1259 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1260 g_array_index(new_process
->user_stack
, guint64
, i
) =
1261 g_array_index(process
->user_stack
, guint64
, i
);
1263 new_process
->current_function
= process
->current_function
;
1264 g_hash_table_insert(new_processes
, new_process
, new_process
);
1268 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1270 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1272 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1273 return new_processes
;
1276 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1279 LttvCPUState
*retval
;
1281 retval
= g_new(LttvCPUState
, n
);
1283 for(i
=0; i
<n
; i
++) {
1284 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1285 retval
[i
].last_irq
= states
[i
].last_irq
;
1286 retval
[i
].last_soft_irq
= states
[i
].last_soft_irq
;
1287 retval
[i
].last_trap
= states
[i
].last_trap
;
1288 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1289 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1290 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1297 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1301 for(i
=0; i
<n
; i
++) {
1302 g_array_free(states
[i
].mode_stack
, TRUE
);
1308 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1311 LttvIRQState
*retval
;
1313 retval
= g_new(LttvIRQState
, n
);
1315 for(i
=0; i
<n
; i
++) {
1316 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1317 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1318 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1319 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1326 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1330 for(i
=0; i
<n
; i
++) {
1331 g_array_free(states
[i
].mode_stack
, TRUE
);
1337 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1340 LttvSoftIRQState
*retval
;
1342 retval
= g_new(LttvSoftIRQState
, n
);
1344 for(i
=0; i
<n
; i
++) {
1345 retval
[i
].pending
= states
[i
].pending
;
1346 retval
[i
].running
= states
[i
].running
;
1352 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1357 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1360 LttvTrapState
*retval
;
1362 retval
= g_new(LttvTrapState
, n
);
1364 for(i
=0; i
<n
; i
++) {
1365 retval
[i
].running
= states
[i
].running
;
1371 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1376 /* bdevstate stuff */
1378 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1380 gint devcode_gint
= devcode
;
1381 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1383 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1384 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1386 gint
* key
= g_new(gint
, 1);
1388 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1396 static LttvBdevState
*bdevstate_new(void)
1398 LttvBdevState
*retval
;
1399 retval
= g_new(LttvBdevState
, 1);
1400 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1405 static void bdevstate_free(LttvBdevState
*bds
)
1407 g_array_free(bds
->mode_stack
, TRUE
);
1411 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1413 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1415 bdevstate_free(bds
);
1418 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1420 LttvBdevState
*retval
;
1422 retval
= bdevstate_new();
1423 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1428 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1430 //GHashTable *ht = (GHashTable *)u;
1431 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1432 LttvBdevState
*newbds
;
1434 newbds
= bdevstate_copy(bds
);
1436 g_hash_table_insert(u
, k
, newbds
);
1439 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1443 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1445 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1450 /* Free a hashtable and the LttvBdevState structures its values
1453 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1455 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1456 g_hash_table_destroy(ht
);
1459 /* The saved state for each trace contains a member "processes", which
1460 stores a copy of the process table, and a member "tracefiles" with
1461 one entry per tracefile. Each tracefile has a "process" member pointing
1462 to the current process and a "position" member storing the tracefile
1463 position (needed to seek to the current "next" event. */
1465 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1467 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1469 LttvTracefileState
*tfcs
;
1471 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1473 guint
*running_process
;
1475 LttvAttributeValue value
;
1477 LttEventPosition
*ep
;
1479 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1480 LTTV_STATE_TRACEFILES
);
1482 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1484 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1486 /* Add the currently running processes array */
1487 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1488 running_process
= g_new(guint
, nb_cpus
);
1489 for(i
=0;i
<nb_cpus
;i
++) {
1490 running_process
[i
] = self
->running_process
[i
]->pid
;
1492 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1494 *(value
.v_pointer
) = running_process
;
1496 g_info("State save");
1498 nb_tracefile
= self
->parent
.tracefiles
->len
;
1500 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1502 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1503 LttvTracefileContext
*, i
));
1504 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1505 value
= lttv_attribute_add(tracefiles_tree
, i
,
1507 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1509 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1511 *(value
.v_uint
) = tfcs
->process
->pid
;
1513 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1515 /* Only save the position if the tfs has not infinite time. */
1516 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1517 // && current_tfcs != tfcs) {
1518 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1519 *(value
.v_pointer
) = NULL
;
1521 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1522 ep
= ltt_event_position_new();
1523 ltt_event_position(e
, ep
);
1524 *(value
.v_pointer
) = ep
;
1526 guint nb_block
, offset
;
1529 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1530 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1532 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1536 /* save the cpu state */
1538 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1540 *(value
.v_uint
) = nb_cpus
;
1542 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1544 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1547 /* save the irq state */
1548 nb_irqs
= self
->nb_irqs
;
1550 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1552 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1555 /* save the soft irq state */
1556 nb_soft_irqs
= self
->nb_soft_irqs
;
1558 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1560 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1563 /* save the trap state */
1564 nb_traps
= self
->nb_traps
;
1566 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1568 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1571 /* save the blkdev states */
1572 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1574 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1578 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1580 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1582 LttvTracefileState
*tfcs
;
1584 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1586 guint
*running_process
;
1588 LttvAttributeType type
;
1590 LttvAttributeValue value
;
1592 LttvAttributeName name
;
1596 LttEventPosition
*ep
;
1598 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1600 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1601 LTTV_STATE_TRACEFILES
);
1603 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1605 g_assert(type
== LTTV_POINTER
);
1606 lttv_state_free_process_table(self
->processes
);
1607 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1609 /* Add the currently running processes array */
1610 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1611 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1613 g_assert(type
== LTTV_POINTER
);
1614 running_process
= *(value
.v_pointer
);
1615 for(i
=0;i
<nb_cpus
;i
++) {
1616 pid
= running_process
[i
];
1617 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1618 g_assert(self
->running_process
[i
] != NULL
);
1621 nb_tracefile
= self
->parent
.tracefiles
->len
;
1623 //g_tree_destroy(tsc->pqueue);
1624 //tsc->pqueue = g_tree_new(compare_tracefile);
1626 /* restore cpu resource states */
1627 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1628 g_assert(type
== LTTV_POINTER
);
1629 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1630 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1632 /* restore irq resource states */
1633 nb_irqs
= self
->nb_irqs
;
1634 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1635 g_assert(type
== LTTV_POINTER
);
1636 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1637 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1639 /* restore soft irq resource states */
1640 nb_soft_irqs
= self
->nb_soft_irqs
;
1641 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1642 g_assert(type
== LTTV_POINTER
);
1643 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1644 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1646 /* restore trap resource states */
1647 nb_traps
= self
->nb_traps
;
1648 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1649 g_assert(type
== LTTV_POINTER
);
1650 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1651 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1653 /* restore the blkdev states */
1654 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1655 g_assert(type
== LTTV_POINTER
);
1656 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1657 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1659 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1661 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1662 LttvTracefileContext
*, i
));
1663 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1664 g_assert(type
== LTTV_GOBJECT
);
1665 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1667 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1669 g_assert(type
== LTTV_UINT
);
1670 pid
= *(value
.v_uint
);
1671 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1673 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1675 g_assert(type
== LTTV_POINTER
);
1676 //g_assert(*(value.v_pointer) != NULL);
1677 ep
= *(value
.v_pointer
);
1678 g_assert(tfcs
->parent
.t_context
!= NULL
);
1680 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1682 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1683 g_tree_remove(tsc
->pqueue
, tfc
);
1686 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1687 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1688 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1689 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1690 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1692 tfc
->timestamp
= ltt_time_infinite
;
1698 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1700 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1702 LttvTracefileState
*tfcs
;
1704 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1706 guint
*running_process
;
1708 LttvAttributeType type
;
1710 LttvAttributeValue value
;
1712 LttvAttributeName name
;
1716 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1717 LTTV_STATE_TRACEFILES
);
1718 g_object_ref(G_OBJECT(tracefiles_tree
));
1719 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1721 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1723 g_assert(type
== LTTV_POINTER
);
1724 lttv_state_free_process_table(*(value
.v_pointer
));
1725 *(value
.v_pointer
) = NULL
;
1726 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1728 /* Free running processes array */
1729 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1731 g_assert(type
== LTTV_POINTER
);
1732 running_process
= *(value
.v_pointer
);
1733 g_free(running_process
);
1735 /* free cpu resource states */
1736 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1737 g_assert(type
== LTTV_UINT
);
1738 nb_cpus
= *value
.v_uint
;
1739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1740 g_assert(type
== LTTV_POINTER
);
1741 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1743 /* free irq resource states */
1744 nb_irqs
= self
->nb_irqs
;
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1746 g_assert(type
== LTTV_POINTER
);
1747 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1749 /* free softirq resource states */
1750 nb_softirqs
= self
->nb_irqs
;
1751 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1752 g_assert(type
== LTTV_POINTER
);
1753 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1755 /* free the blkdev states */
1756 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1757 g_assert(type
== LTTV_POINTER
);
1758 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1760 nb_tracefile
= self
->parent
.tracefiles
->len
;
1762 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1764 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1765 LttvTracefileContext
*, i
));
1766 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1767 g_assert(type
== LTTV_GOBJECT
);
1768 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1770 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1772 g_assert(type
== LTTV_POINTER
);
1773 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1775 g_object_unref(G_OBJECT(tracefiles_tree
));
1779 static void free_saved_state(LttvTraceState
*self
)
1783 LttvAttributeType type
;
1785 LttvAttributeValue value
;
1787 LttvAttributeName name
;
1791 LttvAttribute
*saved_states
;
1793 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1794 LTTV_STATE_SAVED_STATES
);
1796 nb
= lttv_attribute_get_number(saved_states
);
1797 for(i
= 0 ; i
< nb
; i
++) {
1798 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1799 g_assert(type
== LTTV_GOBJECT
);
1800 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1803 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1808 create_max_time(LttvTraceState
*tcs
)
1810 LttvAttributeValue v
;
1812 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1814 g_assert(*(v
.v_pointer
) == NULL
);
1815 *(v
.v_pointer
) = g_new(LttTime
,1);
1816 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1821 get_max_time(LttvTraceState
*tcs
)
1823 LttvAttributeValue v
;
1825 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1827 g_assert(*(v
.v_pointer
) != NULL
);
1828 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1833 free_max_time(LttvTraceState
*tcs
)
1835 LttvAttributeValue v
;
1837 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1839 g_free(*(v
.v_pointer
));
1840 *(v
.v_pointer
) = NULL
;
1844 typedef struct _LttvNameTables
{
1845 // FIXME GQuark *eventtype_names;
1846 GQuark
*syscall_names
;
1852 GQuark
*soft_irq_names
;
1858 create_name_tables(LttvTraceState
*tcs
)
1862 GString
*fe_name
= g_string_new("");
1864 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1866 LttvAttributeValue v
;
1870 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1872 g_assert(*(v
.v_pointer
) == NULL
);
1873 *(v
.v_pointer
) = name_tables
;
1875 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1877 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1878 LTT_FACILITY_KERNEL
,
1879 LTT_EVENT_SYSCALL_ENTRY
,
1880 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1881 NULL
, NULL
, &hooks
)) {
1883 // th = lttv_trace_hook_get_first(&th);
1885 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1886 // nb = ltt_type_element_number(t);
1888 // name_tables->syscall_names = g_new(GQuark, nb);
1889 // name_tables->nb_syscalls = nb;
1891 // for(i = 0 ; i < nb ; i++) {
1892 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1893 // if(!name_tables->syscall_names[i]) {
1894 // GString *string = g_string_new("");
1895 // g_string_printf(string, "syscall %u", i);
1896 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1897 // g_string_free(string, TRUE);
1901 name_tables
->nb_syscalls
= 256;
1902 name_tables
->syscall_names
= g_new(GQuark
, 256);
1903 for(i
= 0 ; i
< 256 ; i
++) {
1904 g_string_printf(fe_name
, "syscall %d", i
);
1905 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1908 name_tables
->syscall_names
= NULL
;
1909 name_tables
->nb_syscalls
= 0;
1911 lttv_trace_hook_remove_all(&hooks
);
1913 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1914 LTT_FACILITY_KERNEL
,
1915 LTT_EVENT_TRAP_ENTRY
,
1916 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1917 NULL
, NULL
, &hooks
)) {
1919 // th = lttv_trace_hook_get_first(&th);
1921 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1922 // //nb = ltt_type_element_number(t);
1924 // name_tables->trap_names = g_new(GQuark, nb);
1925 // for(i = 0 ; i < nb ; i++) {
1926 // name_tables->trap_names[i] = g_quark_from_string(
1927 // ltt_enum_string_get(t, i));
1930 name_tables
->nb_traps
= 256;
1931 name_tables
->trap_names
= g_new(GQuark
, 256);
1932 for(i
= 0 ; i
< 256 ; i
++) {
1933 g_string_printf(fe_name
, "trap %d", i
);
1934 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1937 name_tables
->trap_names
= NULL
;
1938 name_tables
->nb_traps
= 0;
1940 lttv_trace_hook_remove_all(&hooks
);
1942 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1943 LTT_FACILITY_KERNEL
,
1944 LTT_EVENT_IRQ_ENTRY
,
1945 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1946 NULL
, NULL
, &hooks
)) {
1949 name_tables->irq_names = g_new(GQuark, nb);
1950 for(i = 0 ; i < nb ; i++) {
1951 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1955 name_tables
->nb_irqs
= 256;
1956 name_tables
->irq_names
= g_new(GQuark
, 256);
1957 for(i
= 0 ; i
< 256 ; i
++) {
1958 g_string_printf(fe_name
, "irq %d", i
);
1959 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1962 name_tables
->nb_irqs
= 0;
1963 name_tables
->irq_names
= NULL
;
1965 lttv_trace_hook_remove_all(&hooks
);
1967 name_tables->soft_irq_names = g_new(GQuark, nb);
1968 for(i = 0 ; i < nb ; i++) {
1969 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1973 /* the kernel is limited to 32 statically defined softirqs */
1974 name_tables
->nb_softirqs
= 32;
1975 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1976 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1977 g_string_printf(fe_name
, "softirq %d", i
);
1978 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1980 g_array_free(hooks
, TRUE
);
1982 g_string_free(fe_name
, TRUE
);
1987 get_name_tables(LttvTraceState
*tcs
)
1989 LttvNameTables
*name_tables
;
1991 LttvAttributeValue v
;
1993 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1995 g_assert(*(v
.v_pointer
) != NULL
);
1996 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1997 //tcs->eventtype_names = name_tables->eventtype_names;
1998 tcs
->syscall_names
= name_tables
->syscall_names
;
1999 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
2000 tcs
->trap_names
= name_tables
->trap_names
;
2001 tcs
->nb_traps
= name_tables
->nb_traps
;
2002 tcs
->irq_names
= name_tables
->irq_names
;
2003 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
2004 tcs
->nb_irqs
= name_tables
->nb_irqs
;
2005 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2010 free_name_tables(LttvTraceState
*tcs
)
2012 LttvNameTables
*name_tables
;
2014 LttvAttributeValue v
;
2016 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2018 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2019 *(v
.v_pointer
) = NULL
;
2021 // g_free(name_tables->eventtype_names);
2022 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2023 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2024 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2025 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2026 if(name_tables
) g_free(name_tables
);
2029 #ifdef HASH_TABLE_DEBUG
2031 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2033 LttvProcessState
*process
= (LttvProcessState
*)value
;
2035 /* Test for process corruption */
2036 guint stack_len
= process
->execution_stack
->len
;
2039 static void hash_table_check(GHashTable
*table
)
2041 g_hash_table_foreach(table
, test_process
, NULL
);
2047 /* clears the stack and sets the state passed as argument */
2048 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2050 g_array_set_size(cpust
->mode_stack
, 1);
2051 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2054 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2056 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2057 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2060 static void cpu_pop_mode(LttvCPUState
*cpust
)
2062 if(cpust
->mode_stack
->len
<= 1)
2063 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2065 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2068 /* clears the stack and sets the state passed as argument */
2069 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2071 g_array_set_size(bdevst
->mode_stack
, 1);
2072 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2075 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2077 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2078 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2081 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2083 if(bdevst
->mode_stack
->len
<= 1)
2084 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2086 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2089 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2091 g_array_set_size(irqst
->mode_stack
, 1);
2092 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2095 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2097 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2098 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2101 static void irq_pop_mode(LttvIRQState
*irqst
)
2103 if(irqst
->mode_stack
->len
<= 1)
2104 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2106 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2109 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2112 LttvExecutionState
*es
;
2114 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2115 guint cpu
= tfs
->cpu
;
2117 #ifdef HASH_TABLE_DEBUG
2118 hash_table_check(ts
->processes
);
2120 LttvProcessState
*process
= ts
->running_process
[cpu
];
2122 guint depth
= process
->execution_stack
->len
;
2124 process
->execution_stack
=
2125 g_array_set_size(process
->execution_stack
, depth
+ 1);
2128 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2130 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2133 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2134 es
->cum_cpu_time
= ltt_time_zero
;
2135 es
->s
= process
->state
->s
;
2136 process
->state
= es
;
2140 * return 1 when empty, else 0 */
2141 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2142 LttvTracefileState
*tfs
)
2144 guint depth
= process
->execution_stack
->len
;
2150 process
->execution_stack
=
2151 g_array_set_size(process
->execution_stack
, depth
- 1);
2152 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2154 process
->state
->change
= tfs
->parent
.timestamp
;
2159 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2161 guint cpu
= tfs
->cpu
;
2162 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2163 LttvProcessState
*process
= ts
->running_process
[cpu
];
2165 guint depth
= process
->execution_stack
->len
;
2167 if(process
->state
->t
!= t
){
2168 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2169 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2170 g_info("process state has %s when pop_int is %s\n",
2171 g_quark_to_string(process
->state
->t
),
2172 g_quark_to_string(t
));
2173 g_info("{ %u, %u, %s, %s, %s }\n",
2176 g_quark_to_string(process
->name
),
2177 g_quark_to_string(process
->brand
),
2178 g_quark_to_string(process
->state
->s
));
2183 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2184 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2188 process
->execution_stack
=
2189 g_array_set_size(process
->execution_stack
, depth
- 1);
2190 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2192 process
->state
->change
= tfs
->parent
.timestamp
;
2195 struct search_result
{
2196 const LttTime
*time
; /* Requested time */
2197 LttTime
*best
; /* Best result */
2200 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2202 const LttTime
*elem_time
= (const LttTime
*)a
;
2203 /* Explicit non const cast */
2204 struct search_result
*res
= (struct search_result
*)b
;
2206 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2207 /* The usertrace was created before the schedchange */
2208 /* Get larger keys */
2210 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2211 /* The usertrace was created after the schedchange time */
2212 /* Get smaller keys */
2214 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2215 res
->best
= (LttTime
*)elem_time
;
2218 res
->best
= (LttTime
*)elem_time
;
2225 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2226 guint pid
, const LttTime
*timestamp
)
2228 LttvTracefileState
*tfs
= NULL
;
2229 struct search_result res
;
2230 /* Find the usertrace associated with a pid and time interval.
2231 * Search in the usertraces by PID (within a hash) and then, for each
2232 * corresponding element of the array, find the first one with creation
2233 * timestamp the lowest, but higher or equal to "timestamp". */
2234 res
.time
= timestamp
;
2236 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2237 if(usertrace_tree
) {
2238 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2240 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2248 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2249 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2251 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2253 LttvExecutionState
*es
;
2258 process
->tgid
= tgid
;
2260 process
->name
= name
;
2261 process
->brand
= LTTV_STATE_UNBRANDED
;
2262 //process->last_cpu = tfs->cpu_name;
2263 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2264 process
->type
= LTTV_STATE_USER_THREAD
;
2265 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2266 process
->current_function
= 0; //function 0x0 by default.
2268 g_info("Process %u, core %p", process
->pid
, process
);
2269 g_hash_table_insert(tcs
->processes
, process
, process
);
2272 process
->ppid
= parent
->pid
;
2273 process
->creation_time
= *timestamp
;
2276 /* No parent. This process exists but we are missing all information about
2277 its creation. The birth time is set to zero but we remember the time of
2282 process
->creation_time
= ltt_time_zero
;
2285 process
->insertion_time
= *timestamp
;
2286 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2287 process
->creation_time
.tv_nsec
);
2288 process
->pid_time
= g_quark_from_string(buffer
);
2290 process
->free_events
= 0;
2291 //process->last_cpu = tfs->cpu_name;
2292 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2293 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2294 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2295 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2296 es
= process
->state
= &g_array_index(process
->execution_stack
,
2297 LttvExecutionState
, 0);
2298 es
->t
= LTTV_STATE_USER_MODE
;
2299 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2300 es
->entry
= *timestamp
;
2301 //g_assert(timestamp->tv_sec != 0);
2302 es
->change
= *timestamp
;
2303 es
->cum_cpu_time
= ltt_time_zero
;
2304 es
->s
= LTTV_STATE_RUN
;
2306 es
= process
->state
= &g_array_index(process
->execution_stack
,
2307 LttvExecutionState
, 1);
2308 es
->t
= LTTV_STATE_SYSCALL
;
2309 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2310 es
->entry
= *timestamp
;
2311 //g_assert(timestamp->tv_sec != 0);
2312 es
->change
= *timestamp
;
2313 es
->cum_cpu_time
= ltt_time_zero
;
2314 es
->s
= LTTV_STATE_WAIT_FORK
;
2316 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2317 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2318 sizeof(guint64
), 0);
2323 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2326 LttvProcessState key
;
2327 LttvProcessState
*process
;
2331 process
= g_hash_table_lookup(ts
->processes
, &key
);
2336 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2337 const LttTime
*timestamp
)
2339 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2340 LttvExecutionState
*es
;
2342 /* Put ltt_time_zero creation time for unexisting processes */
2343 if(unlikely(process
== NULL
)) {
2344 process
= lttv_state_create_process(ts
,
2345 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2346 /* We are not sure is it's a kernel thread or normal thread, put the
2347 * bottom stack state to unknown */
2348 process
->execution_stack
=
2349 g_array_set_size(process
->execution_stack
, 1);
2350 process
->state
= es
=
2351 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2352 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2353 es
->s
= LTTV_STATE_UNNAMED
;
2358 /* FIXME : this function should be called when we receive an event telling that
2359 * release_task has been called in the kernel. In happens generally when
2360 * the parent waits for its child terminaison, but may also happen in special
2361 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2362 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2363 * of a killed thread group, but isn't the leader.
2365 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2367 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2368 LttvProcessState key
;
2370 /* Wait for both schedule with exit dead and process free to happen.
2371 * They can happen in any order. */
2372 if (++(process
->free_events
) < 2)
2375 key
.pid
= process
->pid
;
2376 key
.cpu
= process
->cpu
;
2377 g_hash_table_remove(ts
->processes
, &key
);
2378 g_array_free(process
->execution_stack
, TRUE
);
2379 g_array_free(process
->user_stack
, TRUE
);
2385 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2387 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2388 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2393 static void lttv_state_free_process_table(GHashTable
*processes
)
2395 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2396 g_hash_table_destroy(processes
);
2400 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2402 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2404 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2405 LttvProcessState
*process
= ts
->running_process
[cpu
];
2406 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2407 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2408 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2409 LttvExecutionSubmode submode
;
2411 guint syscall
= ltt_event_get_unsigned(e
, f
);
2412 expand_syscall_table(ts
, syscall
);
2413 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2414 /* There can be no system call from PID 0 : unknown state */
2415 if(process
->pid
!= 0)
2416 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2421 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2423 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2425 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2426 LttvProcessState
*process
= ts
->running_process
[cpu
];
2428 /* There can be no system call from PID 0 : unknown state */
2429 if(process
->pid
!= 0)
2430 pop_state(s
, LTTV_STATE_SYSCALL
);
2435 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2437 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2438 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2439 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2440 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2441 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2443 LttvExecutionSubmode submode
;
2445 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2447 expand_trap_table(ts
, trap
);
2449 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2451 push_state(s
, LTTV_STATE_TRAP
, submode
);
2453 /* update cpu status */
2454 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2456 /* update trap status */
2457 s
->cpu_state
->last_trap
= trap
;
2458 ts
->trap_states
[trap
].running
++;
2463 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2465 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2466 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2467 gint trap
= s
->cpu_state
->last_trap
;
2469 pop_state(s
, LTTV_STATE_TRAP
);
2471 /* update cpu status */
2472 cpu_pop_mode(s
->cpu_state
);
2474 /* update trap status */
2476 if(ts
->trap_states
[trap
].running
)
2477 ts
->trap_states
[trap
].running
--;
2482 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2484 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2485 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2486 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2487 //guint8 ev_id = ltt_event_eventtype_id(e);
2488 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2489 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2491 LttvExecutionSubmode submode
;
2492 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2494 expand_irq_table(ts
, irq
);
2496 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2498 /* Do something with the info about being in user or system mode when int? */
2499 push_state(s
, LTTV_STATE_IRQ
, submode
);
2501 /* update cpu status */
2502 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2504 /* update irq status */
2505 s
->cpu_state
->last_irq
= irq
;
2506 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2511 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2513 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2514 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2515 gint softirq
= s
->cpu_state
->last_soft_irq
;
2517 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2519 /* update softirq status */
2521 if(ts
->soft_irq_states
[softirq
].running
)
2522 ts
->soft_irq_states
[softirq
].running
--;
2524 /* update cpu status */
2525 cpu_pop_mode(s
->cpu_state
);
2530 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2532 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2533 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2535 pop_state(s
, LTTV_STATE_IRQ
);
2537 /* update cpu status */
2538 cpu_pop_mode(s
->cpu_state
);
2540 /* update irq status */
2541 if (s
->cpu_state
->last_irq
!= -1)
2542 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2547 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2549 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2550 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2551 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2552 //guint8 ev_id = ltt_event_eventtype_id(e);
2553 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2554 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2556 LttvExecutionSubmode submode
;
2557 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2558 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2560 if(softirq
< nb_softirqs
) {
2561 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2563 /* Fixup an incomplete irq table */
2564 GString
*string
= g_string_new("");
2565 g_string_printf(string
, "softirq %llu", softirq
);
2566 submode
= g_quark_from_string(string
->str
);
2567 g_string_free(string
, TRUE
);
2570 /* update softirq status */
2571 /* a soft irq raises are not cumulative */
2572 ts
->soft_irq_states
[softirq
].pending
=1;
2577 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2579 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2580 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2581 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2582 //guint8 ev_id = ltt_event_eventtype_id(e);
2583 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2584 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2585 LttvExecutionSubmode submode
;
2586 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2587 expand_soft_irq_table(ts
, softirq
);
2588 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2590 /* Do something with the info about being in user or system mode when int? */
2591 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2593 /* update cpu status */
2594 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2596 /* update softirq status */
2597 s
->cpu_state
->last_soft_irq
= softirq
;
2598 if(ts
->soft_irq_states
[softirq
].pending
)
2599 ts
->soft_irq_states
[softirq
].pending
--;
2600 ts
->soft_irq_states
[softirq
].running
++;
2605 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2607 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2608 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2609 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2610 //guint8 ev_id = ltt_event_eventtype_id(e);
2611 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2613 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2614 lttv_trace_get_hook_field(th
, 0)));
2615 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2617 expand_irq_table(ts
, irq
);
2618 ts
->irq_names
[irq
] = action
;
2624 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2626 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2627 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2628 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2629 //guint8 ev_id = ltt_event_eventtype_id(e);
2630 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2632 guint major
= ltt_event_get_long_unsigned(e
,
2633 lttv_trace_get_hook_field(th
, 0));
2634 guint minor
= ltt_event_get_long_unsigned(e
,
2635 lttv_trace_get_hook_field(th
, 1));
2636 guint oper
= ltt_event_get_long_unsigned(e
,
2637 lttv_trace_get_hook_field(th
, 2));
2638 guint16 devcode
= MKDEV(major
,minor
);
2640 /* have we seen this block device before? */
2641 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2644 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2646 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2651 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2653 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2654 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2655 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2656 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2658 guint major
= ltt_event_get_long_unsigned(e
,
2659 lttv_trace_get_hook_field(th
, 0));
2660 guint minor
= ltt_event_get_long_unsigned(e
,
2661 lttv_trace_get_hook_field(th
, 1));
2662 //guint oper = ltt_event_get_long_unsigned(e,
2663 // lttv_trace_get_hook_field(th, 2));
2664 guint16 devcode
= MKDEV(major
,minor
);
2666 /* have we seen this block device before? */
2667 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2669 /* update block device */
2670 bdev_pop_mode(bdev
);
2675 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2679 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2680 guint cpu
= tfs
->cpu
;
2681 LttvProcessState
*process
= ts
->running_process
[cpu
];
2683 guint depth
= process
->user_stack
->len
;
2685 process
->user_stack
=
2686 g_array_set_size(process
->user_stack
, depth
+ 1);
2688 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2689 *new_func
= funcptr
;
2690 process
->current_function
= funcptr
;
2693 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2695 guint cpu
= tfs
->cpu
;
2696 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2697 LttvProcessState
*process
= ts
->running_process
[cpu
];
2699 if(process
->current_function
!= funcptr
){
2700 g_info("Different functions (%lu.%09lu): ignore it\n",
2701 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2702 g_info("process state has %llu when pop_function is %llu\n",
2703 process
->current_function
, funcptr
);
2704 g_info("{ %u, %u, %s, %s, %s }\n",
2707 g_quark_to_string(process
->name
),
2708 g_quark_to_string(process
->brand
),
2709 g_quark_to_string(process
->state
->s
));
2712 guint depth
= process
->user_stack
->len
;
2715 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2716 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2720 process
->user_stack
=
2721 g_array_set_size(process
->user_stack
, depth
- 1);
2722 process
->current_function
=
2723 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2727 static gboolean
function_entry(void *hook_data
, void *call_data
)
2729 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2730 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2731 //guint8 ev_id = ltt_event_eventtype_id(e);
2732 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2733 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2734 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2736 push_function(s
, funcptr
);
2740 static gboolean
function_exit(void *hook_data
, void *call_data
)
2742 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2743 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2744 //guint8 ev_id = ltt_event_eventtype_id(e);
2745 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2746 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2747 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2749 pop_function(s
, funcptr
);
2753 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2755 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2756 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2757 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2758 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2763 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2764 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2765 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2767 expand_syscall_table(ts
, id
);
2768 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2773 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2775 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2776 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2777 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2778 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2783 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2784 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2785 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2787 expand_soft_irq_table(ts
, id
);
2788 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2793 static gboolean
schedchange(void *hook_data
, void *call_data
)
2795 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2797 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2798 LttvProcessState
*process
= ts
->running_process
[cpu
];
2799 //LttvProcessState *old_process = ts->running_process[cpu];
2801 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2802 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2803 guint pid_in
, pid_out
;
2806 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2807 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2808 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
;
2900 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2903 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2904 s
->parent
.target_pid
= child_pid
;
2907 f
= lttv_trace_get_hook_field(th
, 2);
2909 child_tgid
= ltt_event_get_unsigned(e
, f
);
2913 /* Mathieu : it seems like the process might have been scheduled in before the
2914 * fork, and, in a rare case, might be the current process. This might happen
2915 * in a SMP case where we don't have enough precision on the clocks.
2917 * Test reenabled after precision fixes on time. (Mathieu) */
2919 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2921 if(unlikely(zombie_process
!= NULL
)) {
2922 /* Reutilisation of PID. Only now we are sure that the old PID
2923 * has been released. FIXME : should know when release_task happens instead.
2925 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2927 for(i
=0; i
< num_cpus
; i
++) {
2928 g_assert(zombie_process
!= ts
->running_process
[i
]);
2931 exit_process(s
, zombie_process
);
2934 g_assert(process
->pid
!= child_pid
);
2935 // FIXME : Add this test in the "known state" section
2936 // g_assert(process->pid == parent_pid);
2937 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2938 if(child_process
== NULL
) {
2939 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2940 child_pid
, child_tgid
,
2941 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2943 /* The process has already been created : due to time imprecision between
2944 * multiple CPUs : it has been scheduled in before creation. Note that we
2945 * shouldn't have this kind of imprecision.
2947 * Simply put a correct parent.
2949 g_error("Process %u has been created at [%lu.%09lu] before \n"
2950 "fork on cpu %u[%lu.%09lu].\n"
2951 "Probably an unsynchronized TSC problem on the traced machine.",
2953 child_process
->creation_time
.tv_sec
,
2954 child_process
->creation_time
.tv_nsec
,
2955 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
2956 //g_assert(0); /* This is a problematic case : the process has been created
2957 // before the fork event */
2958 child_process
->ppid
= process
->pid
;
2959 child_process
->tgid
= child_tgid
;
2961 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2962 child_process
->name
= process
->name
;
2963 child_process
->brand
= process
->brand
;
2968 /* We stamp a newly created process as kernel_thread.
2969 * The thread should not be running yet. */
2970 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2972 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2973 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2974 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2976 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2977 LttvProcessState
*process
;
2978 LttvExecutionState
*es
;
2981 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2982 s
->parent
.target_pid
= pid
;
2984 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2986 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2987 process
->execution_stack
=
2988 g_array_set_size(process
->execution_stack
, 1);
2989 es
= process
->state
=
2990 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2991 es
->t
= LTTV_STATE_SYSCALL
;
2993 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2998 static gboolean
process_exit(void *hook_data
, void *call_data
)
3000 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3001 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3002 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3004 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3005 LttvProcessState
*process
; // = ts->running_process[cpu];
3007 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3008 s
->parent
.target_pid
= pid
;
3010 // FIXME : Add this test in the "known state" section
3011 // g_assert(process->pid == pid);
3013 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3014 if(likely(process
!= NULL
)) {
3015 process
->state
->s
= LTTV_STATE_EXIT
;
3020 static gboolean
process_free(void *hook_data
, void *call_data
)
3022 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3023 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3024 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3025 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3027 LttvProcessState
*process
;
3029 /* PID of the process to release */
3030 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3031 s
->parent
.target_pid
= release_pid
;
3033 g_assert(release_pid
!= 0);
3035 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3036 if(likely(process
!= NULL
))
3037 exit_process(s
, process
);
3040 if(likely(process
!= NULL
)) {
3041 /* release_task is happening at kernel level : we can now safely release
3042 * the data structure of the process */
3043 //This test is fun, though, as it may happen that
3044 //at time t : CPU 0 : process_free
3045 //at time t+150ns : CPU 1 : schedule out
3046 //Clearly due to time imprecision, we disable it. (Mathieu)
3047 //If this weird case happen, we have no choice but to put the
3048 //Currently running process on the cpu to 0.
3049 //I re-enable it following time precision fixes. (Mathieu)
3050 //Well, in the case where an process is freed by a process on another CPU
3051 //and still scheduled, it happens that this is the schedchange that will
3052 //drop the last reference count. Do not free it here!
3053 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3055 for(i
=0; i
< num_cpus
; i
++) {
3056 //g_assert(process != ts->running_process[i]);
3057 if(process
== ts
->running_process
[i
]) {
3058 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3062 if(i
== num_cpus
) /* process is not scheduled */
3063 exit_process(s
, process
);
3070 static gboolean
process_exec(void *hook_data
, void *call_data
)
3072 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3073 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3074 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3075 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3078 LttvProcessState
*process
= ts
->running_process
[cpu
];
3080 #if 0//how to use a sequence that must be transformed in a string
3081 /* PID of the process to release */
3082 guint64 name_len
= ltt_event_field_element_number(e
,
3083 lttv_trace_get_hook_field(th
, 0));
3084 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3085 LttField
*child
= ltt_event_field_element_select(e
,
3086 lttv_trace_get_hook_field(th
, 0), 0);
3088 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3089 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3090 memcpy(null_term_name
, name_begin
, name_len
);
3091 null_term_name
[name_len
] = '\0';
3092 process
->name
= g_quark_from_string(null_term_name
);
3095 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3096 lttv_trace_get_hook_field(th
, 0)));
3097 process
->brand
= LTTV_STATE_UNBRANDED
;
3098 //g_free(null_term_name);
3102 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3104 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3105 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3106 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3107 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3110 LttvProcessState
*process
= ts
->running_process
[cpu
];
3112 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3113 process
->brand
= g_quark_from_string(name
);
3118 static void fix_process(gpointer key
, gpointer value
,
3121 LttvProcessState
*process
;
3122 LttvExecutionState
*es
;
3123 process
= (LttvProcessState
*)value
;
3124 LttTime
*timestamp
= (LttTime
*)user_data
;
3126 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3127 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3128 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3129 es
->t
= LTTV_STATE_SYSCALL
;
3130 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3131 es
->entry
= *timestamp
;
3132 es
->change
= *timestamp
;
3133 es
->cum_cpu_time
= ltt_time_zero
;
3134 if(es
->s
== LTTV_STATE_UNNAMED
)
3135 es
->s
= LTTV_STATE_WAIT
;
3138 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3139 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3140 es
->t
= LTTV_STATE_USER_MODE
;
3141 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3142 es
->entry
= *timestamp
;
3143 //g_assert(timestamp->tv_sec != 0);
3144 es
->change
= *timestamp
;
3145 es
->cum_cpu_time
= ltt_time_zero
;
3146 if(es
->s
== LTTV_STATE_UNNAMED
)
3147 es
->s
= LTTV_STATE_RUN
;
3149 if(process
->execution_stack
->len
== 1) {
3150 /* Still in bottom unknown mode, means never did a system call
3151 * May be either in user mode, syscall mode, running or waiting.*/
3152 /* FIXME : we may be tagging syscall mode when being user mode */
3153 process
->execution_stack
=
3154 g_array_set_size(process
->execution_stack
, 2);
3155 es
= process
->state
= &g_array_index(process
->execution_stack
,
3156 LttvExecutionState
, 1);
3157 es
->t
= LTTV_STATE_SYSCALL
;
3158 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3159 es
->entry
= *timestamp
;
3160 //g_assert(timestamp->tv_sec != 0);
3161 es
->change
= *timestamp
;
3162 es
->cum_cpu_time
= ltt_time_zero
;
3163 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3164 es
->s
= LTTV_STATE_WAIT
;
3170 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3172 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3173 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3174 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3175 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3176 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3178 /* For all processes */
3179 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3180 /* else, if stack[0] is unknown, set to user mode, running */
3182 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3187 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3189 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3190 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3191 //It's slow : optimise later by doing this before reading trace.
3192 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3198 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3199 LttvProcessState
*process
= ts
->running_process
[cpu
];
3200 LttvProcessState
*parent_process
;
3201 struct marker_field
*f
;
3202 GQuark type
, mode
, submode
, status
;
3203 LttvExecutionState
*es
;
3207 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3208 s
->parent
.target_pid
= pid
;
3211 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3214 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3217 f
= lttv_trace_get_hook_field(th
, 3);
3218 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3220 //FIXME: type is rarely used, enum must match possible types.
3223 f
= lttv_trace_get_hook_field(th
, 4);
3224 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3227 f
= lttv_trace_get_hook_field(th
, 5);
3228 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3231 f
= lttv_trace_get_hook_field(th
, 6);
3232 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3235 f
= lttv_trace_get_hook_field(th
, 7);
3237 tgid
= ltt_event_get_unsigned(e
, f
);
3242 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3243 for(i
=0; i
<nb_cpus
; i
++) {
3244 process
= lttv_state_find_process(ts
, i
, pid
);
3245 g_assert(process
!= NULL
);
3247 process
->ppid
= parent_pid
;
3248 process
->tgid
= tgid
;
3249 process
->name
= g_quark_from_string(command
);
3251 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3252 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3256 /* The process might exist if a process was forked while performing the
3258 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3259 if(process
== NULL
) {
3260 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3261 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3262 pid
, tgid
, g_quark_from_string(command
),
3263 &s
->parent
.timestamp
);
3265 /* Keep the stack bottom : a running user mode */
3266 /* Disabled because of inconsistencies in the current statedump states. */
3267 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3268 /* Only keep the bottom
3269 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3270 /* Will cause expected trap when in fact being syscall (even after end of
3272 * Will cause expected interrupt when being syscall. (only before end of
3273 * statedump event) */
3274 // This will cause a "popping last state on stack, ignoring it."
3275 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3276 es
= process
->state
= &g_array_index(process
->execution_stack
,
3277 LttvExecutionState
, 0);
3278 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3279 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3280 es
->s
= LTTV_STATE_UNNAMED
;
3281 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3283 es
->t
= LTTV_STATE_SYSCALL
;
3288 /* User space process :
3289 * bottom : user mode
3290 * either currently running or scheduled out.
3291 * can be scheduled out because interrupted in (user mode or in syscall)
3292 * or because of an explicit call to the scheduler in syscall. Note that
3293 * the scheduler call comes after the irq_exit, so never in interrupt
3295 // temp workaround : set size to 1 : only have user mode bottom of stack.
3296 // will cause g_info message of expected syscall mode when in fact being
3297 // in user mode. Can also cause expected trap when in fact being user
3298 // mode in the event of a page fault reenabling interrupts in the handler.
3299 // Expected syscall and trap can also happen after the end of statedump
3300 // This will cause a "popping last state on stack, ignoring it."
3301 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3302 es
= process
->state
= &g_array_index(process
->execution_stack
,
3303 LttvExecutionState
, 0);
3304 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3305 es
->s
= LTTV_STATE_UNNAMED
;
3306 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3308 es
->t
= LTTV_STATE_USER_MODE
;
3316 es
= process
->state
= &g_array_index(process
->execution_stack
,
3317 LttvExecutionState
, 1);
3318 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3319 es
->s
= LTTV_STATE_UNNAMED
;
3320 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3324 /* The process has already been created :
3325 * Probably was forked while dumping the process state or
3326 * was simply scheduled in prior to get the state dump event.
3328 process
->ppid
= parent_pid
;
3329 process
->tgid
= tgid
;
3330 process
->name
= g_quark_from_string(command
);
3331 process
->type
= type
;
3333 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3335 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3336 if(type
== LTTV_STATE_KERNEL_THREAD
)
3337 es
->t
= LTTV_STATE_SYSCALL
;
3339 es
->t
= LTTV_STATE_USER_MODE
;
3342 /* Don't mess around with the stack, it will eventually become
3343 * ok after the end of state dump. */
3350 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3352 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3354 lttv_state_add_event_hooks(tss
);
3359 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3361 LttvTraceset
*traceset
= self
->parent
.ts
;
3363 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3367 LttvTracefileState
*tfs
;
3373 LttvAttributeValue val
;
3375 nb_trace
= lttv_traceset_number(traceset
);
3376 for(i
= 0 ; i
< nb_trace
; i
++) {
3377 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3379 /* Find the eventtype id for the following events and register the
3380 associated by id hooks. */
3382 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3383 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3386 lttv_trace_find_hook(ts
->parent
.t
,
3387 LTT_FACILITY_KERNEL
,
3388 LTT_EVENT_SYSCALL_ENTRY
,
3389 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3390 syscall_entry
, NULL
, &hooks
);
3392 lttv_trace_find_hook(ts
->parent
.t
,
3393 LTT_FACILITY_KERNEL
,
3394 LTT_EVENT_SYSCALL_EXIT
,
3396 syscall_exit
, NULL
, &hooks
);
3398 lttv_trace_find_hook(ts
->parent
.t
,
3399 LTT_FACILITY_KERNEL
,
3400 LTT_EVENT_TRAP_ENTRY
,
3401 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3402 trap_entry
, NULL
, &hooks
);
3404 lttv_trace_find_hook(ts
->parent
.t
,
3405 LTT_FACILITY_KERNEL
,
3406 LTT_EVENT_TRAP_EXIT
,
3408 trap_exit
, NULL
, &hooks
);
3410 lttv_trace_find_hook(ts
->parent
.t
,
3411 LTT_FACILITY_KERNEL
,
3412 LTT_EVENT_IRQ_ENTRY
,
3413 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3414 irq_entry
, NULL
, &hooks
);
3416 lttv_trace_find_hook(ts
->parent
.t
,
3417 LTT_FACILITY_KERNEL
,
3420 irq_exit
, NULL
, &hooks
);
3422 lttv_trace_find_hook(ts
->parent
.t
,
3423 LTT_FACILITY_KERNEL
,
3424 LTT_EVENT_SOFT_IRQ_RAISE
,
3425 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3426 soft_irq_raise
, NULL
, &hooks
);
3428 lttv_trace_find_hook(ts
->parent
.t
,
3429 LTT_FACILITY_KERNEL
,
3430 LTT_EVENT_SOFT_IRQ_ENTRY
,
3431 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3432 soft_irq_entry
, NULL
, &hooks
);
3434 lttv_trace_find_hook(ts
->parent
.t
,
3435 LTT_FACILITY_KERNEL
,
3436 LTT_EVENT_SOFT_IRQ_EXIT
,
3438 soft_irq_exit
, NULL
, &hooks
);
3440 lttv_trace_find_hook(ts
->parent
.t
,
3441 LTT_FACILITY_KERNEL
,
3442 LTT_EVENT_SCHED_SCHEDULE
,
3443 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3444 LTT_FIELD_PREV_STATE
),
3445 schedchange
, NULL
, &hooks
);
3447 lttv_trace_find_hook(ts
->parent
.t
,
3448 LTT_FACILITY_KERNEL
,
3449 LTT_EVENT_PROCESS_FORK
,
3450 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3451 LTT_FIELD_CHILD_TGID
),
3452 process_fork
, NULL
, &hooks
);
3454 lttv_trace_find_hook(ts
->parent
.t
,
3455 LTT_FACILITY_KERNEL
,
3456 LTT_EVENT_KTHREAD_CREATE
,
3457 FIELD_ARRAY(LTT_FIELD_PID
),
3458 process_kernel_thread
, NULL
, &hooks
);
3460 lttv_trace_find_hook(ts
->parent
.t
,
3461 LTT_FACILITY_KERNEL
,
3462 LTT_EVENT_PROCESS_EXIT
,
3463 FIELD_ARRAY(LTT_FIELD_PID
),
3464 process_exit
, NULL
, &hooks
);
3466 lttv_trace_find_hook(ts
->parent
.t
,
3467 LTT_FACILITY_KERNEL
,
3468 LTT_EVENT_PROCESS_FREE
,
3469 FIELD_ARRAY(LTT_FIELD_PID
),
3470 process_free
, NULL
, &hooks
);
3472 lttv_trace_find_hook(ts
->parent
.t
,
3475 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3476 process_exec
, NULL
, &hooks
);
3478 lttv_trace_find_hook(ts
->parent
.t
,
3479 LTT_FACILITY_USER_GENERIC
,
3480 LTT_EVENT_THREAD_BRAND
,
3481 FIELD_ARRAY(LTT_FIELD_NAME
),
3482 thread_brand
, NULL
, &hooks
);
3484 /* statedump-related hooks */
3485 lttv_trace_find_hook(ts
->parent
.t
,
3487 LTT_EVENT_PROCESS_STATE
,
3488 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3489 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3490 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3491 enum_process_state
, NULL
, &hooks
);
3493 lttv_trace_find_hook(ts
->parent
.t
,
3495 LTT_EVENT_STATEDUMP_END
,
3497 statedump_end
, NULL
, &hooks
);
3499 lttv_trace_find_hook(ts
->parent
.t
,
3501 LTT_EVENT_LIST_INTERRUPT
,
3502 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3503 enum_interrupt
, NULL
, &hooks
);
3505 lttv_trace_find_hook(ts
->parent
.t
,
3507 LTT_EVENT_REQUEST_ISSUE
,
3508 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3509 bdev_request_issue
, NULL
, &hooks
);
3511 lttv_trace_find_hook(ts
->parent
.t
,
3513 LTT_EVENT_REQUEST_COMPLETE
,
3514 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3515 bdev_request_complete
, NULL
, &hooks
);
3517 lttv_trace_find_hook(ts
->parent
.t
,
3518 LTT_FACILITY_USER_GENERIC
,
3519 LTT_EVENT_FUNCTION_ENTRY
,
3520 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3521 function_entry
, NULL
, &hooks
);
3523 lttv_trace_find_hook(ts
->parent
.t
,
3524 LTT_FACILITY_USER_GENERIC
,
3525 LTT_EVENT_FUNCTION_EXIT
,
3526 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3527 function_exit
, NULL
, &hooks
);
3529 lttv_trace_find_hook(ts
->parent
.t
,
3530 LTT_FACILITY_STATEDUMP
,
3531 LTT_EVENT_SYS_CALL_TABLE
,
3532 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3533 dump_syscall
, NULL
, &hooks
);
3535 lttv_trace_find_hook(ts
->parent
.t
,
3536 LTT_FACILITY_STATEDUMP
,
3537 LTT_EVENT_SOFTIRQ_VEC
,
3538 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3539 dump_softirq
, NULL
, &hooks
);
3541 /* Add these hooks to each event_by_id hooks list */
3543 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3545 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3547 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3548 LttvTracefileContext
*, j
));
3550 for(k
= 0 ; k
< hooks
->len
; k
++) {
3551 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3553 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3559 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3560 *(val
.v_pointer
) = hooks
;
3564 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3566 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3568 lttv_state_remove_event_hooks(tss
);
3573 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3575 LttvTraceset
*traceset
= self
->parent
.ts
;
3577 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3581 LttvTracefileState
*tfs
;
3587 LttvAttributeValue val
;
3589 nb_trace
= lttv_traceset_number(traceset
);
3590 for(i
= 0 ; i
< nb_trace
; i
++) {
3591 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3593 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3594 hooks
= *(val
.v_pointer
);
3596 /* Remove these hooks from each event_by_id hooks list */
3598 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3600 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3602 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3603 LttvTracefileContext
*, j
));
3605 for(k
= 0 ; k
< hooks
->len
; k
++) {
3606 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3607 lttv_hooks_remove_data(
3608 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3613 lttv_trace_hook_remove_all(&hooks
);
3614 g_array_free(hooks
, TRUE
);
3618 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3620 guint
*event_count
= (guint
*)hook_data
;
3622 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3623 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3628 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3630 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3632 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3634 LttvAttributeValue value
;
3636 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3637 LTTV_STATE_SAVED_STATES
);
3638 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3639 value
= lttv_attribute_add(saved_states_tree
,
3640 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3641 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3642 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3643 *(value
.v_time
) = self
->parent
.timestamp
;
3644 lttv_state_save(tcs
, saved_state_tree
);
3645 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3646 self
->parent
.timestamp
.tv_nsec
);
3648 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3653 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3655 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3657 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3662 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3670 static gboolean
block_start(void *hook_data
, void *call_data
)
3672 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3674 LttvTracefileState
*tfcs
;
3676 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3678 LttEventPosition
*ep
;
3680 guint i
, nb_block
, nb_event
, nb_tracefile
;
3684 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3686 LttvAttributeValue value
;
3688 ep
= ltt_event_position_new();
3690 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3692 /* Count the number of events added since the last block end in any
3695 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3697 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3698 LttvTracefileContext
, i
));
3699 ltt_event_position(tfcs
->parent
.e
, ep
);
3700 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3701 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3702 tfcs
->saved_position
= nb_event
;
3706 if(tcs
->nb_event
>= tcs
->save_interval
) {
3707 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3708 LTTV_STATE_SAVED_STATES
);
3709 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3710 value
= lttv_attribute_add(saved_states_tree
,
3711 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3712 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3713 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3714 *(value
.v_time
) = self
->parent
.timestamp
;
3715 lttv_state_save(tcs
, saved_state_tree
);
3717 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3718 self
->parent
.timestamp
.tv_nsec
);
3720 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3726 static gboolean
block_end(void *hook_data
, void *call_data
)
3728 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3730 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3734 LttEventPosition
*ep
;
3736 guint nb_block
, nb_event
;
3738 ep
= ltt_event_position_new();
3739 ltt_event_position(self
->parent
.e
, ep
);
3740 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3741 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3742 self
->saved_position
= 0;
3743 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3750 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3752 LttvTraceset
*traceset
= self
->parent
.ts
;
3754 guint i
, j
, nb_trace
, nb_tracefile
;
3758 LttvTracefileState
*tfs
;
3760 LttvTraceHook hook_start
, hook_end
;
3762 nb_trace
= lttv_traceset_number(traceset
);
3763 for(i
= 0 ; i
< nb_trace
; i
++) {
3764 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3766 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3767 NULL
, NULL
, block_start
, &hook_start
);
3768 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3769 NULL
, NULL
, block_end
, &hook_end
);
3771 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3773 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3775 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3776 LttvTracefileContext
, j
));
3777 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3778 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3779 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3780 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3786 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3788 LttvTraceset
*traceset
= self
->parent
.ts
;
3790 guint i
, j
, nb_trace
, nb_tracefile
;
3794 LttvTracefileState
*tfs
;
3797 nb_trace
= lttv_traceset_number(traceset
);
3798 for(i
= 0 ; i
< nb_trace
; i
++) {
3800 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3801 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3803 if(ts
->has_precomputed_states
) continue;
3805 guint
*event_count
= g_new(guint
, 1);
3808 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3810 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3811 LttvTracefileContext
*, j
));
3812 lttv_hooks_add(tfs
->parent
.event
,
3813 state_save_event_hook
,
3820 lttv_process_traceset_begin(&self
->parent
,
3821 NULL
, NULL
, NULL
, NULL
, NULL
);
3825 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3827 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3829 lttv_state_save_add_event_hooks(tss
);
3836 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3838 LttvTraceset
*traceset
= self
->parent
.ts
;
3840 guint i
, j
, nb_trace
, nb_tracefile
;
3844 LttvTracefileState
*tfs
;
3846 LttvTraceHook hook_start
, hook_end
;
3848 nb_trace
= lttv_traceset_number(traceset
);
3849 for(i
= 0 ; i
< nb_trace
; i
++) {
3850 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3852 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3853 NULL
, NULL
, block_start
, &hook_start
);
3855 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3856 NULL
, NULL
, block_end
, &hook_end
);
3858 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3860 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3862 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3863 LttvTracefileContext
, j
));
3864 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3865 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3866 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3867 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3873 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3875 LttvTraceset
*traceset
= self
->parent
.ts
;
3877 guint i
, j
, nb_trace
, nb_tracefile
;
3881 LttvTracefileState
*tfs
;
3883 LttvHooks
*after_trace
= lttv_hooks_new();
3885 lttv_hooks_add(after_trace
,
3886 state_save_after_trace_hook
,
3891 lttv_process_traceset_end(&self
->parent
,
3892 NULL
, after_trace
, NULL
, NULL
, NULL
);
3894 lttv_hooks_destroy(after_trace
);
3896 nb_trace
= lttv_traceset_number(traceset
);
3897 for(i
= 0 ; i
< nb_trace
; i
++) {
3899 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3900 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3902 if(ts
->has_precomputed_states
) continue;
3904 guint
*event_count
= NULL
;
3906 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3908 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3909 LttvTracefileContext
*, j
));
3910 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3911 state_save_event_hook
);
3913 if(event_count
) g_free(event_count
);
3917 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3919 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3921 lttv_state_save_remove_event_hooks(tss
);
3926 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3928 LttvTraceset
*traceset
= self
->parent
.ts
;
3932 int min_pos
, mid_pos
, max_pos
;
3934 guint call_rest
= 0;
3936 LttvTraceState
*tcs
;
3938 LttvAttributeValue value
;
3940 LttvAttributeType type
;
3942 LttvAttributeName name
;
3946 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3948 //g_tree_destroy(self->parent.pqueue);
3949 //self->parent.pqueue = g_tree_new(compare_tracefile);
3951 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3953 nb_trace
= lttv_traceset_number(traceset
);
3954 for(i
= 0 ; i
< nb_trace
; i
++) {
3955 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3957 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3958 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3959 LTTV_STATE_SAVED_STATES
);
3962 if(saved_states_tree
) {
3963 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3964 mid_pos
= max_pos
/ 2;
3965 while(min_pos
< max_pos
) {
3966 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3968 g_assert(type
== LTTV_GOBJECT
);
3969 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3970 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3972 g_assert(type
== LTTV_TIME
);
3973 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3975 closest_tree
= saved_state_tree
;
3977 else max_pos
= mid_pos
- 1;
3979 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3983 /* restore the closest earlier saved state */
3985 lttv_state_restore(tcs
, closest_tree
);
3989 /* There is no saved state, yet we want to have it. Restart at T0 */
3991 restore_init_state(tcs
);
3992 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3995 /* We want to seek quickly without restoring/updating the state */
3997 restore_init_state(tcs
);
3998 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4001 if(!call_rest
) g_info("NOT Calling restore");
4006 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4012 traceset_state_finalize (LttvTracesetState
*self
)
4014 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4015 finalize(G_OBJECT(self
));
4020 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4022 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4024 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4025 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4026 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4027 klass
->new_traceset_context
= new_traceset_context
;
4028 klass
->new_trace_context
= new_trace_context
;
4029 klass
->new_tracefile_context
= new_tracefile_context
;
4034 lttv_traceset_state_get_type(void)
4036 static GType type
= 0;
4038 static const GTypeInfo info
= {
4039 sizeof (LttvTracesetStateClass
),
4040 NULL
, /* base_init */
4041 NULL
, /* base_finalize */
4042 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4043 NULL
, /* class_finalize */
4044 NULL
, /* class_data */
4045 sizeof (LttvTracesetState
),
4046 0, /* n_preallocs */
4047 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4048 NULL
/* value handling */
4051 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4059 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4065 trace_state_finalize (LttvTraceState
*self
)
4067 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4068 finalize(G_OBJECT(self
));
4073 trace_state_class_init (LttvTraceStateClass
*klass
)
4075 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4077 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4078 klass
->state_save
= state_save
;
4079 klass
->state_restore
= state_restore
;
4080 klass
->state_saved_free
= state_saved_free
;
4085 lttv_trace_state_get_type(void)
4087 static GType type
= 0;
4089 static const GTypeInfo info
= {
4090 sizeof (LttvTraceStateClass
),
4091 NULL
, /* base_init */
4092 NULL
, /* base_finalize */
4093 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4094 NULL
, /* class_finalize */
4095 NULL
, /* class_data */
4096 sizeof (LttvTraceState
),
4097 0, /* n_preallocs */
4098 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4099 NULL
/* value handling */
4102 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4103 "LttvTraceStateType", &info
, 0);
4110 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4116 tracefile_state_finalize (LttvTracefileState
*self
)
4118 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4119 finalize(G_OBJECT(self
));
4124 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4126 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4128 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4133 lttv_tracefile_state_get_type(void)
4135 static GType type
= 0;
4137 static const GTypeInfo info
= {
4138 sizeof (LttvTracefileStateClass
),
4139 NULL
, /* base_init */
4140 NULL
, /* base_finalize */
4141 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4142 NULL
, /* class_finalize */
4143 NULL
, /* class_data */
4144 sizeof (LttvTracefileState
),
4145 0, /* n_preallocs */
4146 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4147 NULL
/* value handling */
4150 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4151 "LttvTracefileStateType", &info
, 0);
4157 static void module_init()
4159 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4160 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4161 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4162 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4163 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4164 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4165 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4166 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4167 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4168 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4169 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4170 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4171 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4172 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4173 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4174 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4175 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4176 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4177 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4178 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4179 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4180 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4181 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4182 LTTV_STATE_EVENT
= g_quark_from_string("event");
4183 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4184 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4185 LTTV_STATE_TIME
= g_quark_from_string("time");
4186 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4187 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4188 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4189 g_quark_from_string("trace_state_use_count");
4190 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4191 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4192 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4193 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4194 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4195 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4198 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4199 LTT_FACILITY_FS
= g_quark_from_string("fs");
4200 LTT_FACILITY_LIST
= g_quark_from_string("list");
4201 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4202 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4203 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4205 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4206 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4207 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4208 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4209 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4210 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4211 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4212 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4213 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4214 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4215 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4216 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4217 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4218 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4219 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4220 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4221 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4222 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4223 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4224 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4225 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4226 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4227 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4228 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4229 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4231 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4232 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4233 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4234 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4235 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4236 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4237 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4238 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4239 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4240 LTT_FIELD_PID
= g_quark_from_string("pid");
4241 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4242 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4243 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4244 LTT_FIELD_NAME
= g_quark_from_string("name");
4245 LTT_FIELD_TYPE
= g_quark_from_string("type");
4246 LTT_FIELD_MODE
= g_quark_from_string("mode");
4247 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4248 LTT_FIELD_STATUS
= g_quark_from_string("status");
4249 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4250 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4251 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4252 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4253 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4254 LTT_FIELD_ACTION
= g_quark_from_string("action");
4255 LTT_FIELD_ID
= g_quark_from_string("id");
4256 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4257 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4259 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4260 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4261 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4262 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4263 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4264 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4266 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4267 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4268 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4270 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4271 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4272 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4273 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4276 static void module_destroy()
4281 LTTV_MODULE("state", "State computation", \
4282 "Update the system state, possibly saving it at intervals", \
4283 module_init
, module_destroy
)