1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
31 #include <ltt/marker-desc.h>
34 #include <ltt/ltt-private.h>
38 * usertrace is there only to be able to update the current CPU of the
39 * usertraces when there is a schedchange. it is a way to link the ProcessState
40 * to the associated usertrace. Link only created upon thread creation.
42 * The cpu id is necessary : it gives us back the current ProcessState when we
43 * are considering data from the usertrace.
46 #define PREALLOCATED_EXECUTION_STACK 10
48 /* Facilities Quarks */
52 LTT_FACILITY_KERNEL_ARCH
,
55 LTT_FACILITY_USER_GENERIC
,
57 LTT_FACILITY_STATEDUMP
;
62 LTT_EVENT_SYSCALL_ENTRY
,
63 LTT_EVENT_SYSCALL_EXIT
,
68 LTT_EVENT_SOFT_IRQ_RAISE
,
69 LTT_EVENT_SOFT_IRQ_ENTRY
,
70 LTT_EVENT_SOFT_IRQ_EXIT
,
71 LTT_EVENT_SCHED_SCHEDULE
,
72 LTT_EVENT_PROCESS_FORK
,
73 LTT_EVENT_KTHREAD_CREATE
,
74 LTT_EVENT_PROCESS_EXIT
,
75 LTT_EVENT_PROCESS_FREE
,
77 LTT_EVENT_PROCESS_STATE
,
78 LTT_EVENT_STATEDUMP_END
,
79 LTT_EVENT_FUNCTION_ENTRY
,
80 LTT_EVENT_FUNCTION_EXIT
,
81 LTT_EVENT_THREAD_BRAND
,
82 LTT_EVENT_REQUEST_ISSUE
,
83 LTT_EVENT_REQUEST_COMPLETE
,
84 LTT_EVENT_LIST_INTERRUPT
,
85 LTT_EVENT_SYS_CALL_TABLE
,
86 LTT_EVENT_SOFTIRQ_VEC
;
94 LTT_FIELD_SOFT_IRQ_ID
,
102 LTT_FIELD_CHILD_TGID
,
120 LTTV_STATE_MODE_UNKNOWN
,
121 LTTV_STATE_USER_MODE
,
128 LTTV_STATE_SUBMODE_UNKNOWN
,
129 LTTV_STATE_SUBMODE_NONE
;
133 LTTV_STATE_WAIT_FORK
,
142 LTTV_STATE_UNBRANDED
;
145 LTTV_STATE_USER_THREAD
,
146 LTTV_STATE_KERNEL_THREAD
;
164 LTTV_BDEV_BUSY_READING
,
165 LTTV_BDEV_BUSY_WRITING
;
168 LTTV_STATE_TRACEFILES
,
169 LTTV_STATE_PROCESSES
,
171 LTTV_STATE_RUNNING_PROCESS
,
173 LTTV_STATE_SAVED_STATES
,
174 LTTV_STATE_SAVED_STATES_TIME
,
177 LTTV_STATE_NAME_TABLES
,
178 LTTV_STATE_TRACE_STATE_USE_COUNT
,
179 LTTV_STATE_RESOURCE_CPUS
,
180 LTTV_STATE_RESOURCE_CPUS_COUNT
,
181 LTTV_STATE_RESOURCE_IRQS
,
182 LTTV_STATE_RESOURCE_SOFT_IRQS
,
183 LTTV_STATE_RESOURCE_TRAPS
,
184 LTTV_STATE_RESOURCE_BLKDEVS
;
186 static void create_max_time(LttvTraceState
*tcs
);
188 static void get_max_time(LttvTraceState
*tcs
);
190 static void free_max_time(LttvTraceState
*tcs
);
192 static void create_name_tables(LttvTraceState
*tcs
);
194 static void get_name_tables(LttvTraceState
*tcs
);
196 static void free_name_tables(LttvTraceState
*tcs
);
198 static void free_saved_state(LttvTraceState
*tcs
);
200 static void lttv_state_free_process_table(GHashTable
*processes
);
202 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
203 GPtrArray
*quarktable
);
205 /* Resource function prototypes */
206 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
207 static LttvBdevState
*bdevstate_new(void);
208 static void bdevstate_free(LttvBdevState
*);
209 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
210 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
213 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
215 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
219 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
221 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
225 void lttv_state_state_saved_free(LttvTraceState
*self
,
226 LttvAttribute
*container
)
228 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
232 guint
process_hash(gconstpointer key
)
234 guint pid
= ((const LttvProcessState
*)key
)->pid
;
235 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
239 /* If the hash table hash function is well distributed,
240 * the process_equal should compare different pid */
241 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
243 const LttvProcessState
*process_a
, *process_b
;
246 process_a
= (const LttvProcessState
*)a
;
247 process_b
= (const LttvProcessState
*)b
;
249 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
250 else if(likely(process_a
->pid
== 0 &&
251 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
256 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
258 g_tree_destroy((GTree
*)value
);
261 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
263 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
264 g_hash_table_destroy(usertraces
);
267 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
272 static guint
check_expand(nb
, id
)
277 return max(id
+ 1, nb
* 2);
280 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
281 guint nb
, guint new_nb
)
283 /* Expand an incomplete table */
284 GQuark
*old_table
= *table
;
285 *table
= g_new(GQuark
, new_nb
);
286 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
289 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
290 guint new_nb
, const char *def_string
)
293 GString
*fe_name
= g_string_new("");
294 for(i
= nb
; i
< new_nb
; i
++) {
295 g_string_printf(fe_name
, "%s %d", def_string
, i
);
296 table
[i
] = g_quark_from_string(fe_name
->str
);
298 g_string_free(fe_name
, TRUE
);
301 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
303 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
304 if(likely(new_nb
== ts
->nb_syscalls
))
306 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, new_nb
);
307 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
308 /* Update the table size */
309 ts
->nb_syscalls
= new_nb
;
312 static void expand_trap_table(LttvTraceState
*ts
, int id
)
314 guint new_nb
= check_expand(ts
->nb_traps
, id
);
316 if(likely(new_nb
== ts
->nb_traps
))
318 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
319 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
320 /* Update the table size */
321 ts
->nb_traps
= new_nb
;
323 LttvTrapState
*old_table
= ts
->trap_states
;
324 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
325 memcpy(ts
->trap_states
, old_table
,
326 ts
->nb_traps
* sizeof(LttvTrapState
));
327 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
328 ts
->trap_states
[i
].running
= 0;
331 static void expand_irq_table(LttvTraceState
*ts
, int id
)
333 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
335 if(likely(new_nb
== ts
->nb_irqs
))
337 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
338 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
340 LttvIRQState
*old_table
= ts
->irq_states
;
341 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
342 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
343 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
344 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
347 /* Update the table size */
348 ts
->nb_irqs
= new_nb
;
351 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
353 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
355 if(likely(new_nb
== ts
->nb_soft_irqs
))
357 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
358 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
360 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
361 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
362 memcpy(ts
->soft_irq_states
, old_table
,
363 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
364 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
365 ts
->soft_irq_states
[i
].running
= 0;
367 /* Update the table size */
368 ts
->nb_soft_irqs
= new_nb
;
372 restore_init_state(LttvTraceState
*self
)
374 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
376 //LttvTracefileState *tfcs;
378 LttTime start_time
, end_time
;
380 /* Free the process tables */
381 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
382 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
383 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
384 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
387 /* Seek time to beginning */
388 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
389 // closest. It's the tracecontext job to seek the trace to the beginning
390 // anyway : the init state might be used at the middle of the trace as well...
391 //g_tree_destroy(self->parent.ts_context->pqueue);
392 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
394 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
396 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
398 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
399 nb_irqs
= self
->nb_irqs
;
400 nb_soft_irqs
= self
->nb_soft_irqs
;
401 nb_traps
= self
->nb_traps
;
403 /* Put the per cpu running_process to beginning state : process 0. */
404 for(i
=0; i
< nb_cpus
; i
++) {
405 LttvExecutionState
*es
;
406 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
407 LTTV_STATE_UNNAMED
, &start_time
);
408 /* We are not sure is it's a kernel thread or normal thread, put the
409 * bottom stack state to unknown */
410 self
->running_process
[i
]->execution_stack
=
411 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
412 es
= self
->running_process
[i
]->state
=
413 &g_array_index(self
->running_process
[i
]->execution_stack
,
414 LttvExecutionState
, 0);
415 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
416 es
->s
= LTTV_STATE_UNNAMED
;
418 //self->running_process[i]->state->s = LTTV_STATE_RUN;
419 self
->running_process
[i
]->cpu
= i
;
421 /* reset cpu states */
422 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
423 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
426 /* reset irq states */
427 for(i
=0; i
<nb_irqs
; i
++) {
428 if(self
->irq_states
[i
].mode_stack
->len
> 0)
429 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
432 /* reset softirq states */
433 for(i
=0; i
<nb_soft_irqs
; i
++) {
434 self
->soft_irq_states
[i
].pending
= 0;
435 self
->soft_irq_states
[i
].running
= 0;
438 /* reset trap states */
439 for(i
=0; i
<nb_traps
; i
++) {
440 self
->trap_states
[i
].running
= 0;
443 /* reset bdev states */
444 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
445 //g_hash_table_steal_all(self->bdev_states);
446 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
449 nb_tracefile
= self
->parent
.tracefiles
->len
;
451 for(i
= 0 ; i
< nb_tracefile
; i
++) {
453 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
454 LttvTracefileContext
*, i
));
455 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
456 // tfcs->saved_position = 0;
457 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
458 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
459 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
460 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
465 //static LttTime time_zero = {0,0};
467 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
470 const LttTime
*t1
= (const LttTime
*)a
;
471 const LttTime
*t2
= (const LttTime
*)b
;
473 return ltt_time_compare(*t1
, *t2
);
476 static void free_usertrace_key(gpointer data
)
481 #define MAX_STRING_LEN 4096
484 state_load_saved_states(LttvTraceState
*tcs
)
487 GPtrArray
*quarktable
;
488 const char *trace_path
;
492 tcs
->has_precomputed_states
= FALSE
;
496 gchar buf
[MAX_STRING_LEN
];
499 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
500 strncpy(path
, trace_path
, PATH_MAX
-1);
501 count
= strnlen(trace_path
, PATH_MAX
-1);
502 // quarktable : open, test
503 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
504 fp
= fopen(path
, "r");
506 quarktable
= g_ptr_array_sized_new(4096);
508 /* Index 0 is null */
510 if(hdr
== EOF
) return;
511 g_assert(hdr
== HDR_QUARKS
);
515 if(hdr
== EOF
) break;
516 g_assert(hdr
== HDR_QUARK
);
517 g_ptr_array_set_size(quarktable
, q
+1);
520 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
521 if(buf
[i
] == '\0' || feof(fp
)) break;
524 len
= strnlen(buf
, MAX_STRING_LEN
-1);
525 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
526 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
532 // saved_states : open, test
533 strncpy(path
, trace_path
, PATH_MAX
-1);
534 count
= strnlen(trace_path
, PATH_MAX
-1);
535 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
536 fp
= fopen(path
, "r");
540 if(hdr
!= HDR_TRACE
) goto end
;
542 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
544 tcs
->has_precomputed_states
= TRUE
;
549 /* Free the quarktable */
550 for(i
=0; i
<quarktable
->len
; i
++) {
551 string
= g_ptr_array_index (quarktable
, i
);
554 g_ptr_array_free(quarktable
, TRUE
);
559 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
561 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
564 LttvTraceContext
*tc
;
568 LttvTracefileState
*tfcs
;
570 LttvAttributeValue v
;
572 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
573 init((LttvTracesetContext
*)self
, ts
);
575 nb_trace
= lttv_traceset_number(ts
);
576 for(i
= 0 ; i
< nb_trace
; i
++) {
577 tc
= self
->parent
.traces
[i
];
578 tcs
= LTTV_TRACE_STATE(tc
);
579 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
580 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
584 if(*(v
.v_uint
) == 1) {
585 create_name_tables(tcs
);
586 create_max_time(tcs
);
588 get_name_tables(tcs
);
591 nb_tracefile
= tc
->tracefiles
->len
;
592 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
593 nb_irq
= tcs
->nb_irqs
;
594 tcs
->processes
= NULL
;
595 tcs
->usertraces
= NULL
;
596 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
598 /* init cpu resource stuff */
599 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
600 for(j
= 0; j
<nb_cpu
; j
++) {
601 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
602 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
605 /* init irq resource stuff */
606 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
607 for(j
= 0; j
<nb_irq
; j
++) {
608 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
609 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
612 /* init soft irq stuff */
613 /* the kernel has a statically fixed max of 32 softirqs */
614 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
616 /* init trap stuff */
617 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
619 /* init bdev resource stuff */
620 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
622 restore_init_state(tcs
);
623 for(j
= 0 ; j
< nb_tracefile
; j
++) {
625 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
626 LttvTracefileContext
*, j
));
627 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
628 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
629 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
630 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
631 /* It's a Usertrace */
632 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
633 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
635 if(!usertrace_tree
) {
636 usertrace_tree
= g_tree_new_full(compare_usertraces
,
637 NULL
, free_usertrace_key
, NULL
);
638 g_hash_table_insert(tcs
->usertraces
,
639 (gpointer
)tid
, usertrace_tree
);
641 LttTime
*timestamp
= g_new(LttTime
, 1);
642 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
643 ltt_tracefile_creation(tfcs
->parent
.tf
));
644 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
648 /* See if the trace has saved states */
649 state_load_saved_states(tcs
);
654 fini(LttvTracesetState
*self
)
660 //LttvTracefileState *tfcs;
662 LttvAttributeValue v
;
664 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
665 for(i
= 0 ; i
< nb_trace
; i
++) {
666 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
667 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
670 g_assert(*(v
.v_uint
) != 0);
673 if(*(v
.v_uint
) == 0) {
674 free_name_tables(tcs
);
676 free_saved_state(tcs
);
678 g_free(tcs
->running_process
);
679 tcs
->running_process
= NULL
;
680 lttv_state_free_process_table(tcs
->processes
);
681 lttv_state_free_usertraces(tcs
->usertraces
);
682 tcs
->processes
= NULL
;
683 tcs
->usertraces
= NULL
;
685 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
686 fini((LttvTracesetContext
*)self
);
690 static LttvTracesetContext
*
691 new_traceset_context(LttvTracesetContext
*self
)
693 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
697 static LttvTraceContext
*
698 new_trace_context(LttvTracesetContext
*self
)
700 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
704 static LttvTracefileContext
*
705 new_tracefile_context(LttvTracesetContext
*self
)
707 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
711 /* Write the process state of the trace */
713 static void write_process_state(gpointer key
, gpointer value
,
716 LttvProcessState
*process
;
718 LttvExecutionState
*es
;
720 FILE *fp
= (FILE *)user_data
;
725 process
= (LttvProcessState
*)value
;
727 " <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",
728 process
, process
->pid
, process
->tgid
, process
->ppid
,
729 g_quark_to_string(process
->type
),
730 process
->creation_time
.tv_sec
,
731 process
->creation_time
.tv_nsec
,
732 process
->insertion_time
.tv_sec
,
733 process
->insertion_time
.tv_nsec
,
734 g_quark_to_string(process
->name
),
735 g_quark_to_string(process
->brand
),
736 process
->cpu
, process
->free_events
);
738 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
739 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
740 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
741 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
742 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
743 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
744 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
747 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
748 address
= g_array_index(process
->user_stack
, guint64
, i
);
749 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
753 if(process
->usertrace
) {
754 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
755 g_quark_to_string(process
->usertrace
->tracefile_name
),
756 process
->usertrace
->cpu
);
760 fprintf(fp
, " </PROCESS>\n");
764 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
766 guint i
, nb_tracefile
, nb_block
, offset
;
769 LttvTracefileState
*tfcs
;
773 LttEventPosition
*ep
;
777 ep
= ltt_event_position_new();
779 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
781 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
783 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
784 for(i
=0;i
<nb_cpus
;i
++) {
785 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
786 i
, self
->running_process
[i
]->pid
);
789 nb_tracefile
= self
->parent
.tracefiles
->len
;
791 for(i
= 0 ; i
< nb_tracefile
; i
++) {
793 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
794 LttvTracefileContext
*, i
));
795 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
796 tfcs
->parent
.timestamp
.tv_sec
,
797 tfcs
->parent
.timestamp
.tv_nsec
);
798 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
799 if(e
== NULL
) fprintf(fp
,"/>\n");
801 ltt_event_position(e
, ep
);
802 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
803 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
808 fprintf(fp
,"</PROCESS_STATE>\n");
812 static void write_process_state_raw(gpointer key
, gpointer value
,
815 LttvProcessState
*process
;
817 LttvExecutionState
*es
;
819 FILE *fp
= (FILE *)user_data
;
824 process
= (LttvProcessState
*)value
;
825 fputc(HDR_PROCESS
, fp
);
826 //fwrite(&header, sizeof(header), 1, fp);
827 //fprintf(fp, "%s", g_quark_to_string(process->type));
829 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
830 //fprintf(fp, "%s", g_quark_to_string(process->name));
832 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
833 //fprintf(fp, "%s", g_quark_to_string(process->brand));
835 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
836 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
837 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
838 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
839 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
840 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
841 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
842 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
846 " <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",
847 process
, process
->pid
, process
->tgid
, process
->ppid
,
848 g_quark_to_string(process
->type
),
849 process
->creation_time
.tv_sec
,
850 process
->creation_time
.tv_nsec
,
851 process
->insertion_time
.tv_sec
,
852 process
->insertion_time
.tv_nsec
,
853 g_quark_to_string(process
->name
),
854 g_quark_to_string(process
->brand
),
858 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
859 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
862 //fprintf(fp, "%s", g_quark_to_string(es->t));
864 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
865 //fprintf(fp, "%s", g_quark_to_string(es->n));
867 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
868 //fprintf(fp, "%s", g_quark_to_string(es->s));
870 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
871 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
872 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
873 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
875 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
876 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
877 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
878 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
879 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
883 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
884 address
= g_array_index(process
->user_stack
, guint64
, i
);
885 fputc(HDR_USER_STACK
, fp
);
886 fwrite(&address
, sizeof(address
), 1, fp
);
888 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
893 if(process
->usertrace
) {
894 fputc(HDR_USERTRACE
, fp
);
895 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
897 fwrite(&process
->usertrace
->tracefile_name
,
898 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
899 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
901 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
902 g_quark_to_string(process
->usertrace
->tracefile_name
),
903 process
->usertrace
->cpu
);
910 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
912 guint i
, nb_tracefile
, nb_block
, offset
;
915 LttvTracefileState
*tfcs
;
919 LttEventPosition
*ep
;
923 ep
= ltt_event_position_new();
925 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
926 fputc(HDR_PROCESS_STATE
, fp
);
927 fwrite(&t
, sizeof(t
), 1, fp
);
929 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
931 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
932 for(i
=0;i
<nb_cpus
;i
++) {
934 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
935 fwrite(&self
->running_process
[i
]->pid
,
936 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
937 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
938 // i, self->running_process[i]->pid);
941 nb_tracefile
= self
->parent
.tracefiles
->len
;
943 for(i
= 0 ; i
< nb_tracefile
; i
++) {
945 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
946 LttvTracefileContext
*, i
));
947 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
948 // tfcs->parent.timestamp.tv_sec,
949 // tfcs->parent.timestamp.tv_nsec);
950 fputc(HDR_TRACEFILE
, fp
);
951 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
952 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
953 * position following : end of trace */
954 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
956 ltt_event_position(e
, ep
);
957 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
958 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
960 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
961 fwrite(&offset
, sizeof(offset
), 1, fp
);
962 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
969 /* Read process state from a file */
971 /* Called because a HDR_PROCESS was found */
972 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
973 GPtrArray
*quarktable
)
975 LttvExecutionState
*es
;
976 LttvProcessState
*process
, *parent_process
;
977 LttvProcessState tmp
;
982 /* TODO : check return value */
983 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
984 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
985 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
986 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
987 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
988 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
989 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
990 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
991 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
992 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
995 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
997 /* We must link to the parent */
998 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1000 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1001 if(process
== NULL
) {
1002 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1004 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1005 &tmp
.creation_time
);
1008 process
->insertion_time
= tmp
.insertion_time
;
1009 process
->creation_time
= tmp
.creation_time
;
1010 process
->type
= g_quark_from_string(
1011 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1012 process
->tgid
= tmp
.tgid
;
1013 process
->ppid
= tmp
.ppid
;
1014 process
->brand
= g_quark_from_string(
1015 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1017 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1018 process
->free_events
= tmp
.free_events
;
1021 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1023 gint hdr
= fgetc(fp
);
1024 if(hdr
== EOF
) goto end_loop
;
1028 process
->execution_stack
=
1029 g_array_set_size(process
->execution_stack
,
1030 process
->execution_stack
->len
+ 1);
1031 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1032 process
->execution_stack
->len
-1);
1033 process
->state
= es
;
1035 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1036 es
->t
= g_quark_from_string(
1037 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1038 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1039 es
->n
= g_quark_from_string(
1040 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1041 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1042 es
->s
= g_quark_from_string(
1043 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1044 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1045 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1046 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1048 case HDR_USER_STACK
:
1049 process
->user_stack
= g_array_set_size(process
->user_stack
,
1050 process
->user_stack
->len
+ 1);
1051 address
= &g_array_index(process
->user_stack
, guint64
,
1052 process
->user_stack
->len
-1);
1053 fread(address
, sizeof(address
), 1, fp
);
1054 process
->current_function
= *address
;
1057 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1058 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1070 /* Called because a HDR_PROCESS_STATE was found */
1071 /* Append a saved state to the trace states */
1072 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1074 guint i
, nb_tracefile
, nb_block
, offset
;
1076 LttvTracefileState
*tfcs
;
1078 LttEventPosition
*ep
;
1086 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1088 LttvAttributeValue value
;
1089 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1090 ep
= ltt_event_position_new();
1092 restore_init_state(self
);
1094 fread(&t
, sizeof(t
), 1, fp
);
1097 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1099 if(hdr
== EOF
) goto end_loop
;
1103 /* Call read_process_state_raw */
1104 read_process_state_raw(self
, fp
, quarktable
);
1112 case HDR_USER_STACK
:
1114 case HDR_PROCESS_STATE
:
1120 g_error("Error while parsing saved state file : unknown data header %d",
1126 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1127 for(i
=0;i
<nb_cpus
;i
++) {
1130 g_assert(hdr
== HDR_CPU
);
1131 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1132 g_assert(i
== cpu_num
);
1133 fread(&self
->running_process
[i
]->pid
,
1134 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1137 nb_tracefile
= self
->parent
.tracefiles
->len
;
1139 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1141 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1142 LttvTracefileContext
*, i
));
1143 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1144 // tfcs->parent.timestamp.tv_sec,
1145 // tfcs->parent.timestamp.tv_nsec);
1146 g_tree_remove(pqueue
, &tfcs
->parent
);
1148 g_assert(hdr
== HDR_TRACEFILE
);
1149 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1150 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1151 * position following : end of trace */
1152 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1153 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1154 fread(&offset
, sizeof(offset
), 1, fp
);
1155 fread(&tsc
, sizeof(tsc
), 1, fp
);
1156 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1157 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1159 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1164 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1165 LTTV_STATE_SAVED_STATES
);
1166 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1167 value
= lttv_attribute_add(saved_states_tree
,
1168 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1169 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1170 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1171 *(value
.v_time
) = t
;
1172 lttv_state_save(self
, saved_state_tree
);
1173 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1176 *(self
->max_time_state_recomputed_in_seek
) = t
;
1180 /* Called when a HDR_TRACE is found */
1181 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1182 GPtrArray
*quarktable
)
1187 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1189 if(hdr
== EOF
) goto end_loop
;
1192 case HDR_PROCESS_STATE
:
1193 /* Call read_process_state_raw */
1194 lttv_state_read_raw(tcs
, fp
, quarktable
);
1202 case HDR_USER_STACK
:
1206 g_error("Error while parsing saved state file :"
1207 " unexpected data header %d",
1211 g_error("Error while parsing saved state file : unknown data header %d",
1216 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1217 restore_init_state(tcs
);
1218 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1224 /* Copy each process from an existing hash table to a new one */
1226 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1228 LttvProcessState
*process
, *new_process
;
1230 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1234 process
= (LttvProcessState
*)value
;
1235 new_process
= g_new(LttvProcessState
, 1);
1236 *new_process
= *process
;
1237 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1238 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1239 new_process
->execution_stack
=
1240 g_array_set_size(new_process
->execution_stack
,
1241 process
->execution_stack
->len
);
1242 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1243 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1244 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1246 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1247 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1248 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1249 sizeof(guint64
), 0);
1250 new_process
->user_stack
=
1251 g_array_set_size(new_process
->user_stack
,
1252 process
->user_stack
->len
);
1253 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1254 g_array_index(new_process
->user_stack
, guint64
, i
) =
1255 g_array_index(process
->user_stack
, guint64
, i
);
1257 new_process
->current_function
= process
->current_function
;
1258 g_hash_table_insert(new_processes
, new_process
, new_process
);
1262 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1264 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1266 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1267 return new_processes
;
1270 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1273 LttvCPUState
*retval
;
1275 retval
= g_new(LttvCPUState
, n
);
1277 for(i
=0; i
<n
; i
++) {
1278 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1279 retval
[i
].last_irq
= states
[i
].last_irq
;
1280 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1281 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1282 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1289 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1293 for(i
=0; i
<n
; i
++) {
1294 g_array_free(states
[i
].mode_stack
, TRUE
);
1300 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1303 LttvIRQState
*retval
;
1305 retval
= g_new(LttvIRQState
, n
);
1307 for(i
=0; i
<n
; i
++) {
1308 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1309 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1310 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1311 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1318 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1322 for(i
=0; i
<n
; i
++) {
1323 g_array_free(states
[i
].mode_stack
, TRUE
);
1329 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1332 LttvSoftIRQState
*retval
;
1334 retval
= g_new(LttvSoftIRQState
, n
);
1336 for(i
=0; i
<n
; i
++) {
1337 retval
[i
].pending
= states
[i
].pending
;
1338 retval
[i
].running
= states
[i
].running
;
1344 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1349 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1352 LttvTrapState
*retval
;
1354 retval
= g_new(LttvTrapState
, n
);
1356 for(i
=0; i
<n
; i
++) {
1357 retval
[i
].running
= states
[i
].running
;
1363 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1368 /* bdevstate stuff */
1370 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1372 gint devcode_gint
= devcode
;
1373 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1375 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1376 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1378 gint
* key
= g_new(gint
, 1);
1380 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1388 static LttvBdevState
*bdevstate_new(void)
1390 LttvBdevState
*retval
;
1391 retval
= g_new(LttvBdevState
, 1);
1392 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1397 static void bdevstate_free(LttvBdevState
*bds
)
1399 g_array_free(bds
->mode_stack
, TRUE
);
1403 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1405 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1407 bdevstate_free(bds
);
1410 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1412 LttvBdevState
*retval
;
1414 retval
= bdevstate_new();
1415 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1420 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1422 //GHashTable *ht = (GHashTable *)u;
1423 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1424 LttvBdevState
*newbds
;
1426 newbds
= bdevstate_copy(bds
);
1428 g_hash_table_insert(u
, k
, newbds
);
1431 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1435 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1437 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1442 /* Free a hashtable and the LttvBdevState structures its values
1445 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1447 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1448 g_hash_table_destroy(ht
);
1451 /* The saved state for each trace contains a member "processes", which
1452 stores a copy of the process table, and a member "tracefiles" with
1453 one entry per tracefile. Each tracefile has a "process" member pointing
1454 to the current process and a "position" member storing the tracefile
1455 position (needed to seek to the current "next" event. */
1457 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1459 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1461 LttvTracefileState
*tfcs
;
1463 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1465 guint
*running_process
;
1467 LttvAttributeValue value
;
1469 LttEventPosition
*ep
;
1471 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1472 LTTV_STATE_TRACEFILES
);
1474 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1476 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1478 /* Add the currently running processes array */
1479 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1480 running_process
= g_new(guint
, nb_cpus
);
1481 for(i
=0;i
<nb_cpus
;i
++) {
1482 running_process
[i
] = self
->running_process
[i
]->pid
;
1484 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1486 *(value
.v_pointer
) = running_process
;
1488 g_info("State save");
1490 nb_tracefile
= self
->parent
.tracefiles
->len
;
1492 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1494 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1495 LttvTracefileContext
*, i
));
1496 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1497 value
= lttv_attribute_add(tracefiles_tree
, i
,
1499 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1501 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1503 *(value
.v_uint
) = tfcs
->process
->pid
;
1505 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1507 /* Only save the position if the tfs has not infinite time. */
1508 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1509 // && current_tfcs != tfcs) {
1510 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1511 *(value
.v_pointer
) = NULL
;
1513 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1514 ep
= ltt_event_position_new();
1515 ltt_event_position(e
, ep
);
1516 *(value
.v_pointer
) = ep
;
1518 guint nb_block
, offset
;
1521 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1522 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1524 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1528 /* save the cpu state */
1530 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1532 *(value
.v_uint
) = nb_cpus
;
1534 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1536 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1539 /* save the irq state */
1540 nb_irqs
= self
->nb_irqs
;
1542 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1544 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1547 /* save the soft irq state */
1548 nb_soft_irqs
= self
->nb_soft_irqs
;
1550 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1552 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1555 /* save the trap state */
1556 nb_traps
= self
->nb_traps
;
1558 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1560 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1563 /* save the blkdev states */
1564 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1566 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1570 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1572 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1574 LttvTracefileState
*tfcs
;
1576 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1578 guint
*running_process
;
1580 LttvAttributeType type
;
1582 LttvAttributeValue value
;
1584 LttvAttributeName name
;
1588 LttEventPosition
*ep
;
1590 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1592 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1593 LTTV_STATE_TRACEFILES
);
1595 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1597 g_assert(type
== LTTV_POINTER
);
1598 lttv_state_free_process_table(self
->processes
);
1599 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1601 /* Add the currently running processes array */
1602 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1603 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1605 g_assert(type
== LTTV_POINTER
);
1606 running_process
= *(value
.v_pointer
);
1607 for(i
=0;i
<nb_cpus
;i
++) {
1608 pid
= running_process
[i
];
1609 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1610 g_assert(self
->running_process
[i
] != NULL
);
1613 nb_tracefile
= self
->parent
.tracefiles
->len
;
1615 //g_tree_destroy(tsc->pqueue);
1616 //tsc->pqueue = g_tree_new(compare_tracefile);
1618 /* restore cpu resource states */
1619 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1620 g_assert(type
== LTTV_POINTER
);
1621 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1622 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1624 /* restore irq resource states */
1625 nb_irqs
= self
->nb_irqs
;
1626 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1627 g_assert(type
== LTTV_POINTER
);
1628 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1629 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1631 /* restore soft irq resource states */
1632 nb_soft_irqs
= self
->nb_soft_irqs
;
1633 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1634 g_assert(type
== LTTV_POINTER
);
1635 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1636 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1638 /* restore trap resource states */
1639 nb_traps
= self
->nb_traps
;
1640 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1641 g_assert(type
== LTTV_POINTER
);
1642 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1643 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1645 /* restore the blkdev states */
1646 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1647 g_assert(type
== LTTV_POINTER
);
1648 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1649 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1651 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1653 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1654 LttvTracefileContext
*, i
));
1655 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1656 g_assert(type
== LTTV_GOBJECT
);
1657 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1659 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1661 g_assert(type
== LTTV_UINT
);
1662 pid
= *(value
.v_uint
);
1663 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1665 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1667 g_assert(type
== LTTV_POINTER
);
1668 //g_assert(*(value.v_pointer) != NULL);
1669 ep
= *(value
.v_pointer
);
1670 g_assert(tfcs
->parent
.t_context
!= NULL
);
1672 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1674 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1675 g_tree_remove(tsc
->pqueue
, tfc
);
1678 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1679 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1680 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1681 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1682 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1684 tfc
->timestamp
= ltt_time_infinite
;
1690 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1692 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_softirqs
;
1694 LttvTracefileState
*tfcs
;
1696 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1698 guint
*running_process
;
1700 LttvAttributeType type
;
1702 LttvAttributeValue value
;
1704 LttvAttributeName name
;
1708 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1709 LTTV_STATE_TRACEFILES
);
1710 g_object_ref(G_OBJECT(tracefiles_tree
));
1711 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1713 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1715 g_assert(type
== LTTV_POINTER
);
1716 lttv_state_free_process_table(*(value
.v_pointer
));
1717 *(value
.v_pointer
) = NULL
;
1718 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1720 /* Free running processes array */
1721 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1723 g_assert(type
== LTTV_POINTER
);
1724 running_process
= *(value
.v_pointer
);
1725 g_free(running_process
);
1727 /* free cpu resource states */
1728 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1729 g_assert(type
== LTTV_UINT
);
1730 nb_cpus
= *value
.v_uint
;
1731 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1732 g_assert(type
== LTTV_POINTER
);
1733 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1735 /* free irq resource states */
1736 nb_irqs
= self
->nb_irqs
;
1737 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1738 g_assert(type
== LTTV_POINTER
);
1739 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1741 /* free softirq resource states */
1742 nb_softirqs
= self
->nb_irqs
;
1743 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1744 g_assert(type
== LTTV_POINTER
);
1745 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1747 /* free the blkdev states */
1748 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1749 g_assert(type
== LTTV_POINTER
);
1750 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1752 nb_tracefile
= self
->parent
.tracefiles
->len
;
1754 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1756 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1757 LttvTracefileContext
*, i
));
1758 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1759 g_assert(type
== LTTV_GOBJECT
);
1760 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1762 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1764 g_assert(type
== LTTV_POINTER
);
1765 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1767 g_object_unref(G_OBJECT(tracefiles_tree
));
1771 static void free_saved_state(LttvTraceState
*self
)
1775 LttvAttributeType type
;
1777 LttvAttributeValue value
;
1779 LttvAttributeName name
;
1783 LttvAttribute
*saved_states
;
1785 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1786 LTTV_STATE_SAVED_STATES
);
1788 nb
= lttv_attribute_get_number(saved_states
);
1789 for(i
= 0 ; i
< nb
; i
++) {
1790 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1791 g_assert(type
== LTTV_GOBJECT
);
1792 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1795 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1800 create_max_time(LttvTraceState
*tcs
)
1802 LttvAttributeValue v
;
1804 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1806 g_assert(*(v
.v_pointer
) == NULL
);
1807 *(v
.v_pointer
) = g_new(LttTime
,1);
1808 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1813 get_max_time(LttvTraceState
*tcs
)
1815 LttvAttributeValue v
;
1817 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1819 g_assert(*(v
.v_pointer
) != NULL
);
1820 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1825 free_max_time(LttvTraceState
*tcs
)
1827 LttvAttributeValue v
;
1829 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1831 g_free(*(v
.v_pointer
));
1832 *(v
.v_pointer
) = NULL
;
1836 typedef struct _LttvNameTables
{
1837 // FIXME GQuark *eventtype_names;
1838 GQuark
*syscall_names
;
1844 GQuark
*soft_irq_names
;
1850 create_name_tables(LttvTraceState
*tcs
)
1854 GString
*fe_name
= g_string_new("");
1856 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1858 LttvAttributeValue v
;
1862 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1864 g_assert(*(v
.v_pointer
) == NULL
);
1865 *(v
.v_pointer
) = name_tables
;
1867 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1869 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1870 LTT_FACILITY_KERNEL_ARCH
,
1871 LTT_EVENT_SYSCALL_ENTRY
,
1872 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1873 NULL
, NULL
, &hooks
)) {
1875 // th = lttv_trace_hook_get_first(&th);
1877 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1878 // nb = ltt_type_element_number(t);
1880 // name_tables->syscall_names = g_new(GQuark, nb);
1881 // name_tables->nb_syscalls = nb;
1883 // for(i = 0 ; i < nb ; i++) {
1884 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1885 // if(!name_tables->syscall_names[i]) {
1886 // GString *string = g_string_new("");
1887 // g_string_printf(string, "syscall %u", i);
1888 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1889 // g_string_free(string, TRUE);
1893 name_tables
->nb_syscalls
= 256;
1894 name_tables
->syscall_names
= g_new(GQuark
, 256);
1895 for(i
= 0 ; i
< 256 ; i
++) {
1896 g_string_printf(fe_name
, "syscall %d", i
);
1897 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1900 name_tables
->syscall_names
= NULL
;
1901 name_tables
->nb_syscalls
= 0;
1903 lttv_trace_hook_remove_all(&hooks
);
1905 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1906 LTT_FACILITY_KERNEL_ARCH
,
1907 LTT_EVENT_TRAP_ENTRY
,
1908 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1909 NULL
, NULL
, &hooks
)) {
1911 // th = lttv_trace_hook_get_first(&th);
1913 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1914 // //nb = ltt_type_element_number(t);
1916 // name_tables->trap_names = g_new(GQuark, nb);
1917 // for(i = 0 ; i < nb ; i++) {
1918 // name_tables->trap_names[i] = g_quark_from_string(
1919 // ltt_enum_string_get(t, i));
1922 name_tables
->nb_traps
= 256;
1923 name_tables
->trap_names
= g_new(GQuark
, 256);
1924 for(i
= 0 ; i
< 256 ; i
++) {
1925 g_string_printf(fe_name
, "trap %d", i
);
1926 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1929 name_tables
->trap_names
= NULL
;
1930 name_tables
->nb_traps
= 0;
1932 lttv_trace_hook_remove_all(&hooks
);
1934 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1935 LTT_FACILITY_KERNEL
,
1936 LTT_EVENT_IRQ_ENTRY
,
1937 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1938 NULL
, NULL
, &hooks
)) {
1941 name_tables->irq_names = g_new(GQuark, nb);
1942 for(i = 0 ; i < nb ; i++) {
1943 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1947 name_tables
->nb_irqs
= 256;
1948 name_tables
->irq_names
= g_new(GQuark
, 256);
1949 for(i
= 0 ; i
< 256 ; i
++) {
1950 g_string_printf(fe_name
, "irq %d", i
);
1951 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1954 name_tables
->nb_irqs
= 0;
1955 name_tables
->irq_names
= NULL
;
1957 lttv_trace_hook_remove_all(&hooks
);
1959 name_tables->soft_irq_names = g_new(GQuark, nb);
1960 for(i = 0 ; i < nb ; i++) {
1961 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1965 /* the kernel is limited to 32 statically defined softirqs */
1966 name_tables
->nb_softirqs
= 32;
1967 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1968 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1969 g_string_printf(fe_name
, "softirq %d", i
);
1970 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1972 g_array_free(hooks
, TRUE
);
1974 g_string_free(fe_name
, TRUE
);
1979 get_name_tables(LttvTraceState
*tcs
)
1981 LttvNameTables
*name_tables
;
1983 LttvAttributeValue v
;
1985 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1987 g_assert(*(v
.v_pointer
) != NULL
);
1988 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1989 //tcs->eventtype_names = name_tables->eventtype_names;
1990 tcs
->syscall_names
= name_tables
->syscall_names
;
1991 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1992 tcs
->trap_names
= name_tables
->trap_names
;
1993 tcs
->nb_traps
= name_tables
->nb_traps
;
1994 tcs
->irq_names
= name_tables
->irq_names
;
1995 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1996 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1997 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
2002 free_name_tables(LttvTraceState
*tcs
)
2004 LttvNameTables
*name_tables
;
2006 LttvAttributeValue v
;
2008 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2010 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2011 *(v
.v_pointer
) = NULL
;
2013 // g_free(name_tables->eventtype_names);
2014 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2015 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2016 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2017 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2018 if(name_tables
) g_free(name_tables
);
2021 #ifdef HASH_TABLE_DEBUG
2023 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2025 LttvProcessState
*process
= (LttvProcessState
*)value
;
2027 /* Test for process corruption */
2028 guint stack_len
= process
->execution_stack
->len
;
2031 static void hash_table_check(GHashTable
*table
)
2033 g_hash_table_foreach(table
, test_process
, NULL
);
2039 /* clears the stack and sets the state passed as argument */
2040 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2042 g_array_set_size(cpust
->mode_stack
, 1);
2043 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2046 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2048 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2049 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2052 static void cpu_pop_mode(LttvCPUState
*cpust
)
2054 if(cpust
->mode_stack
->len
<= 1)
2055 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2057 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2060 /* clears the stack and sets the state passed as argument */
2061 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2063 g_array_set_size(bdevst
->mode_stack
, 1);
2064 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2067 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2069 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2070 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2073 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2075 if(bdevst
->mode_stack
->len
<= 1)
2076 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2078 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2081 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2083 g_array_set_size(irqst
->mode_stack
, 1);
2084 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2087 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2089 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2090 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2093 static void irq_pop_mode(LttvIRQState
*irqst
)
2095 if(irqst
->mode_stack
->len
<= 1)
2096 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2098 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2101 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2104 LttvExecutionState
*es
;
2106 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2107 guint cpu
= tfs
->cpu
;
2109 #ifdef HASH_TABLE_DEBUG
2110 hash_table_check(ts
->processes
);
2112 LttvProcessState
*process
= ts
->running_process
[cpu
];
2114 guint depth
= process
->execution_stack
->len
;
2116 process
->execution_stack
=
2117 g_array_set_size(process
->execution_stack
, depth
+ 1);
2120 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2122 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2125 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2126 es
->cum_cpu_time
= ltt_time_zero
;
2127 es
->s
= process
->state
->s
;
2128 process
->state
= es
;
2132 * return 1 when empty, else 0 */
2133 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2134 LttvTracefileState
*tfs
)
2136 guint depth
= process
->execution_stack
->len
;
2142 process
->execution_stack
=
2143 g_array_set_size(process
->execution_stack
, depth
- 1);
2144 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2146 process
->state
->change
= tfs
->parent
.timestamp
;
2151 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2153 guint cpu
= tfs
->cpu
;
2154 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2155 LttvProcessState
*process
= ts
->running_process
[cpu
];
2157 guint depth
= process
->execution_stack
->len
;
2159 if(process
->state
->t
!= t
){
2160 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2161 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2162 g_info("process state has %s when pop_int is %s\n",
2163 g_quark_to_string(process
->state
->t
),
2164 g_quark_to_string(t
));
2165 g_info("{ %u, %u, %s, %s, %s }\n",
2168 g_quark_to_string(process
->name
),
2169 g_quark_to_string(process
->brand
),
2170 g_quark_to_string(process
->state
->s
));
2175 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2176 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2180 process
->execution_stack
=
2181 g_array_set_size(process
->execution_stack
, depth
- 1);
2182 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2184 process
->state
->change
= tfs
->parent
.timestamp
;
2187 struct search_result
{
2188 const LttTime
*time
; /* Requested time */
2189 LttTime
*best
; /* Best result */
2192 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2194 const LttTime
*elem_time
= (const LttTime
*)a
;
2195 /* Explicit non const cast */
2196 struct search_result
*res
= (struct search_result
*)b
;
2198 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2199 /* The usertrace was created before the schedchange */
2200 /* Get larger keys */
2202 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2203 /* The usertrace was created after the schedchange time */
2204 /* Get smaller keys */
2206 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2207 res
->best
= (LttTime
*)elem_time
;
2210 res
->best
= (LttTime
*)elem_time
;
2217 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2218 guint pid
, const LttTime
*timestamp
)
2220 LttvTracefileState
*tfs
= NULL
;
2221 struct search_result res
;
2222 /* Find the usertrace associated with a pid and time interval.
2223 * Search in the usertraces by PID (within a hash) and then, for each
2224 * corresponding element of the array, find the first one with creation
2225 * timestamp the lowest, but higher or equal to "timestamp". */
2226 res
.time
= timestamp
;
2228 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2229 if(usertrace_tree
) {
2230 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2232 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2240 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2241 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2243 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2245 LttvExecutionState
*es
;
2250 process
->tgid
= tgid
;
2252 process
->name
= name
;
2253 process
->brand
= LTTV_STATE_UNBRANDED
;
2254 //process->last_cpu = tfs->cpu_name;
2255 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2256 process
->type
= LTTV_STATE_USER_THREAD
;
2257 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2258 process
->current_function
= 0; //function 0x0 by default.
2260 g_info("Process %u, core %p", process
->pid
, process
);
2261 g_hash_table_insert(tcs
->processes
, process
, process
);
2264 process
->ppid
= parent
->pid
;
2265 process
->creation_time
= *timestamp
;
2268 /* No parent. This process exists but we are missing all information about
2269 its creation. The birth time is set to zero but we remember the time of
2274 process
->creation_time
= ltt_time_zero
;
2277 process
->insertion_time
= *timestamp
;
2278 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2279 process
->creation_time
.tv_nsec
);
2280 process
->pid_time
= g_quark_from_string(buffer
);
2282 process
->free_events
= 0;
2283 //process->last_cpu = tfs->cpu_name;
2284 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2285 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2286 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2287 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2288 es
= process
->state
= &g_array_index(process
->execution_stack
,
2289 LttvExecutionState
, 0);
2290 es
->t
= LTTV_STATE_USER_MODE
;
2291 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2292 es
->entry
= *timestamp
;
2293 //g_assert(timestamp->tv_sec != 0);
2294 es
->change
= *timestamp
;
2295 es
->cum_cpu_time
= ltt_time_zero
;
2296 es
->s
= LTTV_STATE_RUN
;
2298 es
= process
->state
= &g_array_index(process
->execution_stack
,
2299 LttvExecutionState
, 1);
2300 es
->t
= LTTV_STATE_SYSCALL
;
2301 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2302 es
->entry
= *timestamp
;
2303 //g_assert(timestamp->tv_sec != 0);
2304 es
->change
= *timestamp
;
2305 es
->cum_cpu_time
= ltt_time_zero
;
2306 es
->s
= LTTV_STATE_WAIT_FORK
;
2308 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2309 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2310 sizeof(guint64
), 0);
2315 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2318 LttvProcessState key
;
2319 LttvProcessState
*process
;
2323 process
= g_hash_table_lookup(ts
->processes
, &key
);
2328 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2329 const LttTime
*timestamp
)
2331 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2332 LttvExecutionState
*es
;
2334 /* Put ltt_time_zero creation time for unexisting processes */
2335 if(unlikely(process
== NULL
)) {
2336 process
= lttv_state_create_process(ts
,
2337 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2338 /* We are not sure is it's a kernel thread or normal thread, put the
2339 * bottom stack state to unknown */
2340 process
->execution_stack
=
2341 g_array_set_size(process
->execution_stack
, 1);
2342 process
->state
= es
=
2343 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2344 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2345 es
->s
= LTTV_STATE_UNNAMED
;
2350 /* FIXME : this function should be called when we receive an event telling that
2351 * release_task has been called in the kernel. In happens generally when
2352 * the parent waits for its child terminaison, but may also happen in special
2353 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2354 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2355 * of a killed thread group, but isn't the leader.
2357 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2359 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2360 LttvProcessState key
;
2362 /* Wait for both schedule with exit dead and process free to happen.
2363 * They can happen in any order. */
2364 if (++(process
->free_events
) < 2)
2367 key
.pid
= process
->pid
;
2368 key
.cpu
= process
->cpu
;
2369 g_hash_table_remove(ts
->processes
, &key
);
2370 g_array_free(process
->execution_stack
, TRUE
);
2371 g_array_free(process
->user_stack
, TRUE
);
2377 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2379 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2380 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2385 static void lttv_state_free_process_table(GHashTable
*processes
)
2387 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2388 g_hash_table_destroy(processes
);
2392 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2394 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2396 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2397 LttvProcessState
*process
= ts
->running_process
[cpu
];
2398 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2399 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2400 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2401 LttvExecutionSubmode submode
;
2403 guint syscall
= ltt_event_get_unsigned(e
, f
);
2404 expand_syscall_table(ts
, syscall
);
2405 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2406 /* There can be no system call from PID 0 : unknown state */
2407 if(process
->pid
!= 0)
2408 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2413 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2415 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2417 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2418 LttvProcessState
*process
= ts
->running_process
[cpu
];
2420 /* There can be no system call from PID 0 : unknown state */
2421 if(process
->pid
!= 0)
2422 pop_state(s
, LTTV_STATE_SYSCALL
);
2427 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2429 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2430 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2431 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2432 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2433 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2435 LttvExecutionSubmode submode
;
2437 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2439 expand_trap_table(ts
, trap
);
2441 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2443 push_state(s
, LTTV_STATE_TRAP
, submode
);
2445 /* update cpu status */
2446 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2448 /* update trap status */
2449 s
->cpu_state
->last_trap
= trap
;
2450 ts
->trap_states
[trap
].running
++;
2455 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2457 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2458 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2459 guint trap
= s
->cpu_state
->last_trap
;
2461 pop_state(s
, LTTV_STATE_TRAP
);
2463 /* update cpu status */
2464 cpu_pop_mode(s
->cpu_state
);
2466 /* update trap status */
2467 if(ts
->trap_states
[trap
].running
)
2468 ts
->trap_states
[trap
].running
--;
2473 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2475 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2476 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2477 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2478 //guint8 ev_id = ltt_event_eventtype_id(e);
2479 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2480 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2482 LttvExecutionSubmode submode
;
2483 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2485 expand_irq_table(ts
, irq
);
2487 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2489 /* Do something with the info about being in user or system mode when int? */
2490 push_state(s
, LTTV_STATE_IRQ
, submode
);
2492 /* update cpu status */
2493 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2495 /* update irq status */
2496 s
->cpu_state
->last_irq
= irq
;
2497 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2502 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2504 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2505 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2506 guint softirq
= s
->cpu_state
->last_soft_irq
;
2508 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2510 /* update softirq status */
2511 if(ts
->soft_irq_states
[softirq
].running
)
2512 ts
->soft_irq_states
[softirq
].running
--;
2514 /* update cpu status */
2515 cpu_pop_mode(s
->cpu_state
);
2520 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2522 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2523 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2525 pop_state(s
, LTTV_STATE_IRQ
);
2527 /* update cpu status */
2528 cpu_pop_mode(s
->cpu_state
);
2530 /* update irq status */
2531 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2536 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2538 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2539 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2540 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2541 //guint8 ev_id = ltt_event_eventtype_id(e);
2542 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2543 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2545 LttvExecutionSubmode submode
;
2546 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2547 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2549 if(softirq
< nb_softirqs
) {
2550 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2552 /* Fixup an incomplete irq table */
2553 GString
*string
= g_string_new("");
2554 g_string_printf(string
, "softirq %llu", softirq
);
2555 submode
= g_quark_from_string(string
->str
);
2556 g_string_free(string
, TRUE
);
2559 /* update softirq status */
2560 /* a soft irq raises are not cumulative */
2561 ts
->soft_irq_states
[softirq
].pending
=1;
2566 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2568 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2569 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2570 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2571 //guint8 ev_id = ltt_event_eventtype_id(e);
2572 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2573 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2574 LttvExecutionSubmode submode
;
2575 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2576 expand_soft_irq_table(ts
, softirq
);
2577 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2579 /* Do something with the info about being in user or system mode when int? */
2580 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2582 /* update cpu status */
2583 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2585 /* update softirq status */
2586 s
->cpu_state
->last_soft_irq
= softirq
;
2587 if(ts
->soft_irq_states
[softirq
].pending
)
2588 ts
->soft_irq_states
[softirq
].pending
--;
2589 ts
->soft_irq_states
[softirq
].running
++;
2594 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2596 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2597 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2598 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2599 //guint8 ev_id = ltt_event_eventtype_id(e);
2600 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2602 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2603 lttv_trace_get_hook_field(th
, 0)));
2604 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2606 expand_irq_table(ts
, irq
);
2607 ts
->irq_names
[irq
] = action
;
2613 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2615 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2616 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2617 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2618 //guint8 ev_id = ltt_event_eventtype_id(e);
2619 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2621 guint major
= ltt_event_get_long_unsigned(e
,
2622 lttv_trace_get_hook_field(th
, 0));
2623 guint minor
= ltt_event_get_long_unsigned(e
,
2624 lttv_trace_get_hook_field(th
, 1));
2625 guint oper
= ltt_event_get_long_unsigned(e
,
2626 lttv_trace_get_hook_field(th
, 2));
2627 guint16 devcode
= MKDEV(major
,minor
);
2629 /* have we seen this block device before? */
2630 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2633 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2635 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2640 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2642 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2643 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2644 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2645 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2647 guint major
= ltt_event_get_long_unsigned(e
,
2648 lttv_trace_get_hook_field(th
, 0));
2649 guint minor
= ltt_event_get_long_unsigned(e
,
2650 lttv_trace_get_hook_field(th
, 1));
2651 //guint oper = ltt_event_get_long_unsigned(e,
2652 // lttv_trace_get_hook_field(th, 2));
2653 guint16 devcode
= MKDEV(major
,minor
);
2655 /* have we seen this block device before? */
2656 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2658 /* update block device */
2659 bdev_pop_mode(bdev
);
2664 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2668 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2669 guint cpu
= tfs
->cpu
;
2670 LttvProcessState
*process
= ts
->running_process
[cpu
];
2672 guint depth
= process
->user_stack
->len
;
2674 process
->user_stack
=
2675 g_array_set_size(process
->user_stack
, depth
+ 1);
2677 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2678 *new_func
= funcptr
;
2679 process
->current_function
= funcptr
;
2682 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2684 guint cpu
= tfs
->cpu
;
2685 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2686 LttvProcessState
*process
= ts
->running_process
[cpu
];
2688 if(process
->current_function
!= funcptr
){
2689 g_info("Different functions (%lu.%09lu): ignore it\n",
2690 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2691 g_info("process state has %llu when pop_function is %llu\n",
2692 process
->current_function
, funcptr
);
2693 g_info("{ %u, %u, %s, %s, %s }\n",
2696 g_quark_to_string(process
->name
),
2697 g_quark_to_string(process
->brand
),
2698 g_quark_to_string(process
->state
->s
));
2701 guint depth
= process
->user_stack
->len
;
2704 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2705 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2709 process
->user_stack
=
2710 g_array_set_size(process
->user_stack
, depth
- 1);
2711 process
->current_function
=
2712 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2716 static gboolean
function_entry(void *hook_data
, void *call_data
)
2718 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2719 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2720 //guint8 ev_id = ltt_event_eventtype_id(e);
2721 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2722 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2723 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2725 push_function(s
, funcptr
);
2729 static gboolean
function_exit(void *hook_data
, void *call_data
)
2731 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2732 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2733 //guint8 ev_id = ltt_event_eventtype_id(e);
2734 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2735 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2736 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2738 pop_function(s
, funcptr
);
2742 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2744 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2745 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2746 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2747 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2752 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2753 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2754 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2756 expand_syscall_table(ts
, id
);
2757 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2762 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2765 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2767 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2772 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2773 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2774 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2776 expand_soft_irq_table(ts
, id
);
2777 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2782 static gboolean
schedchange(void *hook_data
, void *call_data
)
2784 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2786 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2787 LttvProcessState
*process
= ts
->running_process
[cpu
];
2788 //LttvProcessState *old_process = ts->running_process[cpu];
2790 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2791 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2792 guint pid_in
, pid_out
;
2795 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2796 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2797 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2799 if(likely(process
!= NULL
)) {
2801 /* We could not know but it was not the idle process executing.
2802 This should only happen at the beginning, before the first schedule
2803 event, and when the initial information (current process for each CPU)
2804 is missing. It is not obvious how we could, after the fact, compensate
2805 the wrongly attributed statistics. */
2807 //This test only makes sense once the state is known and if there is no
2808 //missing events. We need to silently ignore schedchange coming after a
2809 //process_free, or it causes glitches. (FIXME)
2810 //if(unlikely(process->pid != pid_out)) {
2811 // g_assert(process->pid == 0);
2813 if(process
->pid
== 0
2814 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2816 /* Scheduling out of pid 0 at beginning of the trace :
2817 * we know for sure it is in syscall mode at this point. */
2818 g_assert(process
->execution_stack
->len
== 1);
2819 process
->state
->t
= LTTV_STATE_SYSCALL
;
2820 process
->state
->s
= LTTV_STATE_WAIT
;
2821 process
->state
->change
= s
->parent
.timestamp
;
2822 process
->state
->entry
= s
->parent
.timestamp
;
2825 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2826 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2827 process
->state
->change
= s
->parent
.timestamp
;
2829 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2830 else process
->state
->s
= LTTV_STATE_WAIT
;
2831 process
->state
->change
= s
->parent
.timestamp
;
2834 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2835 /* see sched.h for states */
2836 if (!exit_process(s
, process
)) {
2837 process
->state
->s
= LTTV_STATE_DEAD
;
2838 process
->state
->change
= s
->parent
.timestamp
;
2843 process
= ts
->running_process
[cpu
] =
2844 lttv_state_find_process_or_create(
2845 (LttvTraceState
*)s
->parent
.t_context
,
2847 &s
->parent
.timestamp
);
2848 process
->state
->s
= LTTV_STATE_RUN
;
2850 if(process
->usertrace
)
2851 process
->usertrace
->cpu
= cpu
;
2852 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2853 process
->state
->change
= s
->parent
.timestamp
;
2855 /* update cpu status */
2857 /* going to idle task */
2858 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2860 /* scheduling a real task.
2861 * we must be careful here:
2862 * if we just schedule()'ed to a process that is
2863 * in a trap, we must put the cpu in trap mode
2865 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2866 if(process
->state
->t
== LTTV_STATE_TRAP
)
2867 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2873 static gboolean
process_fork(void *hook_data
, void *call_data
)
2875 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2876 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2877 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2879 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2880 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2881 //LttvProcessState *zombie_process;
2883 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2884 LttvProcessState
*process
= ts
->running_process
[cpu
];
2885 LttvProcessState
*child_process
;
2886 struct marker_field
*f
;
2889 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2892 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2893 s
->parent
.target_pid
= child_pid
;
2896 f
= lttv_trace_get_hook_field(th
, 2);
2898 child_tgid
= ltt_event_get_unsigned(e
, f
);
2902 /* Mathieu : it seems like the process might have been scheduled in before the
2903 * fork, and, in a rare case, might be the current process. This might happen
2904 * in a SMP case where we don't have enough precision on the clocks.
2906 * Test reenabled after precision fixes on time. (Mathieu) */
2908 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2910 if(unlikely(zombie_process
!= NULL
)) {
2911 /* Reutilisation of PID. Only now we are sure that the old PID
2912 * has been released. FIXME : should know when release_task happens instead.
2914 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2916 for(i
=0; i
< num_cpus
; i
++) {
2917 g_assert(zombie_process
!= ts
->running_process
[i
]);
2920 exit_process(s
, zombie_process
);
2923 g_assert(process
->pid
!= child_pid
);
2924 // FIXME : Add this test in the "known state" section
2925 // g_assert(process->pid == parent_pid);
2926 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2927 if(child_process
== NULL
) {
2928 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2929 child_pid
, child_tgid
,
2930 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2932 /* The process has already been created : due to time imprecision between
2933 * multiple CPUs : it has been scheduled in before creation. Note that we
2934 * shouldn't have this kind of imprecision.
2936 * Simply put a correct parent.
2938 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2939 //g_assert(0); /* This is a problematic case : the process has been created
2940 // before the fork event */
2941 child_process
->ppid
= process
->pid
;
2942 child_process
->tgid
= child_tgid
;
2944 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2945 child_process
->name
= process
->name
;
2946 child_process
->brand
= process
->brand
;
2951 /* We stamp a newly created process as kernel_thread.
2952 * The thread should not be running yet. */
2953 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2955 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2956 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2957 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2959 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2960 LttvProcessState
*process
;
2961 LttvExecutionState
*es
;
2964 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2965 s
->parent
.target_pid
= pid
;
2967 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2969 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2970 process
->execution_stack
=
2971 g_array_set_size(process
->execution_stack
, 1);
2972 es
= process
->state
=
2973 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2974 es
->t
= LTTV_STATE_SYSCALL
;
2976 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2981 static gboolean
process_exit(void *hook_data
, void *call_data
)
2983 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2984 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2985 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2987 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2988 LttvProcessState
*process
; // = ts->running_process[cpu];
2990 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2991 s
->parent
.target_pid
= pid
;
2993 // FIXME : Add this test in the "known state" section
2994 // g_assert(process->pid == pid);
2996 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2997 if(likely(process
!= NULL
)) {
2998 process
->state
->s
= LTTV_STATE_EXIT
;
3003 static gboolean
process_free(void *hook_data
, void *call_data
)
3005 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3006 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3007 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3008 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3010 LttvProcessState
*process
;
3012 /* PID of the process to release */
3013 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3014 s
->parent
.target_pid
= release_pid
;
3016 g_assert(release_pid
!= 0);
3018 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3019 if(likely(process
!= NULL
))
3020 exit_process(s
, process
);
3023 if(likely(process
!= NULL
)) {
3024 /* release_task is happening at kernel level : we can now safely release
3025 * the data structure of the process */
3026 //This test is fun, though, as it may happen that
3027 //at time t : CPU 0 : process_free
3028 //at time t+150ns : CPU 1 : schedule out
3029 //Clearly due to time imprecision, we disable it. (Mathieu)
3030 //If this weird case happen, we have no choice but to put the
3031 //Currently running process on the cpu to 0.
3032 //I re-enable it following time precision fixes. (Mathieu)
3033 //Well, in the case where an process is freed by a process on another CPU
3034 //and still scheduled, it happens that this is the schedchange that will
3035 //drop the last reference count. Do not free it here!
3036 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3038 for(i
=0; i
< num_cpus
; i
++) {
3039 //g_assert(process != ts->running_process[i]);
3040 if(process
== ts
->running_process
[i
]) {
3041 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3045 if(i
== num_cpus
) /* process is not scheduled */
3046 exit_process(s
, process
);
3053 static gboolean
process_exec(void *hook_data
, void *call_data
)
3055 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3056 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3057 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3058 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3061 LttvProcessState
*process
= ts
->running_process
[cpu
];
3063 #if 0//how to use a sequence that must be transformed in a string
3064 /* PID of the process to release */
3065 guint64 name_len
= ltt_event_field_element_number(e
,
3066 lttv_trace_get_hook_field(th
, 0));
3067 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3068 LttField
*child
= ltt_event_field_element_select(e
,
3069 lttv_trace_get_hook_field(th
, 0), 0);
3071 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3072 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3073 memcpy(null_term_name
, name_begin
, name_len
);
3074 null_term_name
[name_len
] = '\0';
3075 process
->name
= g_quark_from_string(null_term_name
);
3078 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3079 lttv_trace_get_hook_field(th
, 0)));
3080 process
->brand
= LTTV_STATE_UNBRANDED
;
3081 //g_free(null_term_name);
3085 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3087 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3088 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3089 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3090 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3093 LttvProcessState
*process
= ts
->running_process
[cpu
];
3095 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3096 process
->brand
= g_quark_from_string(name
);
3101 static void fix_process(gpointer key
, gpointer value
,
3104 LttvProcessState
*process
;
3105 LttvExecutionState
*es
;
3106 process
= (LttvProcessState
*)value
;
3107 LttTime
*timestamp
= (LttTime
*)user_data
;
3109 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3110 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3111 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3112 es
->t
= LTTV_STATE_SYSCALL
;
3113 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3114 es
->entry
= *timestamp
;
3115 es
->change
= *timestamp
;
3116 es
->cum_cpu_time
= ltt_time_zero
;
3117 if(es
->s
== LTTV_STATE_UNNAMED
)
3118 es
->s
= LTTV_STATE_WAIT
;
3121 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3122 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3123 es
->t
= LTTV_STATE_USER_MODE
;
3124 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3125 es
->entry
= *timestamp
;
3126 //g_assert(timestamp->tv_sec != 0);
3127 es
->change
= *timestamp
;
3128 es
->cum_cpu_time
= ltt_time_zero
;
3129 if(es
->s
== LTTV_STATE_UNNAMED
)
3130 es
->s
= LTTV_STATE_RUN
;
3132 if(process
->execution_stack
->len
== 1) {
3133 /* Still in bottom unknown mode, means never did a system call
3134 * May be either in user mode, syscall mode, running or waiting.*/
3135 /* FIXME : we may be tagging syscall mode when being user mode */
3136 process
->execution_stack
=
3137 g_array_set_size(process
->execution_stack
, 2);
3138 es
= process
->state
= &g_array_index(process
->execution_stack
,
3139 LttvExecutionState
, 1);
3140 es
->t
= LTTV_STATE_SYSCALL
;
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_WAIT_FORK
)
3147 es
->s
= LTTV_STATE_WAIT
;
3153 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3155 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3156 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3157 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3158 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3159 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3161 /* For all processes */
3162 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3163 /* else, if stack[0] is unknown, set to user mode, running */
3165 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3170 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3172 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3173 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3174 //It's slow : optimise later by doing this before reading trace.
3175 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3181 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3182 LttvProcessState
*process
= ts
->running_process
[cpu
];
3183 LttvProcessState
*parent_process
;
3184 struct marker_field
*f
;
3185 GQuark type
, mode
, submode
, status
;
3186 LttvExecutionState
*es
;
3190 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3191 s
->parent
.target_pid
= pid
;
3194 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3197 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3200 f
= lttv_trace_get_hook_field(th
, 3);
3201 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3203 //FIXME: type is rarely used, enum must match possible types.
3206 f
= lttv_trace_get_hook_field(th
, 4);
3207 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3210 f
= lttv_trace_get_hook_field(th
, 5);
3211 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3214 f
= lttv_trace_get_hook_field(th
, 6);
3215 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3218 f
= lttv_trace_get_hook_field(th
, 7);
3220 tgid
= ltt_event_get_unsigned(e
, f
);
3225 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3226 for(i
=0; i
<nb_cpus
; i
++) {
3227 process
= lttv_state_find_process(ts
, i
, pid
);
3228 g_assert(process
!= NULL
);
3230 process
->ppid
= parent_pid
;
3231 process
->tgid
= tgid
;
3232 process
->name
= g_quark_from_string(command
);
3234 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3235 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3239 /* The process might exist if a process was forked while performing the
3241 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3242 if(process
== NULL
) {
3243 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3244 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3245 pid
, tgid
, g_quark_from_string(command
),
3246 &s
->parent
.timestamp
);
3248 /* Keep the stack bottom : a running user mode */
3249 /* Disabled because of inconsistencies in the current statedump states. */
3250 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3251 /* Only keep the bottom
3252 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3253 /* Will cause expected trap when in fact being syscall (even after end of
3255 * Will cause expected interrupt when being syscall. (only before end of
3256 * statedump event) */
3257 // This will cause a "popping last state on stack, ignoring it."
3258 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3259 es
= process
->state
= &g_array_index(process
->execution_stack
,
3260 LttvExecutionState
, 0);
3261 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3262 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3263 es
->s
= LTTV_STATE_UNNAMED
;
3264 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3266 es
->t
= LTTV_STATE_SYSCALL
;
3271 /* User space process :
3272 * bottom : user mode
3273 * either currently running or scheduled out.
3274 * can be scheduled out because interrupted in (user mode or in syscall)
3275 * or because of an explicit call to the scheduler in syscall. Note that
3276 * the scheduler call comes after the irq_exit, so never in interrupt
3278 // temp workaround : set size to 1 : only have user mode bottom of stack.
3279 // will cause g_info message of expected syscall mode when in fact being
3280 // in user mode. Can also cause expected trap when in fact being user
3281 // mode in the event of a page fault reenabling interrupts in the handler.
3282 // Expected syscall and trap can also happen after the end of statedump
3283 // This will cause a "popping last state on stack, ignoring it."
3284 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3285 es
= process
->state
= &g_array_index(process
->execution_stack
,
3286 LttvExecutionState
, 0);
3287 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3288 es
->s
= LTTV_STATE_UNNAMED
;
3289 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3291 es
->t
= LTTV_STATE_USER_MODE
;
3299 es
= process
->state
= &g_array_index(process
->execution_stack
,
3300 LttvExecutionState
, 1);
3301 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3302 es
->s
= LTTV_STATE_UNNAMED
;
3303 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3307 /* The process has already been created :
3308 * Probably was forked while dumping the process state or
3309 * was simply scheduled in prior to get the state dump event.
3311 process
->ppid
= parent_pid
;
3312 process
->tgid
= tgid
;
3313 process
->name
= g_quark_from_string(command
);
3314 process
->type
= type
;
3316 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3318 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3319 if(type
== LTTV_STATE_KERNEL_THREAD
)
3320 es
->t
= LTTV_STATE_SYSCALL
;
3322 es
->t
= LTTV_STATE_USER_MODE
;
3325 /* Don't mess around with the stack, it will eventually become
3326 * ok after the end of state dump. */
3333 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3335 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3337 lttv_state_add_event_hooks(tss
);
3342 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3344 LttvTraceset
*traceset
= self
->parent
.ts
;
3346 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3350 LttvTracefileState
*tfs
;
3356 LttvAttributeValue val
;
3358 nb_trace
= lttv_traceset_number(traceset
);
3359 for(i
= 0 ; i
< nb_trace
; i
++) {
3360 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3362 /* Find the eventtype id for the following events and register the
3363 associated by id hooks. */
3365 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3366 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3369 lttv_trace_find_hook(ts
->parent
.t
,
3370 LTT_FACILITY_KERNEL_ARCH
,
3371 LTT_EVENT_SYSCALL_ENTRY
,
3372 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3373 syscall_entry
, NULL
, &hooks
);
3375 lttv_trace_find_hook(ts
->parent
.t
,
3376 LTT_FACILITY_KERNEL_ARCH
,
3377 LTT_EVENT_SYSCALL_EXIT
,
3379 syscall_exit
, NULL
, &hooks
);
3381 lttv_trace_find_hook(ts
->parent
.t
,
3382 LTT_FACILITY_KERNEL_ARCH
,
3383 LTT_EVENT_TRAP_ENTRY
,
3384 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3385 trap_entry
, NULL
, &hooks
);
3387 lttv_trace_find_hook(ts
->parent
.t
,
3388 LTT_FACILITY_KERNEL_ARCH
,
3389 LTT_EVENT_TRAP_EXIT
,
3391 trap_exit
, NULL
, &hooks
);
3393 lttv_trace_find_hook(ts
->parent
.t
,
3394 LTT_FACILITY_KERNEL
,
3395 LTT_EVENT_IRQ_ENTRY
,
3396 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3397 irq_entry
, NULL
, &hooks
);
3399 lttv_trace_find_hook(ts
->parent
.t
,
3400 LTT_FACILITY_KERNEL
,
3403 irq_exit
, NULL
, &hooks
);
3405 lttv_trace_find_hook(ts
->parent
.t
,
3406 LTT_FACILITY_KERNEL
,
3407 LTT_EVENT_SOFT_IRQ_RAISE
,
3408 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3409 soft_irq_raise
, NULL
, &hooks
);
3411 lttv_trace_find_hook(ts
->parent
.t
,
3412 LTT_FACILITY_KERNEL
,
3413 LTT_EVENT_SOFT_IRQ_ENTRY
,
3414 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3415 soft_irq_entry
, NULL
, &hooks
);
3417 lttv_trace_find_hook(ts
->parent
.t
,
3418 LTT_FACILITY_KERNEL
,
3419 LTT_EVENT_SOFT_IRQ_EXIT
,
3421 soft_irq_exit
, NULL
, &hooks
);
3423 lttv_trace_find_hook(ts
->parent
.t
,
3424 LTT_FACILITY_KERNEL
,
3425 LTT_EVENT_SCHED_SCHEDULE
,
3426 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3427 LTT_FIELD_PREV_STATE
),
3428 schedchange
, NULL
, &hooks
);
3430 lttv_trace_find_hook(ts
->parent
.t
,
3431 LTT_FACILITY_KERNEL
,
3432 LTT_EVENT_PROCESS_FORK
,
3433 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3434 LTT_FIELD_CHILD_TGID
),
3435 process_fork
, NULL
, &hooks
);
3437 lttv_trace_find_hook(ts
->parent
.t
,
3438 LTT_FACILITY_KERNEL_ARCH
,
3439 LTT_EVENT_KTHREAD_CREATE
,
3440 FIELD_ARRAY(LTT_FIELD_PID
),
3441 process_kernel_thread
, NULL
, &hooks
);
3443 lttv_trace_find_hook(ts
->parent
.t
,
3444 LTT_FACILITY_KERNEL
,
3445 LTT_EVENT_PROCESS_EXIT
,
3446 FIELD_ARRAY(LTT_FIELD_PID
),
3447 process_exit
, NULL
, &hooks
);
3449 lttv_trace_find_hook(ts
->parent
.t
,
3450 LTT_FACILITY_KERNEL
,
3451 LTT_EVENT_PROCESS_FREE
,
3452 FIELD_ARRAY(LTT_FIELD_PID
),
3453 process_free
, NULL
, &hooks
);
3455 lttv_trace_find_hook(ts
->parent
.t
,
3458 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3459 process_exec
, NULL
, &hooks
);
3461 lttv_trace_find_hook(ts
->parent
.t
,
3462 LTT_FACILITY_USER_GENERIC
,
3463 LTT_EVENT_THREAD_BRAND
,
3464 FIELD_ARRAY(LTT_FIELD_NAME
),
3465 thread_brand
, NULL
, &hooks
);
3467 /* statedump-related hooks */
3468 lttv_trace_find_hook(ts
->parent
.t
,
3470 LTT_EVENT_PROCESS_STATE
,
3471 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3472 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3473 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3474 enum_process_state
, NULL
, &hooks
);
3476 lttv_trace_find_hook(ts
->parent
.t
,
3478 LTT_EVENT_STATEDUMP_END
,
3480 statedump_end
, NULL
, &hooks
);
3482 lttv_trace_find_hook(ts
->parent
.t
,
3484 LTT_EVENT_LIST_INTERRUPT
,
3485 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3486 enum_interrupt
, NULL
, &hooks
);
3488 lttv_trace_find_hook(ts
->parent
.t
,
3490 LTT_EVENT_REQUEST_ISSUE
,
3491 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3492 bdev_request_issue
, NULL
, &hooks
);
3494 lttv_trace_find_hook(ts
->parent
.t
,
3496 LTT_EVENT_REQUEST_COMPLETE
,
3497 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3498 bdev_request_complete
, NULL
, &hooks
);
3500 lttv_trace_find_hook(ts
->parent
.t
,
3501 LTT_FACILITY_USER_GENERIC
,
3502 LTT_EVENT_FUNCTION_ENTRY
,
3503 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3504 function_entry
, NULL
, &hooks
);
3506 lttv_trace_find_hook(ts
->parent
.t
,
3507 LTT_FACILITY_USER_GENERIC
,
3508 LTT_EVENT_FUNCTION_EXIT
,
3509 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3510 function_exit
, NULL
, &hooks
);
3512 lttv_trace_find_hook(ts
->parent
.t
,
3513 LTT_FACILITY_STATEDUMP
,
3514 LTT_EVENT_SYS_CALL_TABLE
,
3515 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3516 dump_syscall
, NULL
, &hooks
);
3518 lttv_trace_find_hook(ts
->parent
.t
,
3519 LTT_FACILITY_STATEDUMP
,
3520 LTT_EVENT_SOFTIRQ_VEC
,
3521 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3522 dump_softirq
, NULL
, &hooks
);
3524 /* Add these hooks to each event_by_id hooks list */
3526 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3528 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3530 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3531 LttvTracefileContext
*, j
));
3533 for(k
= 0 ; k
< hooks
->len
; k
++) {
3534 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3536 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3542 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3543 *(val
.v_pointer
) = hooks
;
3547 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3549 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3551 lttv_state_remove_event_hooks(tss
);
3556 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3558 LttvTraceset
*traceset
= self
->parent
.ts
;
3560 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3564 LttvTracefileState
*tfs
;
3570 LttvAttributeValue val
;
3572 nb_trace
= lttv_traceset_number(traceset
);
3573 for(i
= 0 ; i
< nb_trace
; i
++) {
3574 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3576 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3577 hooks
= *(val
.v_pointer
);
3579 /* Remove these hooks from each event_by_id hooks list */
3581 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3583 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3585 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3586 LttvTracefileContext
*, j
));
3588 for(k
= 0 ; k
< hooks
->len
; k
++) {
3589 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3590 lttv_hooks_remove_data(
3591 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3596 lttv_trace_hook_remove_all(&hooks
);
3597 g_array_free(hooks
, TRUE
);
3601 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3603 guint
*event_count
= (guint
*)hook_data
;
3605 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3606 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3611 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3613 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3615 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3617 LttvAttributeValue value
;
3619 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3620 LTTV_STATE_SAVED_STATES
);
3621 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3622 value
= lttv_attribute_add(saved_states_tree
,
3623 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3624 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3625 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3626 *(value
.v_time
) = self
->parent
.timestamp
;
3627 lttv_state_save(tcs
, saved_state_tree
);
3628 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3629 self
->parent
.timestamp
.tv_nsec
);
3631 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3636 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3638 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3640 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3645 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3653 static gboolean
block_start(void *hook_data
, void *call_data
)
3655 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3657 LttvTracefileState
*tfcs
;
3659 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3661 LttEventPosition
*ep
;
3663 guint i
, nb_block
, nb_event
, nb_tracefile
;
3667 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3669 LttvAttributeValue value
;
3671 ep
= ltt_event_position_new();
3673 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3675 /* Count the number of events added since the last block end in any
3678 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3680 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3681 LttvTracefileContext
, i
));
3682 ltt_event_position(tfcs
->parent
.e
, ep
);
3683 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3684 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3685 tfcs
->saved_position
= nb_event
;
3689 if(tcs
->nb_event
>= tcs
->save_interval
) {
3690 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3691 LTTV_STATE_SAVED_STATES
);
3692 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3693 value
= lttv_attribute_add(saved_states_tree
,
3694 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3695 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3696 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3697 *(value
.v_time
) = self
->parent
.timestamp
;
3698 lttv_state_save(tcs
, saved_state_tree
);
3700 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3701 self
->parent
.timestamp
.tv_nsec
);
3703 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3709 static gboolean
block_end(void *hook_data
, void *call_data
)
3711 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3713 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3717 LttEventPosition
*ep
;
3719 guint nb_block
, nb_event
;
3721 ep
= ltt_event_position_new();
3722 ltt_event_position(self
->parent
.e
, ep
);
3723 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3724 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3725 self
->saved_position
= 0;
3726 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3733 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3735 LttvTraceset
*traceset
= self
->parent
.ts
;
3737 guint i
, j
, nb_trace
, nb_tracefile
;
3741 LttvTracefileState
*tfs
;
3743 LttvTraceHook hook_start
, hook_end
;
3745 nb_trace
= lttv_traceset_number(traceset
);
3746 for(i
= 0 ; i
< nb_trace
; i
++) {
3747 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3749 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3750 NULL
, NULL
, block_start
, &hook_start
);
3751 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3752 NULL
, NULL
, block_end
, &hook_end
);
3754 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3756 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3758 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3759 LttvTracefileContext
, j
));
3760 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3761 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3762 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3763 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3769 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3771 LttvTraceset
*traceset
= self
->parent
.ts
;
3773 guint i
, j
, nb_trace
, nb_tracefile
;
3777 LttvTracefileState
*tfs
;
3780 nb_trace
= lttv_traceset_number(traceset
);
3781 for(i
= 0 ; i
< nb_trace
; i
++) {
3783 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3784 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3786 if(ts
->has_precomputed_states
) continue;
3788 guint
*event_count
= g_new(guint
, 1);
3791 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3793 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3794 LttvTracefileContext
*, j
));
3795 lttv_hooks_add(tfs
->parent
.event
,
3796 state_save_event_hook
,
3803 lttv_process_traceset_begin(&self
->parent
,
3804 NULL
, NULL
, NULL
, NULL
, NULL
);
3808 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3810 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3812 lttv_state_save_add_event_hooks(tss
);
3819 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3821 LttvTraceset
*traceset
= self
->parent
.ts
;
3823 guint i
, j
, nb_trace
, nb_tracefile
;
3827 LttvTracefileState
*tfs
;
3829 LttvTraceHook hook_start
, hook_end
;
3831 nb_trace
= lttv_traceset_number(traceset
);
3832 for(i
= 0 ; i
< nb_trace
; i
++) {
3833 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3835 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3836 NULL
, NULL
, block_start
, &hook_start
);
3838 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3839 NULL
, NULL
, block_end
, &hook_end
);
3841 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3843 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3845 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3846 LttvTracefileContext
, j
));
3847 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3848 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3849 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3850 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3856 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3858 LttvTraceset
*traceset
= self
->parent
.ts
;
3860 guint i
, j
, nb_trace
, nb_tracefile
;
3864 LttvTracefileState
*tfs
;
3866 LttvHooks
*after_trace
= lttv_hooks_new();
3868 lttv_hooks_add(after_trace
,
3869 state_save_after_trace_hook
,
3874 lttv_process_traceset_end(&self
->parent
,
3875 NULL
, after_trace
, NULL
, NULL
, NULL
);
3877 lttv_hooks_destroy(after_trace
);
3879 nb_trace
= lttv_traceset_number(traceset
);
3880 for(i
= 0 ; i
< nb_trace
; i
++) {
3882 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3883 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3885 if(ts
->has_precomputed_states
) continue;
3887 guint
*event_count
= NULL
;
3889 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3891 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3892 LttvTracefileContext
*, j
));
3893 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3894 state_save_event_hook
);
3896 if(event_count
) g_free(event_count
);
3900 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3902 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3904 lttv_state_save_remove_event_hooks(tss
);
3909 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3911 LttvTraceset
*traceset
= self
->parent
.ts
;
3915 int min_pos
, mid_pos
, max_pos
;
3917 guint call_rest
= 0;
3919 LttvTraceState
*tcs
;
3921 LttvAttributeValue value
;
3923 LttvAttributeType type
;
3925 LttvAttributeName name
;
3929 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3931 //g_tree_destroy(self->parent.pqueue);
3932 //self->parent.pqueue = g_tree_new(compare_tracefile);
3934 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3936 nb_trace
= lttv_traceset_number(traceset
);
3937 for(i
= 0 ; i
< nb_trace
; i
++) {
3938 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3940 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3941 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3942 LTTV_STATE_SAVED_STATES
);
3945 if(saved_states_tree
) {
3946 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3947 mid_pos
= max_pos
/ 2;
3948 while(min_pos
< max_pos
) {
3949 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3951 g_assert(type
== LTTV_GOBJECT
);
3952 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3953 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3955 g_assert(type
== LTTV_TIME
);
3956 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3958 closest_tree
= saved_state_tree
;
3960 else max_pos
= mid_pos
- 1;
3962 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3966 /* restore the closest earlier saved state */
3968 lttv_state_restore(tcs
, closest_tree
);
3972 /* There is no saved state, yet we want to have it. Restart at T0 */
3974 restore_init_state(tcs
);
3975 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3978 /* We want to seek quickly without restoring/updating the state */
3980 restore_init_state(tcs
);
3981 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3984 if(!call_rest
) g_info("NOT Calling restore");
3989 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3995 traceset_state_finalize (LttvTracesetState
*self
)
3997 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3998 finalize(G_OBJECT(self
));
4003 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4005 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4007 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4008 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4009 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4010 klass
->new_traceset_context
= new_traceset_context
;
4011 klass
->new_trace_context
= new_trace_context
;
4012 klass
->new_tracefile_context
= new_tracefile_context
;
4017 lttv_traceset_state_get_type(void)
4019 static GType type
= 0;
4021 static const GTypeInfo info
= {
4022 sizeof (LttvTracesetStateClass
),
4023 NULL
, /* base_init */
4024 NULL
, /* base_finalize */
4025 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4026 NULL
, /* class_finalize */
4027 NULL
, /* class_data */
4028 sizeof (LttvTracesetState
),
4029 0, /* n_preallocs */
4030 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4031 NULL
/* value handling */
4034 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4042 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4048 trace_state_finalize (LttvTraceState
*self
)
4050 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4051 finalize(G_OBJECT(self
));
4056 trace_state_class_init (LttvTraceStateClass
*klass
)
4058 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4060 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4061 klass
->state_save
= state_save
;
4062 klass
->state_restore
= state_restore
;
4063 klass
->state_saved_free
= state_saved_free
;
4068 lttv_trace_state_get_type(void)
4070 static GType type
= 0;
4072 static const GTypeInfo info
= {
4073 sizeof (LttvTraceStateClass
),
4074 NULL
, /* base_init */
4075 NULL
, /* base_finalize */
4076 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4077 NULL
, /* class_finalize */
4078 NULL
, /* class_data */
4079 sizeof (LttvTraceState
),
4080 0, /* n_preallocs */
4081 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4082 NULL
/* value handling */
4085 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4086 "LttvTraceStateType", &info
, 0);
4093 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4099 tracefile_state_finalize (LttvTracefileState
*self
)
4101 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4102 finalize(G_OBJECT(self
));
4107 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4109 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4111 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4116 lttv_tracefile_state_get_type(void)
4118 static GType type
= 0;
4120 static const GTypeInfo info
= {
4121 sizeof (LttvTracefileStateClass
),
4122 NULL
, /* base_init */
4123 NULL
, /* base_finalize */
4124 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4125 NULL
, /* class_finalize */
4126 NULL
, /* class_data */
4127 sizeof (LttvTracefileState
),
4128 0, /* n_preallocs */
4129 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4130 NULL
/* value handling */
4133 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4134 "LttvTracefileStateType", &info
, 0);
4140 static void module_init()
4142 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4143 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4144 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4145 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4146 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4147 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4148 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4149 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4150 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4151 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4152 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4153 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4154 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4155 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4156 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4157 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4158 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4159 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4160 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4161 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4162 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4163 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4164 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4165 LTTV_STATE_EVENT
= g_quark_from_string("event");
4166 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4167 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4168 LTTV_STATE_TIME
= g_quark_from_string("time");
4169 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4170 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4171 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4172 g_quark_from_string("trace_state_use_count");
4173 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4174 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4175 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4176 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4177 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4178 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4181 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4182 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4183 LTT_FACILITY_FS
= g_quark_from_string("fs");
4184 LTT_FACILITY_LIST
= g_quark_from_string("list");
4185 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4186 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4187 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4189 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4190 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4191 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4192 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4193 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4194 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4195 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4196 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4197 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4198 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4199 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4200 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4201 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4202 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4203 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4204 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4205 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4206 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4207 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4208 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4209 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4210 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4211 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4212 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4213 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4215 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4216 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4217 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4218 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4219 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4220 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4221 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4222 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4223 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4224 LTT_FIELD_PID
= g_quark_from_string("pid");
4225 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4226 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4227 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4228 LTT_FIELD_NAME
= g_quark_from_string("name");
4229 LTT_FIELD_TYPE
= g_quark_from_string("type");
4230 LTT_FIELD_MODE
= g_quark_from_string("mode");
4231 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4232 LTT_FIELD_STATUS
= g_quark_from_string("status");
4233 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4234 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4235 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4236 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4237 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4238 LTT_FIELD_ACTION
= g_quark_from_string("action");
4239 LTT_FIELD_ID
= g_quark_from_string("id");
4240 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4241 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4243 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4244 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4245 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4246 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4247 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4248 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4250 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4251 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4252 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4254 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4255 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4256 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4257 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4260 static void module_destroy()
4265 LTTV_MODULE("state", "State computation", \
4266 "Update the system state, possibly saving it at intervals", \
4267 module_init
, module_destroy
)