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
, new_nb
);
306 fill_name_table(ts
, ts
->syscall_names
, ts
->nb_syscalls
, new_nb
, "syscall");
307 /* Update the table size */
308 ts
->nb_syscalls
= new_nb
;
311 static void expand_trap_table(LttvTraceState
*ts
, int id
)
313 guint new_nb
= check_expand(ts
->nb_traps
, id
);
315 if(likely(new_nb
== ts
->nb_traps
))
317 expand_name_table(ts
, &ts
->trap_names
, ts
->nb_traps
, new_nb
);
318 fill_name_table(ts
, ts
->trap_names
, ts
->nb_traps
, new_nb
, "trap");
319 /* Update the table size */
320 ts
->nb_traps
= new_nb
;
322 LttvTrapState
*old_table
= ts
->trap_states
;
323 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
324 memcpy(ts
->trap_states
, old_table
,
325 ts
->nb_traps
* sizeof(LttvTrapState
));
326 for(i
= ts
->nb_traps
; i
< new_nb
; i
++)
327 ts
->trap_states
[i
].running
= 0;
330 static void expand_irq_table(LttvTraceState
*ts
, int id
)
332 guint new_nb
= check_expand(ts
->nb_irqs
, id
);
334 if(likely(new_nb
== ts
->nb_irqs
))
336 expand_name_table(ts
, &ts
->irq_names
, ts
->nb_irqs
, new_nb
);
337 fill_name_table(ts
, ts
->irq_names
, ts
->nb_irqs
, new_nb
, "irq");
339 LttvIRQState
*old_table
= ts
->irq_states
;
340 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
341 memcpy(ts
->irq_states
, old_table
, ts
->nb_irqs
* sizeof(LttvIRQState
));
342 for(i
= ts
->nb_irqs
; i
< new_nb
; i
++) {
343 ts
->irq_states
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
346 /* Update the table size */
347 ts
->nb_irqs
= new_nb
;
350 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
352 guint new_nb
= check_expand(ts
->nb_soft_irqs
, id
);
354 if(likely(new_nb
== ts
->nb_soft_irqs
))
356 expand_name_table(ts
, &ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
);
357 fill_name_table(ts
, ts
->soft_irq_names
, ts
->nb_soft_irqs
, new_nb
, "softirq");
359 LttvSoftIRQState
*old_table
= ts
->soft_irq_states
;
360 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
361 memcpy(ts
->soft_irq_states
, old_table
,
362 ts
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
363 for(i
= ts
->nb_soft_irqs
; i
< new_nb
; i
++)
364 ts
->soft_irq_states
[i
].running
= 0;
366 /* Update the table size */
367 ts
->nb_soft_irqs
= new_nb
;
371 restore_init_state(LttvTraceState
*self
)
373 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
375 //LttvTracefileState *tfcs;
377 LttTime start_time
, end_time
;
379 /* Free the process tables */
380 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
381 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
382 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
383 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
386 /* Seek time to beginning */
387 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
388 // closest. It's the tracecontext job to seek the trace to the beginning
389 // anyway : the init state might be used at the middle of the trace as well...
390 //g_tree_destroy(self->parent.ts_context->pqueue);
391 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
393 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
395 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
397 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
398 nb_irqs
= self
->nb_irqs
;
399 nb_soft_irqs
= self
->nb_soft_irqs
;
400 nb_traps
= self
->nb_traps
;
402 /* Put the per cpu running_process to beginning state : process 0. */
403 for(i
=0; i
< nb_cpus
; i
++) {
404 LttvExecutionState
*es
;
405 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
406 LTTV_STATE_UNNAMED
, &start_time
);
407 /* We are not sure is it's a kernel thread or normal thread, put the
408 * bottom stack state to unknown */
409 self
->running_process
[i
]->execution_stack
=
410 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
411 es
= self
->running_process
[i
]->state
=
412 &g_array_index(self
->running_process
[i
]->execution_stack
,
413 LttvExecutionState
, 0);
414 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
415 es
->s
= LTTV_STATE_UNNAMED
;
417 //self->running_process[i]->state->s = LTTV_STATE_RUN;
418 self
->running_process
[i
]->cpu
= i
;
420 /* reset cpu states */
421 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
422 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
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 softirq resource states */
1739 nb_softirqs
= self
->nb_irqs
;
1740 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1741 g_assert(type
== LTTV_POINTER
);
1742 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_softirqs
);
1744 /* free the blkdev states */
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1746 g_assert(type
== LTTV_POINTER
);
1747 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1749 nb_tracefile
= self
->parent
.tracefiles
->len
;
1751 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1753 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1754 LttvTracefileContext
*, i
));
1755 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1756 g_assert(type
== LTTV_GOBJECT
);
1757 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1759 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1761 g_assert(type
== LTTV_POINTER
);
1762 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1764 g_object_unref(G_OBJECT(tracefiles_tree
));
1768 static void free_saved_state(LttvTraceState
*self
)
1772 LttvAttributeType type
;
1774 LttvAttributeValue value
;
1776 LttvAttributeName name
;
1780 LttvAttribute
*saved_states
;
1782 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1783 LTTV_STATE_SAVED_STATES
);
1785 nb
= lttv_attribute_get_number(saved_states
);
1786 for(i
= 0 ; i
< nb
; i
++) {
1787 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1788 g_assert(type
== LTTV_GOBJECT
);
1789 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1792 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1797 create_max_time(LttvTraceState
*tcs
)
1799 LttvAttributeValue v
;
1801 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1803 g_assert(*(v
.v_pointer
) == NULL
);
1804 *(v
.v_pointer
) = g_new(LttTime
,1);
1805 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1810 get_max_time(LttvTraceState
*tcs
)
1812 LttvAttributeValue v
;
1814 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1816 g_assert(*(v
.v_pointer
) != NULL
);
1817 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1822 free_max_time(LttvTraceState
*tcs
)
1824 LttvAttributeValue v
;
1826 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1828 g_free(*(v
.v_pointer
));
1829 *(v
.v_pointer
) = NULL
;
1833 typedef struct _LttvNameTables
{
1834 // FIXME GQuark *eventtype_names;
1835 GQuark
*syscall_names
;
1841 GQuark
*soft_irq_names
;
1847 create_name_tables(LttvTraceState
*tcs
)
1851 GString
*fe_name
= g_string_new("");
1853 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1855 LttvAttributeValue v
;
1859 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1861 g_assert(*(v
.v_pointer
) == NULL
);
1862 *(v
.v_pointer
) = name_tables
;
1864 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1866 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1867 LTT_FACILITY_KERNEL_ARCH
,
1868 LTT_EVENT_SYSCALL_ENTRY
,
1869 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1870 NULL
, NULL
, &hooks
)) {
1872 // th = lttv_trace_hook_get_first(&th);
1874 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1875 // nb = ltt_type_element_number(t);
1877 // name_tables->syscall_names = g_new(GQuark, nb);
1878 // name_tables->nb_syscalls = nb;
1880 // for(i = 0 ; i < nb ; i++) {
1881 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1882 // if(!name_tables->syscall_names[i]) {
1883 // GString *string = g_string_new("");
1884 // g_string_printf(string, "syscall %u", i);
1885 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1886 // g_string_free(string, TRUE);
1890 name_tables
->nb_syscalls
= 256;
1891 name_tables
->syscall_names
= g_new(GQuark
, 256);
1892 for(i
= 0 ; i
< 256 ; i
++) {
1893 g_string_printf(fe_name
, "syscall %d", i
);
1894 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1897 name_tables
->syscall_names
= NULL
;
1898 name_tables
->nb_syscalls
= 0;
1900 lttv_trace_hook_remove_all(&hooks
);
1902 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1903 LTT_FACILITY_KERNEL_ARCH
,
1904 LTT_EVENT_TRAP_ENTRY
,
1905 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1906 NULL
, NULL
, &hooks
)) {
1908 // th = lttv_trace_hook_get_first(&th);
1910 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1911 // //nb = ltt_type_element_number(t);
1913 // name_tables->trap_names = g_new(GQuark, nb);
1914 // for(i = 0 ; i < nb ; i++) {
1915 // name_tables->trap_names[i] = g_quark_from_string(
1916 // ltt_enum_string_get(t, i));
1919 name_tables
->nb_traps
= 256;
1920 name_tables
->trap_names
= g_new(GQuark
, 256);
1921 for(i
= 0 ; i
< 256 ; i
++) {
1922 g_string_printf(fe_name
, "trap %d", i
);
1923 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1926 name_tables
->trap_names
= NULL
;
1927 name_tables
->nb_traps
= 0;
1929 lttv_trace_hook_remove_all(&hooks
);
1931 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1932 LTT_FACILITY_KERNEL
,
1933 LTT_EVENT_IRQ_ENTRY
,
1934 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1935 NULL
, NULL
, &hooks
)) {
1938 name_tables->irq_names = g_new(GQuark, nb);
1939 for(i = 0 ; i < nb ; i++) {
1940 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1944 name_tables
->nb_irqs
= 256;
1945 name_tables
->irq_names
= g_new(GQuark
, 256);
1946 for(i
= 0 ; i
< 256 ; i
++) {
1947 g_string_printf(fe_name
, "irq %d", i
);
1948 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1951 name_tables
->nb_irqs
= 0;
1952 name_tables
->irq_names
= NULL
;
1954 lttv_trace_hook_remove_all(&hooks
);
1956 name_tables->soft_irq_names = g_new(GQuark, nb);
1957 for(i = 0 ; i < nb ; i++) {
1958 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1962 /* the kernel is limited to 32 statically defined softirqs */
1963 name_tables
->nb_softirqs
= 32;
1964 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1965 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1966 g_string_printf(fe_name
, "softirq %d", i
);
1967 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1969 g_array_free(hooks
, TRUE
);
1971 g_string_free(fe_name
, TRUE
);
1976 get_name_tables(LttvTraceState
*tcs
)
1978 LttvNameTables
*name_tables
;
1980 LttvAttributeValue v
;
1982 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1984 g_assert(*(v
.v_pointer
) != NULL
);
1985 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1986 //tcs->eventtype_names = name_tables->eventtype_names;
1987 tcs
->syscall_names
= name_tables
->syscall_names
;
1988 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1989 tcs
->trap_names
= name_tables
->trap_names
;
1990 tcs
->nb_traps
= name_tables
->nb_traps
;
1991 tcs
->irq_names
= name_tables
->irq_names
;
1992 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1993 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1994 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1999 free_name_tables(LttvTraceState
*tcs
)
2001 LttvNameTables
*name_tables
;
2003 LttvAttributeValue v
;
2005 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2007 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2008 *(v
.v_pointer
) = NULL
;
2010 // g_free(name_tables->eventtype_names);
2011 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2012 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2013 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2014 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2015 if(name_tables
) g_free(name_tables
);
2018 #ifdef HASH_TABLE_DEBUG
2020 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2022 LttvProcessState
*process
= (LttvProcessState
*)value
;
2024 /* Test for process corruption */
2025 guint stack_len
= process
->execution_stack
->len
;
2028 static void hash_table_check(GHashTable
*table
)
2030 g_hash_table_foreach(table
, test_process
, NULL
);
2036 /* clears the stack and sets the state passed as argument */
2037 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2039 g_array_set_size(cpust
->mode_stack
, 1);
2040 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2043 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2045 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2046 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2049 static void cpu_pop_mode(LttvCPUState
*cpust
)
2051 if(cpust
->mode_stack
->len
<= 1)
2052 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2054 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2057 /* clears the stack and sets the state passed as argument */
2058 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2060 g_array_set_size(bdevst
->mode_stack
, 1);
2061 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2064 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2066 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2067 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2070 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2072 if(bdevst
->mode_stack
->len
<= 1)
2073 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2075 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2078 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2080 g_array_set_size(irqst
->mode_stack
, 1);
2081 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2084 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2086 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2087 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2090 static void irq_pop_mode(LttvIRQState
*irqst
)
2092 if(irqst
->mode_stack
->len
<= 1)
2093 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2095 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2098 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2101 LttvExecutionState
*es
;
2103 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2104 guint cpu
= tfs
->cpu
;
2106 #ifdef HASH_TABLE_DEBUG
2107 hash_table_check(ts
->processes
);
2109 LttvProcessState
*process
= ts
->running_process
[cpu
];
2111 guint depth
= process
->execution_stack
->len
;
2113 process
->execution_stack
=
2114 g_array_set_size(process
->execution_stack
, depth
+ 1);
2117 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2119 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2122 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2123 es
->cum_cpu_time
= ltt_time_zero
;
2124 es
->s
= process
->state
->s
;
2125 process
->state
= es
;
2129 * return 1 when empty, else 0 */
2130 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2131 LttvTracefileState
*tfs
)
2133 guint depth
= process
->execution_stack
->len
;
2139 process
->execution_stack
=
2140 g_array_set_size(process
->execution_stack
, depth
- 1);
2141 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2143 process
->state
->change
= tfs
->parent
.timestamp
;
2148 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2150 guint cpu
= tfs
->cpu
;
2151 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2152 LttvProcessState
*process
= ts
->running_process
[cpu
];
2154 guint depth
= process
->execution_stack
->len
;
2156 if(process
->state
->t
!= t
){
2157 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2158 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2159 g_info("process state has %s when pop_int is %s\n",
2160 g_quark_to_string(process
->state
->t
),
2161 g_quark_to_string(t
));
2162 g_info("{ %u, %u, %s, %s, %s }\n",
2165 g_quark_to_string(process
->name
),
2166 g_quark_to_string(process
->brand
),
2167 g_quark_to_string(process
->state
->s
));
2172 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2173 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2177 process
->execution_stack
=
2178 g_array_set_size(process
->execution_stack
, depth
- 1);
2179 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2181 process
->state
->change
= tfs
->parent
.timestamp
;
2184 struct search_result
{
2185 const LttTime
*time
; /* Requested time */
2186 LttTime
*best
; /* Best result */
2189 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2191 const LttTime
*elem_time
= (const LttTime
*)a
;
2192 /* Explicit non const cast */
2193 struct search_result
*res
= (struct search_result
*)b
;
2195 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2196 /* The usertrace was created before the schedchange */
2197 /* Get larger keys */
2199 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2200 /* The usertrace was created after the schedchange time */
2201 /* Get smaller keys */
2203 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2204 res
->best
= (LttTime
*)elem_time
;
2207 res
->best
= (LttTime
*)elem_time
;
2214 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2215 guint pid
, const LttTime
*timestamp
)
2217 LttvTracefileState
*tfs
= NULL
;
2218 struct search_result res
;
2219 /* Find the usertrace associated with a pid and time interval.
2220 * Search in the usertraces by PID (within a hash) and then, for each
2221 * corresponding element of the array, find the first one with creation
2222 * timestamp the lowest, but higher or equal to "timestamp". */
2223 res
.time
= timestamp
;
2225 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2226 if(usertrace_tree
) {
2227 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2229 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2237 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2238 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2240 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2242 LttvExecutionState
*es
;
2247 process
->tgid
= tgid
;
2249 process
->name
= name
;
2250 process
->brand
= LTTV_STATE_UNBRANDED
;
2251 //process->last_cpu = tfs->cpu_name;
2252 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2253 process
->type
= LTTV_STATE_USER_THREAD
;
2254 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2255 process
->current_function
= 0; //function 0x0 by default.
2257 g_info("Process %u, core %p", process
->pid
, process
);
2258 g_hash_table_insert(tcs
->processes
, process
, process
);
2261 process
->ppid
= parent
->pid
;
2262 process
->creation_time
= *timestamp
;
2265 /* No parent. This process exists but we are missing all information about
2266 its creation. The birth time is set to zero but we remember the time of
2271 process
->creation_time
= ltt_time_zero
;
2274 process
->insertion_time
= *timestamp
;
2275 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2276 process
->creation_time
.tv_nsec
);
2277 process
->pid_time
= g_quark_from_string(buffer
);
2279 process
->free_events
= 0;
2280 //process->last_cpu = tfs->cpu_name;
2281 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2282 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2283 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2284 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2285 es
= process
->state
= &g_array_index(process
->execution_stack
,
2286 LttvExecutionState
, 0);
2287 es
->t
= LTTV_STATE_USER_MODE
;
2288 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2289 es
->entry
= *timestamp
;
2290 //g_assert(timestamp->tv_sec != 0);
2291 es
->change
= *timestamp
;
2292 es
->cum_cpu_time
= ltt_time_zero
;
2293 es
->s
= LTTV_STATE_RUN
;
2295 es
= process
->state
= &g_array_index(process
->execution_stack
,
2296 LttvExecutionState
, 1);
2297 es
->t
= LTTV_STATE_SYSCALL
;
2298 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2299 es
->entry
= *timestamp
;
2300 //g_assert(timestamp->tv_sec != 0);
2301 es
->change
= *timestamp
;
2302 es
->cum_cpu_time
= ltt_time_zero
;
2303 es
->s
= LTTV_STATE_WAIT_FORK
;
2305 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2306 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2307 sizeof(guint64
), 0);
2312 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2315 LttvProcessState key
;
2316 LttvProcessState
*process
;
2320 process
= g_hash_table_lookup(ts
->processes
, &key
);
2325 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2326 const LttTime
*timestamp
)
2328 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2329 LttvExecutionState
*es
;
2331 /* Put ltt_time_zero creation time for unexisting processes */
2332 if(unlikely(process
== NULL
)) {
2333 process
= lttv_state_create_process(ts
,
2334 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2335 /* We are not sure is it's a kernel thread or normal thread, put the
2336 * bottom stack state to unknown */
2337 process
->execution_stack
=
2338 g_array_set_size(process
->execution_stack
, 1);
2339 process
->state
= es
=
2340 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2341 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2342 es
->s
= LTTV_STATE_UNNAMED
;
2347 /* FIXME : this function should be called when we receive an event telling that
2348 * release_task has been called in the kernel. In happens generally when
2349 * the parent waits for its child terminaison, but may also happen in special
2350 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2351 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2352 * of a killed thread group, but isn't the leader.
2354 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2356 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2357 LttvProcessState key
;
2359 /* Wait for both schedule with exit dead and process free to happen.
2360 * They can happen in any order. */
2361 if (++(process
->free_events
) < 2)
2364 key
.pid
= process
->pid
;
2365 key
.cpu
= process
->cpu
;
2366 g_hash_table_remove(ts
->processes
, &key
);
2367 g_array_free(process
->execution_stack
, TRUE
);
2368 g_array_free(process
->user_stack
, TRUE
);
2374 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2376 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2377 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2382 static void lttv_state_free_process_table(GHashTable
*processes
)
2384 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2385 g_hash_table_destroy(processes
);
2389 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2391 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2393 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2394 LttvProcessState
*process
= ts
->running_process
[cpu
];
2395 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2396 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2397 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2398 LttvExecutionSubmode submode
;
2400 guint syscall
= ltt_event_get_unsigned(e
, f
);
2401 expand_syscall_table(ts
, syscall
);
2402 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2403 /* There can be no system call from PID 0 : unknown state */
2404 if(process
->pid
!= 0)
2405 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2410 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2412 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2414 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2415 LttvProcessState
*process
= ts
->running_process
[cpu
];
2417 /* There can be no system call from PID 0 : unknown state */
2418 if(process
->pid
!= 0)
2419 pop_state(s
, LTTV_STATE_SYSCALL
);
2424 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2426 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2427 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2428 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2429 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2430 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2432 LttvExecutionSubmode submode
;
2434 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2436 expand_trap_table(ts
, trap
);
2438 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2440 push_state(s
, LTTV_STATE_TRAP
, submode
);
2442 /* update cpu status */
2443 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2445 /* update trap status */
2446 s
->cpu_state
->last_trap
= trap
;
2447 ts
->trap_states
[trap
].running
++;
2452 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2454 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2455 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2456 guint trap
= s
->cpu_state
->last_trap
;
2458 pop_state(s
, LTTV_STATE_TRAP
);
2460 /* update cpu status */
2461 cpu_pop_mode(s
->cpu_state
);
2463 /* update trap status */
2464 if(ts
->trap_states
[trap
].running
)
2465 ts
->trap_states
[trap
].running
--;
2470 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2472 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2473 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2474 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2475 //guint8 ev_id = ltt_event_eventtype_id(e);
2476 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2477 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2479 LttvExecutionSubmode submode
;
2480 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2482 expand_irq_table(ts
, irq
);
2484 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2486 /* Do something with the info about being in user or system mode when int? */
2487 push_state(s
, LTTV_STATE_IRQ
, submode
);
2489 /* update cpu status */
2490 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2492 /* update irq status */
2493 s
->cpu_state
->last_irq
= irq
;
2494 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2499 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2501 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2502 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2503 guint softirq
= s
->cpu_state
->last_soft_irq
;
2505 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2507 /* update softirq status */
2508 if(ts
->soft_irq_states
[softirq
].running
)
2509 ts
->soft_irq_states
[softirq
].running
--;
2511 /* update cpu status */
2512 cpu_pop_mode(s
->cpu_state
);
2517 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2519 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2520 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2522 pop_state(s
, LTTV_STATE_IRQ
);
2524 /* update cpu status */
2525 cpu_pop_mode(s
->cpu_state
);
2527 /* update irq status */
2528 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2533 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2535 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2536 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2537 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2538 //guint8 ev_id = ltt_event_eventtype_id(e);
2539 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2540 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2541 LttvExecutionSubmode submode
;
2542 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2543 expand_soft_irq_table(ts
, softirq
);
2544 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2546 /* Do something with the info about being in user or system mode when int? */
2547 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2549 /* update cpu status */
2550 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2552 /* update softirq status */
2553 s
->cpu_state
->last_soft_irq
= softirq
;
2554 ts
->soft_irq_states
[softirq
].running
++;
2559 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2561 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2562 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2563 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2564 //guint8 ev_id = ltt_event_eventtype_id(e);
2565 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2567 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2568 lttv_trace_get_hook_field(th
, 0)));
2569 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2571 expand_irq_table(ts
, irq
);
2572 ts
->irq_names
[irq
] = action
;
2578 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2580 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2581 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2582 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2583 //guint8 ev_id = ltt_event_eventtype_id(e);
2584 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2586 guint major
= ltt_event_get_long_unsigned(e
,
2587 lttv_trace_get_hook_field(th
, 0));
2588 guint minor
= ltt_event_get_long_unsigned(e
,
2589 lttv_trace_get_hook_field(th
, 1));
2590 guint oper
= ltt_event_get_long_unsigned(e
,
2591 lttv_trace_get_hook_field(th
, 2));
2592 guint16 devcode
= MKDEV(major
,minor
);
2594 /* have we seen this block device before? */
2595 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2598 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2600 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2605 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2607 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2608 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2609 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2610 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2612 guint major
= ltt_event_get_long_unsigned(e
,
2613 lttv_trace_get_hook_field(th
, 0));
2614 guint minor
= ltt_event_get_long_unsigned(e
,
2615 lttv_trace_get_hook_field(th
, 1));
2616 //guint oper = ltt_event_get_long_unsigned(e,
2617 // lttv_trace_get_hook_field(th, 2));
2618 guint16 devcode
= MKDEV(major
,minor
);
2620 /* have we seen this block device before? */
2621 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2623 /* update block device */
2624 bdev_pop_mode(bdev
);
2629 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2633 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2634 guint cpu
= tfs
->cpu
;
2635 LttvProcessState
*process
= ts
->running_process
[cpu
];
2637 guint depth
= process
->user_stack
->len
;
2639 process
->user_stack
=
2640 g_array_set_size(process
->user_stack
, depth
+ 1);
2642 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2643 *new_func
= funcptr
;
2644 process
->current_function
= funcptr
;
2647 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2649 guint cpu
= tfs
->cpu
;
2650 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2651 LttvProcessState
*process
= ts
->running_process
[cpu
];
2653 if(process
->current_function
!= funcptr
){
2654 g_info("Different functions (%lu.%09lu): ignore it\n",
2655 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2656 g_info("process state has %llu when pop_function is %llu\n",
2657 process
->current_function
, funcptr
);
2658 g_info("{ %u, %u, %s, %s, %s }\n",
2661 g_quark_to_string(process
->name
),
2662 g_quark_to_string(process
->brand
),
2663 g_quark_to_string(process
->state
->s
));
2666 guint depth
= process
->user_stack
->len
;
2669 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2670 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2674 process
->user_stack
=
2675 g_array_set_size(process
->user_stack
, depth
- 1);
2676 process
->current_function
=
2677 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2681 static gboolean
function_entry(void *hook_data
, void *call_data
)
2683 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2684 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2685 //guint8 ev_id = ltt_event_eventtype_id(e);
2686 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2687 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2688 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2690 push_function(s
, funcptr
);
2694 static gboolean
function_exit(void *hook_data
, void *call_data
)
2696 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2697 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2698 //guint8 ev_id = ltt_event_eventtype_id(e);
2699 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2700 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2701 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2703 pop_function(s
, funcptr
);
2707 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2709 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2710 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2711 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2712 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2717 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2718 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2719 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2721 expand_syscall_table(ts
, id
);
2722 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2727 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2729 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2730 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2731 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2732 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2737 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2738 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2739 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2741 expand_soft_irq_table(ts
, id
);
2742 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2747 static gboolean
schedchange(void *hook_data
, void *call_data
)
2749 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2751 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2752 LttvProcessState
*process
= ts
->running_process
[cpu
];
2753 //LttvProcessState *old_process = ts->running_process[cpu];
2755 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2756 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2757 guint pid_in
, pid_out
;
2760 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2761 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2762 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2764 if(likely(process
!= NULL
)) {
2766 /* We could not know but it was not the idle process executing.
2767 This should only happen at the beginning, before the first schedule
2768 event, and when the initial information (current process for each CPU)
2769 is missing. It is not obvious how we could, after the fact, compensate
2770 the wrongly attributed statistics. */
2772 //This test only makes sense once the state is known and if there is no
2773 //missing events. We need to silently ignore schedchange coming after a
2774 //process_free, or it causes glitches. (FIXME)
2775 //if(unlikely(process->pid != pid_out)) {
2776 // g_assert(process->pid == 0);
2778 if(process
->pid
== 0
2779 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2781 /* Scheduling out of pid 0 at beginning of the trace :
2782 * we know for sure it is in syscall mode at this point. */
2783 g_assert(process
->execution_stack
->len
== 1);
2784 process
->state
->t
= LTTV_STATE_SYSCALL
;
2785 process
->state
->s
= LTTV_STATE_WAIT
;
2786 process
->state
->change
= s
->parent
.timestamp
;
2787 process
->state
->entry
= s
->parent
.timestamp
;
2790 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2791 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2792 process
->state
->change
= s
->parent
.timestamp
;
2794 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2795 else process
->state
->s
= LTTV_STATE_WAIT
;
2796 process
->state
->change
= s
->parent
.timestamp
;
2799 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2800 /* see sched.h for states */
2801 if (!exit_process(s
, process
)) {
2802 process
->state
->s
= LTTV_STATE_DEAD
;
2803 process
->state
->change
= s
->parent
.timestamp
;
2808 process
= ts
->running_process
[cpu
] =
2809 lttv_state_find_process_or_create(
2810 (LttvTraceState
*)s
->parent
.t_context
,
2812 &s
->parent
.timestamp
);
2813 process
->state
->s
= LTTV_STATE_RUN
;
2815 if(process
->usertrace
)
2816 process
->usertrace
->cpu
= cpu
;
2817 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2818 process
->state
->change
= s
->parent
.timestamp
;
2820 /* update cpu status */
2822 /* going to idle task */
2823 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2825 /* scheduling a real task.
2826 * we must be careful here:
2827 * if we just schedule()'ed to a process that is
2828 * in a trap, we must put the cpu in trap mode
2830 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2831 if(process
->state
->t
== LTTV_STATE_TRAP
)
2832 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2838 static gboolean
process_fork(void *hook_data
, void *call_data
)
2840 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2841 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2842 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2844 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2845 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2846 //LttvProcessState *zombie_process;
2848 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2849 LttvProcessState
*process
= ts
->running_process
[cpu
];
2850 LttvProcessState
*child_process
;
2851 struct marker_field
*f
;
2854 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2857 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2858 s
->parent
.target_pid
= child_pid
;
2861 f
= lttv_trace_get_hook_field(th
, 2);
2863 child_tgid
= ltt_event_get_unsigned(e
, f
);
2867 /* Mathieu : it seems like the process might have been scheduled in before the
2868 * fork, and, in a rare case, might be the current process. This might happen
2869 * in a SMP case where we don't have enough precision on the clocks.
2871 * Test reenabled after precision fixes on time. (Mathieu) */
2873 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2875 if(unlikely(zombie_process
!= NULL
)) {
2876 /* Reutilisation of PID. Only now we are sure that the old PID
2877 * has been released. FIXME : should know when release_task happens instead.
2879 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2881 for(i
=0; i
< num_cpus
; i
++) {
2882 g_assert(zombie_process
!= ts
->running_process
[i
]);
2885 exit_process(s
, zombie_process
);
2888 g_assert(process
->pid
!= child_pid
);
2889 // FIXME : Add this test in the "known state" section
2890 // g_assert(process->pid == parent_pid);
2891 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2892 if(child_process
== NULL
) {
2893 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2894 child_pid
, child_tgid
,
2895 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2897 /* The process has already been created : due to time imprecision between
2898 * multiple CPUs : it has been scheduled in before creation. Note that we
2899 * shouldn't have this kind of imprecision.
2901 * Simply put a correct parent.
2903 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2904 //g_assert(0); /* This is a problematic case : the process has been created
2905 // before the fork event */
2906 child_process
->ppid
= process
->pid
;
2907 child_process
->tgid
= child_tgid
;
2909 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2910 child_process
->name
= process
->name
;
2911 child_process
->brand
= process
->brand
;
2916 /* We stamp a newly created process as kernel_thread.
2917 * The thread should not be running yet. */
2918 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2920 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2921 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2922 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2924 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2925 LttvProcessState
*process
;
2926 LttvExecutionState
*es
;
2929 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2930 s
->parent
.target_pid
= pid
;
2932 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2934 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2935 process
->execution_stack
=
2936 g_array_set_size(process
->execution_stack
, 1);
2937 es
= process
->state
=
2938 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2939 es
->t
= LTTV_STATE_SYSCALL
;
2941 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2946 static gboolean
process_exit(void *hook_data
, void *call_data
)
2948 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2949 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2950 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2952 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2953 LttvProcessState
*process
; // = ts->running_process[cpu];
2955 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2956 s
->parent
.target_pid
= pid
;
2958 // FIXME : Add this test in the "known state" section
2959 // g_assert(process->pid == pid);
2961 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2962 if(likely(process
!= NULL
)) {
2963 process
->state
->s
= LTTV_STATE_EXIT
;
2968 static gboolean
process_free(void *hook_data
, void *call_data
)
2970 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2971 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2972 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2973 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2975 LttvProcessState
*process
;
2977 /* PID of the process to release */
2978 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2979 s
->parent
.target_pid
= release_pid
;
2981 g_assert(release_pid
!= 0);
2983 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2984 if(likely(process
!= NULL
))
2985 exit_process(s
, process
);
2988 if(likely(process
!= NULL
)) {
2989 /* release_task is happening at kernel level : we can now safely release
2990 * the data structure of the process */
2991 //This test is fun, though, as it may happen that
2992 //at time t : CPU 0 : process_free
2993 //at time t+150ns : CPU 1 : schedule out
2994 //Clearly due to time imprecision, we disable it. (Mathieu)
2995 //If this weird case happen, we have no choice but to put the
2996 //Currently running process on the cpu to 0.
2997 //I re-enable it following time precision fixes. (Mathieu)
2998 //Well, in the case where an process is freed by a process on another CPU
2999 //and still scheduled, it happens that this is the schedchange that will
3000 //drop the last reference count. Do not free it here!
3001 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3003 for(i
=0; i
< num_cpus
; i
++) {
3004 //g_assert(process != ts->running_process[i]);
3005 if(process
== ts
->running_process
[i
]) {
3006 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3010 if(i
== num_cpus
) /* process is not scheduled */
3011 exit_process(s
, process
);
3018 static gboolean
process_exec(void *hook_data
, void *call_data
)
3020 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3021 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3022 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3023 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3026 LttvProcessState
*process
= ts
->running_process
[cpu
];
3028 #if 0//how to use a sequence that must be transformed in a string
3029 /* PID of the process to release */
3030 guint64 name_len
= ltt_event_field_element_number(e
,
3031 lttv_trace_get_hook_field(th
, 0));
3032 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3033 LttField
*child
= ltt_event_field_element_select(e
,
3034 lttv_trace_get_hook_field(th
, 0), 0);
3036 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3037 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3038 memcpy(null_term_name
, name_begin
, name_len
);
3039 null_term_name
[name_len
] = '\0';
3040 process
->name
= g_quark_from_string(null_term_name
);
3043 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3044 lttv_trace_get_hook_field(th
, 0)));
3045 process
->brand
= LTTV_STATE_UNBRANDED
;
3046 //g_free(null_term_name);
3050 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3052 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3053 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3054 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3055 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3058 LttvProcessState
*process
= ts
->running_process
[cpu
];
3060 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3061 process
->brand
= g_quark_from_string(name
);
3066 static void fix_process(gpointer key
, gpointer value
,
3069 LttvProcessState
*process
;
3070 LttvExecutionState
*es
;
3071 process
= (LttvProcessState
*)value
;
3072 LttTime
*timestamp
= (LttTime
*)user_data
;
3074 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3075 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3076 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3077 es
->t
= LTTV_STATE_SYSCALL
;
3078 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3079 es
->entry
= *timestamp
;
3080 es
->change
= *timestamp
;
3081 es
->cum_cpu_time
= ltt_time_zero
;
3082 if(es
->s
== LTTV_STATE_UNNAMED
)
3083 es
->s
= LTTV_STATE_WAIT
;
3086 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3087 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3088 es
->t
= LTTV_STATE_USER_MODE
;
3089 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3090 es
->entry
= *timestamp
;
3091 //g_assert(timestamp->tv_sec != 0);
3092 es
->change
= *timestamp
;
3093 es
->cum_cpu_time
= ltt_time_zero
;
3094 if(es
->s
== LTTV_STATE_UNNAMED
)
3095 es
->s
= LTTV_STATE_RUN
;
3097 if(process
->execution_stack
->len
== 1) {
3098 /* Still in bottom unknown mode, means never did a system call
3099 * May be either in user mode, syscall mode, running or waiting.*/
3100 /* FIXME : we may be tagging syscall mode when being user mode */
3101 process
->execution_stack
=
3102 g_array_set_size(process
->execution_stack
, 2);
3103 es
= process
->state
= &g_array_index(process
->execution_stack
,
3104 LttvExecutionState
, 1);
3105 es
->t
= LTTV_STATE_SYSCALL
;
3106 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3107 es
->entry
= *timestamp
;
3108 //g_assert(timestamp->tv_sec != 0);
3109 es
->change
= *timestamp
;
3110 es
->cum_cpu_time
= ltt_time_zero
;
3111 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3112 es
->s
= LTTV_STATE_WAIT
;
3118 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3120 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3121 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3122 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3123 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3124 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3126 /* For all processes */
3127 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3128 /* else, if stack[0] is unknown, set to user mode, running */
3130 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3135 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3137 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3138 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3139 //It's slow : optimise later by doing this before reading trace.
3140 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3146 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3147 LttvProcessState
*process
= ts
->running_process
[cpu
];
3148 LttvProcessState
*parent_process
;
3149 struct marker_field
*f
;
3150 GQuark type
, mode
, submode
, status
;
3151 LttvExecutionState
*es
;
3155 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3156 s
->parent
.target_pid
= pid
;
3159 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3162 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3165 f
= lttv_trace_get_hook_field(th
, 3);
3166 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3168 //FIXME: type is rarely used, enum must match possible types.
3171 f
= lttv_trace_get_hook_field(th
, 4);
3172 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3175 f
= lttv_trace_get_hook_field(th
, 5);
3176 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3179 f
= lttv_trace_get_hook_field(th
, 6);
3180 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3183 f
= lttv_trace_get_hook_field(th
, 7);
3185 tgid
= ltt_event_get_unsigned(e
, f
);
3190 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3191 for(i
=0; i
<nb_cpus
; i
++) {
3192 process
= lttv_state_find_process(ts
, i
, pid
);
3193 g_assert(process
!= NULL
);
3195 process
->ppid
= parent_pid
;
3196 process
->tgid
= tgid
;
3197 process
->name
= g_quark_from_string(command
);
3199 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3200 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3204 /* The process might exist if a process was forked while performing the
3206 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3207 if(process
== NULL
) {
3208 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3209 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3210 pid
, tgid
, g_quark_from_string(command
),
3211 &s
->parent
.timestamp
);
3213 /* Keep the stack bottom : a running user mode */
3214 /* Disabled because of inconsistencies in the current statedump states. */
3215 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3216 /* Only keep the bottom
3217 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3218 /* Will cause expected trap when in fact being syscall (even after end of
3220 * Will cause expected interrupt when being syscall. (only before end of
3221 * statedump event) */
3222 // This will cause a "popping last state on stack, ignoring it."
3223 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3224 es
= process
->state
= &g_array_index(process
->execution_stack
,
3225 LttvExecutionState
, 0);
3226 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3227 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3228 es
->s
= LTTV_STATE_UNNAMED
;
3229 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3231 es
->t
= LTTV_STATE_SYSCALL
;
3236 /* User space process :
3237 * bottom : user mode
3238 * either currently running or scheduled out.
3239 * can be scheduled out because interrupted in (user mode or in syscall)
3240 * or because of an explicit call to the scheduler in syscall. Note that
3241 * the scheduler call comes after the irq_exit, so never in interrupt
3243 // temp workaround : set size to 1 : only have user mode bottom of stack.
3244 // will cause g_info message of expected syscall mode when in fact being
3245 // in user mode. Can also cause expected trap when in fact being user
3246 // mode in the event of a page fault reenabling interrupts in the handler.
3247 // Expected syscall and trap can also happen after the end of statedump
3248 // This will cause a "popping last state on stack, ignoring it."
3249 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3250 es
= process
->state
= &g_array_index(process
->execution_stack
,
3251 LttvExecutionState
, 0);
3252 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3253 es
->s
= LTTV_STATE_UNNAMED
;
3254 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3256 es
->t
= LTTV_STATE_USER_MODE
;
3264 es
= process
->state
= &g_array_index(process
->execution_stack
,
3265 LttvExecutionState
, 1);
3266 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3267 es
->s
= LTTV_STATE_UNNAMED
;
3268 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3272 /* The process has already been created :
3273 * Probably was forked while dumping the process state or
3274 * was simply scheduled in prior to get the state dump event.
3276 process
->ppid
= parent_pid
;
3277 process
->tgid
= tgid
;
3278 process
->name
= g_quark_from_string(command
);
3279 process
->type
= type
;
3281 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3283 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3284 if(type
== LTTV_STATE_KERNEL_THREAD
)
3285 es
->t
= LTTV_STATE_SYSCALL
;
3287 es
->t
= LTTV_STATE_USER_MODE
;
3290 /* Don't mess around with the stack, it will eventually become
3291 * ok after the end of state dump. */
3298 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3300 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3302 lttv_state_add_event_hooks(tss
);
3307 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3309 LttvTraceset
*traceset
= self
->parent
.ts
;
3311 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3315 LttvTracefileState
*tfs
;
3321 LttvAttributeValue val
;
3323 nb_trace
= lttv_traceset_number(traceset
);
3324 for(i
= 0 ; i
< nb_trace
; i
++) {
3325 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3327 /* Find the eventtype id for the following events and register the
3328 associated by id hooks. */
3330 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3331 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3334 lttv_trace_find_hook(ts
->parent
.t
,
3335 LTT_FACILITY_KERNEL_ARCH
,
3336 LTT_EVENT_SYSCALL_ENTRY
,
3337 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3338 syscall_entry
, NULL
, &hooks
);
3340 lttv_trace_find_hook(ts
->parent
.t
,
3341 LTT_FACILITY_KERNEL_ARCH
,
3342 LTT_EVENT_SYSCALL_EXIT
,
3344 syscall_exit
, NULL
, &hooks
);
3346 lttv_trace_find_hook(ts
->parent
.t
,
3347 LTT_FACILITY_KERNEL_ARCH
,
3348 LTT_EVENT_TRAP_ENTRY
,
3349 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3350 trap_entry
, NULL
, &hooks
);
3352 lttv_trace_find_hook(ts
->parent
.t
,
3353 LTT_FACILITY_KERNEL_ARCH
,
3354 LTT_EVENT_TRAP_EXIT
,
3356 trap_exit
, NULL
, &hooks
);
3358 lttv_trace_find_hook(ts
->parent
.t
,
3359 LTT_FACILITY_KERNEL
,
3360 LTT_EVENT_IRQ_ENTRY
,
3361 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3362 irq_entry
, NULL
, &hooks
);
3364 lttv_trace_find_hook(ts
->parent
.t
,
3365 LTT_FACILITY_KERNEL
,
3368 irq_exit
, NULL
, &hooks
);
3370 lttv_trace_find_hook(ts
->parent
.t
,
3371 LTT_FACILITY_KERNEL
,
3372 LTT_EVENT_SOFT_IRQ_ENTRY
,
3373 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3374 soft_irq_entry
, NULL
, &hooks
);
3376 lttv_trace_find_hook(ts
->parent
.t
,
3377 LTT_FACILITY_KERNEL
,
3378 LTT_EVENT_SOFT_IRQ_EXIT
,
3380 soft_irq_exit
, NULL
, &hooks
);
3382 lttv_trace_find_hook(ts
->parent
.t
,
3383 LTT_FACILITY_KERNEL
,
3384 LTT_EVENT_SCHED_SCHEDULE
,
3385 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3386 LTT_FIELD_PREV_STATE
),
3387 schedchange
, NULL
, &hooks
);
3389 lttv_trace_find_hook(ts
->parent
.t
,
3390 LTT_FACILITY_KERNEL
,
3391 LTT_EVENT_PROCESS_FORK
,
3392 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3393 LTT_FIELD_CHILD_TGID
),
3394 process_fork
, NULL
, &hooks
);
3396 lttv_trace_find_hook(ts
->parent
.t
,
3397 LTT_FACILITY_KERNEL_ARCH
,
3398 LTT_EVENT_KTHREAD_CREATE
,
3399 FIELD_ARRAY(LTT_FIELD_PID
),
3400 process_kernel_thread
, NULL
, &hooks
);
3402 lttv_trace_find_hook(ts
->parent
.t
,
3403 LTT_FACILITY_KERNEL
,
3404 LTT_EVENT_PROCESS_EXIT
,
3405 FIELD_ARRAY(LTT_FIELD_PID
),
3406 process_exit
, NULL
, &hooks
);
3408 lttv_trace_find_hook(ts
->parent
.t
,
3409 LTT_FACILITY_KERNEL
,
3410 LTT_EVENT_PROCESS_FREE
,
3411 FIELD_ARRAY(LTT_FIELD_PID
),
3412 process_free
, NULL
, &hooks
);
3414 lttv_trace_find_hook(ts
->parent
.t
,
3417 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3418 process_exec
, NULL
, &hooks
);
3420 lttv_trace_find_hook(ts
->parent
.t
,
3421 LTT_FACILITY_USER_GENERIC
,
3422 LTT_EVENT_THREAD_BRAND
,
3423 FIELD_ARRAY(LTT_FIELD_NAME
),
3424 thread_brand
, NULL
, &hooks
);
3426 /* statedump-related hooks */
3427 lttv_trace_find_hook(ts
->parent
.t
,
3429 LTT_EVENT_PROCESS_STATE
,
3430 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3431 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3432 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3433 enum_process_state
, NULL
, &hooks
);
3435 lttv_trace_find_hook(ts
->parent
.t
,
3437 LTT_EVENT_STATEDUMP_END
,
3439 statedump_end
, NULL
, &hooks
);
3441 lttv_trace_find_hook(ts
->parent
.t
,
3443 LTT_EVENT_LIST_INTERRUPT
,
3444 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3445 enum_interrupt
, NULL
, &hooks
);
3447 lttv_trace_find_hook(ts
->parent
.t
,
3449 LTT_EVENT_REQUEST_ISSUE
,
3450 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3451 bdev_request_issue
, NULL
, &hooks
);
3453 lttv_trace_find_hook(ts
->parent
.t
,
3455 LTT_EVENT_REQUEST_COMPLETE
,
3456 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3457 bdev_request_complete
, NULL
, &hooks
);
3459 lttv_trace_find_hook(ts
->parent
.t
,
3460 LTT_FACILITY_USER_GENERIC
,
3461 LTT_EVENT_FUNCTION_ENTRY
,
3462 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3463 function_entry
, NULL
, &hooks
);
3465 lttv_trace_find_hook(ts
->parent
.t
,
3466 LTT_FACILITY_USER_GENERIC
,
3467 LTT_EVENT_FUNCTION_EXIT
,
3468 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3469 function_exit
, NULL
, &hooks
);
3471 lttv_trace_find_hook(ts
->parent
.t
,
3472 LTT_FACILITY_STATEDUMP
,
3473 LTT_EVENT_SYS_CALL_TABLE
,
3474 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3475 dump_syscall
, NULL
, &hooks
);
3477 lttv_trace_find_hook(ts
->parent
.t
,
3478 LTT_FACILITY_STATEDUMP
,
3479 LTT_EVENT_SOFTIRQ_VEC
,
3480 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3481 dump_softirq
, NULL
, &hooks
);
3483 /* Add these hooks to each event_by_id hooks list */
3485 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3487 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3489 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3490 LttvTracefileContext
*, j
));
3492 for(k
= 0 ; k
< hooks
->len
; k
++) {
3493 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3495 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3501 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3502 *(val
.v_pointer
) = hooks
;
3506 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3508 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3510 lttv_state_remove_event_hooks(tss
);
3515 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3517 LttvTraceset
*traceset
= self
->parent
.ts
;
3519 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3523 LttvTracefileState
*tfs
;
3529 LttvAttributeValue val
;
3531 nb_trace
= lttv_traceset_number(traceset
);
3532 for(i
= 0 ; i
< nb_trace
; i
++) {
3533 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3535 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3536 hooks
= *(val
.v_pointer
);
3538 /* Remove these hooks from each event_by_id hooks list */
3540 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3542 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3544 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3545 LttvTracefileContext
*, j
));
3547 for(k
= 0 ; k
< hooks
->len
; k
++) {
3548 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3549 lttv_hooks_remove_data(
3550 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3555 lttv_trace_hook_remove_all(&hooks
);
3556 g_array_free(hooks
, TRUE
);
3560 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3562 guint
*event_count
= (guint
*)hook_data
;
3564 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3565 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3570 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3572 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3574 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3576 LttvAttributeValue value
;
3578 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3579 LTTV_STATE_SAVED_STATES
);
3580 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3581 value
= lttv_attribute_add(saved_states_tree
,
3582 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3583 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3584 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3585 *(value
.v_time
) = self
->parent
.timestamp
;
3586 lttv_state_save(tcs
, saved_state_tree
);
3587 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3588 self
->parent
.timestamp
.tv_nsec
);
3590 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3595 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3597 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3599 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3604 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3612 static gboolean
block_start(void *hook_data
, void *call_data
)
3614 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3616 LttvTracefileState
*tfcs
;
3618 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3620 LttEventPosition
*ep
;
3622 guint i
, nb_block
, nb_event
, nb_tracefile
;
3626 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3628 LttvAttributeValue value
;
3630 ep
= ltt_event_position_new();
3632 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3634 /* Count the number of events added since the last block end in any
3637 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3639 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3640 LttvTracefileContext
, i
));
3641 ltt_event_position(tfcs
->parent
.e
, ep
);
3642 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3643 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3644 tfcs
->saved_position
= nb_event
;
3648 if(tcs
->nb_event
>= tcs
->save_interval
) {
3649 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3650 LTTV_STATE_SAVED_STATES
);
3651 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3652 value
= lttv_attribute_add(saved_states_tree
,
3653 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3654 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3655 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3656 *(value
.v_time
) = self
->parent
.timestamp
;
3657 lttv_state_save(tcs
, saved_state_tree
);
3659 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3660 self
->parent
.timestamp
.tv_nsec
);
3662 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3668 static gboolean
block_end(void *hook_data
, void *call_data
)
3670 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3672 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3676 LttEventPosition
*ep
;
3678 guint nb_block
, nb_event
;
3680 ep
= ltt_event_position_new();
3681 ltt_event_position(self
->parent
.e
, ep
);
3682 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3683 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3684 self
->saved_position
= 0;
3685 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3692 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3694 LttvTraceset
*traceset
= self
->parent
.ts
;
3696 guint i
, j
, nb_trace
, nb_tracefile
;
3700 LttvTracefileState
*tfs
;
3702 LttvTraceHook hook_start
, hook_end
;
3704 nb_trace
= lttv_traceset_number(traceset
);
3705 for(i
= 0 ; i
< nb_trace
; i
++) {
3706 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3708 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3709 NULL
, NULL
, block_start
, &hook_start
);
3710 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3711 NULL
, NULL
, block_end
, &hook_end
);
3713 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3715 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3717 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3718 LttvTracefileContext
, j
));
3719 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3720 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3721 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3722 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3728 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3730 LttvTraceset
*traceset
= self
->parent
.ts
;
3732 guint i
, j
, nb_trace
, nb_tracefile
;
3736 LttvTracefileState
*tfs
;
3739 nb_trace
= lttv_traceset_number(traceset
);
3740 for(i
= 0 ; i
< nb_trace
; i
++) {
3742 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3743 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3745 if(ts
->has_precomputed_states
) continue;
3747 guint
*event_count
= g_new(guint
, 1);
3750 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3752 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3753 LttvTracefileContext
*, j
));
3754 lttv_hooks_add(tfs
->parent
.event
,
3755 state_save_event_hook
,
3762 lttv_process_traceset_begin(&self
->parent
,
3763 NULL
, NULL
, NULL
, NULL
, NULL
);
3767 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3769 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3771 lttv_state_save_add_event_hooks(tss
);
3778 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3780 LttvTraceset
*traceset
= self
->parent
.ts
;
3782 guint i
, j
, nb_trace
, nb_tracefile
;
3786 LttvTracefileState
*tfs
;
3788 LttvTraceHook hook_start
, hook_end
;
3790 nb_trace
= lttv_traceset_number(traceset
);
3791 for(i
= 0 ; i
< nb_trace
; i
++) {
3792 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3794 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3795 NULL
, NULL
, block_start
, &hook_start
);
3797 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3798 NULL
, NULL
, block_end
, &hook_end
);
3800 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3802 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3804 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3805 LttvTracefileContext
, j
));
3806 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3807 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3808 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3809 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3815 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3817 LttvTraceset
*traceset
= self
->parent
.ts
;
3819 guint i
, j
, nb_trace
, nb_tracefile
;
3823 LttvTracefileState
*tfs
;
3825 LttvHooks
*after_trace
= lttv_hooks_new();
3827 lttv_hooks_add(after_trace
,
3828 state_save_after_trace_hook
,
3833 lttv_process_traceset_end(&self
->parent
,
3834 NULL
, after_trace
, NULL
, NULL
, NULL
);
3836 lttv_hooks_destroy(after_trace
);
3838 nb_trace
= lttv_traceset_number(traceset
);
3839 for(i
= 0 ; i
< nb_trace
; i
++) {
3841 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3842 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3844 if(ts
->has_precomputed_states
) continue;
3846 guint
*event_count
= NULL
;
3848 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3850 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3851 LttvTracefileContext
*, j
));
3852 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3853 state_save_event_hook
);
3855 if(event_count
) g_free(event_count
);
3859 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3861 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3863 lttv_state_save_remove_event_hooks(tss
);
3868 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3870 LttvTraceset
*traceset
= self
->parent
.ts
;
3874 int min_pos
, mid_pos
, max_pos
;
3876 guint call_rest
= 0;
3878 LttvTraceState
*tcs
;
3880 LttvAttributeValue value
;
3882 LttvAttributeType type
;
3884 LttvAttributeName name
;
3888 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3890 //g_tree_destroy(self->parent.pqueue);
3891 //self->parent.pqueue = g_tree_new(compare_tracefile);
3893 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3895 nb_trace
= lttv_traceset_number(traceset
);
3896 for(i
= 0 ; i
< nb_trace
; i
++) {
3897 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3899 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3900 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3901 LTTV_STATE_SAVED_STATES
);
3904 if(saved_states_tree
) {
3905 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3906 mid_pos
= max_pos
/ 2;
3907 while(min_pos
< max_pos
) {
3908 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3910 g_assert(type
== LTTV_GOBJECT
);
3911 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3912 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3914 g_assert(type
== LTTV_TIME
);
3915 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3917 closest_tree
= saved_state_tree
;
3919 else max_pos
= mid_pos
- 1;
3921 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3925 /* restore the closest earlier saved state */
3927 lttv_state_restore(tcs
, closest_tree
);
3931 /* There is no saved state, yet we want to have it. Restart at T0 */
3933 restore_init_state(tcs
);
3934 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3937 /* We want to seek quickly without restoring/updating the state */
3939 restore_init_state(tcs
);
3940 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3943 if(!call_rest
) g_info("NOT Calling restore");
3948 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3954 traceset_state_finalize (LttvTracesetState
*self
)
3956 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3957 finalize(G_OBJECT(self
));
3962 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3964 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3966 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3967 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3968 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3969 klass
->new_traceset_context
= new_traceset_context
;
3970 klass
->new_trace_context
= new_trace_context
;
3971 klass
->new_tracefile_context
= new_tracefile_context
;
3976 lttv_traceset_state_get_type(void)
3978 static GType type
= 0;
3980 static const GTypeInfo info
= {
3981 sizeof (LttvTracesetStateClass
),
3982 NULL
, /* base_init */
3983 NULL
, /* base_finalize */
3984 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3985 NULL
, /* class_finalize */
3986 NULL
, /* class_data */
3987 sizeof (LttvTracesetState
),
3988 0, /* n_preallocs */
3989 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3990 NULL
/* value handling */
3993 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4001 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4007 trace_state_finalize (LttvTraceState
*self
)
4009 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4010 finalize(G_OBJECT(self
));
4015 trace_state_class_init (LttvTraceStateClass
*klass
)
4017 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4019 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4020 klass
->state_save
= state_save
;
4021 klass
->state_restore
= state_restore
;
4022 klass
->state_saved_free
= state_saved_free
;
4027 lttv_trace_state_get_type(void)
4029 static GType type
= 0;
4031 static const GTypeInfo info
= {
4032 sizeof (LttvTraceStateClass
),
4033 NULL
, /* base_init */
4034 NULL
, /* base_finalize */
4035 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4036 NULL
, /* class_finalize */
4037 NULL
, /* class_data */
4038 sizeof (LttvTraceState
),
4039 0, /* n_preallocs */
4040 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4041 NULL
/* value handling */
4044 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4045 "LttvTraceStateType", &info
, 0);
4052 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4058 tracefile_state_finalize (LttvTracefileState
*self
)
4060 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4061 finalize(G_OBJECT(self
));
4066 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4068 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4070 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4075 lttv_tracefile_state_get_type(void)
4077 static GType type
= 0;
4079 static const GTypeInfo info
= {
4080 sizeof (LttvTracefileStateClass
),
4081 NULL
, /* base_init */
4082 NULL
, /* base_finalize */
4083 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4084 NULL
, /* class_finalize */
4085 NULL
, /* class_data */
4086 sizeof (LttvTracefileState
),
4087 0, /* n_preallocs */
4088 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4089 NULL
/* value handling */
4092 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4093 "LttvTracefileStateType", &info
, 0);
4099 static void module_init()
4101 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4102 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4103 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4104 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4105 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4106 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4107 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4108 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4109 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4110 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4111 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4112 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4113 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4114 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4115 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4116 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4117 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4118 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4119 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4120 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4121 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4122 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4123 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4124 LTTV_STATE_EVENT
= g_quark_from_string("event");
4125 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4126 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4127 LTTV_STATE_TIME
= g_quark_from_string("time");
4128 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4129 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4130 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4131 g_quark_from_string("trace_state_use_count");
4132 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4133 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4134 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4135 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4136 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4137 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4140 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4141 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4142 LTT_FACILITY_FS
= g_quark_from_string("fs");
4143 LTT_FACILITY_LIST
= g_quark_from_string("list");
4144 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4145 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4146 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4148 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4149 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4150 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4151 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4152 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4153 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4154 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4155 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4156 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4157 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4158 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4159 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4160 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4161 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4162 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4163 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4164 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4165 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4166 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4167 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4168 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4169 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4170 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4171 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4173 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4174 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4175 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4176 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4177 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4178 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4179 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4180 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4181 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4182 LTT_FIELD_PID
= g_quark_from_string("pid");
4183 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4184 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4185 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4186 LTT_FIELD_NAME
= g_quark_from_string("name");
4187 LTT_FIELD_TYPE
= g_quark_from_string("type");
4188 LTT_FIELD_MODE
= g_quark_from_string("mode");
4189 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4190 LTT_FIELD_STATUS
= g_quark_from_string("status");
4191 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4192 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4193 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4194 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4195 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4196 LTT_FIELD_ACTION
= g_quark_from_string("action");
4197 LTT_FIELD_ID
= g_quark_from_string("id");
4198 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4199 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4201 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4202 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4203 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4204 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4205 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4206 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4208 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4209 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4210 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4212 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4213 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4214 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4215 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4218 static void module_destroy()
4223 LTTV_MODULE("state", "State computation", \
4224 "Update the system state, possibly saving it at intervals", \
4225 module_init
, module_destroy
)