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_ENTRY
,
69 LTT_EVENT_SOFT_IRQ_EXIT
,
70 LTT_EVENT_SCHED_SCHEDULE
,
71 LTT_EVENT_PROCESS_FORK
,
72 LTT_EVENT_KTHREAD_CREATE
,
73 LTT_EVENT_PROCESS_EXIT
,
74 LTT_EVENT_PROCESS_FREE
,
76 LTT_EVENT_PROCESS_STATE
,
77 LTT_EVENT_STATEDUMP_END
,
78 LTT_EVENT_FUNCTION_ENTRY
,
79 LTT_EVENT_FUNCTION_EXIT
,
80 LTT_EVENT_THREAD_BRAND
,
81 LTT_EVENT_REQUEST_ISSUE
,
82 LTT_EVENT_REQUEST_COMPLETE
,
83 LTT_EVENT_LIST_INTERRUPT
,
84 LTT_EVENT_SYS_CALL_TABLE
,
85 LTT_EVENT_SOFTIRQ_VEC
;
93 LTT_FIELD_SOFT_IRQ_ID
,
101 LTT_FIELD_CHILD_TGID
,
119 LTTV_STATE_MODE_UNKNOWN
,
120 LTTV_STATE_USER_MODE
,
127 LTTV_STATE_SUBMODE_UNKNOWN
,
128 LTTV_STATE_SUBMODE_NONE
;
132 LTTV_STATE_WAIT_FORK
,
141 LTTV_STATE_UNBRANDED
;
144 LTTV_STATE_USER_THREAD
,
145 LTTV_STATE_KERNEL_THREAD
;
163 LTTV_BDEV_BUSY_READING
,
164 LTTV_BDEV_BUSY_WRITING
;
167 LTTV_STATE_TRACEFILES
,
168 LTTV_STATE_PROCESSES
,
170 LTTV_STATE_RUNNING_PROCESS
,
172 LTTV_STATE_SAVED_STATES
,
173 LTTV_STATE_SAVED_STATES_TIME
,
176 LTTV_STATE_NAME_TABLES
,
177 LTTV_STATE_TRACE_STATE_USE_COUNT
,
178 LTTV_STATE_RESOURCE_CPUS
,
179 LTTV_STATE_RESOURCE_CPUS_COUNT
,
180 LTTV_STATE_RESOURCE_IRQS
,
181 LTTV_STATE_RESOURCE_SOFT_IRQS
,
182 LTTV_STATE_RESOURCE_TRAPS
,
183 LTTV_STATE_RESOURCE_BLKDEVS
;
185 static void create_max_time(LttvTraceState
*tcs
);
187 static void get_max_time(LttvTraceState
*tcs
);
189 static void free_max_time(LttvTraceState
*tcs
);
191 static void create_name_tables(LttvTraceState
*tcs
);
193 static void get_name_tables(LttvTraceState
*tcs
);
195 static void free_name_tables(LttvTraceState
*tcs
);
197 static void free_saved_state(LttvTraceState
*tcs
);
199 static void lttv_state_free_process_table(GHashTable
*processes
);
201 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
202 GPtrArray
*quarktable
);
204 /* Resource function prototypes */
205 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
206 static LttvBdevState
*bdevstate_new(void);
207 static void bdevstate_free(LttvBdevState
*);
208 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
209 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
212 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
214 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
218 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
220 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
224 void lttv_state_state_saved_free(LttvTraceState
*self
,
225 LttvAttribute
*container
)
227 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
231 guint
process_hash(gconstpointer key
)
233 guint pid
= ((const LttvProcessState
*)key
)->pid
;
234 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
238 /* If the hash table hash function is well distributed,
239 * the process_equal should compare different pid */
240 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
242 const LttvProcessState
*process_a
, *process_b
;
245 process_a
= (const LttvProcessState
*)a
;
246 process_b
= (const LttvProcessState
*)b
;
248 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
249 else if(likely(process_a
->pid
== 0 &&
250 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
255 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
257 g_tree_destroy((GTree
*)value
);
260 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
262 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
263 g_hash_table_destroy(usertraces
);
266 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
271 static guint
check_expand(nb
, id
)
276 return max(id
+ 1, nb
* 2);
279 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
280 guint nb
, guint new_nb
)
282 /* Expand an incomplete table */
283 GQuark
*old_table
= *table
;
284 *table
= g_new(GQuark
, new_nb
);
285 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
288 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
289 guint new_nb
, const char *def_string
)
292 GString
*fe_name
= g_string_new("");
293 for(i
= nb
; i
< new_nb
; i
++) {
294 g_string_printf(fe_name
, "%s %d", def_string
, i
);
295 table
[i
] = g_quark_from_string(fe_name
->str
);
297 g_string_free(fe_name
, TRUE
);
300 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
302 guint new_nb
= check_expand(ts
->nb_syscalls
, id
);
303 if(likely(new_nb
== ts
->nb_syscalls
))
305 expand_name_table(ts
, &ts
->syscall_names
, ts
->nb_syscalls
, id
);
306 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
307 /* Update the table size */
308 ts
->nb_syscalls
= new_nb
;
311 static void expand_trap_table(LttvTraceState
*ts
, int id
)
313 guint new_nb
= check_expand(ts
->nb_traps
, id
);
315 if(likely(new_nb
== ts
->nb_traps
))
317 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
318 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
319 /* Update the table size */
320 ts
->nb_traps
= new_nb
;
322 LttvTrapState
*old_table
= ts
->trap_states
;
323 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
324 memcpy(ts
->trap_states
, old_table
,
325 ts
->nb_traps
* sizeof(LttvTrapState
));
326 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
327 ts
->trap_states
[i
].running
= 0;
330 static void expand_irq_table(LttvTraceState
*ts
, int id
)
332 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
334 if(likely(new_nb
== ts
->nb_irqs
))
336 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
337 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
339 LttvIRQState
*old_table
= ts
->irq_states
;
340 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
341 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
342 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
343 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
346 /* Update the table size */
347 ts
->nb_irqs
= new_nb
;
350 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
352 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
354 if(likely(new_nb
== ts
->nb_soft_irqs
))
356 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
357 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
359 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
360 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
361 memcpy(ts
->soft_irq_states
, old_table
,
362 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
363 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
364 ts
->soft_irq_states
[i
].running
= 0;
366 /* Update the table size */
367 ts
->nb_soft_irqs
= new_nb
;
371 restore_init_state(LttvTraceState
*self
)
373 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
375 //LttvTracefileState *tfcs;
377 LttTime start_time
, end_time
;
379 /* Free the process tables */
380 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
381 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
382 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
383 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
386 /* Seek time to beginning */
387 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
388 // closest. It's the tracecontext job to seek the trace to the beginning
389 // anyway : the init state might be used at the middle of the trace as well...
390 //g_tree_destroy(self->parent.ts_context->pqueue);
391 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
393 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
395 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
397 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
398 nb_irqs
= self
->nb_irqs
;
399 nb_soft_irqs
= self
->nb_soft_irqs
;
400 nb_traps
= self
->nb_traps
;
402 /* Put the per cpu running_process to beginning state : process 0. */
403 for(i
=0; i
< nb_cpus
; i
++) {
404 LttvExecutionState
*es
;
405 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
406 LTTV_STATE_UNNAMED
, &start_time
);
407 /* We are not sure is it's a kernel thread or normal thread, put the
408 * bottom stack state to unknown */
409 self
->running_process
[i
]->execution_stack
=
410 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
411 es
= self
->running_process
[i
]->state
=
412 &g_array_index(self
->running_process
[i
]->execution_stack
,
413 LttvExecutionState
, 0);
414 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
415 es
->s
= LTTV_STATE_UNNAMED
;
417 //self->running_process[i]->state->s = LTTV_STATE_RUN;
418 self
->running_process
[i
]->cpu
= i
;
420 /* reset cpu states */
421 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
422 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
425 /* reset irq states */
426 for(i
=0; i
<nb_irqs
; i
++) {
427 if(self
->irq_states
[i
].mode_stack
->len
> 0)
428 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
431 /* reset softirq states */
432 for(i
=0; i
<nb_soft_irqs
; i
++) {
433 self
->soft_irq_states
[i
].running
= 0;
436 /* reset trap states */
437 for(i
=0; i
<nb_traps
; i
++) {
438 self
->trap_states
[i
].running
= 0;
441 /* reset bdev states */
442 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
443 //g_hash_table_steal_all(self->bdev_states);
444 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
447 nb_tracefile
= self
->parent
.tracefiles
->len
;
449 for(i
= 0 ; i
< nb_tracefile
; i
++) {
451 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
452 LttvTracefileContext
*, i
));
453 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
454 // tfcs->saved_position = 0;
455 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
456 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
457 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
458 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
463 //static LttTime time_zero = {0,0};
465 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
468 const LttTime
*t1
= (const LttTime
*)a
;
469 const LttTime
*t2
= (const LttTime
*)b
;
471 return ltt_time_compare(*t1
, *t2
);
474 static void free_usertrace_key(gpointer data
)
479 #define MAX_STRING_LEN 4096
482 state_load_saved_states(LttvTraceState
*tcs
)
485 GPtrArray
*quarktable
;
486 const char *trace_path
;
490 tcs
->has_precomputed_states
= FALSE
;
494 gchar buf
[MAX_STRING_LEN
];
497 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
498 strncpy(path
, trace_path
, PATH_MAX
-1);
499 count
= strnlen(trace_path
, PATH_MAX
-1);
500 // quarktable : open, test
501 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
502 fp
= fopen(path
, "r");
504 quarktable
= g_ptr_array_sized_new(4096);
506 /* Index 0 is null */
508 if(hdr
== EOF
) return;
509 g_assert(hdr
== HDR_QUARKS
);
513 if(hdr
== EOF
) break;
514 g_assert(hdr
== HDR_QUARK
);
515 g_ptr_array_set_size(quarktable
, q
+1);
518 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
519 if(buf
[i
] == '\0' || feof(fp
)) break;
522 len
= strnlen(buf
, MAX_STRING_LEN
-1);
523 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
524 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
530 // saved_states : open, test
531 strncpy(path
, trace_path
, PATH_MAX
-1);
532 count
= strnlen(trace_path
, PATH_MAX
-1);
533 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
534 fp
= fopen(path
, "r");
538 if(hdr
!= HDR_TRACE
) goto end
;
540 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
542 tcs
->has_precomputed_states
= TRUE
;
547 /* Free the quarktable */
548 for(i
=0; i
<quarktable
->len
; i
++) {
549 string
= g_ptr_array_index (quarktable
, i
);
552 g_ptr_array_free(quarktable
, TRUE
);
557 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
559 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
562 LttvTraceContext
*tc
;
566 LttvTracefileState
*tfcs
;
568 LttvAttributeValue v
;
570 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
571 init((LttvTracesetContext
*)self
, ts
);
573 nb_trace
= lttv_traceset_number(ts
);
574 for(i
= 0 ; i
< nb_trace
; i
++) {
575 tc
= self
->parent
.traces
[i
];
576 tcs
= LTTV_TRACE_STATE(tc
);
577 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
578 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
582 if(*(v
.v_uint
) == 1) {
583 create_name_tables(tcs
);
584 create_max_time(tcs
);
586 get_name_tables(tcs
);
589 nb_tracefile
= tc
->tracefiles
->len
;
590 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
591 nb_irq
= tcs
->nb_irqs
;
592 tcs
->processes
= NULL
;
593 tcs
->usertraces
= NULL
;
594 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
596 /* init cpu resource stuff */
597 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
598 for(j
= 0; j
<nb_cpu
; j
++) {
599 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
600 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
603 /* init irq resource stuff */
604 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
605 for(j
= 0; j
<nb_irq
; j
++) {
606 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
607 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
610 /* init soft irq stuff */
611 /* the kernel has a statically fixed max of 32 softirqs */
612 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
614 /* init trap stuff */
615 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
617 /* init bdev resource stuff */
618 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
620 restore_init_state(tcs
);
621 for(j
= 0 ; j
< nb_tracefile
; j
++) {
623 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
624 LttvTracefileContext
*, j
));
625 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
626 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
627 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
628 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
629 /* It's a Usertrace */
630 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
631 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
633 if(!usertrace_tree
) {
634 usertrace_tree
= g_tree_new_full(compare_usertraces
,
635 NULL
, free_usertrace_key
, NULL
);
636 g_hash_table_insert(tcs
->usertraces
,
637 (gpointer
)tid
, usertrace_tree
);
639 LttTime
*timestamp
= g_new(LttTime
, 1);
640 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
641 ltt_tracefile_creation(tfcs
->parent
.tf
));
642 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
646 /* See if the trace has saved states */
647 state_load_saved_states(tcs
);
652 fini(LttvTracesetState
*self
)
658 //LttvTracefileState *tfcs;
660 LttvAttributeValue v
;
662 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
663 for(i
= 0 ; i
< nb_trace
; i
++) {
664 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
665 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
668 g_assert(*(v
.v_uint
) != 0);
671 if(*(v
.v_uint
) == 0) {
672 free_name_tables(tcs
);
674 free_saved_state(tcs
);
676 g_free(tcs
->running_process
);
677 tcs
->running_process
= NULL
;
678 lttv_state_free_process_table(tcs
->processes
);
679 lttv_state_free_usertraces(tcs
->usertraces
);
680 tcs
->processes
= NULL
;
681 tcs
->usertraces
= NULL
;
683 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
684 fini((LttvTracesetContext
*)self
);
688 static LttvTracesetContext
*
689 new_traceset_context(LttvTracesetContext
*self
)
691 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
695 static LttvTraceContext
*
696 new_trace_context(LttvTracesetContext
*self
)
698 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
702 static LttvTracefileContext
*
703 new_tracefile_context(LttvTracesetContext
*self
)
705 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
709 /* Write the process state of the trace */
711 static void write_process_state(gpointer key
, gpointer value
,
714 LttvProcessState
*process
;
716 LttvExecutionState
*es
;
718 FILE *fp
= (FILE *)user_data
;
723 process
= (LttvProcessState
*)value
;
725 " <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",
726 process
, process
->pid
, process
->tgid
, process
->ppid
,
727 g_quark_to_string(process
->type
),
728 process
->creation_time
.tv_sec
,
729 process
->creation_time
.tv_nsec
,
730 process
->insertion_time
.tv_sec
,
731 process
->insertion_time
.tv_nsec
,
732 g_quark_to_string(process
->name
),
733 g_quark_to_string(process
->brand
),
734 process
->cpu
, process
->free_events
);
736 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
737 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
738 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
739 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
740 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
741 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
742 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
745 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
746 address
= g_array_index(process
->user_stack
, guint64
, i
);
747 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
751 if(process
->usertrace
) {
752 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
753 g_quark_to_string(process
->usertrace
->tracefile_name
),
754 process
->usertrace
->cpu
);
758 fprintf(fp
, " </PROCESS>\n");
762 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
764 guint i
, nb_tracefile
, nb_block
, offset
;
767 LttvTracefileState
*tfcs
;
771 LttEventPosition
*ep
;
775 ep
= ltt_event_position_new();
777 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
779 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
781 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
782 for(i
=0;i
<nb_cpus
;i
++) {
783 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
784 i
, self
->running_process
[i
]->pid
);
787 nb_tracefile
= self
->parent
.tracefiles
->len
;
789 for(i
= 0 ; i
< nb_tracefile
; i
++) {
791 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
792 LttvTracefileContext
*, i
));
793 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
794 tfcs
->parent
.timestamp
.tv_sec
,
795 tfcs
->parent
.timestamp
.tv_nsec
);
796 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
797 if(e
== NULL
) fprintf(fp
,"/>\n");
799 ltt_event_position(e
, ep
);
800 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
801 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
806 fprintf(fp
,"</PROCESS_STATE>\n");
810 static void write_process_state_raw(gpointer key
, gpointer value
,
813 LttvProcessState
*process
;
815 LttvExecutionState
*es
;
817 FILE *fp
= (FILE *)user_data
;
822 process
= (LttvProcessState
*)value
;
823 fputc(HDR_PROCESS
, fp
);
824 //fwrite(&header, sizeof(header), 1, fp);
825 //fprintf(fp, "%s", g_quark_to_string(process->type));
827 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
828 //fprintf(fp, "%s", g_quark_to_string(process->name));
830 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
831 //fprintf(fp, "%s", g_quark_to_string(process->brand));
833 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
834 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
835 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
836 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
837 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
838 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
839 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
840 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
844 " <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",
845 process
, process
->pid
, process
->tgid
, process
->ppid
,
846 g_quark_to_string(process
->type
),
847 process
->creation_time
.tv_sec
,
848 process
->creation_time
.tv_nsec
,
849 process
->insertion_time
.tv_sec
,
850 process
->insertion_time
.tv_nsec
,
851 g_quark_to_string(process
->name
),
852 g_quark_to_string(process
->brand
),
856 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
857 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
860 //fprintf(fp, "%s", g_quark_to_string(es->t));
862 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
863 //fprintf(fp, "%s", g_quark_to_string(es->n));
865 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
866 //fprintf(fp, "%s", g_quark_to_string(es->s));
868 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
869 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
870 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
871 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
873 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
874 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
875 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
876 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
877 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
881 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
882 address
= g_array_index(process
->user_stack
, guint64
, i
);
883 fputc(HDR_USER_STACK
, fp
);
884 fwrite(&address
, sizeof(address
), 1, fp
);
886 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
891 if(process
->usertrace
) {
892 fputc(HDR_USERTRACE
, fp
);
893 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
895 fwrite(&process
->usertrace
->tracefile_name
,
896 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
897 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
899 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
900 g_quark_to_string(process
->usertrace
->tracefile_name
),
901 process
->usertrace
->cpu
);
908 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
910 guint i
, nb_tracefile
, nb_block
, offset
;
913 LttvTracefileState
*tfcs
;
917 LttEventPosition
*ep
;
921 ep
= ltt_event_position_new();
923 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
924 fputc(HDR_PROCESS_STATE
, fp
);
925 fwrite(&t
, sizeof(t
), 1, fp
);
927 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
929 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
930 for(i
=0;i
<nb_cpus
;i
++) {
932 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
933 fwrite(&self
->running_process
[i
]->pid
,
934 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
935 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
936 // i, self->running_process[i]->pid);
939 nb_tracefile
= self
->parent
.tracefiles
->len
;
941 for(i
= 0 ; i
< nb_tracefile
; i
++) {
943 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
944 LttvTracefileContext
*, i
));
945 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
946 // tfcs->parent.timestamp.tv_sec,
947 // tfcs->parent.timestamp.tv_nsec);
948 fputc(HDR_TRACEFILE
, fp
);
949 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
950 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
951 * position following : end of trace */
952 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
954 ltt_event_position(e
, ep
);
955 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
956 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
958 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
959 fwrite(&offset
, sizeof(offset
), 1, fp
);
960 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
967 /* Read process state from a file */
969 /* Called because a HDR_PROCESS was found */
970 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
971 GPtrArray
*quarktable
)
973 LttvExecutionState
*es
;
974 LttvProcessState
*process
, *parent_process
;
975 LttvProcessState tmp
;
980 /* TODO : check return value */
981 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
982 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
983 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
984 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
985 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
986 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
987 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
988 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
989 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
990 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
993 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
995 /* We must link to the parent */
996 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
998 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
999 if(process
== NULL
) {
1000 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1002 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1003 &tmp
.creation_time
);
1006 process
->insertion_time
= tmp
.insertion_time
;
1007 process
->creation_time
= tmp
.creation_time
;
1008 process
->type
= g_quark_from_string(
1009 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1010 process
->tgid
= tmp
.tgid
;
1011 process
->ppid
= tmp
.ppid
;
1012 process
->brand
= g_quark_from_string(
1013 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1015 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1016 process
->free_events
= tmp
.free_events
;
1019 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1021 gint hdr
= fgetc(fp
);
1022 if(hdr
== EOF
) goto end_loop
;
1026 process
->execution_stack
=
1027 g_array_set_size(process
->execution_stack
,
1028 process
->execution_stack
->len
+ 1);
1029 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1030 process
->execution_stack
->len
-1);
1031 process
->state
= es
;
1033 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1034 es
->t
= g_quark_from_string(
1035 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1036 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1037 es
->n
= g_quark_from_string(
1038 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1039 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1040 es
->s
= g_quark_from_string(
1041 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1042 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1043 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1044 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1046 case HDR_USER_STACK
:
1047 process
->user_stack
= g_array_set_size(process
->user_stack
,
1048 process
->user_stack
->len
+ 1);
1049 address
= &g_array_index(process
->user_stack
, guint64
,
1050 process
->user_stack
->len
-1);
1051 fread(address
, sizeof(address
), 1, fp
);
1052 process
->current_function
= *address
;
1055 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1056 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1068 /* Called because a HDR_PROCESS_STATE was found */
1069 /* Append a saved state to the trace states */
1070 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1072 guint i
, nb_tracefile
, nb_block
, offset
;
1074 LttvTracefileState
*tfcs
;
1076 LttEventPosition
*ep
;
1084 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1086 LttvAttributeValue value
;
1087 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1088 ep
= ltt_event_position_new();
1090 restore_init_state(self
);
1092 fread(&t
, sizeof(t
), 1, fp
);
1095 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1097 if(hdr
== EOF
) goto end_loop
;
1101 /* Call read_process_state_raw */
1102 read_process_state_raw(self
, fp
, quarktable
);
1110 case HDR_USER_STACK
:
1112 case HDR_PROCESS_STATE
:
1118 g_error("Error while parsing saved state file : unknown data header %d",
1124 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1125 for(i
=0;i
<nb_cpus
;i
++) {
1128 g_assert(hdr
== HDR_CPU
);
1129 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1130 g_assert(i
== cpu_num
);
1131 fread(&self
->running_process
[i
]->pid
,
1132 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1135 nb_tracefile
= self
->parent
.tracefiles
->len
;
1137 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1139 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1140 LttvTracefileContext
*, i
));
1141 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1142 // tfcs->parent.timestamp.tv_sec,
1143 // tfcs->parent.timestamp.tv_nsec);
1144 g_tree_remove(pqueue
, &tfcs
->parent
);
1146 g_assert(hdr
== HDR_TRACEFILE
);
1147 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1148 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1149 * position following : end of trace */
1150 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1151 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1152 fread(&offset
, sizeof(offset
), 1, fp
);
1153 fread(&tsc
, sizeof(tsc
), 1, fp
);
1154 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1155 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1157 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1162 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1163 LTTV_STATE_SAVED_STATES
);
1164 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1165 value
= lttv_attribute_add(saved_states_tree
,
1166 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1167 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1168 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1169 *(value
.v_time
) = t
;
1170 lttv_state_save(self
, saved_state_tree
);
1171 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1174 *(self
->max_time_state_recomputed_in_seek
) = t
;
1178 /* Called when a HDR_TRACE is found */
1179 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1180 GPtrArray
*quarktable
)
1185 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1187 if(hdr
== EOF
) goto end_loop
;
1190 case HDR_PROCESS_STATE
:
1191 /* Call read_process_state_raw */
1192 lttv_state_read_raw(tcs
, fp
, quarktable
);
1200 case HDR_USER_STACK
:
1204 g_error("Error while parsing saved state file :"
1205 " unexpected data header %d",
1209 g_error("Error while parsing saved state file : unknown data header %d",
1214 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1215 restore_init_state(tcs
);
1216 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1222 /* Copy each process from an existing hash table to a new one */
1224 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1226 LttvProcessState
*process
, *new_process
;
1228 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1232 process
= (LttvProcessState
*)value
;
1233 new_process
= g_new(LttvProcessState
, 1);
1234 *new_process
= *process
;
1235 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1236 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1237 new_process
->execution_stack
=
1238 g_array_set_size(new_process
->execution_stack
,
1239 process
->execution_stack
->len
);
1240 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1241 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1242 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1244 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1245 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1246 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1247 sizeof(guint64
), 0);
1248 new_process
->user_stack
=
1249 g_array_set_size(new_process
->user_stack
,
1250 process
->user_stack
->len
);
1251 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1252 g_array_index(new_process
->user_stack
, guint64
, i
) =
1253 g_array_index(process
->user_stack
, guint64
, i
);
1255 new_process
->current_function
= process
->current_function
;
1256 g_hash_table_insert(new_processes
, new_process
, new_process
);
1260 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1262 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1264 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1265 return new_processes
;
1268 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1271 LttvCPUState
*retval
;
1273 retval
= g_new(LttvCPUState
, n
);
1275 for(i
=0; i
<n
; i
++) {
1276 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1277 retval
[i
].last_irq
= states
[i
].last_irq
;
1278 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1279 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1280 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1287 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1291 for(i
=0; i
<n
; i
++) {
1292 g_array_free(states
[i
].mode_stack
, TRUE
);
1298 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1301 LttvIRQState
*retval
;
1303 retval
= g_new(LttvIRQState
, n
);
1305 for(i
=0; i
<n
; i
++) {
1306 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1307 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1308 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1309 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1316 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1320 for(i
=0; i
<n
; i
++) {
1321 g_array_free(states
[i
].mode_stack
, TRUE
);
1327 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1330 LttvSoftIRQState
*retval
;
1332 retval
= g_new(LttvSoftIRQState
, n
);
1334 for(i
=0; i
<n
; i
++) {
1335 retval
[i
].running
= states
[i
].running
;
1341 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1346 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1349 LttvTrapState
*retval
;
1351 retval
= g_new(LttvTrapState
, n
);
1353 for(i
=0; i
<n
; i
++) {
1354 retval
[i
].running
= states
[i
].running
;
1360 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1365 /* bdevstate stuff */
1367 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1369 gint devcode_gint
= devcode
;
1370 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1372 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1373 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1375 gint
* key
= g_new(gint
, 1);
1377 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1385 static LttvBdevState
*bdevstate_new(void)
1387 LttvBdevState
*retval
;
1388 retval
= g_new(LttvBdevState
, 1);
1389 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1394 static void bdevstate_free(LttvBdevState
*bds
)
1396 g_array_free(bds
->mode_stack
, TRUE
);
1400 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1402 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1404 bdevstate_free(bds
);
1407 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1409 LttvBdevState
*retval
;
1411 retval
= bdevstate_new();
1412 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1417 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1419 //GHashTable *ht = (GHashTable *)u;
1420 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1421 LttvBdevState
*newbds
;
1423 newbds
= bdevstate_copy(bds
);
1425 g_hash_table_insert(u
, k
, newbds
);
1428 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1432 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1434 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1439 /* Free a hashtable and the LttvBdevState structures its values
1442 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1444 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1445 g_hash_table_destroy(ht
);
1448 /* The saved state for each trace contains a member "processes", which
1449 stores a copy of the process table, and a member "tracefiles" with
1450 one entry per tracefile. Each tracefile has a "process" member pointing
1451 to the current process and a "position" member storing the tracefile
1452 position (needed to seek to the current "next" event. */
1454 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1456 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1458 LttvTracefileState
*tfcs
;
1460 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1462 guint
*running_process
;
1464 LttvAttributeValue value
;
1466 LttEventPosition
*ep
;
1468 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1469 LTTV_STATE_TRACEFILES
);
1471 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1473 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1475 /* Add the currently running processes array */
1476 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1477 running_process
= g_new(guint
, nb_cpus
);
1478 for(i
=0;i
<nb_cpus
;i
++) {
1479 running_process
[i
] = self
->running_process
[i
]->pid
;
1481 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1483 *(value
.v_pointer
) = running_process
;
1485 g_info("State save");
1487 nb_tracefile
= self
->parent
.tracefiles
->len
;
1489 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1491 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1492 LttvTracefileContext
*, i
));
1493 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1494 value
= lttv_attribute_add(tracefiles_tree
, i
,
1496 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1498 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1500 *(value
.v_uint
) = tfcs
->process
->pid
;
1502 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1504 /* Only save the position if the tfs has not infinite time. */
1505 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1506 // && current_tfcs != tfcs) {
1507 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1508 *(value
.v_pointer
) = NULL
;
1510 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1511 ep
= ltt_event_position_new();
1512 ltt_event_position(e
, ep
);
1513 *(value
.v_pointer
) = ep
;
1515 guint nb_block
, offset
;
1518 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1519 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1521 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1525 /* save the cpu state */
1527 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1529 *(value
.v_uint
) = nb_cpus
;
1531 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1533 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1536 /* save the irq state */
1537 nb_irqs
= self
->nb_irqs
;
1539 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1541 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1544 /* save the soft irq state */
1545 nb_soft_irqs
= self
->nb_soft_irqs
;
1547 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1549 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1552 /* save the trap state */
1553 nb_traps
= self
->nb_traps
;
1555 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1557 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1560 /* save the blkdev states */
1561 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1563 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1567 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1569 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1571 LttvTracefileState
*tfcs
;
1573 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1575 guint
*running_process
;
1577 LttvAttributeType type
;
1579 LttvAttributeValue value
;
1581 LttvAttributeName name
;
1585 LttEventPosition
*ep
;
1587 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1589 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1590 LTTV_STATE_TRACEFILES
);
1592 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1594 g_assert(type
== LTTV_POINTER
);
1595 lttv_state_free_process_table(self
->processes
);
1596 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1598 /* Add the currently running processes array */
1599 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1600 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1602 g_assert(type
== LTTV_POINTER
);
1603 running_process
= *(value
.v_pointer
);
1604 for(i
=0;i
<nb_cpus
;i
++) {
1605 pid
= running_process
[i
];
1606 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1607 g_assert(self
->running_process
[i
] != NULL
);
1610 nb_tracefile
= self
->parent
.tracefiles
->len
;
1612 //g_tree_destroy(tsc->pqueue);
1613 //tsc->pqueue = g_tree_new(compare_tracefile);
1615 /* restore cpu resource states */
1616 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1617 g_assert(type
== LTTV_POINTER
);
1618 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1619 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1621 /* restore irq resource states */
1622 nb_irqs
= self
->nb_irqs
;
1623 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1624 g_assert(type
== LTTV_POINTER
);
1625 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1626 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1628 /* restore soft irq resource states */
1629 nb_soft_irqs
= self
->nb_soft_irqs
;
1630 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1631 g_assert(type
== LTTV_POINTER
);
1632 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1633 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1635 /* restore trap resource states */
1636 nb_traps
= self
->nb_traps
;
1637 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1638 g_assert(type
== LTTV_POINTER
);
1639 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1640 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1642 /* restore the blkdev states */
1643 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1644 g_assert(type
== LTTV_POINTER
);
1645 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1646 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1648 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1650 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1651 LttvTracefileContext
*, i
));
1652 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1653 g_assert(type
== LTTV_GOBJECT
);
1654 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1656 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1658 g_assert(type
== LTTV_UINT
);
1659 pid
= *(value
.v_uint
);
1660 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1662 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1664 g_assert(type
== LTTV_POINTER
);
1665 //g_assert(*(value.v_pointer) != NULL);
1666 ep
= *(value
.v_pointer
);
1667 g_assert(tfcs
->parent
.t_context
!= NULL
);
1669 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1671 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1672 g_tree_remove(tsc
->pqueue
, tfc
);
1675 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1676 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1677 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1678 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1679 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1681 tfc
->timestamp
= ltt_time_infinite
;
1687 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1689 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1691 LttvTracefileState
*tfcs
;
1693 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1695 guint
*running_process
;
1697 LttvAttributeType type
;
1699 LttvAttributeValue value
;
1701 LttvAttributeName name
;
1705 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1706 LTTV_STATE_TRACEFILES
);
1707 g_object_ref(G_OBJECT(tracefiles_tree
));
1708 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1710 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1712 g_assert(type
== LTTV_POINTER
);
1713 lttv_state_free_process_table(*(value
.v_pointer
));
1714 *(value
.v_pointer
) = NULL
;
1715 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1717 /* Free running processes array */
1718 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1720 g_assert(type
== LTTV_POINTER
);
1721 running_process
= *(value
.v_pointer
);
1722 g_free(running_process
);
1724 /* free cpu resource states */
1725 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1726 g_assert(type
== LTTV_UINT
);
1727 nb_cpus
= *value
.v_uint
;
1728 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1729 g_assert(type
== LTTV_POINTER
);
1730 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1732 /* free irq resource states */
1733 nb_irqs
= self
->nb_irqs
;
1734 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1735 g_assert(type
== LTTV_POINTER
);
1736 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1738 /* free the blkdev states */
1739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1740 g_assert(type
== LTTV_POINTER
);
1741 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1743 nb_tracefile
= self
->parent
.tracefiles
->len
;
1745 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1747 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1748 LttvTracefileContext
*, i
));
1749 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1750 g_assert(type
== LTTV_GOBJECT
);
1751 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1753 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1755 g_assert(type
== LTTV_POINTER
);
1756 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1758 g_object_unref(G_OBJECT(tracefiles_tree
));
1762 static void free_saved_state(LttvTraceState
*self
)
1766 LttvAttributeType type
;
1768 LttvAttributeValue value
;
1770 LttvAttributeName name
;
1774 LttvAttribute
*saved_states
;
1776 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1777 LTTV_STATE_SAVED_STATES
);
1779 nb
= lttv_attribute_get_number(saved_states
);
1780 for(i
= 0 ; i
< nb
; i
++) {
1781 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1782 g_assert(type
== LTTV_GOBJECT
);
1783 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1786 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1791 create_max_time(LttvTraceState
*tcs
)
1793 LttvAttributeValue v
;
1795 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1797 g_assert(*(v
.v_pointer
) == NULL
);
1798 *(v
.v_pointer
) = g_new(LttTime
,1);
1799 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1804 get_max_time(LttvTraceState
*tcs
)
1806 LttvAttributeValue v
;
1808 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1810 g_assert(*(v
.v_pointer
) != NULL
);
1811 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1816 free_max_time(LttvTraceState
*tcs
)
1818 LttvAttributeValue v
;
1820 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1822 g_free(*(v
.v_pointer
));
1823 *(v
.v_pointer
) = NULL
;
1827 typedef struct _LttvNameTables
{
1828 // FIXME GQuark *eventtype_names;
1829 GQuark
*syscall_names
;
1835 GQuark
*soft_irq_names
;
1841 create_name_tables(LttvTraceState
*tcs
)
1845 GString
*fe_name
= g_string_new("");
1847 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1849 LttvAttributeValue v
;
1853 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1855 g_assert(*(v
.v_pointer
) == NULL
);
1856 *(v
.v_pointer
) = name_tables
;
1858 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1860 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1861 LTT_FACILITY_KERNEL_ARCH
,
1862 LTT_EVENT_SYSCALL_ENTRY
,
1863 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1864 NULL
, NULL
, &hooks
)) {
1866 // th = lttv_trace_hook_get_first(&th);
1868 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1869 // nb = ltt_type_element_number(t);
1871 // name_tables->syscall_names = g_new(GQuark, nb);
1872 // name_tables->nb_syscalls = nb;
1874 // for(i = 0 ; i < nb ; i++) {
1875 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1876 // if(!name_tables->syscall_names[i]) {
1877 // GString *string = g_string_new("");
1878 // g_string_printf(string, "syscall %u", i);
1879 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1880 // g_string_free(string, TRUE);
1884 name_tables
->nb_syscalls
= 256;
1885 name_tables
->syscall_names
= g_new(GQuark
, 256);
1886 for(i
= 0 ; i
< 256 ; i
++) {
1887 g_string_printf(fe_name
, "syscall %d", i
);
1888 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1891 name_tables
->syscall_names
= NULL
;
1892 name_tables
->nb_syscalls
= 0;
1894 lttv_trace_hook_remove_all(&hooks
);
1896 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1897 LTT_FACILITY_KERNEL_ARCH
,
1898 LTT_EVENT_TRAP_ENTRY
,
1899 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1900 NULL
, NULL
, &hooks
)) {
1902 // th = lttv_trace_hook_get_first(&th);
1904 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1905 // //nb = ltt_type_element_number(t);
1907 // name_tables->trap_names = g_new(GQuark, nb);
1908 // for(i = 0 ; i < nb ; i++) {
1909 // name_tables->trap_names[i] = g_quark_from_string(
1910 // ltt_enum_string_get(t, i));
1913 name_tables
->nb_traps
= 256;
1914 name_tables
->trap_names
= g_new(GQuark
, 256);
1915 for(i
= 0 ; i
< 256 ; i
++) {
1916 g_string_printf(fe_name
, "trap %d", i
);
1917 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1920 name_tables
->trap_names
= NULL
;
1921 name_tables
->nb_traps
= 0;
1923 lttv_trace_hook_remove_all(&hooks
);
1925 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1926 LTT_FACILITY_KERNEL
,
1927 LTT_EVENT_IRQ_ENTRY
,
1928 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1929 NULL
, NULL
, &hooks
)) {
1932 name_tables->irq_names = g_new(GQuark, nb);
1933 for(i = 0 ; i < nb ; i++) {
1934 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1938 name_tables
->nb_irqs
= 256;
1939 name_tables
->irq_names
= g_new(GQuark
, 256);
1940 for(i
= 0 ; i
< 256 ; i
++) {
1941 g_string_printf(fe_name
, "irq %d", i
);
1942 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1945 name_tables
->nb_irqs
= 0;
1946 name_tables
->irq_names
= NULL
;
1948 lttv_trace_hook_remove_all(&hooks
);
1950 name_tables->soft_irq_names = g_new(GQuark, nb);
1951 for(i = 0 ; i < nb ; i++) {
1952 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1956 /* the kernel is limited to 32 statically defined softirqs */
1957 name_tables
->nb_softirqs
= 32;
1958 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1959 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1960 g_string_printf(fe_name
, "softirq %d", i
);
1961 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1963 g_array_free(hooks
, TRUE
);
1965 g_string_free(fe_name
, TRUE
);
1970 get_name_tables(LttvTraceState
*tcs
)
1972 LttvNameTables
*name_tables
;
1974 LttvAttributeValue v
;
1976 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1978 g_assert(*(v
.v_pointer
) != NULL
);
1979 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1980 //tcs->eventtype_names = name_tables->eventtype_names;
1981 tcs
->syscall_names
= name_tables
->syscall_names
;
1982 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1983 tcs
->trap_names
= name_tables
->trap_names
;
1984 tcs
->nb_traps
= name_tables
->nb_traps
;
1985 tcs
->irq_names
= name_tables
->irq_names
;
1986 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1987 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1988 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1993 free_name_tables(LttvTraceState
*tcs
)
1995 LttvNameTables
*name_tables
;
1997 LttvAttributeValue v
;
1999 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2001 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2002 *(v
.v_pointer
) = NULL
;
2004 // g_free(name_tables->eventtype_names);
2005 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2006 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2007 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2008 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2009 if(name_tables
) g_free(name_tables
);
2012 #ifdef HASH_TABLE_DEBUG
2014 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2016 LttvProcessState
*process
= (LttvProcessState
*)value
;
2018 /* Test for process corruption */
2019 guint stack_len
= process
->execution_stack
->len
;
2022 static void hash_table_check(GHashTable
*table
)
2024 g_hash_table_foreach(table
, test_process
, NULL
);
2030 /* clears the stack and sets the state passed as argument */
2031 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2033 g_array_set_size(cpust
->mode_stack
, 1);
2034 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2037 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2039 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2040 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2043 static void cpu_pop_mode(LttvCPUState
*cpust
)
2045 if(cpust
->mode_stack
->len
<= 1)
2046 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2048 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2051 /* clears the stack and sets the state passed as argument */
2052 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2054 g_array_set_size(bdevst
->mode_stack
, 1);
2055 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2058 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2060 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2061 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2064 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2066 if(bdevst
->mode_stack
->len
<= 1)
2067 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2069 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2072 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2074 g_array_set_size(irqst
->mode_stack
, 1);
2075 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2078 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2080 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2081 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2084 static void irq_pop_mode(LttvIRQState
*irqst
)
2086 if(irqst
->mode_stack
->len
<= 1)
2087 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2089 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2092 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2095 LttvExecutionState
*es
;
2097 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2098 guint cpu
= tfs
->cpu
;
2100 #ifdef HASH_TABLE_DEBUG
2101 hash_table_check(ts
->processes
);
2103 LttvProcessState
*process
= ts
->running_process
[cpu
];
2105 guint depth
= process
->execution_stack
->len
;
2107 process
->execution_stack
=
2108 g_array_set_size(process
->execution_stack
, depth
+ 1);
2111 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2113 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2116 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2117 es
->cum_cpu_time
= ltt_time_zero
;
2118 es
->s
= process
->state
->s
;
2119 process
->state
= es
;
2123 * return 1 when empty, else 0 */
2124 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2125 LttvTracefileState
*tfs
)
2127 guint depth
= process
->execution_stack
->len
;
2133 process
->execution_stack
=
2134 g_array_set_size(process
->execution_stack
, depth
- 1);
2135 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2137 process
->state
->change
= tfs
->parent
.timestamp
;
2142 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2144 guint cpu
= tfs
->cpu
;
2145 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2146 LttvProcessState
*process
= ts
->running_process
[cpu
];
2148 guint depth
= process
->execution_stack
->len
;
2150 if(process
->state
->t
!= t
){
2151 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2152 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2153 g_info("process state has %s when pop_int is %s\n",
2154 g_quark_to_string(process
->state
->t
),
2155 g_quark_to_string(t
));
2156 g_info("{ %u, %u, %s, %s, %s }\n",
2159 g_quark_to_string(process
->name
),
2160 g_quark_to_string(process
->brand
),
2161 g_quark_to_string(process
->state
->s
));
2166 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2167 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2171 process
->execution_stack
=
2172 g_array_set_size(process
->execution_stack
, depth
- 1);
2173 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2175 process
->state
->change
= tfs
->parent
.timestamp
;
2178 struct search_result
{
2179 const LttTime
*time
; /* Requested time */
2180 LttTime
*best
; /* Best result */
2183 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2185 const LttTime
*elem_time
= (const LttTime
*)a
;
2186 /* Explicit non const cast */
2187 struct search_result
*res
= (struct search_result
*)b
;
2189 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2190 /* The usertrace was created before the schedchange */
2191 /* Get larger keys */
2193 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2194 /* The usertrace was created after the schedchange time */
2195 /* Get smaller keys */
2197 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2198 res
->best
= (LttTime
*)elem_time
;
2201 res
->best
= (LttTime
*)elem_time
;
2208 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2209 guint pid
, const LttTime
*timestamp
)
2211 LttvTracefileState
*tfs
= NULL
;
2212 struct search_result res
;
2213 /* Find the usertrace associated with a pid and time interval.
2214 * Search in the usertraces by PID (within a hash) and then, for each
2215 * corresponding element of the array, find the first one with creation
2216 * timestamp the lowest, but higher or equal to "timestamp". */
2217 res
.time
= timestamp
;
2219 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2220 if(usertrace_tree
) {
2221 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2223 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2231 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2232 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2234 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2236 LttvExecutionState
*es
;
2241 process
->tgid
= tgid
;
2243 process
->name
= name
;
2244 process
->brand
= LTTV_STATE_UNBRANDED
;
2245 //process->last_cpu = tfs->cpu_name;
2246 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2247 process
->type
= LTTV_STATE_USER_THREAD
;
2248 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2249 process
->current_function
= 0; //function 0x0 by default.
2251 g_info("Process %u, core %p", process
->pid
, process
);
2252 g_hash_table_insert(tcs
->processes
, process
, process
);
2255 process
->ppid
= parent
->pid
;
2256 process
->creation_time
= *timestamp
;
2259 /* No parent. This process exists but we are missing all information about
2260 its creation. The birth time is set to zero but we remember the time of
2265 process
->creation_time
= ltt_time_zero
;
2268 process
->insertion_time
= *timestamp
;
2269 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2270 process
->creation_time
.tv_nsec
);
2271 process
->pid_time
= g_quark_from_string(buffer
);
2273 process
->free_events
= 0;
2274 //process->last_cpu = tfs->cpu_name;
2275 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2276 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2277 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2278 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2279 es
= process
->state
= &g_array_index(process
->execution_stack
,
2280 LttvExecutionState
, 0);
2281 es
->t
= LTTV_STATE_USER_MODE
;
2282 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2283 es
->entry
= *timestamp
;
2284 //g_assert(timestamp->tv_sec != 0);
2285 es
->change
= *timestamp
;
2286 es
->cum_cpu_time
= ltt_time_zero
;
2287 es
->s
= LTTV_STATE_RUN
;
2289 es
= process
->state
= &g_array_index(process
->execution_stack
,
2290 LttvExecutionState
, 1);
2291 es
->t
= LTTV_STATE_SYSCALL
;
2292 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2293 es
->entry
= *timestamp
;
2294 //g_assert(timestamp->tv_sec != 0);
2295 es
->change
= *timestamp
;
2296 es
->cum_cpu_time
= ltt_time_zero
;
2297 es
->s
= LTTV_STATE_WAIT_FORK
;
2299 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2300 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2301 sizeof(guint64
), 0);
2306 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2309 LttvProcessState key
;
2310 LttvProcessState
*process
;
2314 process
= g_hash_table_lookup(ts
->processes
, &key
);
2319 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2320 const LttTime
*timestamp
)
2322 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2323 LttvExecutionState
*es
;
2325 /* Put ltt_time_zero creation time for unexisting processes */
2326 if(unlikely(process
== NULL
)) {
2327 process
= lttv_state_create_process(ts
,
2328 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2329 /* We are not sure is it's a kernel thread or normal thread, put the
2330 * bottom stack state to unknown */
2331 process
->execution_stack
=
2332 g_array_set_size(process
->execution_stack
, 1);
2333 process
->state
= es
=
2334 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2335 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2336 es
->s
= LTTV_STATE_UNNAMED
;
2341 /* FIXME : this function should be called when we receive an event telling that
2342 * release_task has been called in the kernel. In happens generally when
2343 * the parent waits for its child terminaison, but may also happen in special
2344 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2345 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2346 * of a killed thread group, but isn't the leader.
2348 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2350 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2351 LttvProcessState key
;
2353 /* Wait for both schedule with exit dead and process free to happen.
2354 * They can happen in any order. */
2355 if (++(process
->free_events
) < 2)
2358 key
.pid
= process
->pid
;
2359 key
.cpu
= process
->cpu
;
2360 g_hash_table_remove(ts
->processes
, &key
);
2361 g_array_free(process
->execution_stack
, TRUE
);
2362 g_array_free(process
->user_stack
, TRUE
);
2368 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2370 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2371 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2376 static void lttv_state_free_process_table(GHashTable
*processes
)
2378 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2379 g_hash_table_destroy(processes
);
2383 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2385 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2387 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2388 LttvProcessState
*process
= ts
->running_process
[cpu
];
2389 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2390 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2391 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2392 LttvExecutionSubmode submode
;
2394 guint syscall
= ltt_event_get_unsigned(e
, f
);
2395 expand_syscall_table(ts
, syscall
);
2396 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2397 /* There can be no system call from PID 0 : unknown state */
2398 if(process
->pid
!= 0)
2399 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2404 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2406 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2408 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2409 LttvProcessState
*process
= ts
->running_process
[cpu
];
2411 /* There can be no system call from PID 0 : unknown state */
2412 if(process
->pid
!= 0)
2413 pop_state(s
, LTTV_STATE_SYSCALL
);
2418 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2420 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2421 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2422 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2423 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2424 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2426 LttvExecutionSubmode submode
;
2428 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2430 expand_trap_table(ts
, trap
);
2432 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2434 push_state(s
, LTTV_STATE_TRAP
, submode
);
2436 /* update cpu status */
2437 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2439 /* update trap status */
2440 s
->cpu_state
->last_trap
= trap
;
2441 ts
->trap_states
[trap
].running
++;
2446 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2448 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2449 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2450 guint trap
= s
->cpu_state
->last_trap
;
2452 pop_state(s
, LTTV_STATE_TRAP
);
2454 /* update cpu status */
2455 cpu_pop_mode(s
->cpu_state
);
2457 /* update trap status */
2458 if(ts
->trap_states
[trap
].running
)
2459 ts
->trap_states
[trap
].running
--;
2464 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2466 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2467 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2468 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2469 //guint8 ev_id = ltt_event_eventtype_id(e);
2470 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2471 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2473 LttvExecutionSubmode submode
;
2474 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2476 expand_irq_table(ts
, irq
);
2478 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2480 /* Do something with the info about being in user or system mode when int? */
2481 push_state(s
, LTTV_STATE_IRQ
, submode
);
2483 /* update cpu status */
2484 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2486 /* update irq status */
2487 s
->cpu_state
->last_irq
= irq
;
2488 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2493 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2495 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2496 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2497 guint softirq
= s
->cpu_state
->last_soft_irq
;
2499 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2501 /* update softirq status */
2502 if(ts
->soft_irq_states
[softirq
].running
)
2503 ts
->soft_irq_states
[softirq
].running
--;
2505 /* update cpu status */
2506 cpu_pop_mode(s
->cpu_state
);
2511 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2513 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2514 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2516 pop_state(s
, LTTV_STATE_IRQ
);
2518 /* update cpu status */
2519 cpu_pop_mode(s
->cpu_state
);
2521 /* update irq status */
2522 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2527 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2529 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2530 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2531 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2532 //guint8 ev_id = ltt_event_eventtype_id(e);
2533 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2534 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2535 LttvExecutionSubmode submode
;
2536 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2537 expand_soft_irq_table(ts
, softirq
);
2538 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2540 /* Do something with the info about being in user or system mode when int? */
2541 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2543 /* update cpu status */
2544 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2546 /* update softirq status */
2547 s
->cpu_state
->last_soft_irq
= softirq
;
2548 ts
->soft_irq_states
[softirq
].running
++;
2553 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2555 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2556 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2557 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2558 //guint8 ev_id = ltt_event_eventtype_id(e);
2559 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2561 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2562 lttv_trace_get_hook_field(th
, 0)));
2563 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2565 expand_irq_table(ts
, irq
);
2566 ts
->irq_names
[irq
] = action
;
2572 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2574 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2575 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2576 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2577 //guint8 ev_id = ltt_event_eventtype_id(e);
2578 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2580 guint major
= ltt_event_get_long_unsigned(e
,
2581 lttv_trace_get_hook_field(th
, 0));
2582 guint minor
= ltt_event_get_long_unsigned(e
,
2583 lttv_trace_get_hook_field(th
, 1));
2584 guint oper
= ltt_event_get_long_unsigned(e
,
2585 lttv_trace_get_hook_field(th
, 2));
2586 guint16 devcode
= MKDEV(major
,minor
);
2588 /* have we seen this block device before? */
2589 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2592 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2594 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2599 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2601 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2602 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2603 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2604 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2606 guint major
= ltt_event_get_long_unsigned(e
,
2607 lttv_trace_get_hook_field(th
, 0));
2608 guint minor
= ltt_event_get_long_unsigned(e
,
2609 lttv_trace_get_hook_field(th
, 1));
2610 //guint oper = ltt_event_get_long_unsigned(e,
2611 // lttv_trace_get_hook_field(th, 2));
2612 guint16 devcode
= MKDEV(major
,minor
);
2614 /* have we seen this block device before? */
2615 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2617 /* update block device */
2618 bdev_pop_mode(bdev
);
2623 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2627 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2628 guint cpu
= tfs
->cpu
;
2629 LttvProcessState
*process
= ts
->running_process
[cpu
];
2631 guint depth
= process
->user_stack
->len
;
2633 process
->user_stack
=
2634 g_array_set_size(process
->user_stack
, depth
+ 1);
2636 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2637 *new_func
= funcptr
;
2638 process
->current_function
= funcptr
;
2641 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2643 guint cpu
= tfs
->cpu
;
2644 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2645 LttvProcessState
*process
= ts
->running_process
[cpu
];
2647 if(process
->current_function
!= funcptr
){
2648 g_info("Different functions (%lu.%09lu): ignore it\n",
2649 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2650 g_info("process state has %llu when pop_function is %llu\n",
2651 process
->current_function
, funcptr
);
2652 g_info("{ %u, %u, %s, %s, %s }\n",
2655 g_quark_to_string(process
->name
),
2656 g_quark_to_string(process
->brand
),
2657 g_quark_to_string(process
->state
->s
));
2660 guint depth
= process
->user_stack
->len
;
2663 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2664 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2668 process
->user_stack
=
2669 g_array_set_size(process
->user_stack
, depth
- 1);
2670 process
->current_function
=
2671 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2675 static gboolean
function_entry(void *hook_data
, void *call_data
)
2677 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2678 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2679 //guint8 ev_id = ltt_event_eventtype_id(e);
2680 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2681 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2682 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2684 push_function(s
, funcptr
);
2688 static gboolean
function_exit(void *hook_data
, void *call_data
)
2690 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2691 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2692 //guint8 ev_id = ltt_event_eventtype_id(e);
2693 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2694 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2695 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2697 pop_function(s
, funcptr
);
2701 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2703 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2704 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2705 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2706 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2711 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2712 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2713 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2715 expand_syscall_table(ts
, id
);
2716 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2721 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2723 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2724 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2725 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2726 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2731 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2732 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2733 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2735 expand_soft_irq_table(ts
, id
);
2736 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2741 static gboolean
schedchange(void *hook_data
, void *call_data
)
2743 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2745 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2746 LttvProcessState
*process
= ts
->running_process
[cpu
];
2747 //LttvProcessState *old_process = ts->running_process[cpu];
2749 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2750 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2751 guint pid_in
, pid_out
;
2754 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2755 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2756 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2758 if(likely(process
!= NULL
)) {
2760 /* We could not know but it was not the idle process executing.
2761 This should only happen at the beginning, before the first schedule
2762 event, and when the initial information (current process for each CPU)
2763 is missing. It is not obvious how we could, after the fact, compensate
2764 the wrongly attributed statistics. */
2766 //This test only makes sense once the state is known and if there is no
2767 //missing events. We need to silently ignore schedchange coming after a
2768 //process_free, or it causes glitches. (FIXME)
2769 //if(unlikely(process->pid != pid_out)) {
2770 // g_assert(process->pid == 0);
2772 if(process
->pid
== 0
2773 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2775 /* Scheduling out of pid 0 at beginning of the trace :
2776 * we know for sure it is in syscall mode at this point. */
2777 g_assert(process
->execution_stack
->len
== 1);
2778 process
->state
->t
= LTTV_STATE_SYSCALL
;
2779 process
->state
->s
= LTTV_STATE_WAIT
;
2780 process
->state
->change
= s
->parent
.timestamp
;
2781 process
->state
->entry
= s
->parent
.timestamp
;
2784 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2785 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2786 process
->state
->change
= s
->parent
.timestamp
;
2788 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2789 else process
->state
->s
= LTTV_STATE_WAIT
;
2790 process
->state
->change
= s
->parent
.timestamp
;
2793 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2794 /* see sched.h for states */
2795 if (!exit_process(s
, process
)) {
2796 process
->state
->s
= LTTV_STATE_DEAD
;
2797 process
->state
->change
= s
->parent
.timestamp
;
2802 process
= ts
->running_process
[cpu
] =
2803 lttv_state_find_process_or_create(
2804 (LttvTraceState
*)s
->parent
.t_context
,
2806 &s
->parent
.timestamp
);
2807 process
->state
->s
= LTTV_STATE_RUN
;
2809 if(process
->usertrace
)
2810 process
->usertrace
->cpu
= cpu
;
2811 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2812 process
->state
->change
= s
->parent
.timestamp
;
2814 /* update cpu status */
2816 /* going to idle task */
2817 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2819 /* scheduling a real task.
2820 * we must be careful here:
2821 * if we just schedule()'ed to a process that is
2822 * in a trap, we must put the cpu in trap mode
2824 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2825 if(process
->state
->t
== LTTV_STATE_TRAP
)
2826 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2832 static gboolean
process_fork(void *hook_data
, void *call_data
)
2834 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2835 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2836 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2838 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2839 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2840 //LttvProcessState *zombie_process;
2842 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2843 LttvProcessState
*process
= ts
->running_process
[cpu
];
2844 LttvProcessState
*child_process
;
2845 struct marker_field
*f
;
2848 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2851 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2852 s
->parent
.target_pid
= child_pid
;
2855 f
= lttv_trace_get_hook_field(th
, 2);
2857 child_tgid
= ltt_event_get_unsigned(e
, f
);
2861 /* Mathieu : it seems like the process might have been scheduled in before the
2862 * fork, and, in a rare case, might be the current process. This might happen
2863 * in a SMP case where we don't have enough precision on the clocks.
2865 * Test reenabled after precision fixes on time. (Mathieu) */
2867 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2869 if(unlikely(zombie_process
!= NULL
)) {
2870 /* Reutilisation of PID. Only now we are sure that the old PID
2871 * has been released. FIXME : should know when release_task happens instead.
2873 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2875 for(i
=0; i
< num_cpus
; i
++) {
2876 g_assert(zombie_process
!= ts
->running_process
[i
]);
2879 exit_process(s
, zombie_process
);
2882 g_assert(process
->pid
!= child_pid
);
2883 // FIXME : Add this test in the "known state" section
2884 // g_assert(process->pid == parent_pid);
2885 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2886 if(child_process
== NULL
) {
2887 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2888 child_pid
, child_tgid
,
2889 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2891 /* The process has already been created : due to time imprecision between
2892 * multiple CPUs : it has been scheduled in before creation. Note that we
2893 * shouldn't have this kind of imprecision.
2895 * Simply put a correct parent.
2897 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2898 //g_assert(0); /* This is a problematic case : the process has been created
2899 // before the fork event */
2900 child_process
->ppid
= process
->pid
;
2901 child_process
->tgid
= child_tgid
;
2903 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2904 child_process
->name
= process
->name
;
2905 child_process
->brand
= process
->brand
;
2910 /* We stamp a newly created process as kernel_thread.
2911 * The thread should not be running yet. */
2912 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2914 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2915 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2916 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2918 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2919 LttvProcessState
*process
;
2920 LttvExecutionState
*es
;
2923 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2924 s
->parent
.target_pid
= pid
;
2926 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2928 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2929 process
->execution_stack
=
2930 g_array_set_size(process
->execution_stack
, 1);
2931 es
= process
->state
=
2932 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2933 es
->t
= LTTV_STATE_SYSCALL
;
2935 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2940 static gboolean
process_exit(void *hook_data
, void *call_data
)
2942 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2943 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2944 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2946 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2947 LttvProcessState
*process
; // = ts->running_process[cpu];
2949 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2950 s
->parent
.target_pid
= pid
;
2952 // FIXME : Add this test in the "known state" section
2953 // g_assert(process->pid == pid);
2955 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2956 if(likely(process
!= NULL
)) {
2957 process
->state
->s
= LTTV_STATE_EXIT
;
2962 static gboolean
process_free(void *hook_data
, void *call_data
)
2964 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2965 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2966 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2967 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2969 LttvProcessState
*process
;
2971 /* PID of the process to release */
2972 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2973 s
->parent
.target_pid
= release_pid
;
2975 g_assert(release_pid
!= 0);
2977 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2978 if(likely(process
!= NULL
))
2979 exit_process(s
, process
);
2982 if(likely(process
!= NULL
)) {
2983 /* release_task is happening at kernel level : we can now safely release
2984 * the data structure of the process */
2985 //This test is fun, though, as it may happen that
2986 //at time t : CPU 0 : process_free
2987 //at time t+150ns : CPU 1 : schedule out
2988 //Clearly due to time imprecision, we disable it. (Mathieu)
2989 //If this weird case happen, we have no choice but to put the
2990 //Currently running process on the cpu to 0.
2991 //I re-enable it following time precision fixes. (Mathieu)
2992 //Well, in the case where an process is freed by a process on another CPU
2993 //and still scheduled, it happens that this is the schedchange that will
2994 //drop the last reference count. Do not free it here!
2995 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2997 for(i
=0; i
< num_cpus
; i
++) {
2998 //g_assert(process != ts->running_process[i]);
2999 if(process
== ts
->running_process
[i
]) {
3000 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3004 if(i
== num_cpus
) /* process is not scheduled */
3005 exit_process(s
, process
);
3012 static gboolean
process_exec(void *hook_data
, void *call_data
)
3014 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3015 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3016 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3017 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3020 LttvProcessState
*process
= ts
->running_process
[cpu
];
3022 #if 0//how to use a sequence that must be transformed in a string
3023 /* PID of the process to release */
3024 guint64 name_len
= ltt_event_field_element_number(e
,
3025 lttv_trace_get_hook_field(th
, 0));
3026 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3027 LttField
*child
= ltt_event_field_element_select(e
,
3028 lttv_trace_get_hook_field(th
, 0), 0);
3030 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3031 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3032 memcpy(null_term_name
, name_begin
, name_len
);
3033 null_term_name
[name_len
] = '\0';
3034 process
->name
= g_quark_from_string(null_term_name
);
3037 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3038 lttv_trace_get_hook_field(th
, 0)));
3039 process
->brand
= LTTV_STATE_UNBRANDED
;
3040 //g_free(null_term_name);
3044 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3046 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3047 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3048 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3049 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3052 LttvProcessState
*process
= ts
->running_process
[cpu
];
3054 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3055 process
->brand
= g_quark_from_string(name
);
3060 static void fix_process(gpointer key
, gpointer value
,
3063 LttvProcessState
*process
;
3064 LttvExecutionState
*es
;
3065 process
= (LttvProcessState
*)value
;
3066 LttTime
*timestamp
= (LttTime
*)user_data
;
3068 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3069 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3070 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3071 es
->t
= LTTV_STATE_SYSCALL
;
3072 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3073 es
->entry
= *timestamp
;
3074 es
->change
= *timestamp
;
3075 es
->cum_cpu_time
= ltt_time_zero
;
3076 if(es
->s
== LTTV_STATE_UNNAMED
)
3077 es
->s
= LTTV_STATE_WAIT
;
3080 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3081 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3082 es
->t
= LTTV_STATE_USER_MODE
;
3083 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3084 es
->entry
= *timestamp
;
3085 //g_assert(timestamp->tv_sec != 0);
3086 es
->change
= *timestamp
;
3087 es
->cum_cpu_time
= ltt_time_zero
;
3088 if(es
->s
== LTTV_STATE_UNNAMED
)
3089 es
->s
= LTTV_STATE_RUN
;
3091 if(process
->execution_stack
->len
== 1) {
3092 /* Still in bottom unknown mode, means never did a system call
3093 * May be either in user mode, syscall mode, running or waiting.*/
3094 /* FIXME : we may be tagging syscall mode when being user mode */
3095 process
->execution_stack
=
3096 g_array_set_size(process
->execution_stack
, 2);
3097 es
= process
->state
= &g_array_index(process
->execution_stack
,
3098 LttvExecutionState
, 1);
3099 es
->t
= LTTV_STATE_SYSCALL
;
3100 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3101 es
->entry
= *timestamp
;
3102 //g_assert(timestamp->tv_sec != 0);
3103 es
->change
= *timestamp
;
3104 es
->cum_cpu_time
= ltt_time_zero
;
3105 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3106 es
->s
= LTTV_STATE_WAIT
;
3112 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3114 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3115 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3116 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3117 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3118 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3120 /* For all processes */
3121 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3122 /* else, if stack[0] is unknown, set to user mode, running */
3124 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3129 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3131 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3132 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3133 //It's slow : optimise later by doing this before reading trace.
3134 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3140 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3141 LttvProcessState
*process
= ts
->running_process
[cpu
];
3142 LttvProcessState
*parent_process
;
3143 struct marker_field
*f
;
3144 GQuark type
, mode
, submode
, status
;
3145 LttvExecutionState
*es
;
3149 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3150 s
->parent
.target_pid
= pid
;
3153 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3156 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3159 f
= lttv_trace_get_hook_field(th
, 3);
3160 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3162 //FIXME: type is rarely used, enum must match possible types.
3165 f
= lttv_trace_get_hook_field(th
, 4);
3166 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3169 f
= lttv_trace_get_hook_field(th
, 5);
3170 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3173 f
= lttv_trace_get_hook_field(th
, 6);
3174 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3177 f
= lttv_trace_get_hook_field(th
, 7);
3179 tgid
= ltt_event_get_unsigned(e
, f
);
3184 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3185 for(i
=0; i
<nb_cpus
; i
++) {
3186 process
= lttv_state_find_process(ts
, i
, pid
);
3187 g_assert(process
!= NULL
);
3189 process
->ppid
= parent_pid
;
3190 process
->tgid
= tgid
;
3191 process
->name
= g_quark_from_string(command
);
3193 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3194 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3198 /* The process might exist if a process was forked while performing the
3200 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3201 if(process
== NULL
) {
3202 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3203 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3204 pid
, tgid
, g_quark_from_string(command
),
3205 &s
->parent
.timestamp
);
3207 /* Keep the stack bottom : a running user mode */
3208 /* Disabled because of inconsistencies in the current statedump states. */
3209 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3210 /* Only keep the bottom
3211 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3212 /* Will cause expected trap when in fact being syscall (even after end of
3214 * Will cause expected interrupt when being syscall. (only before end of
3215 * statedump event) */
3216 // This will cause a "popping last state on stack, ignoring it."
3217 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3218 es
= process
->state
= &g_array_index(process
->execution_stack
,
3219 LttvExecutionState
, 0);
3220 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3221 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3222 es
->s
= LTTV_STATE_UNNAMED
;
3223 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3225 es
->t
= LTTV_STATE_SYSCALL
;
3230 /* User space process :
3231 * bottom : user mode
3232 * either currently running or scheduled out.
3233 * can be scheduled out because interrupted in (user mode or in syscall)
3234 * or because of an explicit call to the scheduler in syscall. Note that
3235 * the scheduler call comes after the irq_exit, so never in interrupt
3237 // temp workaround : set size to 1 : only have user mode bottom of stack.
3238 // will cause g_info message of expected syscall mode when in fact being
3239 // in user mode. Can also cause expected trap when in fact being user
3240 // mode in the event of a page fault reenabling interrupts in the handler.
3241 // Expected syscall and trap can also happen after the end of statedump
3242 // This will cause a "popping last state on stack, ignoring it."
3243 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3244 es
= process
->state
= &g_array_index(process
->execution_stack
,
3245 LttvExecutionState
, 0);
3246 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3247 es
->s
= LTTV_STATE_UNNAMED
;
3248 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3250 es
->t
= LTTV_STATE_USER_MODE
;
3258 es
= process
->state
= &g_array_index(process
->execution_stack
,
3259 LttvExecutionState
, 1);
3260 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3261 es
->s
= LTTV_STATE_UNNAMED
;
3262 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3266 /* The process has already been created :
3267 * Probably was forked while dumping the process state or
3268 * was simply scheduled in prior to get the state dump event.
3270 process
->ppid
= parent_pid
;
3271 process
->tgid
= tgid
;
3272 process
->name
= g_quark_from_string(command
);
3273 process
->type
= type
;
3275 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3277 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3278 if(type
== LTTV_STATE_KERNEL_THREAD
)
3279 es
->t
= LTTV_STATE_SYSCALL
;
3281 es
->t
= LTTV_STATE_USER_MODE
;
3284 /* Don't mess around with the stack, it will eventually become
3285 * ok after the end of state dump. */
3292 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3294 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3296 lttv_state_add_event_hooks(tss
);
3301 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3303 LttvTraceset
*traceset
= self
->parent
.ts
;
3305 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3309 LttvTracefileState
*tfs
;
3315 LttvAttributeValue val
;
3317 nb_trace
= lttv_traceset_number(traceset
);
3318 for(i
= 0 ; i
< nb_trace
; i
++) {
3319 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3321 /* Find the eventtype id for the following events and register the
3322 associated by id hooks. */
3324 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3325 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3328 lttv_trace_find_hook(ts
->parent
.t
,
3329 LTT_FACILITY_KERNEL_ARCH
,
3330 LTT_EVENT_SYSCALL_ENTRY
,
3331 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3332 syscall_entry
, NULL
, &hooks
);
3334 lttv_trace_find_hook(ts
->parent
.t
,
3335 LTT_FACILITY_KERNEL_ARCH
,
3336 LTT_EVENT_SYSCALL_EXIT
,
3338 syscall_exit
, NULL
, &hooks
);
3340 lttv_trace_find_hook(ts
->parent
.t
,
3341 LTT_FACILITY_KERNEL_ARCH
,
3342 LTT_EVENT_TRAP_ENTRY
,
3343 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3344 trap_entry
, NULL
, &hooks
);
3346 lttv_trace_find_hook(ts
->parent
.t
,
3347 LTT_FACILITY_KERNEL_ARCH
,
3348 LTT_EVENT_TRAP_EXIT
,
3350 trap_exit
, NULL
, &hooks
);
3352 lttv_trace_find_hook(ts
->parent
.t
,
3353 LTT_FACILITY_KERNEL
,
3354 LTT_EVENT_IRQ_ENTRY
,
3355 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3356 irq_entry
, NULL
, &hooks
);
3358 lttv_trace_find_hook(ts
->parent
.t
,
3359 LTT_FACILITY_KERNEL
,
3362 irq_exit
, NULL
, &hooks
);
3364 lttv_trace_find_hook(ts
->parent
.t
,
3365 LTT_FACILITY_KERNEL
,
3366 LTT_EVENT_SOFT_IRQ_ENTRY
,
3367 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3368 soft_irq_entry
, NULL
, &hooks
);
3370 lttv_trace_find_hook(ts
->parent
.t
,
3371 LTT_FACILITY_KERNEL
,
3372 LTT_EVENT_SOFT_IRQ_EXIT
,
3374 soft_irq_exit
, NULL
, &hooks
);
3376 lttv_trace_find_hook(ts
->parent
.t
,
3377 LTT_FACILITY_KERNEL
,
3378 LTT_EVENT_SCHED_SCHEDULE
,
3379 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3380 LTT_FIELD_PREV_STATE
),
3381 schedchange
, NULL
, &hooks
);
3383 lttv_trace_find_hook(ts
->parent
.t
,
3384 LTT_FACILITY_KERNEL
,
3385 LTT_EVENT_PROCESS_FORK
,
3386 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3387 LTT_FIELD_CHILD_TGID
),
3388 process_fork
, NULL
, &hooks
);
3390 lttv_trace_find_hook(ts
->parent
.t
,
3391 LTT_FACILITY_KERNEL_ARCH
,
3392 LTT_EVENT_KTHREAD_CREATE
,
3393 FIELD_ARRAY(LTT_FIELD_PID
),
3394 process_kernel_thread
, NULL
, &hooks
);
3396 lttv_trace_find_hook(ts
->parent
.t
,
3397 LTT_FACILITY_KERNEL
,
3398 LTT_EVENT_PROCESS_EXIT
,
3399 FIELD_ARRAY(LTT_FIELD_PID
),
3400 process_exit
, NULL
, &hooks
);
3402 lttv_trace_find_hook(ts
->parent
.t
,
3403 LTT_FACILITY_KERNEL
,
3404 LTT_EVENT_PROCESS_FREE
,
3405 FIELD_ARRAY(LTT_FIELD_PID
),
3406 process_free
, NULL
, &hooks
);
3408 lttv_trace_find_hook(ts
->parent
.t
,
3411 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3412 process_exec
, NULL
, &hooks
);
3414 lttv_trace_find_hook(ts
->parent
.t
,
3415 LTT_FACILITY_USER_GENERIC
,
3416 LTT_EVENT_THREAD_BRAND
,
3417 FIELD_ARRAY(LTT_FIELD_NAME
),
3418 thread_brand
, NULL
, &hooks
);
3420 /* statedump-related hooks */
3421 lttv_trace_find_hook(ts
->parent
.t
,
3423 LTT_EVENT_PROCESS_STATE
,
3424 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3425 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3426 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3427 enum_process_state
, NULL
, &hooks
);
3429 lttv_trace_find_hook(ts
->parent
.t
,
3431 LTT_EVENT_STATEDUMP_END
,
3433 statedump_end
, NULL
, &hooks
);
3435 lttv_trace_find_hook(ts
->parent
.t
,
3437 LTT_EVENT_LIST_INTERRUPT
,
3438 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3439 enum_interrupt
, NULL
, &hooks
);
3441 lttv_trace_find_hook(ts
->parent
.t
,
3443 LTT_EVENT_REQUEST_ISSUE
,
3444 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3445 bdev_request_issue
, NULL
, &hooks
);
3447 lttv_trace_find_hook(ts
->parent
.t
,
3449 LTT_EVENT_REQUEST_COMPLETE
,
3450 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3451 bdev_request_complete
, NULL
, &hooks
);
3453 lttv_trace_find_hook(ts
->parent
.t
,
3454 LTT_FACILITY_USER_GENERIC
,
3455 LTT_EVENT_FUNCTION_ENTRY
,
3456 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3457 function_entry
, NULL
, &hooks
);
3459 lttv_trace_find_hook(ts
->parent
.t
,
3460 LTT_FACILITY_USER_GENERIC
,
3461 LTT_EVENT_FUNCTION_EXIT
,
3462 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3463 function_exit
, NULL
, &hooks
);
3465 lttv_trace_find_hook(ts
->parent
.t
,
3466 LTT_FACILITY_STATEDUMP
,
3467 LTT_EVENT_SYS_CALL_TABLE
,
3468 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3469 dump_syscall
, NULL
, &hooks
);
3471 lttv_trace_find_hook(ts
->parent
.t
,
3472 LTT_FACILITY_STATEDUMP
,
3473 LTT_EVENT_SOFTIRQ_VEC
,
3474 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3475 dump_softirq
, NULL
, &hooks
);
3477 /* Add these hooks to each event_by_id hooks list */
3479 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3481 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3483 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3484 LttvTracefileContext
*, j
));
3486 for(k
= 0 ; k
< hooks
->len
; k
++) {
3487 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3489 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3495 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3496 *(val
.v_pointer
) = hooks
;
3500 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3502 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3504 lttv_state_remove_event_hooks(tss
);
3509 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3511 LttvTraceset
*traceset
= self
->parent
.ts
;
3513 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3517 LttvTracefileState
*tfs
;
3523 LttvAttributeValue val
;
3525 nb_trace
= lttv_traceset_number(traceset
);
3526 for(i
= 0 ; i
< nb_trace
; i
++) {
3527 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3529 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3530 hooks
= *(val
.v_pointer
);
3532 /* Remove these hooks from each event_by_id hooks list */
3534 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3536 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3538 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3539 LttvTracefileContext
*, j
));
3541 for(k
= 0 ; k
< hooks
->len
; k
++) {
3542 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3543 lttv_hooks_remove_data(
3544 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3549 lttv_trace_hook_remove_all(&hooks
);
3550 g_array_free(hooks
, TRUE
);
3554 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3556 guint
*event_count
= (guint
*)hook_data
;
3558 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3559 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3564 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3566 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3568 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3570 LttvAttributeValue value
;
3572 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3573 LTTV_STATE_SAVED_STATES
);
3574 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3575 value
= lttv_attribute_add(saved_states_tree
,
3576 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3577 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3578 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3579 *(value
.v_time
) = self
->parent
.timestamp
;
3580 lttv_state_save(tcs
, saved_state_tree
);
3581 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3582 self
->parent
.timestamp
.tv_nsec
);
3584 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3589 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3591 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3593 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3598 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3606 static gboolean
block_start(void *hook_data
, void *call_data
)
3608 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3610 LttvTracefileState
*tfcs
;
3612 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3614 LttEventPosition
*ep
;
3616 guint i
, nb_block
, nb_event
, nb_tracefile
;
3620 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3622 LttvAttributeValue value
;
3624 ep
= ltt_event_position_new();
3626 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3628 /* Count the number of events added since the last block end in any
3631 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3633 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3634 LttvTracefileContext
, i
));
3635 ltt_event_position(tfcs
->parent
.e
, ep
);
3636 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3637 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3638 tfcs
->saved_position
= nb_event
;
3642 if(tcs
->nb_event
>= tcs
->save_interval
) {
3643 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3644 LTTV_STATE_SAVED_STATES
);
3645 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3646 value
= lttv_attribute_add(saved_states_tree
,
3647 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3648 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3649 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3650 *(value
.v_time
) = self
->parent
.timestamp
;
3651 lttv_state_save(tcs
, saved_state_tree
);
3653 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3654 self
->parent
.timestamp
.tv_nsec
);
3656 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3662 static gboolean
block_end(void *hook_data
, void *call_data
)
3664 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3666 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3670 LttEventPosition
*ep
;
3672 guint nb_block
, nb_event
;
3674 ep
= ltt_event_position_new();
3675 ltt_event_position(self
->parent
.e
, ep
);
3676 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3677 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3678 self
->saved_position
= 0;
3679 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3686 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3688 LttvTraceset
*traceset
= self
->parent
.ts
;
3690 guint i
, j
, nb_trace
, nb_tracefile
;
3694 LttvTracefileState
*tfs
;
3696 LttvTraceHook hook_start
, hook_end
;
3698 nb_trace
= lttv_traceset_number(traceset
);
3699 for(i
= 0 ; i
< nb_trace
; i
++) {
3700 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3702 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3703 NULL
, NULL
, block_start
, &hook_start
);
3704 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3705 NULL
, NULL
, block_end
, &hook_end
);
3707 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3709 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3711 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3712 LttvTracefileContext
, j
));
3713 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3714 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3715 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3716 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3722 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3724 LttvTraceset
*traceset
= self
->parent
.ts
;
3726 guint i
, j
, nb_trace
, nb_tracefile
;
3730 LttvTracefileState
*tfs
;
3733 nb_trace
= lttv_traceset_number(traceset
);
3734 for(i
= 0 ; i
< nb_trace
; i
++) {
3736 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3737 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3739 if(ts
->has_precomputed_states
) continue;
3741 guint
*event_count
= g_new(guint
, 1);
3744 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3746 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3747 LttvTracefileContext
*, j
));
3748 lttv_hooks_add(tfs
->parent
.event
,
3749 state_save_event_hook
,
3756 lttv_process_traceset_begin(&self
->parent
,
3757 NULL
, NULL
, NULL
, NULL
, NULL
);
3761 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3763 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3765 lttv_state_save_add_event_hooks(tss
);
3772 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3774 LttvTraceset
*traceset
= self
->parent
.ts
;
3776 guint i
, j
, nb_trace
, nb_tracefile
;
3780 LttvTracefileState
*tfs
;
3782 LttvTraceHook hook_start
, hook_end
;
3784 nb_trace
= lttv_traceset_number(traceset
);
3785 for(i
= 0 ; i
< nb_trace
; i
++) {
3786 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3788 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3789 NULL
, NULL
, block_start
, &hook_start
);
3791 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3792 NULL
, NULL
, block_end
, &hook_end
);
3794 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3796 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3798 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3799 LttvTracefileContext
, j
));
3800 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3801 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3802 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3803 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3809 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3811 LttvTraceset
*traceset
= self
->parent
.ts
;
3813 guint i
, j
, nb_trace
, nb_tracefile
;
3817 LttvTracefileState
*tfs
;
3819 LttvHooks
*after_trace
= lttv_hooks_new();
3821 lttv_hooks_add(after_trace
,
3822 state_save_after_trace_hook
,
3827 lttv_process_traceset_end(&self
->parent
,
3828 NULL
, after_trace
, NULL
, NULL
, NULL
);
3830 lttv_hooks_destroy(after_trace
);
3832 nb_trace
= lttv_traceset_number(traceset
);
3833 for(i
= 0 ; i
< nb_trace
; i
++) {
3835 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3836 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3838 if(ts
->has_precomputed_states
) continue;
3840 guint
*event_count
= NULL
;
3842 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3844 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3845 LttvTracefileContext
*, j
));
3846 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3847 state_save_event_hook
);
3849 if(event_count
) g_free(event_count
);
3853 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3855 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3857 lttv_state_save_remove_event_hooks(tss
);
3862 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3864 LttvTraceset
*traceset
= self
->parent
.ts
;
3868 int min_pos
, mid_pos
, max_pos
;
3870 guint call_rest
= 0;
3872 LttvTraceState
*tcs
;
3874 LttvAttributeValue value
;
3876 LttvAttributeType type
;
3878 LttvAttributeName name
;
3882 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3884 //g_tree_destroy(self->parent.pqueue);
3885 //self->parent.pqueue = g_tree_new(compare_tracefile);
3887 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3889 nb_trace
= lttv_traceset_number(traceset
);
3890 for(i
= 0 ; i
< nb_trace
; i
++) {
3891 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3893 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3894 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3895 LTTV_STATE_SAVED_STATES
);
3898 if(saved_states_tree
) {
3899 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3900 mid_pos
= max_pos
/ 2;
3901 while(min_pos
< max_pos
) {
3902 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3904 g_assert(type
== LTTV_GOBJECT
);
3905 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3906 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3908 g_assert(type
== LTTV_TIME
);
3909 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3911 closest_tree
= saved_state_tree
;
3913 else max_pos
= mid_pos
- 1;
3915 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3919 /* restore the closest earlier saved state */
3921 lttv_state_restore(tcs
, closest_tree
);
3925 /* There is no saved state, yet we want to have it. Restart at T0 */
3927 restore_init_state(tcs
);
3928 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3931 /* We want to seek quickly without restoring/updating the state */
3933 restore_init_state(tcs
);
3934 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3937 if(!call_rest
) g_info("NOT Calling restore");
3942 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3948 traceset_state_finalize (LttvTracesetState
*self
)
3950 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3951 finalize(G_OBJECT(self
));
3956 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3958 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3960 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3961 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3962 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3963 klass
->new_traceset_context
= new_traceset_context
;
3964 klass
->new_trace_context
= new_trace_context
;
3965 klass
->new_tracefile_context
= new_tracefile_context
;
3970 lttv_traceset_state_get_type(void)
3972 static GType type
= 0;
3974 static const GTypeInfo info
= {
3975 sizeof (LttvTracesetStateClass
),
3976 NULL
, /* base_init */
3977 NULL
, /* base_finalize */
3978 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3979 NULL
, /* class_finalize */
3980 NULL
, /* class_data */
3981 sizeof (LttvTracesetState
),
3982 0, /* n_preallocs */
3983 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3984 NULL
/* value handling */
3987 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3995 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4001 trace_state_finalize (LttvTraceState
*self
)
4003 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4004 finalize(G_OBJECT(self
));
4009 trace_state_class_init (LttvTraceStateClass
*klass
)
4011 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4013 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4014 klass
->state_save
= state_save
;
4015 klass
->state_restore
= state_restore
;
4016 klass
->state_saved_free
= state_saved_free
;
4021 lttv_trace_state_get_type(void)
4023 static GType type
= 0;
4025 static const GTypeInfo info
= {
4026 sizeof (LttvTraceStateClass
),
4027 NULL
, /* base_init */
4028 NULL
, /* base_finalize */
4029 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4030 NULL
, /* class_finalize */
4031 NULL
, /* class_data */
4032 sizeof (LttvTraceState
),
4033 0, /* n_preallocs */
4034 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4035 NULL
/* value handling */
4038 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4039 "LttvTraceStateType", &info
, 0);
4046 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4052 tracefile_state_finalize (LttvTracefileState
*self
)
4054 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4055 finalize(G_OBJECT(self
));
4060 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4062 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4064 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4069 lttv_tracefile_state_get_type(void)
4071 static GType type
= 0;
4073 static const GTypeInfo info
= {
4074 sizeof (LttvTracefileStateClass
),
4075 NULL
, /* base_init */
4076 NULL
, /* base_finalize */
4077 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4078 NULL
, /* class_finalize */
4079 NULL
, /* class_data */
4080 sizeof (LttvTracefileState
),
4081 0, /* n_preallocs */
4082 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4083 NULL
/* value handling */
4086 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4087 "LttvTracefileStateType", &info
, 0);
4093 static void module_init()
4095 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4096 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4097 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4098 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4099 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4100 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4101 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4102 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4103 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4104 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4105 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4106 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4107 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4108 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4109 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4110 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4111 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4112 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4113 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4114 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4115 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4116 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4117 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4118 LTTV_STATE_EVENT
= g_quark_from_string("event");
4119 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4120 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4121 LTTV_STATE_TIME
= g_quark_from_string("time");
4122 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4123 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4124 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4125 g_quark_from_string("trace_state_use_count");
4126 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4127 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4128 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4129 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4130 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4131 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4134 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4135 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4136 LTT_FACILITY_FS
= g_quark_from_string("fs");
4137 LTT_FACILITY_LIST
= g_quark_from_string("list");
4138 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4139 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4140 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4142 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4143 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4144 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4145 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4146 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4147 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4148 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4149 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4150 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4151 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4152 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4153 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4154 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4155 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4156 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4157 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4158 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4159 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4160 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4161 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4162 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4163 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4164 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4165 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4167 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4168 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4169 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4170 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4171 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4172 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4173 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4174 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4175 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4176 LTT_FIELD_PID
= g_quark_from_string("pid");
4177 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4178 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4179 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4180 LTT_FIELD_NAME
= g_quark_from_string("name");
4181 LTT_FIELD_TYPE
= g_quark_from_string("type");
4182 LTT_FIELD_MODE
= g_quark_from_string("mode");
4183 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4184 LTT_FIELD_STATUS
= g_quark_from_string("status");
4185 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4186 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4187 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4188 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4189 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4190 LTT_FIELD_ACTION
= g_quark_from_string("action");
4191 LTT_FIELD_ID
= g_quark_from_string("id");
4192 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4193 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4195 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4196 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4197 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4198 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4199 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4200 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4202 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4203 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4204 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4206 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4207 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4208 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4209 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4212 static void module_destroy()
4217 LTTV_MODULE("state", "State computation", \
4218 "Update the system state, possibly saving it at intervals", \
4219 module_init
, module_destroy
)