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>
39 * usertrace is there only to be able to update the current CPU of the
40 * usertraces when there is a schedchange. it is a way to link the ProcessState
41 * to the associated usertrace. Link only created upon thread creation.
43 * The cpu id is necessary : it gives us back the current ProcessState when we
44 * are considering data from the usertrace.
47 #define PREALLOCATED_EXECUTION_STACK 10
53 LTT_CHANNEL_GLOBAL_STATE
,
54 LTT_CHANNEL_IRQ_STATE
,
55 LTT_CHANNEL_MODULE_STATE
,
56 LTT_CHANNEL_NETIF_STATE
,
57 LTT_CHANNEL_SOFTIRQ_STATE
,
58 LTT_CHANNEL_SWAP_STATE
,
59 LTT_CHANNEL_SYSCALL_STATE
,
60 LTT_CHANNEL_TASK_STATE
,
62 LTT_CHANNEL_KPROBE_STATE
,
66 LTT_CHANNEL_USERSPACE
,
72 LTT_EVENT_SYSCALL_ENTRY
,
73 LTT_EVENT_SYSCALL_EXIT
,
74 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
75 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
76 LTT_EVENT_PAGE_FAULT_ENTRY
,
77 LTT_EVENT_PAGE_FAULT_EXIT
,
82 LTT_EVENT_SOFT_IRQ_RAISE
,
83 LTT_EVENT_SOFT_IRQ_ENTRY
,
84 LTT_EVENT_SOFT_IRQ_EXIT
,
85 LTT_EVENT_SCHED_SCHEDULE
,
86 LTT_EVENT_SCHED_TRY_WAKEUP
,
87 LTT_EVENT_PROCESS_FORK
,
88 LTT_EVENT_KTHREAD_CREATE
,
89 LTT_EVENT_PROCESS_EXIT
,
90 LTT_EVENT_PROCESS_FREE
,
92 LTT_EVENT_PROCESS_STATE
,
93 LTT_EVENT_STATEDUMP_END
,
94 LTT_EVENT_FUNCTION_ENTRY
,
95 LTT_EVENT_FUNCTION_EXIT
,
96 LTT_EVENT_THREAD_BRAND
,
97 LTT_EVENT_REQUEST_ISSUE
,
98 LTT_EVENT_REQUEST_COMPLETE
,
99 LTT_EVENT_LIST_INTERRUPT
,
100 LTT_EVENT_SYS_CALL_TABLE
,
101 LTT_EVENT_SOFTIRQ_VEC
,
102 LTT_EVENT_KPROBE_TABLE
,
106 LTT_EVENT_POLL_EVENT
;
111 LTT_FIELD_SYSCALL_ID
,
114 LTT_FIELD_SOFT_IRQ_ID
,
117 LTT_FIELD_PREV_STATE
,
118 LTT_FIELD_PARENT_PID
,
122 LTT_FIELD_CHILD_TGID
,
144 LTTV_STATE_MODE_UNKNOWN
,
145 LTTV_STATE_USER_MODE
,
146 LTTV_STATE_MAYBE_USER_MODE
,
148 LTTV_STATE_MAYBE_SYSCALL
,
150 LTTV_STATE_MAYBE_TRAP
,
155 LTTV_STATE_SUBMODE_UNKNOWN
,
156 LTTV_STATE_SUBMODE_NONE
;
160 LTTV_STATE_WAIT_FORK
,
169 LTTV_STATE_UNBRANDED
;
172 LTTV_STATE_USER_THREAD
,
173 LTTV_STATE_KERNEL_THREAD
;
191 LTTV_BDEV_BUSY_READING
,
192 LTTV_BDEV_BUSY_WRITING
;
195 LTTV_STATE_TRACEFILES
,
196 LTTV_STATE_PROCESSES
,
198 LTTV_STATE_RUNNING_PROCESS
,
200 LTTV_STATE_SAVED_STATES
,
201 LTTV_STATE_SAVED_STATES_TIME
,
204 LTTV_STATE_NAME_TABLES
,
205 LTTV_STATE_TRACE_STATE_USE_COUNT
,
206 LTTV_STATE_RESOURCE_CPUS
,
207 LTTV_STATE_RESOURCE_CPUS_COUNT
,
208 LTTV_STATE_RESOURCE_IRQS
,
209 LTTV_STATE_RESOURCE_SOFT_IRQS
,
210 LTTV_STATE_RESOURCE_TRAPS
,
211 LTTV_STATE_RESOURCE_BLKDEVS
;
213 static void create_max_time(LttvTraceState
*tcs
);
215 static void get_max_time(LttvTraceState
*tcs
);
217 static void free_max_time(LttvTraceState
*tcs
);
219 static void create_name_tables(LttvTraceState
*tcs
);
221 static void get_name_tables(LttvTraceState
*tcs
);
223 static void free_name_tables(LttvTraceState
*tcs
);
225 static void free_saved_state(LttvTraceState
*tcs
);
227 static void lttv_state_free_process_table(GHashTable
*processes
);
229 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
230 GPtrArray
*quarktable
);
232 /* Resource function prototypes */
233 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
);
234 static LttvBdevState
*bdevstate_new(void);
235 static void bdevstate_free(LttvBdevState
*);
236 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
237 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
240 #if (__WORDSIZE == 32)
241 guint
guint64_hash(gconstpointer key
)
243 guint64 ukey
= *(const guint64
*)key
;
245 return (guint
)ukey
^ (guint
)(ukey
>> 32);
248 gboolean
guint64_equal(gconstpointer a
, gconstpointer b
)
250 guint64 ua
= *(const guint64
*)a
;
251 guint64 ub
= *(const guint64
*)b
;
257 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
259 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
263 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
265 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
269 void lttv_state_state_saved_free(LttvTraceState
*self
,
270 LttvAttribute
*container
)
272 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
276 guint
process_hash(gconstpointer key
)
278 guint pid
= ((const LttvProcessState
*)key
)->pid
;
279 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
283 /* If the hash table hash function is well distributed,
284 * the process_equal should compare different pid */
285 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
287 const LttvProcessState
*process_a
, *process_b
;
290 process_a
= (const LttvProcessState
*)a
;
291 process_b
= (const LttvProcessState
*)b
;
293 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
294 else if(likely(process_a
->pid
== 0 &&
295 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
300 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
302 g_tree_destroy((GTree
*)value
);
305 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
307 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
308 g_hash_table_destroy(usertraces
);
311 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
316 static guint
check_expand(nb
, id
)
321 return max(id
+ 1, nb
* 2);
324 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
325 guint nb
, guint new_nb
)
327 /* Expand an incomplete table */
328 GQuark
*old_table
= *table
;
329 *table
= g_new(GQuark
, new_nb
);
330 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
334 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
335 guint new_nb
, const char *def_string
)
338 GString
*fe_name
= g_string_new("");
339 for(i
= nb
; i
< new_nb
; i
++) {
340 g_string_printf(fe_name
, "%s %d", def_string
, i
);
341 table
[i
] = g_quark_from_string(fe_name
->str
);
343 g_string_free(fe_name
, TRUE
);
346 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
348 LttvNameTables
*nt
= ts
->name_tables
;
351 new_nb
= check_expand(nt
->nb_syscalls
, id
);
352 if(likely(new_nb
== nt
->nb_syscalls
))
354 expand_name_table(ts
, &nt
->syscall_names
, nt
->nb_syscalls
, new_nb
);
355 fill_name_table(ts
, nt
->syscall_names
, nt
->nb_syscalls
, new_nb
, "syscall");
356 /* Update the table size */
357 nt
->nb_syscalls
= new_nb
;
360 static void expand_kprobe_table(LttvTraceState
*ts
, guint64 ip
, char *symbol
)
362 LttvNameTables
*nt
= ts
->name_tables
;
363 #if (__WORDSIZE == 32)
364 guint64
*ip_ptr
= g_new(guint64
, 1);
365 g_hash_table_insert(nt
->kprobe_hash
, ip_ptr
,
366 (gpointer
)(glong
)g_quark_from_string(symbol
));
368 g_hash_table_insert(nt
->kprobe_hash
, (gpointer
)ip
,
369 (gpointer
)(glong
)g_quark_from_string(symbol
));
373 static void expand_trap_table(LttvTraceState
*ts
, int id
)
375 LttvNameTables
*nt
= ts
->name_tables
;
376 LttvTrapState
*old_table
;
379 new_nb
= check_expand(nt
->nb_traps
, id
);
380 if(likely(new_nb
== nt
->nb_traps
))
383 expand_name_table(ts
, &nt
->trap_names
, nt
->nb_traps
, new_nb
);
384 fill_name_table(ts
, nt
->trap_names
, nt
->nb_traps
, new_nb
, "trap");
386 old_table
= ts
->trap_states
;
387 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
388 memcpy(ts
->trap_states
, old_table
, nt
->nb_traps
* sizeof(LttvTrapState
));
390 for(i
= nt
->nb_traps
; i
< new_nb
; i
++)
391 ts
->trap_states
[i
].running
= 0;
393 /* Update the table size */
394 nt
->nb_traps
= new_nb
;
397 static void expand_irq_table(LttvTraceState
*ts
, int id
)
399 LttvNameTables
*nt
= ts
->name_tables
;
400 LttvIRQState
*old_table
;
403 new_nb
= check_expand(nt
->nb_irqs
, id
);
404 if(likely(new_nb
== nt
->nb_irqs
))
407 expand_name_table(ts
, &nt
->irq_names
, nt
->nb_irqs
, new_nb
);
408 fill_name_table(ts
, nt
->irq_names
, nt
->nb_irqs
, new_nb
, "irq");
410 old_table
= ts
->irq_states
;
411 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
412 memcpy(ts
->irq_states
, old_table
, nt
->nb_irqs
* sizeof(LttvIRQState
));
414 for(i
= nt
->nb_irqs
; i
< new_nb
; i
++)
415 ts
->irq_states
[i
].mode_stack
=
416 g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
418 /* Update the table size */
419 nt
->nb_irqs
= new_nb
;
422 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
424 LttvNameTables
*nt
= ts
->name_tables
;
425 LttvSoftIRQState
*old_table
;
428 new_nb
= check_expand(nt
->nb_soft_irqs
, id
);
429 if(likely(new_nb
== nt
->nb_soft_irqs
))
432 expand_name_table(ts
, &nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
);
433 fill_name_table(ts
, nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
, "softirq");
435 old_table
= ts
->soft_irq_states
;
436 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
437 memcpy(ts
->soft_irq_states
, old_table
,
438 nt
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
440 for(i
= nt
->nb_soft_irqs
; i
< new_nb
; i
++)
441 ts
->soft_irq_states
[i
].running
= 0;
443 /* Update the table size */
444 nt
->nb_soft_irqs
= new_nb
;
447 static void restore_init_state(LttvTraceState
*self
)
449 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
451 //LttvTracefileState *tfcs;
453 LttTime start_time
, end_time
;
455 /* Free the process tables */
456 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
457 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
458 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
459 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
462 /* Seek time to beginning */
463 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
464 // closest. It's the tracecontext job to seek the trace to the beginning
465 // anyway : the init state might be used at the middle of the trace as well...
466 //g_tree_destroy(self->parent.ts_context->pqueue);
467 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
469 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
471 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
473 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
474 nb_irqs
= self
->name_tables
->nb_irqs
;
475 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
476 nb_traps
= self
->name_tables
->nb_traps
;
478 /* Put the per cpu running_process to beginning state : process 0. */
479 for(i
=0; i
< nb_cpus
; i
++) {
480 LttvExecutionState
*es
;
481 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
482 LTTV_STATE_UNNAMED
, &start_time
);
483 /* We are not sure is it's a kernel thread or normal thread, put the
484 * bottom stack state to unknown */
485 self
->running_process
[i
]->execution_stack
=
486 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
487 es
= self
->running_process
[i
]->state
=
488 &g_array_index(self
->running_process
[i
]->execution_stack
,
489 LttvExecutionState
, 0);
490 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
491 es
->s
= LTTV_STATE_UNNAMED
;
493 //self->running_process[i]->state->s = LTTV_STATE_RUN;
494 self
->running_process
[i
]->cpu
= i
;
496 /* reset cpu states */
497 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
498 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0,
499 self
->cpu_states
[i
].mode_stack
->len
);
500 if(self
->cpu_states
[i
].irq_stack
->len
)
501 g_array_remove_range(self
->cpu_states
[i
].irq_stack
, 0,
502 self
->cpu_states
[i
].irq_stack
->len
);
503 if(self
->cpu_states
[i
].softirq_stack
->len
)
504 g_array_remove_range(self
->cpu_states
[i
].softirq_stack
, 0,
505 self
->cpu_states
[i
].softirq_stack
->len
);
506 if(self
->cpu_states
[i
].trap_stack
->len
)
507 g_array_remove_range(self
->cpu_states
[i
].trap_stack
, 0,
508 self
->cpu_states
[i
].trap_stack
->len
);
512 /* reset irq states */
513 for(i
=0; i
<nb_irqs
; i
++) {
514 if(self
->irq_states
[i
].mode_stack
->len
> 0)
515 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0,
516 self
->irq_states
[i
].mode_stack
->len
);
519 /* reset softirq states */
520 for(i
=0; i
<nb_soft_irqs
; i
++) {
521 self
->soft_irq_states
[i
].pending
= 0;
522 self
->soft_irq_states
[i
].running
= 0;
525 /* reset trap states */
526 for(i
=0; i
<nb_traps
; i
++) {
527 self
->trap_states
[i
].running
= 0;
530 /* reset bdev states */
531 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
532 //g_hash_table_steal_all(self->bdev_states);
533 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
536 nb_tracefile
= self
->parent
.tracefiles
->len
;
538 for(i
= 0 ; i
< nb_tracefile
; i
++) {
540 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
541 LttvTracefileContext
*, i
));
542 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
543 // tfcs->saved_position = 0;
544 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
545 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
546 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
547 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
552 //static LttTime time_zero = {0,0};
554 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
557 const LttTime
*t1
= (const LttTime
*)a
;
558 const LttTime
*t2
= (const LttTime
*)b
;
560 return ltt_time_compare(*t1
, *t2
);
563 static void free_usertrace_key(gpointer data
)
568 #define MAX_STRING_LEN 4096
570 static void state_load_saved_states(LttvTraceState
*tcs
)
573 GPtrArray
*quarktable
;
574 const char *trace_path
;
578 tcs
->has_precomputed_states
= FALSE
;
582 gchar buf
[MAX_STRING_LEN
];
586 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
587 strncpy(path
, trace_path
, PATH_MAX
-1);
588 count
= strnlen(trace_path
, PATH_MAX
-1);
589 // quarktable : open, test
590 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
591 fp
= fopen(path
, "r");
593 quarktable
= g_ptr_array_sized_new(4096);
595 /* Index 0 is null */
597 if(hdr
== EOF
) return;
598 g_assert(hdr
== HDR_QUARKS
);
602 if(hdr
== EOF
) break;
603 g_assert(hdr
== HDR_QUARK
);
604 g_ptr_array_set_size(quarktable
, q
+1);
607 res
= fread(&buf
[i
], sizeof(gchar
), 1, fp
);
609 if(buf
[i
] == '\0' || feof(fp
)) break;
612 len
= strnlen(buf
, MAX_STRING_LEN
-1);
613 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
614 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
620 // saved_states : open, test
621 strncpy(path
, trace_path
, PATH_MAX
-1);
622 count
= strnlen(trace_path
, PATH_MAX
-1);
623 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
624 fp
= fopen(path
, "r");
628 if(hdr
!= HDR_TRACE
) goto end
;
630 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
632 tcs
->has_precomputed_states
= TRUE
;
637 /* Free the quarktable */
638 for(i
=0; i
<quarktable
->len
; i
++) {
639 string
= g_ptr_array_index (quarktable
, i
);
642 g_ptr_array_free(quarktable
, TRUE
);
646 static void init(LttvTracesetState
*self
, LttvTraceset
*ts
)
648 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
651 LttvTraceContext
*tc
;
655 LttvTracefileState
*tfcs
;
657 LttvAttributeValue v
;
659 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
660 init((LttvTracesetContext
*)self
, ts
);
662 nb_trace
= lttv_traceset_number(ts
);
663 for(i
= 0 ; i
< nb_trace
; i
++) {
664 tc
= self
->parent
.traces
[i
];
665 tcs
= LTTV_TRACE_STATE(tc
);
666 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
667 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
671 if(*(v
.v_uint
) == 1) {
672 create_name_tables(tcs
);
673 create_max_time(tcs
);
675 get_name_tables(tcs
);
678 nb_tracefile
= tc
->tracefiles
->len
;
679 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
680 nb_irq
= tcs
->name_tables
->nb_irqs
;
681 tcs
->processes
= NULL
;
682 tcs
->usertraces
= NULL
;
683 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
685 /* init cpu resource stuff */
686 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
687 for(j
= 0; j
<nb_cpu
; j
++) {
688 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
689 tcs
->cpu_states
[j
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
690 tcs
->cpu_states
[j
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
691 tcs
->cpu_states
[j
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
692 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
695 /* init irq resource stuff */
696 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
697 for(j
= 0; j
<nb_irq
; j
++) {
698 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
699 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
702 /* init soft irq stuff */
703 /* the kernel has a statically fixed max of 32 softirqs */
704 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->name_tables
->nb_soft_irqs
);
706 /* init trap stuff */
707 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->name_tables
->nb_traps
);
709 /* init bdev resource stuff */
710 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
712 restore_init_state(tcs
);
713 for(j
= 0 ; j
< nb_tracefile
; j
++) {
715 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
716 LttvTracefileContext
*, j
));
717 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
718 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
719 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
720 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
721 /* It's a Usertrace */
722 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
723 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
724 GUINT_TO_POINTER(tid
));
725 if(!usertrace_tree
) {
726 usertrace_tree
= g_tree_new_full(compare_usertraces
,
727 NULL
, free_usertrace_key
, NULL
);
728 g_hash_table_insert(tcs
->usertraces
,
729 GUINT_TO_POINTER(tid
), usertrace_tree
);
731 LttTime
*timestamp
= g_new(LttTime
, 1);
732 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
733 ltt_tracefile_creation(tfcs
->parent
.tf
));
734 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
738 /* See if the trace has saved states */
739 state_load_saved_states(tcs
);
743 static void fini(LttvTracesetState
*self
)
749 //LttvTracefileState *tfcs;
751 LttvAttributeValue v
;
753 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
754 for(i
= 0 ; i
< nb_trace
; i
++) {
755 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
756 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
759 g_assert(*(v
.v_uint
) != 0);
762 if(*(v
.v_uint
) == 0) {
763 free_name_tables(tcs
);
765 free_saved_state(tcs
);
767 g_free(tcs
->running_process
);
768 tcs
->running_process
= NULL
;
769 lttv_state_free_process_table(tcs
->processes
);
770 lttv_state_free_usertraces(tcs
->usertraces
);
771 tcs
->processes
= NULL
;
772 tcs
->usertraces
= NULL
;
774 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
775 fini((LttvTracesetContext
*)self
);
779 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
781 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
785 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
787 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
791 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
793 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
797 /* Write the process state of the trace */
799 static void write_process_state(gpointer key
, gpointer value
,
802 LttvProcessState
*process
;
804 LttvExecutionState
*es
;
806 FILE *fp
= (FILE *)user_data
;
811 process
= (LttvProcessState
*)value
;
812 fprintf(fp
," <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",
813 process
, process
->pid
, process
->tgid
, process
->ppid
,
814 g_quark_to_string(process
->type
),
815 process
->creation_time
.tv_sec
,
816 process
->creation_time
.tv_nsec
,
817 process
->insertion_time
.tv_sec
,
818 process
->insertion_time
.tv_nsec
,
819 g_quark_to_string(process
->name
),
820 g_quark_to_string(process
->brand
),
821 process
->cpu
, process
->free_events
);
823 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
824 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
825 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
826 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
827 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
828 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
829 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
832 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
833 address
= g_array_index(process
->user_stack
, guint64
, i
);
834 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n", address
);
837 if(process
->usertrace
) {
838 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
839 g_quark_to_string(process
->usertrace
->tracefile_name
),
840 process
->usertrace
->cpu
);
844 fprintf(fp
, " </PROCESS>\n");
848 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
850 guint i
, nb_tracefile
, nb_block
, offset
;
853 LttvTracefileState
*tfcs
;
857 LttEventPosition
*ep
;
861 ep
= ltt_event_position_new();
863 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
865 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
867 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
868 for(i
=0;i
<nb_cpus
;i
++) {
869 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
870 i
, self
->running_process
[i
]->pid
);
873 nb_tracefile
= self
->parent
.tracefiles
->len
;
875 for(i
= 0 ; i
< nb_tracefile
; i
++) {
877 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
878 LttvTracefileContext
*, i
));
879 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
880 tfcs
->parent
.timestamp
.tv_sec
,
881 tfcs
->parent
.timestamp
.tv_nsec
);
882 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
883 if(e
== NULL
) fprintf(fp
,"/>\n");
885 ltt_event_position(e
, ep
);
886 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
887 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
892 fprintf(fp
,"</PROCESS_STATE>\n");
896 static void write_process_state_raw(gpointer key
, gpointer value
,
899 LttvProcessState
*process
;
901 LttvExecutionState
*es
;
903 FILE *fp
= (FILE *)user_data
;
908 process
= (LttvProcessState
*)value
;
909 fputc(HDR_PROCESS
, fp
);
910 //fwrite(&header, sizeof(header), 1, fp);
911 //fprintf(fp, "%s", g_quark_to_string(process->type));
913 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
914 //fprintf(fp, "%s", g_quark_to_string(process->name));
916 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
917 //fprintf(fp, "%s", g_quark_to_string(process->brand));
919 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
920 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
921 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
922 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
923 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
924 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
925 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
926 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
929 fprintf(fp
," <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",
930 process
, process
->pid
, process
->tgid
, process
->ppid
,
931 g_quark_to_string(process
->type
),
932 process
->creation_time
.tv_sec
,
933 process
->creation_time
.tv_nsec
,
934 process
->insertion_time
.tv_sec
,
935 process
->insertion_time
.tv_nsec
,
936 g_quark_to_string(process
->name
),
937 g_quark_to_string(process
->brand
),
941 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
942 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
945 //fprintf(fp, "%s", g_quark_to_string(es->t));
947 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
948 //fprintf(fp, "%s", g_quark_to_string(es->n));
950 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
951 //fprintf(fp, "%s", g_quark_to_string(es->s));
953 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
954 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
955 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
956 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
958 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
959 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
960 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
961 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
962 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
966 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
967 address
= g_array_index(process
->user_stack
, guint64
, i
);
968 fputc(HDR_USER_STACK
, fp
);
969 fwrite(&address
, sizeof(address
), 1, fp
);
971 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n", address
);
975 if(process
->usertrace
) {
976 fputc(HDR_USERTRACE
, fp
);
977 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
979 fwrite(&process
->usertrace
->tracefile_name
,
980 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
981 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
983 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
984 g_quark_to_string(process
->usertrace
->tracefile_name
),
985 process
->usertrace
->cpu
);
992 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
994 guint i
, nb_tracefile
, nb_block
, offset
;
997 LttvTracefileState
*tfcs
;
1001 LttEventPosition
*ep
;
1005 ep
= ltt_event_position_new();
1007 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1008 fputc(HDR_PROCESS_STATE
, fp
);
1009 fwrite(&t
, sizeof(t
), 1, fp
);
1011 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
1013 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1014 for(i
=0;i
<nb_cpus
;i
++) {
1016 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
1017 fwrite(&self
->running_process
[i
]->pid
,
1018 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1019 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1020 // i, self->running_process[i]->pid);
1023 nb_tracefile
= self
->parent
.tracefiles
->len
;
1025 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1027 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1028 LttvTracefileContext
*, i
));
1029 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1030 // tfcs->parent.timestamp.tv_sec,
1031 // tfcs->parent.timestamp.tv_nsec);
1032 fputc(HDR_TRACEFILE
, fp
);
1033 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1034 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1035 * position following : end of trace */
1036 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1038 ltt_event_position(e
, ep
);
1039 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1040 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1042 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
1043 fwrite(&offset
, sizeof(offset
), 1, fp
);
1044 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
1051 /* Read process state from a file */
1053 /* Called because a HDR_PROCESS was found */
1054 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
1055 GPtrArray
*quarktable
)
1057 LttvExecutionState
*es
;
1058 LttvProcessState
*process
, *parent_process
;
1059 LttvProcessState tmp
;
1065 res
= fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1066 res
+= fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1067 res
+= fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1068 res
+= fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1069 res
+= fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1070 res
+= fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1071 res
+= fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1072 res
+= fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1073 res
+= fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1074 res
+= fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1075 g_assert(res
== 10);
1078 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1080 /* We must link to the parent */
1081 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1083 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1084 if(process
== NULL
) {
1085 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1087 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1088 &tmp
.creation_time
);
1091 process
->insertion_time
= tmp
.insertion_time
;
1092 process
->creation_time
= tmp
.creation_time
;
1093 process
->type
= g_quark_from_string(
1094 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1095 process
->tgid
= tmp
.tgid
;
1096 process
->ppid
= tmp
.ppid
;
1097 process
->brand
= g_quark_from_string(
1098 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1100 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1101 process
->free_events
= tmp
.free_events
;
1104 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1106 gint hdr
= fgetc(fp
);
1107 if(hdr
== EOF
) goto end_loop
;
1111 process
->execution_stack
=
1112 g_array_set_size(process
->execution_stack
,
1113 process
->execution_stack
->len
+ 1);
1114 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1115 process
->execution_stack
->len
-1);
1116 process
->state
= es
;
1118 res
= fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1120 es
->t
= g_quark_from_string(
1121 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1122 res
= fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1124 es
->n
= g_quark_from_string(
1125 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1126 res
= fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1128 es
->s
= g_quark_from_string(
1129 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1130 res
= fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1131 res
+= fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1132 res
+= fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1136 case HDR_USER_STACK
:
1137 process
->user_stack
= g_array_set_size(process
->user_stack
,
1138 process
->user_stack
->len
+ 1);
1139 address
= &g_array_index(process
->user_stack
, guint64
,
1140 process
->user_stack
->len
-1);
1141 res
= fread(address
, sizeof(address
), 1, fp
);
1143 process
->current_function
= *address
;
1147 res
= fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1148 res
+= fread(&process
->usertrace
->cpu
,
1149 sizeof(process
->usertrace
->cpu
), 1, fp
);
1163 /* Called because a HDR_PROCESS_STATE was found */
1164 /* Append a saved state to the trace states */
1165 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1167 guint i
, nb_tracefile
, nb_block
, offset
;
1169 LttvTracefileState
*tfcs
;
1171 LttEventPosition
*ep
;
1180 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1182 LttvAttributeValue value
;
1183 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1184 ep
= ltt_event_position_new();
1186 restore_init_state(self
);
1188 res
= fread(&t
, sizeof(t
), 1, fp
);
1192 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1194 if(hdr
== EOF
) goto end_loop
;
1198 /* Call read_process_state_raw */
1199 read_process_state_raw(self
, fp
, quarktable
);
1207 case HDR_USER_STACK
:
1209 case HDR_PROCESS_STATE
:
1215 g_error("Error while parsing saved state file : unknown data header %d",
1221 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1222 for(i
=0;i
<nb_cpus
;i
++) {
1225 g_assert(hdr
== HDR_CPU
);
1226 res
= fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1228 g_assert(i
== cpu_num
);
1229 res
= fread(&self
->running_process
[i
]->pid
,
1230 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1234 nb_tracefile
= self
->parent
.tracefiles
->len
;
1236 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1238 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1239 LttvTracefileContext
*, i
));
1240 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1241 // tfcs->parent.timestamp.tv_sec,
1242 // tfcs->parent.timestamp.tv_nsec);
1243 g_tree_remove(pqueue
, &tfcs
->parent
);
1245 g_assert(hdr
== HDR_TRACEFILE
);
1246 res
= fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1248 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1249 * position following : end of trace */
1250 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1251 res
= fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1252 res
+= fread(&offset
, sizeof(offset
), 1, fp
);
1253 res
+= fread(&tsc
, sizeof(tsc
), 1, fp
);
1255 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1256 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1258 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1263 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1264 LTTV_STATE_SAVED_STATES
);
1265 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1266 value
= lttv_attribute_add(saved_states_tree
,
1267 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1268 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1269 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1270 *(value
.v_time
) = t
;
1271 lttv_state_save(self
, saved_state_tree
);
1272 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1275 *(self
->max_time_state_recomputed_in_seek
) = t
;
1279 /* Called when a HDR_TRACE is found */
1280 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1281 GPtrArray
*quarktable
)
1286 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1288 if(hdr
== EOF
) goto end_loop
;
1291 case HDR_PROCESS_STATE
:
1292 /* Call read_process_state_raw */
1293 lttv_state_read_raw(tcs
, fp
, quarktable
);
1301 case HDR_USER_STACK
:
1305 g_error("Error while parsing saved state file :"
1306 " unexpected data header %d",
1310 g_error("Error while parsing saved state file : unknown data header %d",
1315 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1316 restore_init_state(tcs
);
1317 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1323 /* Copy each process from an existing hash table to a new one */
1325 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1327 LttvProcessState
*process
, *new_process
;
1329 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1333 process
= (LttvProcessState
*)value
;
1334 new_process
= g_new(LttvProcessState
, 1);
1335 *new_process
= *process
;
1336 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1337 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1338 new_process
->execution_stack
=
1339 g_array_set_size(new_process
->execution_stack
,
1340 process
->execution_stack
->len
);
1341 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1342 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1343 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1345 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1346 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1347 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1348 sizeof(guint64
), 0);
1349 new_process
->user_stack
= g_array_set_size(new_process
->user_stack
,
1350 process
->user_stack
->len
);
1351 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1352 g_array_index(new_process
->user_stack
, guint64
, i
) =
1353 g_array_index(process
->user_stack
, guint64
, i
);
1355 new_process
->current_function
= process
->current_function
;
1357 /* fd hash table stuff */
1363 /* copy every item in the hash table */
1364 new_process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1366 g_hash_table_iter_init(&it
, process
->fds
);
1367 while (g_hash_table_iter_next (&it
, (void *)&key
, (void *)&value
)) {
1368 g_hash_table_insert(new_process
->fds
, key
, value
);
1372 /* When done creating the new process state, insert it in the
1374 g_hash_table_insert(new_processes
, new_process
, new_process
);
1378 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1380 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1382 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1383 return new_processes
;
1386 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1389 LttvCPUState
*retval
;
1391 retval
= g_new(LttvCPUState
, n
);
1393 for(i
=0; i
<n
; i
++) {
1394 retval
[i
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1395 g_array_set_size(retval
[i
].irq_stack
, states
[i
].irq_stack
->len
);
1396 for(j
=0; j
<states
[i
].irq_stack
->len
; j
++) {
1397 g_array_index(retval
[i
].irq_stack
, gint
, j
) =
1398 g_array_index(states
[i
].irq_stack
, gint
, j
);
1401 retval
[i
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1402 g_array_set_size(retval
[i
].softirq_stack
, states
[i
].softirq_stack
->len
);
1403 for(j
=0; j
<states
[i
].softirq_stack
->len
; j
++) {
1404 g_array_index(retval
[i
].softirq_stack
, gint
, j
) =
1405 g_array_index(states
[i
].softirq_stack
, gint
, j
);
1408 retval
[i
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1409 g_array_set_size(retval
[i
].trap_stack
, states
[i
].trap_stack
->len
);
1410 for(j
=0; j
<states
[i
].trap_stack
->len
; j
++) {
1411 g_array_index(retval
[i
].trap_stack
, gint
, j
) =
1412 g_array_index(states
[i
].trap_stack
, gint
, j
);
1415 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1416 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1417 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1418 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1419 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1426 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1430 for(i
=0; i
<n
; i
++) {
1431 g_array_free(states
[i
].mode_stack
, TRUE
);
1432 g_array_free(states
[i
].irq_stack
, TRUE
);
1433 g_array_free(states
[i
].softirq_stack
, TRUE
);
1434 g_array_free(states
[i
].trap_stack
, TRUE
);
1440 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1443 LttvIRQState
*retval
;
1445 retval
= g_new(LttvIRQState
, n
);
1447 for(i
=0; i
<n
; i
++) {
1448 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1449 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1450 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1451 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1452 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1459 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1463 for(i
=0; i
<n
; i
++) {
1464 g_array_free(states
[i
].mode_stack
, TRUE
);
1470 static LttvSoftIRQState
*
1471 lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1474 LttvSoftIRQState
*retval
;
1476 retval
= g_new(LttvSoftIRQState
, n
);
1478 for(i
=0; i
<n
; i
++) {
1479 retval
[i
].pending
= states
[i
].pending
;
1480 retval
[i
].running
= states
[i
].running
;
1486 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1491 static LttvTrapState
*
1492 lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1495 LttvTrapState
*retval
;
1497 retval
= g_new(LttvTrapState
, n
);
1499 for(i
=0; i
<n
; i
++) {
1500 retval
[i
].running
= states
[i
].running
;
1506 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1511 /* bdevstate stuff */
1513 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
)
1515 gint devcode_gint
= devcode
;
1516 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1518 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1519 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1521 gint
* key
= g_new(gint
, 1);
1523 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1531 static LttvBdevState
*bdevstate_new(void)
1533 LttvBdevState
*retval
;
1534 retval
= g_new(LttvBdevState
, 1);
1535 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1540 static void bdevstate_free(LttvBdevState
*bds
)
1542 g_array_free(bds
->mode_stack
, TRUE
);
1546 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1548 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1550 bdevstate_free(bds
);
1553 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1555 LttvBdevState
*retval
;
1557 retval
= bdevstate_new();
1558 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
,
1559 bds
->mode_stack
->len
);
1564 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1566 //GHashTable *ht = (GHashTable *)u;
1567 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1568 LttvBdevState
*newbds
;
1570 newbds
= bdevstate_copy(bds
);
1572 g_hash_table_insert(u
, k
, newbds
);
1575 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1579 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1581 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1586 /* Free a hashtable and the LttvBdevState structures its values
1589 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1591 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1592 g_hash_table_destroy(ht
);
1595 /* The saved state for each trace contains a member "processes", which
1596 stores a copy of the process table, and a member "tracefiles" with
1597 one entry per tracefile. Each tracefile has a "process" member pointing
1598 to the current process and a "position" member storing the tracefile
1599 position (needed to seek to the current "next" event. */
1601 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1603 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1605 LttvTracefileState
*tfcs
;
1607 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1609 guint
*running_process
;
1611 LttvAttributeValue value
;
1613 LttEventPosition
*ep
;
1615 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1616 LTTV_STATE_TRACEFILES
);
1618 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1620 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1622 /* Add the currently running processes array */
1623 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1624 running_process
= g_new(guint
, nb_cpus
);
1625 for(i
=0;i
<nb_cpus
;i
++) {
1626 running_process
[i
] = self
->running_process
[i
]->pid
;
1628 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1630 *(value
.v_pointer
) = running_process
;
1632 g_info("State save");
1634 nb_tracefile
= self
->parent
.tracefiles
->len
;
1636 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1638 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1639 LttvTracefileContext
*, i
));
1640 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1641 value
= lttv_attribute_add(tracefiles_tree
, i
,
1643 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1645 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1647 *(value
.v_uint
) = tfcs
->process
->pid
;
1649 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1651 /* Only save the position if the tfs has not infinite time. */
1652 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1653 // && current_tfcs != tfcs) {
1654 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1655 *(value
.v_pointer
) = NULL
;
1657 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1658 ep
= ltt_event_position_new();
1659 ltt_event_position(e
, ep
);
1660 *(value
.v_pointer
) = ep
;
1662 guint nb_block
, offset
;
1665 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1666 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
,
1667 offset
, tsc
, tfcs
->parent
.timestamp
.tv_sec
,
1668 tfcs
->parent
.timestamp
.tv_nsec
);
1672 /* save the cpu state */
1674 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1676 *(value
.v_uint
) = nb_cpus
;
1678 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1680 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1683 /* save the irq state */
1684 nb_irqs
= self
->name_tables
->nb_irqs
;
1686 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1688 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1691 /* save the soft irq state */
1692 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1694 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1696 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1699 /* save the trap state */
1700 nb_traps
= self
->name_tables
->nb_traps
;
1702 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1704 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1707 /* save the blkdev states */
1708 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1710 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1714 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1716 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1718 LttvTracefileState
*tfcs
;
1720 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1722 guint
*running_process
;
1724 LttvAttributeType type
;
1726 LttvAttributeValue value
;
1728 LttvAttributeName name
;
1732 LttEventPosition
*ep
;
1734 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1737 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1738 LTTV_STATE_TRACEFILES
);
1740 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1742 g_assert(type
== LTTV_POINTER
);
1743 lttv_state_free_process_table(self
->processes
);
1744 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1746 /* Add the currently running processes array */
1747 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1748 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1750 g_assert(type
== LTTV_POINTER
);
1751 running_process
= *(value
.v_pointer
);
1752 for(i
=0;i
<nb_cpus
;i
++) {
1753 pid
= running_process
[i
];
1754 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1755 g_assert(self
->running_process
[i
] != NULL
);
1758 nb_tracefile
= self
->parent
.tracefiles
->len
;
1760 //g_tree_destroy(tsc->pqueue);
1761 //tsc->pqueue = g_tree_new(compare_tracefile);
1763 /* restore cpu resource states */
1764 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1765 g_assert(type
== LTTV_POINTER
);
1766 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1767 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1769 /* restore irq resource states */
1770 nb_irqs
= self
->name_tables
->nb_irqs
;
1771 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1772 g_assert(type
== LTTV_POINTER
);
1773 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1774 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1776 /* restore soft irq resource states */
1777 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1778 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1779 g_assert(type
== LTTV_POINTER
);
1780 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1781 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1783 /* restore trap resource states */
1784 nb_traps
= self
->name_tables
->nb_traps
;
1785 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1786 g_assert(type
== LTTV_POINTER
);
1787 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1788 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1790 /* restore the blkdev states */
1791 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1792 g_assert(type
== LTTV_POINTER
);
1793 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1794 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1796 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1798 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1799 LttvTracefileContext
*, i
));
1800 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1801 g_assert(type
== LTTV_GOBJECT
);
1802 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1804 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1806 g_assert(type
== LTTV_UINT
);
1807 pid
= *(value
.v_uint
);
1808 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1810 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1812 g_assert(type
== LTTV_POINTER
);
1813 //g_assert(*(value.v_pointer) != NULL);
1814 ep
= *(value
.v_pointer
);
1815 g_assert(tfcs
->parent
.t_context
!= NULL
);
1817 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1819 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1820 g_tree_remove(tsc
->pqueue
, tfc
);
1823 retval
= ltt_tracefile_seek_position(tfc
->tf
, ep
);
1824 g_assert_cmpint(retval
, ==, 0);
1825 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1826 g_assert_cmpint(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
),
1828 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1829 g_info("Restoring state for a tf at time %lu.%lu",
1830 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1832 tfc
->timestamp
= ltt_time_infinite
;
1838 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1840 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1842 LttvTracefileState
*tfcs
;
1844 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1846 guint
*running_process
;
1848 LttvAttributeType type
;
1850 LttvAttributeValue value
;
1852 LttvAttributeName name
;
1856 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1857 LTTV_STATE_TRACEFILES
);
1858 g_object_ref(G_OBJECT(tracefiles_tree
));
1859 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1861 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1863 g_assert(type
== LTTV_POINTER
);
1864 lttv_state_free_process_table(*(value
.v_pointer
));
1865 *(value
.v_pointer
) = NULL
;
1866 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1868 /* Free running processes array */
1869 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1871 g_assert(type
== LTTV_POINTER
);
1872 running_process
= *(value
.v_pointer
);
1873 g_free(running_process
);
1875 /* free cpu resource states */
1876 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1877 g_assert(type
== LTTV_UINT
);
1878 nb_cpus
= *value
.v_uint
;
1879 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1880 g_assert(type
== LTTV_POINTER
);
1881 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1883 /* free irq resource states */
1884 nb_irqs
= self
->name_tables
->nb_irqs
;
1885 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1886 g_assert(type
== LTTV_POINTER
);
1887 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1889 /* free softirq resource states */
1890 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1891 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1892 g_assert(type
== LTTV_POINTER
);
1893 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1895 /* free the blkdev states */
1896 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1897 g_assert(type
== LTTV_POINTER
);
1898 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1900 nb_tracefile
= self
->parent
.tracefiles
->len
;
1902 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1904 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1905 LttvTracefileContext
*, i
));
1906 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1907 g_assert(type
== LTTV_GOBJECT
);
1908 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1910 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1912 g_assert(type
== LTTV_POINTER
);
1913 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1915 g_object_unref(G_OBJECT(tracefiles_tree
));
1919 static void free_saved_state(LttvTraceState
*self
)
1923 LttvAttributeType type
;
1925 LttvAttributeValue value
;
1927 LttvAttributeName name
;
1931 LttvAttribute
*saved_states
;
1933 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1934 LTTV_STATE_SAVED_STATES
);
1936 nb
= lttv_attribute_get_number(saved_states
);
1937 for(i
= 0 ; i
< nb
; i
++) {
1938 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1939 g_assert(type
== LTTV_GOBJECT
);
1940 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1943 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1947 static void create_max_time(LttvTraceState
*tcs
)
1949 LttvAttributeValue v
;
1951 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1953 g_assert(*(v
.v_pointer
) == NULL
);
1954 *(v
.v_pointer
) = g_new(LttTime
,1);
1955 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1959 static void get_max_time(LttvTraceState
*tcs
)
1961 LttvAttributeValue v
;
1963 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1965 g_assert(*(v
.v_pointer
) != NULL
);
1966 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1970 static void free_max_time(LttvTraceState
*tcs
)
1972 LttvAttributeValue v
;
1974 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1976 g_free(*(v
.v_pointer
));
1977 *(v
.v_pointer
) = NULL
;
1980 static void create_name_tables(LttvTraceState
*tcs
)
1984 GString
*fe_name
= g_string_new("");
1986 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1988 LttvAttributeValue v
;
1992 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1994 g_assert(*(v
.v_pointer
) == NULL
);
1995 *(v
.v_pointer
) = name_tables
;
1997 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1999 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2001 LTT_EVENT_SYSCALL_ENTRY
,
2002 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
2003 NULL
, NULL
, &hooks
)) {
2005 // th = lttv_trace_hook_get_first(&th);
2007 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2008 // nb = ltt_type_element_number(t);
2010 // name_tables->syscall_names = g_new(GQuark, nb);
2011 // name_tables->nb_syscalls = nb;
2013 // for(i = 0 ; i < nb ; i++) {
2014 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
2015 // if(!name_tables->syscall_names[i]) {
2016 // GString *string = g_string_new("");
2017 // g_string_printf(string, "syscall %u", i);
2018 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
2019 // g_string_free(string, TRUE);
2023 name_tables
->nb_syscalls
= 256;
2024 name_tables
->syscall_names
= g_new(GQuark
, 256);
2025 for(i
= 0 ; i
< 256 ; i
++) {
2026 g_string_printf(fe_name
, "syscall %d", i
);
2027 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2030 name_tables
->syscall_names
= NULL
;
2031 name_tables
->nb_syscalls
= 0;
2033 lttv_trace_hook_remove_all(&hooks
);
2035 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2037 LTT_EVENT_TRAP_ENTRY
,
2038 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2039 NULL
, NULL
, &hooks
) ||
2040 !lttv_trace_find_hook(tcs
->parent
.t
,
2042 LTT_EVENT_PAGE_FAULT_ENTRY
,
2043 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2044 NULL
, NULL
, &hooks
)) {
2046 // th = lttv_trace_hook_get_first(&th);
2048 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2049 // //nb = ltt_type_element_number(t);
2051 // name_tables->trap_names = g_new(GQuark, nb);
2052 // for(i = 0 ; i < nb ; i++) {
2053 // name_tables->trap_names[i] = g_quark_from_string(
2054 // ltt_enum_string_get(t, i));
2057 name_tables
->nb_traps
= 256;
2058 name_tables
->trap_names
= g_new(GQuark
, 256);
2059 for(i
= 0 ; i
< 256 ; i
++) {
2060 g_string_printf(fe_name
, "trap %d", i
);
2061 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2064 name_tables
->trap_names
= NULL
;
2065 name_tables
->nb_traps
= 0;
2067 lttv_trace_hook_remove_all(&hooks
);
2069 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2071 LTT_EVENT_IRQ_ENTRY
,
2072 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
2073 NULL
, NULL
, &hooks
)) {
2076 name_tables->irq_names = g_new(GQuark, nb);
2077 for(i = 0 ; i < nb ; i++) {
2078 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2081 /* FIXME: LttvIRQState *irq_states should become a g_array */
2082 /* temp fix: increase from 256 to 512 default size */
2084 name_tables
->nb_irqs
= 512;
2085 name_tables
->irq_names
= g_new(GQuark
, 512);
2086 for(i
= 0 ; i
< 512 ; i
++) {
2087 g_string_printf(fe_name
, "irq %d", i
);
2088 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2091 name_tables
->nb_irqs
= 0;
2092 name_tables
->irq_names
= NULL
;
2094 lttv_trace_hook_remove_all(&hooks
);
2096 name_tables->soft_irq_names = g_new(GQuark, nb);
2097 for(i = 0 ; i < nb ; i++) {
2098 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2102 /* the kernel is limited to 32 statically defined softirqs */
2103 name_tables
->nb_soft_irqs
= 32;
2104 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_soft_irqs
);
2105 for(i
= 0 ; i
< name_tables
->nb_soft_irqs
; i
++) {
2106 g_string_printf(fe_name
, "softirq %d", i
);
2107 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2109 g_array_free(hooks
, TRUE
);
2111 g_string_free(fe_name
, TRUE
);
2113 #if (__WORDSIZE == 32)
2114 name_tables
->kprobe_hash
= g_hash_table_new_full(guint64_hash
, guint64_equal
,
2117 name_tables
->kprobe_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2122 static void get_name_tables(LttvTraceState
*tcs
)
2124 LttvAttributeValue v
;
2126 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2128 g_assert(*(v
.v_pointer
) != NULL
);
2129 tcs
->name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2133 static void free_name_tables(LttvTraceState
*tcs
)
2135 LttvNameTables
*name_tables
;
2137 LttvAttributeValue v
;
2139 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2141 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2142 *(v
.v_pointer
) = NULL
;
2144 // g_free(name_tables->eventtype_names);
2145 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2146 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2147 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2148 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2149 g_hash_table_destroy(name_tables
->kprobe_hash
);
2150 g_free(name_tables
);
2153 #ifdef HASH_TABLE_DEBUG
2155 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2157 LttvProcessState
*process
= (LttvProcessState
*)value
;
2159 /* Test for process corruption */
2160 guint stack_len
= process
->execution_stack
->len
;
2163 static void hash_table_check(GHashTable
*table
)
2165 g_hash_table_foreach(table
, test_process
, NULL
);
2171 /* clears the stack and sets the state passed as argument */
2172 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2174 g_array_set_size(cpust
->mode_stack
, 1);
2175 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2178 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2180 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2181 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2184 static void cpu_pop_mode(LttvCPUState
*cpust
)
2186 if(cpust
->mode_stack
->len
<= 1)
2187 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2189 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2192 /* clears the stack and sets the state passed as argument */
2193 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2195 g_array_set_size(bdevst
->mode_stack
, 1);
2196 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2199 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2201 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2202 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2205 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2207 if(bdevst
->mode_stack
->len
<= 1)
2208 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2210 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2213 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2215 g_array_set_size(irqst
->mode_stack
, 1);
2216 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2219 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2221 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2222 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2225 static void irq_pop_mode(LttvIRQState
*irqst
)
2227 if(irqst
->mode_stack
->len
<= 1)
2228 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2230 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2233 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2236 LttvExecutionState
*es
;
2238 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2239 guint cpu
= tfs
->cpu
;
2241 #ifdef HASH_TABLE_DEBUG
2242 hash_table_check(ts
->processes
);
2244 LttvProcessState
*process
= ts
->running_process
[cpu
];
2246 guint depth
= process
->execution_stack
->len
;
2248 process
->execution_stack
=
2249 g_array_set_size(process
->execution_stack
, depth
+ 1);
2252 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2254 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2257 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2258 es
->cum_cpu_time
= ltt_time_zero
;
2259 es
->s
= process
->state
->s
;
2260 process
->state
= es
;
2264 * return 1 when empty, else 0 */
2266 lttv_state_pop_state_cleanup(LttvProcessState
*process
, LttvTracefileState
*tfs
)
2268 guint depth
= process
->execution_stack
->len
;
2274 process
->execution_stack
=
2275 g_array_set_size(process
->execution_stack
, depth
- 1);
2276 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2278 process
->state
->change
= tfs
->parent
.timestamp
;
2283 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2285 guint cpu
= tfs
->cpu
;
2286 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2287 LttvProcessState
*process
= ts
->running_process
[cpu
];
2289 guint depth
= process
->execution_stack
->len
;
2291 if(process
->state
->t
!= t
){
2292 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2293 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2294 g_info("process state has %s when pop_int is %s\n",
2295 g_quark_to_string(process
->state
->t
),
2296 g_quark_to_string(t
));
2297 g_info("{ %u, %u, %s, %s, %s }\n",
2300 g_quark_to_string(process
->name
),
2301 g_quark_to_string(process
->brand
),
2302 g_quark_to_string(process
->state
->s
));
2307 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2308 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2312 process
->execution_stack
=
2313 g_array_set_size(process
->execution_stack
, depth
- 1);
2314 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2316 process
->state
->change
= tfs
->parent
.timestamp
;
2319 struct search_result
{
2320 const LttTime
*time
; /* Requested time */
2321 LttTime
*best
; /* Best result */
2324 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2326 const LttTime
*elem_time
= (const LttTime
*)a
;
2327 /* Explicit non const cast */
2328 struct search_result
*res
= (struct search_result
*)b
;
2330 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2331 /* The usertrace was created before the schedchange */
2332 /* Get larger keys */
2334 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2335 /* The usertrace was created after the schedchange time */
2336 /* Get smaller keys */
2338 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2339 res
->best
= (LttTime
*)elem_time
;
2342 res
->best
= (LttTime
*)elem_time
;
2349 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2350 guint pid
, const LttTime
*timestamp
)
2352 LttvTracefileState
*tfs
= NULL
;
2353 struct search_result res
;
2354 /* Find the usertrace associated with a pid and time interval.
2355 * Search in the usertraces by PID (within a hash) and then, for each
2356 * corresponding element of the array, find the first one with creation
2357 * timestamp the lowest, but higher or equal to "timestamp". */
2358 res
.time
= timestamp
;
2360 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2361 GUINT_TO_POINTER(pid
));
2362 if(usertrace_tree
) {
2363 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2365 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2371 /* Return a new and initialized LttvProcessState structure */
2373 LttvProcessState
*lttv_state_create_process(LttvTraceState
*tcs
,
2374 LttvProcessState
*parent
, guint cpu
, guint pid
,
2375 guint tgid
, GQuark name
, const LttTime
*timestamp
)
2377 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2379 LttvExecutionState
*es
;
2384 process
->tgid
= tgid
;
2386 process
->name
= name
;
2387 process
->brand
= LTTV_STATE_UNBRANDED
;
2388 //process->last_cpu = tfs->cpu_name;
2389 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2390 process
->type
= LTTV_STATE_USER_THREAD
;
2391 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2392 process
->current_function
= 0; //function 0x0 by default.
2394 g_info("Process %u, core %p", process
->pid
, process
);
2395 g_hash_table_insert(tcs
->processes
, process
, process
);
2398 process
->ppid
= parent
->pid
;
2399 process
->creation_time
= *timestamp
;
2402 /* No parent. This process exists but we are missing all information about
2403 its creation. The birth time is set to zero but we remember the time of
2408 process
->creation_time
= ltt_time_zero
;
2411 process
->insertion_time
= *timestamp
;
2412 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2413 process
->creation_time
.tv_nsec
);
2414 process
->pid_time
= g_quark_from_string(buffer
);
2416 process
->free_events
= 0;
2417 //process->last_cpu = tfs->cpu_name;
2418 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2419 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2420 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2421 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2422 es
= process
->state
= &g_array_index(process
->execution_stack
,
2423 LttvExecutionState
, 0);
2424 es
->t
= LTTV_STATE_USER_MODE
;
2425 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2426 es
->entry
= *timestamp
;
2427 //g_assert(timestamp->tv_sec != 0);
2428 es
->change
= *timestamp
;
2429 es
->cum_cpu_time
= ltt_time_zero
;
2430 es
->s
= LTTV_STATE_RUN
;
2432 es
= process
->state
= &g_array_index(process
->execution_stack
,
2433 LttvExecutionState
, 1);
2434 es
->t
= LTTV_STATE_SYSCALL
;
2435 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2436 es
->entry
= *timestamp
;
2437 //g_assert(timestamp->tv_sec != 0);
2438 es
->change
= *timestamp
;
2439 es
->cum_cpu_time
= ltt_time_zero
;
2440 es
->s
= LTTV_STATE_WAIT_FORK
;
2442 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2443 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2444 sizeof(guint64
), 0);
2446 process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2452 lttv_state_find_process(LttvTraceState
*ts
, guint cpu
, guint pid
)
2454 LttvProcessState key
;
2455 LttvProcessState
*process
;
2459 process
= g_hash_table_lookup(ts
->processes
, &key
);
2463 LttvProcessState
*lttv_state_find_process_or_create(LttvTraceState
*ts
,
2464 guint cpu
, guint pid
, const LttTime
*timestamp
)
2466 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2467 LttvExecutionState
*es
;
2469 /* Put ltt_time_zero creation time for unexisting processes */
2470 if(unlikely(process
== NULL
)) {
2471 process
= lttv_state_create_process(ts
,
2472 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2473 /* We are not sure is it's a kernel thread or normal thread, put the
2474 * bottom stack state to unknown */
2475 process
->execution_stack
=
2476 g_array_set_size(process
->execution_stack
, 1);
2477 process
->state
= es
=
2478 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2479 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2480 es
->s
= LTTV_STATE_UNNAMED
;
2485 /* FIXME : this function should be called when we receive an event telling that
2486 * release_task has been called in the kernel. In happens generally when
2487 * the parent waits for its child termination, but may also happens in special
2488 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2489 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2490 * of a killed thread group, but isn't the leader.
2492 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2494 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2495 LttvProcessState key
;
2497 /* Wait for both schedule with exit dead and process free to happen.
2498 * They can happen in any order. */
2499 if (++(process
->free_events
) < 2)
2502 key
.pid
= process
->pid
;
2503 key
.cpu
= process
->cpu
;
2504 g_hash_table_remove(ts
->processes
, &key
);
2505 g_array_free(process
->execution_stack
, TRUE
);
2506 g_array_free(process
->user_stack
, TRUE
);
2508 /* the following also clears the content */
2509 g_hash_table_destroy(process
->fds
);
2516 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2518 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2519 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2521 /* the following also clears the content */
2522 g_hash_table_destroy(((LttvProcessState
*)value
)->fds
);
2528 static void lttv_state_free_process_table(GHashTable
*processes
)
2530 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2531 g_hash_table_destroy(processes
);
2535 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2537 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2539 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2540 LttvProcessState
*process
= ts
->running_process
[cpu
];
2541 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2542 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2543 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2544 LttvExecutionSubmode submode
;
2545 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2547 guint syscall
= ltt_event_get_unsigned(e
, f
);
2548 expand_syscall_table(ts
, syscall
);
2549 submode
= nt
->syscall_names
[syscall
];
2550 /* There can be no system call from PID 0 : unknown state */
2551 if(process
->pid
!= 0)
2552 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2557 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2559 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2561 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2562 LttvProcessState
*process
= ts
->running_process
[cpu
];
2564 /* There can be no system call from PID 0 : unknown state */
2565 if(process
->pid
!= 0)
2566 pop_state(s
, LTTV_STATE_SYSCALL
);
2571 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2573 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2574 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2575 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2576 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2577 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2578 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2580 LttvExecutionSubmode submode
;
2582 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2584 expand_trap_table(ts
, trap
);
2586 submode
= nt
->trap_names
[trap
];
2588 push_state(s
, LTTV_STATE_TRAP
, submode
);
2590 /* update cpu status */
2591 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2593 /* update trap status */
2594 g_array_append_val(s
->cpu_state
->trap_stack
, trap
);
2595 ts
->trap_states
[trap
].running
++;
2600 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2602 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2603 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2605 pop_state(s
, LTTV_STATE_TRAP
);
2607 /* update cpu status */
2608 cpu_pop_mode(s
->cpu_state
);
2610 /* update trap status */
2611 if (s
->cpu_state
->trap_stack
->len
> 0) {
2612 gint last
= g_array_index(s
->cpu_state
->trap_stack
, gint
,
2613 s
->cpu_state
->trap_stack
->len
-1);
2614 if(ts
->trap_states
[last
].running
)
2615 ts
->trap_states
[last
].running
--;
2616 g_array_remove_index(s
->cpu_state
->trap_stack
,
2617 s
->cpu_state
->trap_stack
->len
-1);
2622 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2624 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2625 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2626 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2627 //guint8 ev_id = ltt_event_eventtype_id(e);
2628 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2629 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2630 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2632 LttvExecutionSubmode submode
;
2633 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2635 expand_irq_table(ts
, irq
);
2637 submode
= nt
->irq_names
[irq
];
2639 /* Do something with the info about being in user or system mode when int? */
2640 push_state(s
, LTTV_STATE_IRQ
, submode
);
2642 /* update cpu status */
2643 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2645 /* update irq status */
2646 g_array_append_val(s
->cpu_state
->irq_stack
, irq
);
2647 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2652 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2654 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2655 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2657 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2659 /* update cpu status */
2660 cpu_pop_mode(s
->cpu_state
);
2662 /* update softirq status */
2663 if (s
->cpu_state
->softirq_stack
->len
> 0) {
2664 gint last
= g_array_index(s
->cpu_state
->softirq_stack
, gint
, s
->cpu_state
->softirq_stack
->len
-1);
2665 if(ts
->soft_irq_states
[last
].running
)
2666 ts
->soft_irq_states
[last
].running
--;
2667 g_array_remove_index(s
->cpu_state
->softirq_stack
, s
->cpu_state
->softirq_stack
->len
-1);
2672 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2674 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2675 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2677 pop_state(s
, LTTV_STATE_IRQ
);
2679 /* update cpu status */
2680 cpu_pop_mode(s
->cpu_state
);
2682 /* update irq status */
2683 if (s
->cpu_state
->irq_stack
->len
> 0) {
2684 gint last
= g_array_index(s
->cpu_state
->irq_stack
, gint
, s
->cpu_state
->irq_stack
->len
-1);
2685 g_array_remove_index(s
->cpu_state
->irq_stack
, s
->cpu_state
->irq_stack
->len
-1);
2686 irq_pop_mode(&ts
->irq_states
[last
]);
2692 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2694 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2695 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2696 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2697 //guint8 ev_id = ltt_event_eventtype_id(e);
2698 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2699 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2700 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2702 LttvExecutionSubmode submode
;
2703 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2704 guint64 nb_softirqs
= nt
->nb_soft_irqs
;
2706 if(softirq
< nb_softirqs
) {
2707 submode
= nt
->soft_irq_names
[softirq
];
2709 /* Fixup an incomplete irq table */
2710 GString
*string
= g_string_new("");
2711 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2712 submode
= g_quark_from_string(string
->str
);
2713 g_string_free(string
, TRUE
);
2716 /* update softirq status */
2717 /* a soft irq raises are not cumulative */
2718 ts
->soft_irq_states
[softirq
].pending
=1;
2723 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2725 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2726 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2727 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2728 //guint8 ev_id = ltt_event_eventtype_id(e);
2729 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2730 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2731 LttvExecutionSubmode submode
;
2732 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2733 expand_soft_irq_table(ts
, softirq
);
2734 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2735 submode
= nt
->soft_irq_names
[softirq
];
2737 /* Do something with the info about being in user or system mode when int? */
2738 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2740 /* update cpu status */
2741 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2743 /* update softirq status */
2744 g_array_append_val(s
->cpu_state
->softirq_stack
, softirq
);
2745 if(ts
->soft_irq_states
[softirq
].pending
)
2746 ts
->soft_irq_states
[softirq
].pending
--;
2747 ts
->soft_irq_states
[softirq
].running
++;
2752 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2754 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2755 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2756 LttvNameTables
*nt
= ts
->name_tables
;
2757 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2758 //guint8 ev_id = ltt_event_eventtype_id(e);
2759 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2761 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2762 lttv_trace_get_hook_field(th
, 0)));
2763 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2765 expand_irq_table(ts
, irq
);
2766 nt
->irq_names
[irq
] = action
;
2772 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2774 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2775 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2776 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2777 //guint8 ev_id = ltt_event_eventtype_id(e);
2778 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2780 guint major
= ltt_event_get_long_unsigned(e
,
2781 lttv_trace_get_hook_field(th
, 0));
2782 guint minor
= ltt_event_get_long_unsigned(e
,
2783 lttv_trace_get_hook_field(th
, 1));
2784 guint oper
= ltt_event_get_long_unsigned(e
,
2785 lttv_trace_get_hook_field(th
, 2));
2786 guint32 devcode
= MKDEV(major
,minor
);
2788 /* have we seen this block device before? */
2789 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2792 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2794 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2799 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2801 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2802 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2803 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2804 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2806 guint major
= ltt_event_get_long_unsigned(e
,
2807 lttv_trace_get_hook_field(th
, 0));
2808 guint minor
= ltt_event_get_long_unsigned(e
,
2809 lttv_trace_get_hook_field(th
, 1));
2810 //guint oper = ltt_event_get_long_unsigned(e,
2811 // lttv_trace_get_hook_field(th, 2));
2812 guint32 devcode
= MKDEV(major
,minor
);
2814 /* have we seen this block device before? */
2815 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2817 /* update block device */
2818 bdev_pop_mode(bdev
);
2823 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2827 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2828 guint cpu
= tfs
->cpu
;
2829 LttvProcessState
*process
= ts
->running_process
[cpu
];
2831 guint depth
= process
->user_stack
->len
;
2833 process
->user_stack
=
2834 g_array_set_size(process
->user_stack
, depth
+ 1);
2836 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2837 *new_func
= funcptr
;
2838 process
->current_function
= funcptr
;
2841 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2843 guint cpu
= tfs
->cpu
;
2844 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2845 LttvProcessState
*process
= ts
->running_process
[cpu
];
2847 if(process
->current_function
!= funcptr
){
2848 g_info("Different functions (%lu.%09lu): ignore it\n",
2849 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2850 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2851 process
->current_function
, funcptr
);
2852 g_info("{ %u, %u, %s, %s, %s }\n",
2855 g_quark_to_string(process
->name
),
2856 g_quark_to_string(process
->brand
),
2857 g_quark_to_string(process
->state
->s
));
2860 guint depth
= process
->user_stack
->len
;
2863 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2864 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2868 process
->user_stack
=
2869 g_array_set_size(process
->user_stack
, depth
- 1);
2870 process
->current_function
=
2871 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2875 static gboolean
function_entry(void *hook_data
, void *call_data
)
2877 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2878 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2879 //guint8 ev_id = ltt_event_eventtype_id(e);
2880 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2881 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2882 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2884 push_function(s
, funcptr
);
2888 static gboolean
function_exit(void *hook_data
, void *call_data
)
2890 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2891 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2892 //guint8 ev_id = ltt_event_eventtype_id(e);
2893 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2894 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2895 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2897 pop_function(s
, funcptr
);
2901 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2903 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2904 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2905 LttvNameTables
*nt
= ts
->name_tables
;
2906 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2907 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2912 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2913 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2914 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2916 expand_syscall_table(ts
, id
);
2917 nt
->syscall_names
[id
] = g_quark_from_string(symbol
);
2922 static gboolean
dump_kprobe(void *hook_data
, void *call_data
)
2924 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2925 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2926 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2927 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2931 ip
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2932 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 1));
2934 expand_kprobe_table(ts
, ip
, symbol
);
2939 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2941 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2942 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2943 LttvNameTables
*nt
= ts
->name_tables
;
2944 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2945 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2950 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2951 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2952 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2954 expand_soft_irq_table(ts
, id
);
2955 nt
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2960 static gboolean
sched_try_wakeup(void *hook_data
, void *call_data
)
2962 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2963 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2964 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2965 LttvProcessState
*process
;
2969 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
2970 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2972 process
= lttv_state_find_process_or_create(
2973 (LttvTraceState
*)s
->parent
.t_context
,
2974 woken_cpu
, woken_pid
,
2975 &s
->parent
.timestamp
);
2977 if (process
->state
->s
== LTTV_STATE_WAIT
|| process
->state
->s
== LTTV_STATE_WAIT_FORK
)
2979 process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2980 process
->state
->change
= s
->parent
.timestamp
;
2983 g_debug("Wakeup: process %d on CPU %u\n", woken_pid
, woken_cpu
);
2988 static gboolean
schedchange(void *hook_data
, void *call_data
)
2990 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2992 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2993 LttvProcessState
*process
= ts
->running_process
[cpu
];
2994 //LttvProcessState *old_process = ts->running_process[cpu];
2996 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2997 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2998 guint pid_in
, pid_out
;
3001 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3002 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3003 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
3005 if(likely(process
!= NULL
)) {
3007 /* We could not know but it was not the idle process executing.
3008 This should only happen at the beginning, before the first schedule
3009 event, and when the initial information (current process for each CPU)
3010 is missing. It is not obvious how we could, after the fact, compensate
3011 the wrongly attributed statistics. */
3013 //This test only makes sense once the state is known and if there is no
3014 //missing events. We need to silently ignore schedchange coming after a
3015 //process_free, or it causes glitches. (FIXME)
3016 //if(unlikely(process->pid != pid_out)) {
3017 // g_assert(process->pid == 0);
3019 if(process
->pid
== 0
3020 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3023 * Scheduling out of pid 0 at beginning of the trace.
3024 * We are typically in system call mode at this point although
3025 * (FIXME) we might be in a trap handler.
3027 g_assert(process
->execution_stack
->len
== 1);
3028 process
->state
->t
= LTTV_STATE_SYSCALL
;
3029 process
->state
->s
= LTTV_STATE_WAIT
;
3030 process
->state
->change
= s
->parent
.timestamp
;
3031 process
->state
->entry
= s
->parent
.timestamp
;
3034 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
3035 process
->state
->s
= LTTV_STATE_ZOMBIE
;
3036 process
->state
->change
= s
->parent
.timestamp
;
3038 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
3039 else process
->state
->s
= LTTV_STATE_WAIT
;
3040 process
->state
->change
= s
->parent
.timestamp
;
3043 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
3044 /* see sched.h for states */
3045 if (!exit_process(s
, process
)) {
3046 process
->state
->s
= LTTV_STATE_DEAD
;
3047 process
->state
->change
= s
->parent
.timestamp
;
3052 process
= ts
->running_process
[cpu
] = lttv_state_find_process_or_create(
3053 (LttvTraceState
*)s
->parent
.t_context
,
3055 &s
->parent
.timestamp
);
3056 process
->state
->s
= LTTV_STATE_RUN
;
3058 if(process
->usertrace
)
3059 process
->usertrace
->cpu
= cpu
;
3060 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3061 process
->state
->change
= s
->parent
.timestamp
;
3063 /* update cpu status */
3065 /* going to idle task */
3066 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
3068 /* scheduling a real task.
3069 * we must be careful here:
3070 * if we just schedule()'ed to a process that is
3071 * in a trap, we must put the cpu in trap mode
3073 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
3074 if(process
->state
->t
== LTTV_STATE_TRAP
)
3075 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
3081 static gboolean
process_fork(void *hook_data
, void *call_data
)
3083 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3084 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3085 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3087 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
3088 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
3089 //LttvProcessState *zombie_process;
3091 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3092 LttvProcessState
*process
= ts
->running_process
[cpu
];
3093 LttvProcessState
*child_process
;
3094 struct marker_field
*f
;
3097 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3100 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3101 s
->parent
.target_pid
= child_pid
;
3104 f
= lttv_trace_get_hook_field(th
, 2);
3106 child_tgid
= ltt_event_get_unsigned(e
, f
);
3110 /* Mathieu : it seems like the process might have been scheduled in before the
3111 * fork, and, in a rare case, might be the current process. This might happen
3112 * in a SMP case where we don't have enough precision on the clocks.
3114 * Test reenabled after precision fixes on time. (Mathieu) */
3116 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3118 if(unlikely(zombie_process
!= NULL
)) {
3119 /* Reutilisation of PID. Only now we are sure that the old PID
3120 * has been released. FIXME : should know when release_task happens instead.
3122 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3124 for(i
=0; i
< num_cpus
; i
++) {
3125 g_assert(zombie_process
!= ts
->running_process
[i
]);
3128 exit_process(s
, zombie_process
);
3131 g_assert(process
->pid
!= child_pid
);
3132 // FIXME : Add this test in the "known state" section
3133 // g_assert(process->pid == parent_pid);
3134 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3135 if(child_process
== NULL
) {
3136 child_process
= lttv_state_create_process(ts
, process
, cpu
,
3137 child_pid
, child_tgid
,
3138 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
3140 /* The process has already been created : due to time imprecision between
3141 * multiple CPUs : it has been scheduled in before creation. Note that we
3142 * shouldn't have this kind of imprecision.
3144 * Simply put a correct parent.
3146 g_error("Process %u has been created at [%lu.%09lu] "
3147 "and inserted at [%lu.%09lu] before \n"
3148 "fork on cpu %u[%lu.%09lu].\n"
3149 "Probably an unsynchronized TSC problem on the traced machine.",
3151 child_process
->creation_time
.tv_sec
,
3152 child_process
->creation_time
.tv_nsec
,
3153 child_process
->insertion_time
.tv_sec
,
3154 child_process
->insertion_time
.tv_nsec
,
3155 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
3156 //g_assert(0); /* This is a problematic case : the process has been created
3157 // before the fork event */
3158 child_process
->ppid
= process
->pid
;
3159 child_process
->tgid
= child_tgid
;
3161 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
3162 child_process
->name
= process
->name
;
3163 child_process
->brand
= process
->brand
;
3168 /* We stamp a newly created process as kernel_thread.
3169 * The thread should not be running yet. */
3170 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
3172 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3173 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3174 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3176 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3177 LttvProcessState
*process
;
3178 LttvExecutionState
*es
;
3181 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3182 s
->parent
.target_pid
= pid
;
3184 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3186 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3187 process
->execution_stack
=
3188 g_array_set_size(process
->execution_stack
, 1);
3189 es
= process
->state
=
3190 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3191 es
->t
= LTTV_STATE_SYSCALL
;
3193 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3198 static gboolean
process_exit(void *hook_data
, void *call_data
)
3200 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3201 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3202 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3204 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3205 LttvProcessState
*process
; // = ts->running_process[cpu];
3207 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3208 s
->parent
.target_pid
= pid
;
3210 // FIXME : Add this test in the "known state" section
3211 // g_assert(process->pid == pid);
3213 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3214 if(likely(process
!= NULL
)) {
3215 process
->state
->s
= LTTV_STATE_EXIT
;
3220 static gboolean
process_free(void *hook_data
, void *call_data
)
3222 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3223 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3224 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3225 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3227 LttvProcessState
*process
;
3229 /* PID of the process to release */
3230 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3231 s
->parent
.target_pid
= release_pid
;
3233 g_assert(release_pid
!= 0);
3235 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3236 if(likely(process
!= NULL
))
3237 exit_process(s
, process
);
3240 if(likely(process
!= NULL
)) {
3241 /* release_task is happening at kernel level : we can now safely release
3242 * the data structure of the process */
3243 //This test is fun, though, as it may happen that
3244 //at time t : CPU 0 : process_free
3245 //at time t+150ns : CPU 1 : schedule out
3246 //Clearly due to time imprecision, we disable it. (Mathieu)
3247 //If this weird case happen, we have no choice but to put the
3248 //Currently running process on the cpu to 0.
3249 //I re-enable it following time precision fixes. (Mathieu)
3250 //Well, in the case where an process is freed by a process on another CPU
3251 //and still scheduled, it happens that this is the schedchange that will
3252 //drop the last reference count. Do not free it here!
3253 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3255 for(i
=0; i
< num_cpus
; i
++) {
3256 //g_assert(process != ts->running_process[i]);
3257 if(process
== ts
->running_process
[i
]) {
3258 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3262 if(i
== num_cpus
) /* process is not scheduled */
3263 exit_process(s
, process
);
3270 static gboolean
process_exec(void *hook_data
, void *call_data
)
3272 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3273 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3274 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3275 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3278 LttvProcessState
*process
= ts
->running_process
[cpu
];
3280 #if 0//how to use a sequence that must be transformed in a string
3281 /* PID of the process to release */
3282 guint64 name_len
= ltt_event_field_element_number(e
,
3283 lttv_trace_get_hook_field(th
, 0));
3284 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3285 LttField
*child
= ltt_event_field_element_select(e
,
3286 lttv_trace_get_hook_field(th
, 0), 0);
3288 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3289 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3290 memcpy(null_term_name
, name_begin
, name_len
);
3291 null_term_name
[name_len
] = '\0';
3292 process
->name
= g_quark_from_string(null_term_name
);
3295 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3296 lttv_trace_get_hook_field(th
, 0)));
3297 process
->brand
= LTTV_STATE_UNBRANDED
;
3298 //g_free(null_term_name);
3302 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3304 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3305 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3306 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3307 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3310 LttvProcessState
*process
= ts
->running_process
[cpu
];
3312 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3313 process
->brand
= g_quark_from_string(name
);
3318 static gboolean
fs_open(void *hook_data
, void *call_data
)
3320 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3321 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3322 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3323 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3324 struct marker_field
*f
;
3328 LttvProcessState
*process
= ts
->running_process
[cpu
];
3330 f
= lttv_trace_get_hook_field(th
, 0);
3331 fd
= ltt_event_get_int(e
, f
);
3333 f
= lttv_trace_get_hook_field(th
, 1);
3334 filename
= ltt_event_get_string(e
, f
);
3336 g_hash_table_insert(process
->fds
, (gpointer
)(long)fd
,
3337 (gpointer
)(unsigned long)g_quark_from_string(filename
));
3342 static void print_stack(LttvProcessState
*process
)
3344 LttvExecutionState
*es
;
3347 g_debug("Execution stack for process %u %s:\n",
3348 process
->pid
, g_quark_to_string(process
->name
));
3350 for (i
= 0; i
< process
->execution_stack
->len
; i
++) {
3351 es
= &g_array_index(process
->execution_stack
,
3352 LttvExecutionState
, i
);
3353 g_debug("Depth %d mode %s submode %s status %s\n",
3354 i
, g_quark_to_string(es
->t
),
3355 g_quark_to_string(es
->n
),
3356 g_quark_to_string(es
->s
));
3361 static void fix_process(gpointer key
, gpointer value
, gpointer user_data
)
3363 LttvProcessState
*process
;
3364 LttvExecutionState
*es
;
3365 process
= (LttvProcessState
*)value
;
3366 LttTime
*timestamp
= (LttTime
*)user_data
;
3368 print_stack(process
);
3370 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3371 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3372 if(es
->t
== LTTV_STATE_MAYBE_SYSCALL
) {
3373 es
->t
= LTTV_STATE_SYSCALL
;
3374 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3375 es
->entry
= *timestamp
;
3376 es
->change
= *timestamp
;
3377 es
->cum_cpu_time
= ltt_time_zero
;
3378 if(es
->s
== LTTV_STATE_UNNAMED
)
3379 es
->s
= LTTV_STATE_WAIT
;
3382 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3383 if(es
->t
== LTTV_STATE_MAYBE_USER_MODE
) {
3384 es
->t
= LTTV_STATE_USER_MODE
;
3385 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3386 es
->entry
= *timestamp
;
3387 //g_assert(timestamp->tv_sec != 0);
3388 es
->change
= *timestamp
;
3389 es
->cum_cpu_time
= ltt_time_zero
;
3390 if(es
->s
== LTTV_STATE_UNNAMED
)
3391 es
->s
= LTTV_STATE_RUN
;
3393 if(process
->execution_stack
->len
== 1) {
3394 /* Still in bottom unknown mode, means we either:
3395 * - never did a system call
3396 * - are scheduled out from user mode.
3397 * May be either in user mode, syscall mode, running or waiting.*/
3398 /* CHECK : we may be tagging syscall mode when being user mode
3399 * (should be fixed now) */
3400 if (es
->s
== LTTV_STATE_WAIT_CPU
) {
3401 /* nothing to do: scheduled out from userspace */
3403 process
->execution_stack
=
3404 g_array_set_size(process
->execution_stack
, 2);
3405 es
= process
->state
= &g_array_index(process
->execution_stack
,
3406 LttvExecutionState
, 1);
3407 es
->t
= LTTV_STATE_SYSCALL
;
3408 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3409 es
->entry
= *timestamp
;
3410 //g_assert(timestamp->tv_sec != 0);
3411 es
->change
= *timestamp
;
3412 es
->cum_cpu_time
= ltt_time_zero
;
3413 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3414 es
->s
= LTTV_STATE_WAIT
;
3421 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3423 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3424 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3425 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3426 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3427 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3429 /* For all processes */
3430 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3431 /* else, if stack[0] is unknown, set to user mode, running */
3433 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3438 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3440 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3441 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3442 //It's slow : optimise later by doing this before reading trace.
3443 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3449 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3450 LttvProcessState
*process
= ts
->running_process
[cpu
];
3451 LttvProcessState
*parent_process
;
3452 struct marker_field
*f
;
3453 GQuark type
, mode
, submode
, status
;
3454 LttvExecutionState
*es
;
3458 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3459 s
->parent
.target_pid
= pid
;
3462 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3465 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3468 f
= lttv_trace_get_hook_field(th
, 3);
3469 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3471 //FIXME: type is rarely used, enum must match possible types.
3474 f
= lttv_trace_get_hook_field(th
, 4);
3475 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3478 f
= lttv_trace_get_hook_field(th
, 5);
3479 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3482 f
= lttv_trace_get_hook_field(th
, 6);
3483 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3486 f
= lttv_trace_get_hook_field(th
, 7);
3488 tgid
= ltt_event_get_unsigned(e
, f
);
3493 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3494 for(i
=0; i
<nb_cpus
; i
++) {
3495 process
= lttv_state_find_process(ts
, i
, pid
);
3496 g_assert(process
!= NULL
);
3498 process
->ppid
= parent_pid
;
3499 process
->tgid
= tgid
;
3500 process
->name
= g_quark_from_string(command
);
3501 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3502 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3506 /* The process might exist if a process was forked while performing the
3508 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3509 if(process
== NULL
) {
3510 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3511 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3512 pid
, tgid
, g_quark_from_string(command
),
3513 &s
->parent
.timestamp
);
3515 /* Keep the stack bottom : a running user mode */
3516 /* Disabled because of inconsistencies in the current statedump states. */
3517 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3518 /* Only keep the bottom
3519 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3520 /* Will cause expected trap when in fact being syscall (even after end of
3522 * Will cause expected interrupt when being syscall. (only before end of
3523 * statedump event) */
3524 // This will cause a "popping last state on stack, ignoring it."
3525 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3526 es
= process
->state
= &g_array_index(process
->execution_stack
,
3527 LttvExecutionState
, 0);
3528 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3529 es
->t
= LTTV_STATE_MAYBE_SYSCALL
;
3530 es
->s
= LTTV_STATE_UNNAMED
;
3531 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3535 /* User space process :
3536 * bottom : user mode
3537 * either currently running or scheduled out.
3538 * can be scheduled out because interrupted in (user mode or in syscall)
3539 * or because of an explicit call to the scheduler in syscall. Note that
3540 * the scheduler call comes after the irq_exit, so never in interrupt
3542 // temp workaround : set size to 1 : only have user mode bottom of stack.
3543 // will cause g_info message of expected syscall mode when in fact being
3544 // in user mode. Can also cause expected trap when in fact being user
3545 // mode in the event of a page fault reenabling interrupts in the handler.
3546 // Expected syscall and trap can also happen after the end of statedump
3547 // This will cause a "popping last state on stack, ignoring it."
3548 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3549 es
= process
->state
= &g_array_index(process
->execution_stack
,
3550 LttvExecutionState
, 0);
3551 es
->t
= LTTV_STATE_MAYBE_USER_MODE
;
3552 es
->s
= LTTV_STATE_UNNAMED
;
3553 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3560 es
= process
->state
= &g_array_index(process
->execution_stack
,
3561 LttvExecutionState
, 1);
3562 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3563 es
->s
= LTTV_STATE_UNNAMED
;
3564 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3568 /* The process has already been created :
3569 * Probably was forked while dumping the process state or
3570 * was simply scheduled in prior to get the state dump event.
3572 process
->ppid
= parent_pid
;
3573 process
->tgid
= tgid
;
3574 process
->name
= g_quark_from_string(command
);
3575 process
->type
= type
;
3576 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3578 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3579 if(type
== LTTV_STATE_KERNEL_THREAD
)
3580 es
->t
= LTTV_STATE_SYSCALL
;
3582 es
->t
= LTTV_STATE_USER_MODE
;
3585 /* Don't mess around with the stack, it will eventually become
3586 * ok after the end of state dump. */
3593 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3595 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3597 lttv_state_add_event_hooks(tss
);
3602 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3604 LttvTraceset
*traceset
= self
->parent
.ts
;
3606 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3610 LttvTracefileState
*tfs
;
3616 LttvAttributeValue val
;
3618 nb_trace
= lttv_traceset_number(traceset
);
3619 for(i
= 0 ; i
< nb_trace
; i
++) {
3620 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3622 /* Find the eventtype id for the following events and register the
3623 associated by id hooks. */
3625 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 20);
3626 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3629 lttv_trace_find_hook(ts
->parent
.t
,
3631 LTT_EVENT_SYSCALL_ENTRY
,
3632 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3633 syscall_entry
, NULL
, &hooks
);
3635 lttv_trace_find_hook(ts
->parent
.t
,
3637 LTT_EVENT_SYSCALL_EXIT
,
3639 syscall_exit
, NULL
, &hooks
);
3641 lttv_trace_find_hook(ts
->parent
.t
,
3643 LTT_EVENT_TRAP_ENTRY
,
3644 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3645 trap_entry
, NULL
, &hooks
);
3647 lttv_trace_find_hook(ts
->parent
.t
,
3649 LTT_EVENT_TRAP_EXIT
,
3651 trap_exit
, NULL
, &hooks
);
3653 lttv_trace_find_hook(ts
->parent
.t
,
3655 LTT_EVENT_PAGE_FAULT_ENTRY
,
3656 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3657 trap_entry
, NULL
, &hooks
);
3659 lttv_trace_find_hook(ts
->parent
.t
,
3661 LTT_EVENT_PAGE_FAULT_EXIT
,
3663 trap_exit
, NULL
, &hooks
);
3665 lttv_trace_find_hook(ts
->parent
.t
,
3667 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3668 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3669 trap_entry
, NULL
, &hooks
);
3671 lttv_trace_find_hook(ts
->parent
.t
,
3673 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3675 trap_exit
, NULL
, &hooks
);
3677 lttv_trace_find_hook(ts
->parent
.t
,
3679 LTT_EVENT_IRQ_ENTRY
,
3680 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3681 irq_entry
, NULL
, &hooks
);
3683 lttv_trace_find_hook(ts
->parent
.t
,
3687 irq_exit
, NULL
, &hooks
);
3689 lttv_trace_find_hook(ts
->parent
.t
,
3691 LTT_EVENT_SOFT_IRQ_RAISE
,
3692 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3693 soft_irq_raise
, NULL
, &hooks
);
3695 lttv_trace_find_hook(ts
->parent
.t
,
3697 LTT_EVENT_SOFT_IRQ_ENTRY
,
3698 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3699 soft_irq_entry
, NULL
, &hooks
);
3701 lttv_trace_find_hook(ts
->parent
.t
,
3703 LTT_EVENT_SOFT_IRQ_EXIT
,
3705 soft_irq_exit
, NULL
, &hooks
);
3707 lttv_trace_find_hook(ts
->parent
.t
,
3709 LTT_EVENT_SCHED_SCHEDULE
,
3710 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3711 LTT_FIELD_PREV_STATE
),
3712 schedchange
, NULL
, &hooks
);
3714 lttv_trace_find_hook(ts
->parent
.t
,
3716 LTT_EVENT_SCHED_TRY_WAKEUP
,
3717 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_CPU_ID
, LTT_FIELD_STATE
),
3718 sched_try_wakeup
, NULL
, &hooks
);
3720 lttv_trace_find_hook(ts
->parent
.t
,
3722 LTT_EVENT_PROCESS_FORK
,
3723 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3724 LTT_FIELD_CHILD_TGID
),
3725 process_fork
, NULL
, &hooks
);
3727 lttv_trace_find_hook(ts
->parent
.t
,
3729 LTT_EVENT_KTHREAD_CREATE
,
3730 FIELD_ARRAY(LTT_FIELD_PID
),
3731 process_kernel_thread
, NULL
, &hooks
);
3733 lttv_trace_find_hook(ts
->parent
.t
,
3735 LTT_EVENT_PROCESS_EXIT
,
3736 FIELD_ARRAY(LTT_FIELD_PID
),
3737 process_exit
, NULL
, &hooks
);
3739 lttv_trace_find_hook(ts
->parent
.t
,
3741 LTT_EVENT_PROCESS_FREE
,
3742 FIELD_ARRAY(LTT_FIELD_PID
),
3743 process_free
, NULL
, &hooks
);
3745 lttv_trace_find_hook(ts
->parent
.t
,
3748 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3749 process_exec
, NULL
, &hooks
);
3751 lttv_trace_find_hook(ts
->parent
.t
,
3752 LTT_CHANNEL_USERSPACE
,
3753 LTT_EVENT_THREAD_BRAND
,
3754 FIELD_ARRAY(LTT_FIELD_NAME
),
3755 thread_brand
, NULL
, &hooks
);
3757 /* statedump-related hooks */
3758 lttv_trace_find_hook(ts
->parent
.t
,
3759 LTT_CHANNEL_TASK_STATE
,
3760 LTT_EVENT_PROCESS_STATE
,
3761 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3762 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3763 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3764 enum_process_state
, NULL
, &hooks
);
3766 lttv_trace_find_hook(ts
->parent
.t
,
3767 LTT_CHANNEL_GLOBAL_STATE
,
3768 LTT_EVENT_STATEDUMP_END
,
3770 statedump_end
, NULL
, &hooks
);
3772 lttv_trace_find_hook(ts
->parent
.t
,
3773 LTT_CHANNEL_IRQ_STATE
,
3774 LTT_EVENT_LIST_INTERRUPT
,
3775 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3776 enum_interrupt
, NULL
, &hooks
);
3778 lttv_trace_find_hook(ts
->parent
.t
,
3780 LTT_EVENT_REQUEST_ISSUE
,
3781 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3782 bdev_request_issue
, NULL
, &hooks
);
3784 lttv_trace_find_hook(ts
->parent
.t
,
3786 LTT_EVENT_REQUEST_COMPLETE
,
3787 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3788 bdev_request_complete
, NULL
, &hooks
);
3790 lttv_trace_find_hook(ts
->parent
.t
,
3791 LTT_CHANNEL_USERSPACE
,
3792 LTT_EVENT_FUNCTION_ENTRY
,
3793 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3794 function_entry
, NULL
, &hooks
);
3796 lttv_trace_find_hook(ts
->parent
.t
,
3797 LTT_CHANNEL_USERSPACE
,
3798 LTT_EVENT_FUNCTION_EXIT
,
3799 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3800 function_exit
, NULL
, &hooks
);
3802 lttv_trace_find_hook(ts
->parent
.t
,
3803 LTT_CHANNEL_SYSCALL_STATE
,
3804 LTT_EVENT_SYS_CALL_TABLE
,
3805 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3806 dump_syscall
, NULL
, &hooks
);
3808 lttv_trace_find_hook(ts
->parent
.t
,
3809 LTT_CHANNEL_KPROBE_STATE
,
3810 LTT_EVENT_KPROBE_TABLE
,
3811 FIELD_ARRAY(LTT_FIELD_IP
, LTT_FIELD_SYMBOL
),
3812 dump_kprobe
, NULL
, &hooks
);
3814 lttv_trace_find_hook(ts
->parent
.t
,
3815 LTT_CHANNEL_SOFTIRQ_STATE
,
3816 LTT_EVENT_SOFTIRQ_VEC
,
3817 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3818 dump_softirq
, NULL
, &hooks
);
3820 lttv_trace_find_hook(ts
->parent
.t
,
3823 FIELD_ARRAY(LTT_FIELD_FD
, LTT_FIELD_FILENAME
),
3824 fs_open
, NULL
, &hooks
);
3826 /* Add these hooks to each event_by_id hooks list */
3828 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3830 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3832 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3833 LttvTracefileContext
*, j
));
3835 for(k
= 0 ; k
< hooks
->len
; k
++) {
3836 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3837 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3839 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3845 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3846 *(val
.v_pointer
) = hooks
;
3850 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3852 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3854 lttv_state_remove_event_hooks(tss
);
3859 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3861 LttvTraceset
*traceset
= self
->parent
.ts
;
3863 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3867 LttvTracefileState
*tfs
;
3873 LttvAttributeValue val
;
3875 nb_trace
= lttv_traceset_number(traceset
);
3876 for(i
= 0 ; i
< nb_trace
; i
++) {
3877 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3879 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3880 hooks
= *(val
.v_pointer
);
3882 /* Remove these hooks from each event_by_id hooks list */
3884 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3886 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3888 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3889 LttvTracefileContext
*, j
));
3891 for(k
= 0 ; k
< hooks
->len
; k
++) {
3892 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3893 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3894 lttv_hooks_remove_data(
3895 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3900 lttv_trace_hook_remove_all(&hooks
);
3901 g_array_free(hooks
, TRUE
);
3905 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3907 guint
*event_count
= (guint
*)hook_data
;
3909 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3910 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3915 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3917 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3919 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3921 LttvAttributeValue value
;
3923 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3924 LTTV_STATE_SAVED_STATES
);
3925 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3926 value
= lttv_attribute_add(saved_states_tree
,
3927 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3928 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3929 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3930 *(value
.v_time
) = self
->parent
.timestamp
;
3931 lttv_state_save(tcs
, saved_state_tree
);
3932 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3933 self
->parent
.timestamp
.tv_nsec
);
3935 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3940 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3942 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3944 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3949 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3957 static gboolean
block_start(void *hook_data
, void *call_data
)
3959 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3961 LttvTracefileState
*tfcs
;
3963 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3965 LttEventPosition
*ep
;
3967 guint i
, nb_block
, nb_event
, nb_tracefile
;
3971 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3973 LttvAttributeValue value
;
3975 ep
= ltt_event_position_new();
3977 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3979 /* Count the number of events added since the last block end in any
3982 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3984 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3985 LttvTracefileContext
, i
));
3986 ltt_event_position(tfcs
->parent
.e
, ep
);
3987 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3988 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3989 tfcs
->saved_position
= nb_event
;
3993 if(tcs
->nb_event
>= tcs
->save_interval
) {
3994 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3995 LTTV_STATE_SAVED_STATES
);
3996 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3997 value
= lttv_attribute_add(saved_states_tree
,
3998 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3999 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
4000 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
4001 *(value
.v_time
) = self
->parent
.timestamp
;
4002 lttv_state_save(tcs
, saved_state_tree
);
4004 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
4005 self
->parent
.timestamp
.tv_nsec
);
4007 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4013 static gboolean
block_end(void *hook_data
, void *call_data
)
4015 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
4017 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
4021 LttEventPosition
*ep
;
4023 guint nb_block
, nb_event
;
4025 ep
= ltt_event_position_new();
4026 ltt_event_position(self
->parent
.e
, ep
);
4027 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
4028 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
4029 self
->saved_position
= 0;
4030 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4037 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4039 LttvTraceset
*traceset
= self
->parent
.ts
;
4041 guint i
, j
, nb_trace
, nb_tracefile
;
4045 LttvTracefileState
*tfs
;
4047 LttvTraceHook hook_start
, hook_end
;
4049 nb_trace
= lttv_traceset_number(traceset
);
4050 for(i
= 0 ; i
< nb_trace
; i
++) {
4051 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4053 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4054 NULL
, NULL
, block_start
, &hook_start
);
4055 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4056 NULL
, NULL
, block_end
, &hook_end
);
4058 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4060 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4062 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4063 LttvTracefileContext
, j
));
4064 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4065 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
4066 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4067 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
4073 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4075 LttvTraceset
*traceset
= self
->parent
.ts
;
4077 guint i
, j
, nb_trace
, nb_tracefile
;
4081 LttvTracefileState
*tfs
;
4084 nb_trace
= lttv_traceset_number(traceset
);
4085 for(i
= 0 ; i
< nb_trace
; i
++) {
4087 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4088 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4090 if(ts
->has_precomputed_states
) continue;
4092 guint
*event_count
= g_new(guint
, 1);
4095 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4097 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4098 LttvTracefileContext
*, j
));
4099 lttv_hooks_add(tfs
->parent
.event
,
4100 state_save_event_hook
,
4107 lttv_process_traceset_begin(&self
->parent
,
4108 NULL
, NULL
, NULL
, NULL
, NULL
);
4112 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
4114 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4116 lttv_state_save_add_event_hooks(tss
);
4123 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4125 LttvTraceset
*traceset
= self
->parent
.ts
;
4127 guint i
, j
, nb_trace
, nb_tracefile
;
4131 LttvTracefileState
*tfs
;
4133 LttvTraceHook hook_start
, hook_end
;
4135 nb_trace
= lttv_traceset_number(traceset
);
4136 for(i
= 0 ; i
< nb_trace
; i
++) {
4137 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
4139 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4140 NULL
, NULL
, block_start
, &hook_start
);
4142 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4143 NULL
, NULL
, block_end
, &hook_end
);
4145 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4147 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4149 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4150 LttvTracefileContext
, j
));
4151 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4152 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
4153 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4154 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
4160 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4162 LttvTraceset
*traceset
= self
->parent
.ts
;
4164 guint i
, j
, nb_trace
, nb_tracefile
;
4168 LttvTracefileState
*tfs
;
4170 LttvHooks
*after_trace
= lttv_hooks_new();
4172 lttv_hooks_add(after_trace
,
4173 state_save_after_trace_hook
,
4178 lttv_process_traceset_end(&self
->parent
,
4179 NULL
, after_trace
, NULL
, NULL
, NULL
);
4181 lttv_hooks_destroy(after_trace
);
4183 nb_trace
= lttv_traceset_number(traceset
);
4184 for(i
= 0 ; i
< nb_trace
; i
++) {
4186 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4187 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4189 if(ts
->has_precomputed_states
) continue;
4191 guint
*event_count
= NULL
;
4193 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4195 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4196 LttvTracefileContext
*, j
));
4197 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
4198 state_save_event_hook
);
4200 if(event_count
) g_free(event_count
);
4204 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
4206 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4208 lttv_state_save_remove_event_hooks(tss
);
4213 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
4215 LttvTraceset
*traceset
= self
->parent
.ts
;
4219 int min_pos
, mid_pos
, max_pos
;
4221 guint call_rest
= 0;
4223 LttvTraceState
*tcs
;
4225 LttvAttributeValue value
;
4227 LttvAttributeType type
;
4229 LttvAttributeName name
;
4233 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
4235 //g_tree_destroy(self->parent.pqueue);
4236 //self->parent.pqueue = g_tree_new(compare_tracefile);
4238 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
4240 nb_trace
= lttv_traceset_number(traceset
);
4241 for(i
= 0 ; i
< nb_trace
; i
++) {
4242 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4244 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4245 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4246 LTTV_STATE_SAVED_STATES
);
4249 if(saved_states_tree
) {
4250 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4251 mid_pos
= max_pos
/ 2;
4252 while(min_pos
< max_pos
) {
4253 type
= lttv_attribute_get(saved_states_tree
, mid_pos
,
4254 &name
, &value
, &is_named
);
4255 g_assert(type
== LTTV_GOBJECT
);
4256 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4257 type
= lttv_attribute_get_by_name(saved_state_tree
,
4258 LTTV_STATE_TIME
, &value
);
4259 g_assert(type
== LTTV_TIME
);
4260 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4262 closest_tree
= saved_state_tree
;
4264 else max_pos
= mid_pos
- 1;
4266 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4270 /* restore the closest earlier saved state */
4272 lttv_state_restore(tcs
, closest_tree
);
4276 /* There is no saved state, yet we want to have it. Restart at T0 */
4278 restore_init_state(tcs
);
4279 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4282 /* We want to seek quickly without restoring/updating the state */
4284 restore_init_state(tcs
);
4285 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4288 if(!call_rest
) g_info("NOT Calling restore");
4292 static void traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4297 static void traceset_state_finalize (LttvTracesetState
*self
)
4299 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4300 finalize(G_OBJECT(self
));
4304 static void traceset_state_class_init (LttvTracesetContextClass
*klass
)
4306 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4308 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4309 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4310 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4311 klass
->new_traceset_context
= new_traceset_context
;
4312 klass
->new_trace_context
= new_trace_context
;
4313 klass
->new_tracefile_context
= new_tracefile_context
;
4317 GType
lttv_traceset_state_get_type(void)
4319 static GType type
= 0;
4321 static const GTypeInfo info
= {
4322 sizeof (LttvTracesetStateClass
),
4323 NULL
, /* base_init */
4324 NULL
, /* base_finalize */
4325 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4326 NULL
, /* class_finalize */
4327 NULL
, /* class_data */
4328 sizeof (LttvTracesetState
),
4329 0, /* n_preallocs */
4330 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4331 NULL
/* value handling */
4334 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4341 static void trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4346 static void trace_state_finalize (LttvTraceState
*self
)
4348 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4349 finalize(G_OBJECT(self
));
4353 static void trace_state_class_init (LttvTraceStateClass
*klass
)
4355 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4357 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4358 klass
->state_save
= state_save
;
4359 klass
->state_restore
= state_restore
;
4360 klass
->state_saved_free
= state_saved_free
;
4364 GType
lttv_trace_state_get_type(void)
4366 static GType type
= 0;
4368 static const GTypeInfo info
= {
4369 sizeof (LttvTraceStateClass
),
4370 NULL
, /* base_init */
4371 NULL
, /* base_finalize */
4372 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4373 NULL
, /* class_finalize */
4374 NULL
, /* class_data */
4375 sizeof (LttvTraceState
),
4376 0, /* n_preallocs */
4377 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4378 NULL
/* value handling */
4381 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4382 "LttvTraceStateType", &info
, 0);
4388 static void tracefile_state_instance_init (GTypeInstance
*instance
,
4394 static void tracefile_state_finalize (LttvTracefileState
*self
)
4396 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4397 finalize(G_OBJECT(self
));
4401 static void tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4403 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4405 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4409 GType
lttv_tracefile_state_get_type(void)
4411 static GType type
= 0;
4413 static const GTypeInfo info
= {
4414 sizeof (LttvTracefileStateClass
),
4415 NULL
, /* base_init */
4416 NULL
, /* base_finalize */
4417 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4418 NULL
, /* class_finalize */
4419 NULL
, /* class_data */
4420 sizeof (LttvTracefileState
),
4421 0, /* n_preallocs */
4422 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4423 NULL
/* value handling */
4426 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4427 "LttvTracefileStateType", &info
, 0);
4433 static void module_init()
4435 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4436 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4437 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4438 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4439 LTTV_STATE_MAYBE_USER_MODE
= g_quark_from_string("MAYBE_USER_MODE");
4440 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4441 LTTV_STATE_MAYBE_SYSCALL
= g_quark_from_string("MAYBE_SYSCALL");
4442 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4443 LTTV_STATE_MAYBE_TRAP
= g_quark_from_string("MAYBE_TRAP");
4444 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4445 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4446 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4447 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4448 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4449 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4450 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4451 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4452 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4453 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4454 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4455 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4456 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4457 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4458 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4459 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4460 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4461 LTTV_STATE_EVENT
= g_quark_from_string("event");
4462 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4463 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4464 LTTV_STATE_TIME
= g_quark_from_string("time");
4465 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4466 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4467 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4468 g_quark_from_string("trace_state_use_count");
4469 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4470 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4471 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4472 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4473 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4474 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4476 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4477 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4478 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4479 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4480 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4481 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4482 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4483 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4484 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4485 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4486 LTT_CHANNEL_KPROBE_STATE
= g_quark_from_string("kprobe_state");
4487 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4488 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4489 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4490 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4491 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4493 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4494 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4495 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4496 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4497 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4498 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4499 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4500 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4501 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4502 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4503 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4504 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4505 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4506 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4507 LTT_EVENT_SCHED_TRY_WAKEUP
= g_quark_from_string("sched_try_wakeup");
4508 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4509 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4510 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4511 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4512 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4513 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4514 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4515 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4516 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4517 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4518 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4519 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4520 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4521 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4522 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4523 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4524 LTT_EVENT_KPROBE
= g_quark_from_string("kprobe");
4525 LTT_EVENT_OPEN
= g_quark_from_string("open");
4526 LTT_EVENT_READ
= g_quark_from_string("read");
4527 LTT_EVENT_POLL_EVENT
= g_quark_from_string("poll_event");
4529 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4530 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4531 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4532 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4533 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4534 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4535 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4536 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4537 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4538 LTT_FIELD_PID
= g_quark_from_string("pid");
4539 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4540 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4541 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4542 LTT_FIELD_NAME
= g_quark_from_string("name");
4543 LTT_FIELD_TYPE
= g_quark_from_string("type");
4544 LTT_FIELD_MODE
= g_quark_from_string("mode");
4545 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4546 LTT_FIELD_STATUS
= g_quark_from_string("status");
4547 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4548 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4549 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4550 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4551 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4552 LTT_FIELD_ACTION
= g_quark_from_string("action");
4553 LTT_FIELD_ID
= g_quark_from_string("id");
4554 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4555 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4556 LTT_FIELD_IP
= g_quark_from_string("ip");
4557 LTT_FIELD_FD
= g_quark_from_string("fd");
4558 LTT_FIELD_STATE
= g_quark_from_string("state");
4559 LTT_FIELD_CPU_ID
= g_quark_from_string("cpu_id");
4561 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4562 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4563 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4564 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4565 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4566 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4568 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4569 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4570 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4572 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4573 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4574 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4575 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4578 static void module_destroy()
4583 LTTV_MODULE("state", "State computation", \
4584 "Update the system state, possibly saving it at intervals", \
4585 module_init
, module_destroy
)