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
);
665 for(i
= 0 ; i
< nb_trace
; i
++) {
666 tc
= self
->parent
.traces
[i
];
667 tcs
= LTTV_TRACE_STATE(tc
);
668 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
669 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
673 if(*(v
.v_uint
) == 1) {
674 create_name_tables(tcs
);
675 create_max_time(tcs
);
677 get_name_tables(tcs
);
680 nb_tracefile
= tc
->tracefiles
->len
;
681 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
682 nb_irq
= tcs
->name_tables
->nb_irqs
;
683 tcs
->processes
= NULL
;
684 tcs
->usertraces
= NULL
;
685 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
687 /* init cpu resource stuff */
688 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
689 for(j
= 0; j
<nb_cpu
; j
++) {
690 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
691 tcs
->cpu_states
[j
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
692 tcs
->cpu_states
[j
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
693 tcs
->cpu_states
[j
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
694 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
697 /* init irq resource stuff */
698 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
699 for(j
= 0; j
<nb_irq
; j
++) {
700 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
701 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
704 /* init soft irq stuff */
705 /* the kernel has a statically fixed max of 32 softirqs */
706 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->name_tables
->nb_soft_irqs
);
708 /* init trap stuff */
709 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->name_tables
->nb_traps
);
711 /* init bdev resource stuff */
712 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
714 restore_init_state(tcs
);
715 for(j
= 0 ; j
< nb_tracefile
; j
++) {
717 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
718 LttvTracefileContext
*, j
));
719 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
720 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
721 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
722 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
723 /* It's a Usertrace */
724 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
725 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
726 GUINT_TO_POINTER(tid
));
727 if(!usertrace_tree
) {
728 usertrace_tree
= g_tree_new_full(compare_usertraces
,
729 NULL
, free_usertrace_key
, NULL
);
730 g_hash_table_insert(tcs
->usertraces
,
731 GUINT_TO_POINTER(tid
), usertrace_tree
);
733 LttTime
*timestamp
= g_new(LttTime
, 1);
734 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
735 ltt_tracefile_creation(tfcs
->parent
.tf
));
736 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
740 /* See if the trace has saved states */
741 state_load_saved_states(tcs
);
746 static void fini(LttvTracesetState
*self
)
753 //LttvTracefileState *tfcs;
755 LttvAttributeValue v
;
757 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
758 for(i
= 0 ; i
< nb_trace
; i
++) {
759 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
760 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
763 g_assert(*(v
.v_uint
) != 0);
766 if(*(v
.v_uint
) == 0) {
767 free_name_tables(tcs
);
769 free_saved_state(tcs
);
771 g_free(tcs
->running_process
);
772 tcs
->running_process
= NULL
;
773 lttv_state_free_process_table(tcs
->processes
);
774 lttv_state_free_usertraces(tcs
->usertraces
);
775 tcs
->processes
= NULL
;
776 tcs
->usertraces
= NULL
;
779 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
780 fini((LttvTracesetContext
*)self
);
784 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
786 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
790 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
792 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
796 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
798 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
802 /* Write the process state of the trace */
804 static void write_process_state(gpointer key
, gpointer value
,
807 LttvProcessState
*process
;
809 LttvExecutionState
*es
;
811 FILE *fp
= (FILE *)user_data
;
816 process
= (LttvProcessState
*)value
;
817 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",
818 process
, process
->pid
, process
->tgid
, process
->ppid
,
819 g_quark_to_string(process
->type
),
820 process
->creation_time
.tv_sec
,
821 process
->creation_time
.tv_nsec
,
822 process
->insertion_time
.tv_sec
,
823 process
->insertion_time
.tv_nsec
,
824 g_quark_to_string(process
->name
),
825 g_quark_to_string(process
->brand
),
826 process
->cpu
, process
->free_events
);
828 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
829 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
830 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
831 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
832 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
833 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
834 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
837 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
838 address
= g_array_index(process
->user_stack
, guint64
, i
);
839 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n", address
);
842 if(process
->usertrace
) {
843 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
844 g_quark_to_string(process
->usertrace
->tracefile_name
),
845 process
->usertrace
->cpu
);
849 fprintf(fp
, " </PROCESS>\n");
853 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
855 guint i
, nb_tracefile
, nb_block
, offset
;
858 LttvTracefileState
*tfcs
;
862 LttEventPosition
*ep
;
866 ep
= ltt_event_position_new();
868 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
870 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
872 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
873 for(i
=0;i
<nb_cpus
;i
++) {
874 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
875 i
, self
->running_process
[i
]->pid
);
878 nb_tracefile
= self
->parent
.tracefiles
->len
;
880 for(i
= 0 ; i
< nb_tracefile
; i
++) {
882 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
883 LttvTracefileContext
*, i
));
884 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
885 tfcs
->parent
.timestamp
.tv_sec
,
886 tfcs
->parent
.timestamp
.tv_nsec
);
887 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
888 if(e
== NULL
) fprintf(fp
,"/>\n");
890 ltt_event_position(e
, ep
);
891 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
892 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
897 fprintf(fp
,"</PROCESS_STATE>\n");
901 static void write_process_state_raw(gpointer key
, gpointer value
,
904 LttvProcessState
*process
;
906 LttvExecutionState
*es
;
908 FILE *fp
= (FILE *)user_data
;
913 process
= (LttvProcessState
*)value
;
914 fputc(HDR_PROCESS
, fp
);
915 //fwrite(&header, sizeof(header), 1, fp);
916 //fprintf(fp, "%s", g_quark_to_string(process->type));
918 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
919 //fprintf(fp, "%s", g_quark_to_string(process->name));
921 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
922 //fprintf(fp, "%s", g_quark_to_string(process->brand));
924 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
925 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
926 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
927 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
928 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
929 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
930 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
931 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
934 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",
935 process
, process
->pid
, process
->tgid
, process
->ppid
,
936 g_quark_to_string(process
->type
),
937 process
->creation_time
.tv_sec
,
938 process
->creation_time
.tv_nsec
,
939 process
->insertion_time
.tv_sec
,
940 process
->insertion_time
.tv_nsec
,
941 g_quark_to_string(process
->name
),
942 g_quark_to_string(process
->brand
),
946 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
947 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
950 //fprintf(fp, "%s", g_quark_to_string(es->t));
952 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
953 //fprintf(fp, "%s", g_quark_to_string(es->n));
955 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
956 //fprintf(fp, "%s", g_quark_to_string(es->s));
958 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
959 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
960 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
961 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
963 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
964 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
965 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
966 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
967 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
971 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
972 address
= g_array_index(process
->user_stack
, guint64
, i
);
973 fputc(HDR_USER_STACK
, fp
);
974 fwrite(&address
, sizeof(address
), 1, fp
);
976 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n", address
);
980 if(process
->usertrace
) {
981 fputc(HDR_USERTRACE
, fp
);
982 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
984 fwrite(&process
->usertrace
->tracefile_name
,
985 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
986 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
988 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
989 g_quark_to_string(process
->usertrace
->tracefile_name
),
990 process
->usertrace
->cpu
);
997 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
999 guint i
, nb_tracefile
, nb_block
, offset
;
1002 LttvTracefileState
*tfcs
;
1006 LttEventPosition
*ep
;
1010 ep
= ltt_event_position_new();
1012 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1013 fputc(HDR_PROCESS_STATE
, fp
);
1014 fwrite(&t
, sizeof(t
), 1, fp
);
1016 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
1018 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1019 for(i
=0;i
<nb_cpus
;i
++) {
1021 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
1022 fwrite(&self
->running_process
[i
]->pid
,
1023 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1024 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1025 // i, self->running_process[i]->pid);
1028 nb_tracefile
= self
->parent
.tracefiles
->len
;
1030 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1032 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1033 LttvTracefileContext
*, i
));
1034 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1035 // tfcs->parent.timestamp.tv_sec,
1036 // tfcs->parent.timestamp.tv_nsec);
1037 fputc(HDR_TRACEFILE
, fp
);
1038 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1039 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1040 * position following : end of trace */
1041 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1043 ltt_event_position(e
, ep
);
1044 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1045 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1047 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
1048 fwrite(&offset
, sizeof(offset
), 1, fp
);
1049 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
1056 /* Read process state from a file */
1058 /* Called because a HDR_PROCESS was found */
1059 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
1060 GPtrArray
*quarktable
)
1062 LttvExecutionState
*es
;
1063 LttvProcessState
*process
, *parent_process
;
1064 LttvProcessState tmp
;
1070 res
= fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1071 res
+= fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1072 res
+= fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1073 res
+= fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1074 res
+= fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1075 res
+= fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1076 res
+= fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1077 res
+= fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1078 res
+= fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1079 res
+= fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1080 g_assert(res
== 10);
1083 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1085 /* We must link to the parent */
1086 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1088 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1089 if(process
== NULL
) {
1090 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1092 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1093 &tmp
.creation_time
);
1096 process
->insertion_time
= tmp
.insertion_time
;
1097 process
->creation_time
= tmp
.creation_time
;
1098 process
->type
= g_quark_from_string(
1099 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1100 process
->tgid
= tmp
.tgid
;
1101 process
->ppid
= tmp
.ppid
;
1102 process
->brand
= g_quark_from_string(
1103 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1105 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1106 process
->free_events
= tmp
.free_events
;
1109 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1111 gint hdr
= fgetc(fp
);
1112 if(hdr
== EOF
) goto end_loop
;
1116 process
->execution_stack
=
1117 g_array_set_size(process
->execution_stack
,
1118 process
->execution_stack
->len
+ 1);
1119 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1120 process
->execution_stack
->len
-1);
1121 process
->state
= es
;
1123 res
= fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1125 es
->t
= g_quark_from_string(
1126 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1127 res
= fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1129 es
->n
= g_quark_from_string(
1130 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1131 res
= fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1133 es
->s
= g_quark_from_string(
1134 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1135 res
= fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1136 res
+= fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1137 res
+= fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1141 case HDR_USER_STACK
:
1142 process
->user_stack
= g_array_set_size(process
->user_stack
,
1143 process
->user_stack
->len
+ 1);
1144 address
= &g_array_index(process
->user_stack
, guint64
,
1145 process
->user_stack
->len
-1);
1146 res
= fread(address
, sizeof(address
), 1, fp
);
1148 process
->current_function
= *address
;
1152 res
= fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1153 res
+= fread(&process
->usertrace
->cpu
,
1154 sizeof(process
->usertrace
->cpu
), 1, fp
);
1168 /* Called because a HDR_PROCESS_STATE was found */
1169 /* Append a saved state to the trace states */
1170 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1172 guint i
, nb_tracefile
, nb_block
, offset
;
1174 LttvTracefileState
*tfcs
;
1176 LttEventPosition
*ep
;
1185 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1187 LttvAttributeValue value
;
1188 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1189 ep
= ltt_event_position_new();
1191 restore_init_state(self
);
1193 res
= fread(&t
, sizeof(t
), 1, fp
);
1197 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1199 if(hdr
== EOF
) goto end_loop
;
1203 /* Call read_process_state_raw */
1204 read_process_state_raw(self
, fp
, quarktable
);
1212 case HDR_USER_STACK
:
1214 case HDR_PROCESS_STATE
:
1220 g_error("Error while parsing saved state file : unknown data header %d",
1226 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1227 for(i
=0;i
<nb_cpus
;i
++) {
1230 g_assert(hdr
== HDR_CPU
);
1231 res
= fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1233 g_assert(i
== cpu_num
);
1234 res
= fread(&self
->running_process
[i
]->pid
,
1235 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1239 nb_tracefile
= self
->parent
.tracefiles
->len
;
1241 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1243 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1244 LttvTracefileContext
*, i
));
1245 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1246 // tfcs->parent.timestamp.tv_sec,
1247 // tfcs->parent.timestamp.tv_nsec);
1248 g_tree_remove(pqueue
, &tfcs
->parent
);
1250 g_assert(hdr
== HDR_TRACEFILE
);
1251 res
= fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1253 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1254 * position following : end of trace */
1255 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1256 res
= fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1257 res
+= fread(&offset
, sizeof(offset
), 1, fp
);
1258 res
+= fread(&tsc
, sizeof(tsc
), 1, fp
);
1260 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1261 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1263 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1268 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1269 LTTV_STATE_SAVED_STATES
);
1270 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1271 value
= lttv_attribute_add(saved_states_tree
,
1272 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1273 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1274 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1275 *(value
.v_time
) = t
;
1276 lttv_state_save(self
, saved_state_tree
);
1277 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1280 *(self
->max_time_state_recomputed_in_seek
) = t
;
1284 /* Called when a HDR_TRACE is found */
1285 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1286 GPtrArray
*quarktable
)
1291 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1293 if(hdr
== EOF
) goto end_loop
;
1296 case HDR_PROCESS_STATE
:
1297 /* Call read_process_state_raw */
1298 lttv_state_read_raw(tcs
, fp
, quarktable
);
1306 case HDR_USER_STACK
:
1310 g_error("Error while parsing saved state file :"
1311 " unexpected data header %d",
1315 g_error("Error while parsing saved state file : unknown data header %d",
1320 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1321 restore_init_state(tcs
);
1322 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1328 /* Copy each process from an existing hash table to a new one */
1330 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1332 LttvProcessState
*process
, *new_process
;
1334 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1338 process
= (LttvProcessState
*)value
;
1339 new_process
= g_new(LttvProcessState
, 1);
1340 *new_process
= *process
;
1341 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1342 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1343 new_process
->execution_stack
=
1344 g_array_set_size(new_process
->execution_stack
,
1345 process
->execution_stack
->len
);
1346 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1347 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1348 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1350 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1351 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1352 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1353 sizeof(guint64
), 0);
1354 new_process
->user_stack
= g_array_set_size(new_process
->user_stack
,
1355 process
->user_stack
->len
);
1356 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1357 g_array_index(new_process
->user_stack
, guint64
, i
) =
1358 g_array_index(process
->user_stack
, guint64
, i
);
1360 new_process
->current_function
= process
->current_function
;
1362 /* fd hash table stuff */
1368 /* copy every item in the hash table */
1369 new_process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1371 g_hash_table_iter_init(&it
, process
->fds
);
1372 while (g_hash_table_iter_next (&it
, (void *)&key
, (void *)&value
)) {
1373 g_hash_table_insert(new_process
->fds
, key
, value
);
1377 /* When done creating the new process state, insert it in the
1379 g_hash_table_insert(new_processes
, new_process
, new_process
);
1383 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1385 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1387 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1388 return new_processes
;
1391 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1394 LttvCPUState
*retval
;
1396 retval
= g_new(LttvCPUState
, n
);
1398 for(i
=0; i
<n
; i
++) {
1399 retval
[i
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1400 g_array_set_size(retval
[i
].irq_stack
, states
[i
].irq_stack
->len
);
1401 for(j
=0; j
<states
[i
].irq_stack
->len
; j
++) {
1402 g_array_index(retval
[i
].irq_stack
, gint
, j
) =
1403 g_array_index(states
[i
].irq_stack
, gint
, j
);
1406 retval
[i
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1407 g_array_set_size(retval
[i
].softirq_stack
, states
[i
].softirq_stack
->len
);
1408 for(j
=0; j
<states
[i
].softirq_stack
->len
; j
++) {
1409 g_array_index(retval
[i
].softirq_stack
, gint
, j
) =
1410 g_array_index(states
[i
].softirq_stack
, gint
, j
);
1413 retval
[i
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1414 g_array_set_size(retval
[i
].trap_stack
, states
[i
].trap_stack
->len
);
1415 for(j
=0; j
<states
[i
].trap_stack
->len
; j
++) {
1416 g_array_index(retval
[i
].trap_stack
, gint
, j
) =
1417 g_array_index(states
[i
].trap_stack
, gint
, j
);
1420 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1421 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1422 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1423 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1424 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1431 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1435 for(i
=0; i
<n
; i
++) {
1436 g_array_free(states
[i
].mode_stack
, TRUE
);
1437 g_array_free(states
[i
].irq_stack
, TRUE
);
1438 g_array_free(states
[i
].softirq_stack
, TRUE
);
1439 g_array_free(states
[i
].trap_stack
, TRUE
);
1445 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1448 LttvIRQState
*retval
;
1450 retval
= g_new(LttvIRQState
, n
);
1452 for(i
=0; i
<n
; i
++) {
1453 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1454 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1455 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1456 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1457 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1464 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1468 for(i
=0; i
<n
; i
++) {
1469 g_array_free(states
[i
].mode_stack
, TRUE
);
1475 static LttvSoftIRQState
*
1476 lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1479 LttvSoftIRQState
*retval
;
1481 retval
= g_new(LttvSoftIRQState
, n
);
1483 for(i
=0; i
<n
; i
++) {
1484 retval
[i
].pending
= states
[i
].pending
;
1485 retval
[i
].running
= states
[i
].running
;
1491 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1496 static LttvTrapState
*
1497 lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1500 LttvTrapState
*retval
;
1502 retval
= g_new(LttvTrapState
, n
);
1504 for(i
=0; i
<n
; i
++) {
1505 retval
[i
].running
= states
[i
].running
;
1511 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1516 /* bdevstate stuff */
1518 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
)
1520 gint devcode_gint
= devcode
;
1521 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1523 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1524 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1526 gint
* key
= g_new(gint
, 1);
1528 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1536 static LttvBdevState
*bdevstate_new(void)
1538 LttvBdevState
*retval
;
1539 retval
= g_new(LttvBdevState
, 1);
1540 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1545 static void bdevstate_free(LttvBdevState
*bds
)
1547 g_array_free(bds
->mode_stack
, TRUE
);
1551 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1553 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1555 bdevstate_free(bds
);
1558 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1560 LttvBdevState
*retval
;
1562 retval
= bdevstate_new();
1563 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
,
1564 bds
->mode_stack
->len
);
1569 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1571 //GHashTable *ht = (GHashTable *)u;
1572 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1573 LttvBdevState
*newbds
;
1575 newbds
= bdevstate_copy(bds
);
1577 g_hash_table_insert(u
, k
, newbds
);
1580 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1584 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1586 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1591 /* Free a hashtable and the LttvBdevState structures its values
1594 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1596 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1597 g_hash_table_destroy(ht
);
1600 /* The saved state for each trace contains a member "processes", which
1601 stores a copy of the process table, and a member "tracefiles" with
1602 one entry per tracefile. Each tracefile has a "process" member pointing
1603 to the current process and a "position" member storing the tracefile
1604 position (needed to seek to the current "next" event. */
1606 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1608 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1610 LttvTracefileState
*tfcs
;
1612 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1614 guint
*running_process
;
1616 LttvAttributeValue value
;
1618 LttEventPosition
*ep
;
1620 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1621 LTTV_STATE_TRACEFILES
);
1623 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1625 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1627 /* Add the currently running processes array */
1628 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1629 running_process
= g_new(guint
, nb_cpus
);
1630 for(i
=0;i
<nb_cpus
;i
++) {
1631 running_process
[i
] = self
->running_process
[i
]->pid
;
1633 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1635 *(value
.v_pointer
) = running_process
;
1637 g_info("State save");
1639 nb_tracefile
= self
->parent
.tracefiles
->len
;
1641 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1643 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1644 LttvTracefileContext
*, i
));
1645 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1646 value
= lttv_attribute_add(tracefiles_tree
, i
,
1648 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1650 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1652 *(value
.v_uint
) = tfcs
->process
->pid
;
1654 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1656 /* Only save the position if the tfs has not infinite time. */
1657 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1658 // && current_tfcs != tfcs) {
1659 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1660 *(value
.v_pointer
) = NULL
;
1662 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1663 ep
= ltt_event_position_new();
1664 ltt_event_position(e
, ep
);
1665 *(value
.v_pointer
) = ep
;
1667 guint nb_block
, offset
;
1670 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1671 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
,
1672 offset
, tsc
, tfcs
->parent
.timestamp
.tv_sec
,
1673 tfcs
->parent
.timestamp
.tv_nsec
);
1677 /* save the cpu state */
1679 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1681 *(value
.v_uint
) = nb_cpus
;
1683 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1685 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1688 /* save the irq state */
1689 nb_irqs
= self
->name_tables
->nb_irqs
;
1691 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1693 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1696 /* save the soft irq state */
1697 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1699 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1701 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1704 /* save the trap state */
1705 nb_traps
= self
->name_tables
->nb_traps
;
1707 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1709 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1712 /* save the blkdev states */
1713 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1715 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1719 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1721 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1723 LttvTracefileState
*tfcs
;
1725 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1727 guint
*running_process
;
1729 LttvAttributeType type
;
1731 LttvAttributeValue value
;
1733 LttvAttributeName name
;
1737 LttEventPosition
*ep
;
1739 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1742 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1743 LTTV_STATE_TRACEFILES
);
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1747 g_assert(type
== LTTV_POINTER
);
1748 lttv_state_free_process_table(self
->processes
);
1749 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1751 /* Add the currently running processes array */
1752 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1753 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1755 g_assert(type
== LTTV_POINTER
);
1756 running_process
= *(value
.v_pointer
);
1757 for(i
=0;i
<nb_cpus
;i
++) {
1758 pid
= running_process
[i
];
1759 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1760 g_assert(self
->running_process
[i
] != NULL
);
1763 nb_tracefile
= self
->parent
.tracefiles
->len
;
1765 //g_tree_destroy(tsc->pqueue);
1766 //tsc->pqueue = g_tree_new(compare_tracefile);
1768 /* restore cpu resource states */
1769 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1770 g_assert(type
== LTTV_POINTER
);
1771 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1772 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1774 /* restore irq resource states */
1775 nb_irqs
= self
->name_tables
->nb_irqs
;
1776 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1777 g_assert(type
== LTTV_POINTER
);
1778 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1779 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1781 /* restore soft irq resource states */
1782 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1783 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1784 g_assert(type
== LTTV_POINTER
);
1785 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1786 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1788 /* restore trap resource states */
1789 nb_traps
= self
->name_tables
->nb_traps
;
1790 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1791 g_assert(type
== LTTV_POINTER
);
1792 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1793 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1795 /* restore the blkdev states */
1796 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1797 g_assert(type
== LTTV_POINTER
);
1798 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1799 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1801 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1803 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1804 LttvTracefileContext
*, i
));
1805 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1806 g_assert(type
== LTTV_GOBJECT
);
1807 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1809 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1811 g_assert(type
== LTTV_UINT
);
1812 pid
= *(value
.v_uint
);
1813 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1815 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1817 g_assert(type
== LTTV_POINTER
);
1818 //g_assert(*(value.v_pointer) != NULL);
1819 ep
= *(value
.v_pointer
);
1820 g_assert(tfcs
->parent
.t_context
!= NULL
);
1822 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1824 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1825 g_tree_remove(tsc
->pqueue
, tfc
);
1828 retval
= ltt_tracefile_seek_position(tfc
->tf
, ep
);
1829 g_assert_cmpint(retval
, ==, 0);
1830 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1831 g_assert_cmpint(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
),
1833 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1834 g_info("Restoring state for a tf at time %lu.%lu",
1835 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1837 tfc
->timestamp
= ltt_time_infinite
;
1843 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1845 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1847 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1849 guint
*running_process
;
1851 LttvAttributeType type
;
1853 LttvAttributeValue value
;
1855 LttvAttributeName name
;
1859 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1860 LTTV_STATE_TRACEFILES
);
1861 g_object_ref(G_OBJECT(tracefiles_tree
));
1862 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1864 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1866 g_assert(type
== LTTV_POINTER
);
1867 lttv_state_free_process_table(*(value
.v_pointer
));
1868 *(value
.v_pointer
) = NULL
;
1869 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1871 /* Free running processes array */
1872 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1874 g_assert(type
== LTTV_POINTER
);
1875 running_process
= *(value
.v_pointer
);
1876 g_free(running_process
);
1878 /* free cpu resource states */
1879 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1880 g_assert(type
== LTTV_UINT
);
1881 nb_cpus
= *value
.v_uint
;
1882 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1883 g_assert(type
== LTTV_POINTER
);
1884 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1886 /* free irq resource states */
1887 nb_irqs
= self
->name_tables
->nb_irqs
;
1888 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1889 g_assert(type
== LTTV_POINTER
);
1890 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1892 /* free softirq resource states */
1893 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1894 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1895 g_assert(type
== LTTV_POINTER
);
1896 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1898 /* free the blkdev states */
1899 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1900 g_assert(type
== LTTV_POINTER
);
1901 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1903 nb_tracefile
= self
->parent
.tracefiles
->len
;
1905 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1907 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1908 g_assert(type
== LTTV_GOBJECT
);
1909 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1911 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1913 g_assert(type
== LTTV_POINTER
);
1914 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1916 g_object_unref(G_OBJECT(tracefiles_tree
));
1920 static void free_saved_state(LttvTraceState
*self
)
1924 LttvAttributeType type
;
1926 LttvAttributeValue value
;
1928 LttvAttributeName name
;
1932 LttvAttribute
*saved_states
;
1934 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1935 LTTV_STATE_SAVED_STATES
);
1937 nb
= lttv_attribute_get_number(saved_states
);
1938 for(i
= 0 ; i
< nb
; i
++) {
1939 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1940 g_assert(type
== LTTV_GOBJECT
);
1941 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1944 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1948 static void create_max_time(LttvTraceState
*tcs
)
1950 LttvAttributeValue v
;
1952 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1954 g_assert(*(v
.v_pointer
) == NULL
);
1955 *(v
.v_pointer
) = g_new(LttTime
,1);
1956 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1960 static void get_max_time(LttvTraceState
*tcs
)
1962 LttvAttributeValue v
;
1964 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1966 g_assert(*(v
.v_pointer
) != NULL
);
1967 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1971 static void free_max_time(LttvTraceState
*tcs
)
1973 LttvAttributeValue v
;
1975 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1977 g_free(*(v
.v_pointer
));
1978 *(v
.v_pointer
) = NULL
;
1981 static void create_name_tables(LttvTraceState
*tcs
)
1985 GString
*fe_name
= g_string_new("");
1987 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1989 LttvAttributeValue v
;
1993 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1995 g_assert(*(v
.v_pointer
) == NULL
);
1996 *(v
.v_pointer
) = name_tables
;
1998 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
2000 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2002 LTT_EVENT_SYSCALL_ENTRY
,
2003 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
2004 NULL
, NULL
, &hooks
)) {
2006 // th = lttv_trace_hook_get_first(&th);
2008 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2009 // nb = ltt_type_element_number(t);
2011 // name_tables->syscall_names = g_new(GQuark, nb);
2012 // name_tables->nb_syscalls = nb;
2014 // for(i = 0 ; i < nb ; i++) {
2015 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
2016 // if(!name_tables->syscall_names[i]) {
2017 // GString *string = g_string_new("");
2018 // g_string_printf(string, "syscall %u", i);
2019 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
2020 // g_string_free(string, TRUE);
2024 name_tables
->nb_syscalls
= PREALLOC_NB_SYSCALLS
;
2025 name_tables
->syscall_names
= g_new(GQuark
, name_tables
->nb_syscalls
);
2026 for(i
= 0 ; i
< name_tables
->nb_syscalls
; i
++) {
2027 g_string_printf(fe_name
, "syscall %d", i
);
2028 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2031 name_tables
->syscall_names
= NULL
;
2032 name_tables
->nb_syscalls
= 0;
2034 lttv_trace_hook_remove_all(&hooks
);
2036 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2038 LTT_EVENT_TRAP_ENTRY
,
2039 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2040 NULL
, NULL
, &hooks
) ||
2041 !lttv_trace_find_hook(tcs
->parent
.t
,
2043 LTT_EVENT_PAGE_FAULT_ENTRY
,
2044 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2045 NULL
, NULL
, &hooks
)) {
2047 // th = lttv_trace_hook_get_first(&th);
2049 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2050 // //nb = ltt_type_element_number(t);
2052 // name_tables->trap_names = g_new(GQuark, nb);
2053 // for(i = 0 ; i < nb ; i++) {
2054 // name_tables->trap_names[i] = g_quark_from_string(
2055 // ltt_enum_string_get(t, i));
2058 name_tables
->nb_traps
= PREALLOC_NB_TRAPS
;
2059 name_tables
->trap_names
= g_new(GQuark
, name_tables
->nb_traps
);
2060 for(i
= 0 ; i
< name_tables
->nb_traps
; i
++) {
2061 g_string_printf(fe_name
, "trap %d", i
);
2062 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2065 name_tables
->trap_names
= NULL
;
2066 name_tables
->nb_traps
= 0;
2068 lttv_trace_hook_remove_all(&hooks
);
2070 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2072 LTT_EVENT_IRQ_ENTRY
,
2073 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
2074 NULL
, NULL
, &hooks
)) {
2077 name_tables->irq_names = g_new(GQuark, nb);
2078 for(i = 0 ; i < nb ; i++) {
2079 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2082 /* FIXME: LttvIRQState *irq_states should become a g_array */
2084 name_tables
->nb_irqs
= PREALLOC_NB_IRQS
;
2085 name_tables
->irq_names
= g_new(GQuark
, name_tables
->nb_irqs
);
2086 for(i
= 0 ; i
< name_tables
->nb_irqs
; 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 name_tables
->nb_soft_irqs
= PREALLOC_NB_SOFT_IRQS
;
2103 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_soft_irqs
);
2104 for(i
= 0 ; i
< name_tables
->nb_soft_irqs
; i
++) {
2105 g_string_printf(fe_name
, "softirq %d", i
);
2106 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2108 g_array_free(hooks
, TRUE
);
2110 g_string_free(fe_name
, TRUE
);
2112 #if (__WORDSIZE == 32)
2113 name_tables
->kprobe_hash
= g_hash_table_new_full(guint64_hash
, guint64_equal
,
2116 name_tables
->kprobe_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2121 static void get_name_tables(LttvTraceState
*tcs
)
2123 LttvAttributeValue v
;
2125 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2127 g_assert(*(v
.v_pointer
) != NULL
);
2128 tcs
->name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2132 static void free_name_tables(LttvTraceState
*tcs
)
2134 LttvNameTables
*name_tables
;
2136 LttvAttributeValue v
;
2138 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2140 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2141 *(v
.v_pointer
) = NULL
;
2143 // g_free(name_tables->eventtype_names);
2144 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2145 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2146 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2147 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2148 g_hash_table_destroy(name_tables
->kprobe_hash
);
2149 g_free(name_tables
);
2152 #ifdef HASH_TABLE_DEBUG
2154 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2156 LttvProcessState
*process
= (LttvProcessState
*)value
;
2158 /* Test for process corruption */
2159 guint stack_len
= process
->execution_stack
->len
;
2162 static void hash_table_check(GHashTable
*table
)
2164 g_hash_table_foreach(table
, test_process
, NULL
);
2170 /* clears the stack and sets the state passed as argument */
2171 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2173 g_array_set_size(cpust
->mode_stack
, 1);
2174 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2177 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2179 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2180 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2183 static void cpu_pop_mode(LttvCPUState
*cpust
)
2185 if(cpust
->mode_stack
->len
<= 1)
2186 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2188 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2191 /* clears the stack and sets the state passed as argument */
2192 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2194 g_array_set_size(bdevst
->mode_stack
, 1);
2195 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2198 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2200 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2201 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2204 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2206 if(bdevst
->mode_stack
->len
<= 1)
2207 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2209 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2212 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2214 g_array_set_size(irqst
->mode_stack
, 1);
2215 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2218 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2220 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2221 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2224 static void irq_pop_mode(LttvIRQState
*irqst
)
2226 if(irqst
->mode_stack
->len
<= 1)
2227 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2229 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2232 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2235 LttvExecutionState
*es
;
2237 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2238 guint cpu
= tfs
->cpu
;
2240 #ifdef HASH_TABLE_DEBUG
2241 hash_table_check(ts
->processes
);
2243 LttvProcessState
*process
= ts
->running_process
[cpu
];
2245 guint depth
= process
->execution_stack
->len
;
2247 process
->execution_stack
=
2248 g_array_set_size(process
->execution_stack
, depth
+ 1);
2251 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2253 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2256 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2257 es
->cum_cpu_time
= ltt_time_zero
;
2258 es
->s
= process
->state
->s
;
2259 process
->state
= es
;
2263 * return 1 when empty, else 0 */
2265 lttv_state_pop_state_cleanup(LttvProcessState
*process
, LttvTracefileState
*tfs
)
2267 guint depth
= process
->execution_stack
->len
;
2273 process
->execution_stack
=
2274 g_array_set_size(process
->execution_stack
, depth
- 1);
2275 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2277 process
->state
->change
= tfs
->parent
.timestamp
;
2282 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2284 guint cpu
= tfs
->cpu
;
2285 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2286 LttvProcessState
*process
= ts
->running_process
[cpu
];
2288 guint depth
= process
->execution_stack
->len
;
2290 if(process
->state
->t
!= t
){
2291 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2292 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2293 g_info("process state has %s when pop_int is %s\n",
2294 g_quark_to_string(process
->state
->t
),
2295 g_quark_to_string(t
));
2296 g_info("{ %u, %u, %s, %s, %s }\n",
2299 g_quark_to_string(process
->name
),
2300 g_quark_to_string(process
->brand
),
2301 g_quark_to_string(process
->state
->s
));
2306 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2307 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2311 process
->execution_stack
=
2312 g_array_set_size(process
->execution_stack
, depth
- 1);
2313 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2315 process
->state
->change
= tfs
->parent
.timestamp
;
2318 struct search_result
{
2319 const LttTime
*time
; /* Requested time */
2320 LttTime
*best
; /* Best result */
2323 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2325 const LttTime
*elem_time
= (const LttTime
*)a
;
2326 /* Explicit non const cast */
2327 struct search_result
*res
= (struct search_result
*)b
;
2329 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2330 /* The usertrace was created before the schedchange */
2331 /* Get larger keys */
2333 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2334 /* The usertrace was created after the schedchange time */
2335 /* Get smaller keys */
2337 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2338 res
->best
= (LttTime
*)elem_time
;
2341 res
->best
= (LttTime
*)elem_time
;
2348 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2349 guint pid
, const LttTime
*timestamp
)
2351 LttvTracefileState
*tfs
= NULL
;
2352 struct search_result res
;
2353 /* Find the usertrace associated with a pid and time interval.
2354 * Search in the usertraces by PID (within a hash) and then, for each
2355 * corresponding element of the array, find the first one with creation
2356 * timestamp the lowest, but higher or equal to "timestamp". */
2357 res
.time
= timestamp
;
2359 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2360 GUINT_TO_POINTER(pid
));
2361 if(usertrace_tree
) {
2362 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2364 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2370 /* Return a new and initialized LttvProcessState structure */
2372 LttvProcessState
*lttv_state_create_process(LttvTraceState
*tcs
,
2373 LttvProcessState
*parent
, guint cpu
, guint pid
,
2374 guint tgid
, GQuark name
, const LttTime
*timestamp
)
2376 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2378 LttvExecutionState
*es
;
2383 process
->tgid
= tgid
;
2385 process
->name
= name
;
2386 process
->brand
= LTTV_STATE_UNBRANDED
;
2387 //process->last_cpu = tfs->cpu_name;
2388 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2389 process
->type
= LTTV_STATE_USER_THREAD
;
2390 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2391 process
->current_function
= 0; //function 0x0 by default.
2393 g_info("Process %u, core %p", process
->pid
, process
);
2394 g_hash_table_insert(tcs
->processes
, process
, process
);
2397 process
->ppid
= parent
->pid
;
2398 process
->creation_time
= *timestamp
;
2401 /* No parent. This process exists but we are missing all information about
2402 its creation. The birth time is set to zero but we remember the time of
2407 process
->creation_time
= ltt_time_zero
;
2410 process
->insertion_time
= *timestamp
;
2411 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2412 process
->creation_time
.tv_nsec
);
2413 process
->pid_time
= g_quark_from_string(buffer
);
2415 process
->free_events
= 0;
2416 //process->last_cpu = tfs->cpu_name;
2417 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2418 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2419 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2420 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2421 es
= process
->state
= &g_array_index(process
->execution_stack
,
2422 LttvExecutionState
, 0);
2423 es
->t
= LTTV_STATE_USER_MODE
;
2424 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2425 es
->entry
= *timestamp
;
2426 //g_assert(timestamp->tv_sec != 0);
2427 es
->change
= *timestamp
;
2428 es
->cum_cpu_time
= ltt_time_zero
;
2429 es
->s
= LTTV_STATE_RUN
;
2431 es
= process
->state
= &g_array_index(process
->execution_stack
,
2432 LttvExecutionState
, 1);
2433 es
->t
= LTTV_STATE_SYSCALL
;
2434 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2435 es
->entry
= *timestamp
;
2436 //g_assert(timestamp->tv_sec != 0);
2437 es
->change
= *timestamp
;
2438 es
->cum_cpu_time
= ltt_time_zero
;
2439 es
->s
= LTTV_STATE_WAIT_FORK
;
2441 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2442 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2443 sizeof(guint64
), 0);
2445 process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2451 lttv_state_find_process(LttvTraceState
*ts
, guint cpu
, guint pid
)
2453 LttvProcessState key
;
2454 LttvProcessState
*process
;
2458 process
= g_hash_table_lookup(ts
->processes
, &key
);
2462 LttvProcessState
*lttv_state_find_process_or_create(LttvTraceState
*ts
,
2463 guint cpu
, guint pid
, const LttTime
*timestamp
)
2465 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2466 LttvExecutionState
*es
;
2468 /* Put ltt_time_zero creation time for unexisting processes */
2469 if(unlikely(process
== NULL
)) {
2470 process
= lttv_state_create_process(ts
,
2471 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2472 /* We are not sure is it's a kernel thread or normal thread, put the
2473 * bottom stack state to unknown */
2474 process
->execution_stack
=
2475 g_array_set_size(process
->execution_stack
, 1);
2476 process
->state
= es
=
2477 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2478 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2479 es
->s
= LTTV_STATE_UNNAMED
;
2484 /* FIXME : this function should be called when we receive an event telling that
2485 * release_task has been called in the kernel. In happens generally when
2486 * the parent waits for its child termination, but may also happens in special
2487 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2488 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2489 * of a killed thread group, but isn't the leader.
2491 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2493 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2494 LttvProcessState key
;
2496 /* Wait for both schedule with exit dead and process free to happen.
2497 * They can happen in any order. */
2498 if (++(process
->free_events
) < 2)
2501 key
.pid
= process
->pid
;
2502 key
.cpu
= process
->cpu
;
2503 g_hash_table_remove(ts
->processes
, &key
);
2504 g_array_free(process
->execution_stack
, TRUE
);
2505 g_array_free(process
->user_stack
, TRUE
);
2507 /* the following also clears the content */
2508 g_hash_table_destroy(process
->fds
);
2515 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2517 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2518 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2520 /* the following also clears the content */
2521 g_hash_table_destroy(((LttvProcessState
*)value
)->fds
);
2527 static void lttv_state_free_process_table(GHashTable
*processes
)
2529 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2530 g_hash_table_destroy(processes
);
2534 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2536 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2538 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2539 LttvProcessState
*process
= ts
->running_process
[cpu
];
2540 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2541 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2542 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2543 LttvExecutionSubmode submode
;
2544 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2546 guint syscall
= ltt_event_get_unsigned(e
, f
);
2547 expand_syscall_table(ts
, syscall
);
2548 submode
= nt
->syscall_names
[syscall
];
2549 /* There can be no system call from PID 0 : unknown state */
2550 if(process
->pid
!= 0)
2551 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2556 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2558 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2560 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2561 LttvProcessState
*process
= ts
->running_process
[cpu
];
2563 /* There can be no system call from PID 0 : unknown state */
2564 if(process
->pid
!= 0)
2565 pop_state(s
, LTTV_STATE_SYSCALL
);
2570 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2572 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2573 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2574 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2575 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2576 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2577 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2579 LttvExecutionSubmode submode
;
2581 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2583 expand_trap_table(ts
, trap
);
2585 submode
= nt
->trap_names
[trap
];
2587 push_state(s
, LTTV_STATE_TRAP
, submode
);
2589 /* update cpu status */
2590 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2592 /* update trap status */
2593 g_array_append_val(s
->cpu_state
->trap_stack
, trap
);
2594 ts
->trap_states
[trap
].running
++;
2599 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2601 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2602 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2604 pop_state(s
, LTTV_STATE_TRAP
);
2606 /* update cpu status */
2607 cpu_pop_mode(s
->cpu_state
);
2609 /* update trap status */
2610 if (s
->cpu_state
->trap_stack
->len
> 0) {
2611 gint last
= g_array_index(s
->cpu_state
->trap_stack
, gint
,
2612 s
->cpu_state
->trap_stack
->len
-1);
2613 if(ts
->trap_states
[last
].running
)
2614 ts
->trap_states
[last
].running
--;
2615 g_array_remove_index(s
->cpu_state
->trap_stack
,
2616 s
->cpu_state
->trap_stack
->len
-1);
2621 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2623 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2624 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2625 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2626 //guint8 ev_id = ltt_event_eventtype_id(e);
2627 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2628 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2629 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2631 LttvExecutionSubmode submode
;
2632 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2634 expand_irq_table(ts
, irq
);
2636 submode
= nt
->irq_names
[irq
];
2638 /* Do something with the info about being in user or system mode when int? */
2639 push_state(s
, LTTV_STATE_IRQ
, submode
);
2641 /* update cpu status */
2642 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2644 /* update irq status */
2645 g_array_append_val(s
->cpu_state
->irq_stack
, irq
);
2646 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2651 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2653 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2654 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2656 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2658 /* update cpu status */
2659 cpu_pop_mode(s
->cpu_state
);
2661 /* update softirq status */
2662 if (s
->cpu_state
->softirq_stack
->len
> 0) {
2663 gint last
= g_array_index(s
->cpu_state
->softirq_stack
, gint
, s
->cpu_state
->softirq_stack
->len
-1);
2664 if(ts
->soft_irq_states
[last
].running
)
2665 ts
->soft_irq_states
[last
].running
--;
2666 g_array_remove_index(s
->cpu_state
->softirq_stack
, s
->cpu_state
->softirq_stack
->len
-1);
2671 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2673 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2674 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2676 pop_state(s
, LTTV_STATE_IRQ
);
2678 /* update cpu status */
2679 cpu_pop_mode(s
->cpu_state
);
2681 /* update irq status */
2682 if (s
->cpu_state
->irq_stack
->len
> 0) {
2683 gint last
= g_array_index(s
->cpu_state
->irq_stack
, gint
, s
->cpu_state
->irq_stack
->len
-1);
2684 g_array_remove_index(s
->cpu_state
->irq_stack
, s
->cpu_state
->irq_stack
->len
-1);
2685 irq_pop_mode(&ts
->irq_states
[last
]);
2691 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2693 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2694 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2695 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2696 //guint8 ev_id = ltt_event_eventtype_id(e);
2697 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2698 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2700 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2702 expand_soft_irq_table(ts
, softirq
);
2704 /* update softirq status */
2705 /* a soft irq raises are not cumulative */
2706 ts
->soft_irq_states
[softirq
].pending
=1;
2711 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2713 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2714 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2715 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2716 //guint8 ev_id = ltt_event_eventtype_id(e);
2717 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2718 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2719 LttvExecutionSubmode submode
;
2720 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2721 expand_soft_irq_table(ts
, softirq
);
2722 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2723 submode
= nt
->soft_irq_names
[softirq
];
2725 /* Do something with the info about being in user or system mode when int? */
2726 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2728 /* update cpu status */
2729 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2731 /* update softirq status */
2732 g_array_append_val(s
->cpu_state
->softirq_stack
, softirq
);
2733 if(ts
->soft_irq_states
[softirq
].pending
)
2734 ts
->soft_irq_states
[softirq
].pending
--;
2735 ts
->soft_irq_states
[softirq
].running
++;
2740 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2742 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2743 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2744 LttvNameTables
*nt
= ts
->name_tables
;
2745 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2746 //guint8 ev_id = ltt_event_eventtype_id(e);
2747 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2749 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2750 lttv_trace_get_hook_field(th
, 0)));
2751 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2753 expand_irq_table(ts
, irq
);
2754 nt
->irq_names
[irq
] = action
;
2760 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2762 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2763 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2764 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2765 //guint8 ev_id = ltt_event_eventtype_id(e);
2766 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2768 guint major
= ltt_event_get_long_unsigned(e
,
2769 lttv_trace_get_hook_field(th
, 0));
2770 guint minor
= ltt_event_get_long_unsigned(e
,
2771 lttv_trace_get_hook_field(th
, 1));
2772 guint oper
= ltt_event_get_long_unsigned(e
,
2773 lttv_trace_get_hook_field(th
, 2));
2774 guint32 devcode
= MKDEV(major
,minor
);
2776 /* have we seen this block device before? */
2777 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2780 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2782 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2787 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2789 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2790 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2791 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2792 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2794 guint major
= ltt_event_get_long_unsigned(e
,
2795 lttv_trace_get_hook_field(th
, 0));
2796 guint minor
= ltt_event_get_long_unsigned(e
,
2797 lttv_trace_get_hook_field(th
, 1));
2798 //guint oper = ltt_event_get_long_unsigned(e,
2799 // lttv_trace_get_hook_field(th, 2));
2800 guint32 devcode
= MKDEV(major
,minor
);
2802 /* have we seen this block device before? */
2803 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2805 /* update block device */
2806 bdev_pop_mode(bdev
);
2811 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2815 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2816 guint cpu
= tfs
->cpu
;
2817 LttvProcessState
*process
= ts
->running_process
[cpu
];
2819 guint depth
= process
->user_stack
->len
;
2821 process
->user_stack
=
2822 g_array_set_size(process
->user_stack
, depth
+ 1);
2824 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2825 *new_func
= funcptr
;
2826 process
->current_function
= funcptr
;
2829 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2831 guint cpu
= tfs
->cpu
;
2832 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2833 LttvProcessState
*process
= ts
->running_process
[cpu
];
2835 if(process
->current_function
!= funcptr
){
2836 g_info("Different functions (%lu.%09lu): ignore it\n",
2837 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2838 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2839 process
->current_function
, funcptr
);
2840 g_info("{ %u, %u, %s, %s, %s }\n",
2843 g_quark_to_string(process
->name
),
2844 g_quark_to_string(process
->brand
),
2845 g_quark_to_string(process
->state
->s
));
2848 guint depth
= process
->user_stack
->len
;
2851 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2852 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2856 process
->user_stack
=
2857 g_array_set_size(process
->user_stack
, depth
- 1);
2858 process
->current_function
=
2859 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2863 static gboolean
function_entry(void *hook_data
, void *call_data
)
2865 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2866 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2867 //guint8 ev_id = ltt_event_eventtype_id(e);
2868 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2869 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2870 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2872 push_function(s
, funcptr
);
2876 static gboolean
function_exit(void *hook_data
, void *call_data
)
2878 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2879 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2880 //guint8 ev_id = ltt_event_eventtype_id(e);
2881 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2882 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2883 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2885 pop_function(s
, funcptr
);
2889 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2891 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2892 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2893 LttvNameTables
*nt
= ts
->name_tables
;
2894 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2895 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2899 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2900 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2902 expand_syscall_table(ts
, id
);
2903 nt
->syscall_names
[id
] = g_quark_from_string(symbol
);
2908 static gboolean
dump_kprobe(void *hook_data
, void *call_data
)
2910 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2911 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2912 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2913 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2917 ip
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2918 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 1));
2920 expand_kprobe_table(ts
, ip
, symbol
);
2925 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2927 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2928 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2929 LttvNameTables
*nt
= ts
->name_tables
;
2930 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2931 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2935 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2936 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2938 expand_soft_irq_table(ts
, id
);
2939 nt
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2944 static gboolean
sched_try_wakeup(void *hook_data
, void *call_data
)
2946 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2947 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2948 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2949 LttvProcessState
*process
;
2953 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
2954 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2956 process
= lttv_state_find_process_or_create(
2957 (LttvTraceState
*)s
->parent
.t_context
,
2958 woken_cpu
, woken_pid
,
2959 &s
->parent
.timestamp
);
2961 if (process
->state
->s
== LTTV_STATE_WAIT
|| process
->state
->s
== LTTV_STATE_WAIT_FORK
)
2963 process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2964 process
->state
->change
= s
->parent
.timestamp
;
2967 g_debug("Wakeup: process %d on CPU %u\n", woken_pid
, woken_cpu
);
2972 static gboolean
schedchange(void *hook_data
, void *call_data
)
2974 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2976 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2977 LttvProcessState
*process
= ts
->running_process
[cpu
];
2978 //LttvProcessState *old_process = ts->running_process[cpu];
2980 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2981 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2982 guint pid_in
, pid_out
;
2985 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2986 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2987 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2989 if(likely(process
!= NULL
)) {
2991 /* We could not know but it was not the idle process executing.
2992 This should only happen at the beginning, before the first schedule
2993 event, and when the initial information (current process for each CPU)
2994 is missing. It is not obvious how we could, after the fact, compensate
2995 the wrongly attributed statistics. */
2997 //This test only makes sense once the state is known and if there is no
2998 //missing events. We need to silently ignore schedchange coming after a
2999 //process_free, or it causes glitches. (FIXME)
3000 //if(unlikely(process->pid != pid_out)) {
3001 // g_assert(process->pid == 0);
3003 if(process
->pid
== 0
3004 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3007 * Scheduling out of pid 0 at beginning of the trace.
3008 * We are typically in system call mode at this point although
3009 * (FIXME) we might be in a trap handler.
3011 g_assert(process
->execution_stack
->len
== 1);
3012 process
->state
->t
= LTTV_STATE_SYSCALL
;
3013 process
->state
->s
= LTTV_STATE_WAIT
;
3014 process
->state
->change
= s
->parent
.timestamp
;
3015 process
->state
->entry
= s
->parent
.timestamp
;
3018 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
3019 process
->state
->s
= LTTV_STATE_ZOMBIE
;
3020 process
->state
->change
= s
->parent
.timestamp
;
3022 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
3023 else process
->state
->s
= LTTV_STATE_WAIT
;
3024 process
->state
->change
= s
->parent
.timestamp
;
3027 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
3028 /* see sched.h for states */
3029 if (!exit_process(s
, process
)) {
3030 process
->state
->s
= LTTV_STATE_DEAD
;
3031 process
->state
->change
= s
->parent
.timestamp
;
3036 process
= ts
->running_process
[cpu
] = lttv_state_find_process_or_create(
3037 (LttvTraceState
*)s
->parent
.t_context
,
3039 &s
->parent
.timestamp
);
3040 process
->state
->s
= LTTV_STATE_RUN
;
3042 if(process
->usertrace
)
3043 process
->usertrace
->cpu
= cpu
;
3044 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3045 process
->state
->change
= s
->parent
.timestamp
;
3047 /* update cpu status */
3049 /* going to idle task */
3050 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
3052 /* scheduling a real task.
3053 * we must be careful here:
3054 * if we just schedule()'ed to a process that is
3055 * in a trap, we must put the cpu in trap mode
3057 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
3058 if(process
->state
->t
== LTTV_STATE_TRAP
)
3059 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
3065 static gboolean
process_fork(void *hook_data
, void *call_data
)
3067 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3068 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3069 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3070 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
3071 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
3072 //LttvProcessState *zombie_process;
3074 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3075 LttvProcessState
*process
= ts
->running_process
[cpu
];
3076 LttvProcessState
*child_process
;
3077 struct marker_field
*f
;
3079 /* Skip Parent PID param */
3082 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3083 s
->parent
.target_pid
= child_pid
;
3086 f
= lttv_trace_get_hook_field(th
, 2);
3088 child_tgid
= ltt_event_get_unsigned(e
, f
);
3092 /* Mathieu : it seems like the process might have been scheduled in before the
3093 * fork, and, in a rare case, might be the current process. This might happen
3094 * in a SMP case where we don't have enough precision on the clocks.
3096 * Test reenabled after precision fixes on time. (Mathieu) */
3098 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3100 if(unlikely(zombie_process
!= NULL
)) {
3101 /* Reutilisation of PID. Only now we are sure that the old PID
3102 * has been released. FIXME : should know when release_task happens instead.
3104 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3106 for(i
=0; i
< num_cpus
; i
++) {
3107 g_assert(zombie_process
!= ts
->running_process
[i
]);
3110 exit_process(s
, zombie_process
);
3113 g_assert(process
->pid
!= child_pid
);
3114 // FIXME : Add this test in the "known state" section
3115 // g_assert(process->pid == parent_pid);
3116 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3117 if(child_process
== NULL
) {
3118 child_process
= lttv_state_create_process(ts
, process
, cpu
,
3119 child_pid
, child_tgid
,
3120 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
3122 /* The process has already been created : due to time imprecision between
3123 * multiple CPUs : it has been scheduled in before creation. Note that we
3124 * shouldn't have this kind of imprecision.
3126 * Simply put a correct parent.
3128 g_error("Process %u has been created at [%lu.%09lu] "
3129 "and inserted at [%lu.%09lu] before \n"
3130 "fork on cpu %u[%lu.%09lu].\n"
3131 "Probably an unsynchronized TSC problem on the traced machine.",
3133 child_process
->creation_time
.tv_sec
,
3134 child_process
->creation_time
.tv_nsec
,
3135 child_process
->insertion_time
.tv_sec
,
3136 child_process
->insertion_time
.tv_nsec
,
3137 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
3138 //g_assert(0); /* This is a problematic case : the process has been created
3139 // before the fork event */
3140 child_process
->ppid
= process
->pid
;
3141 child_process
->tgid
= child_tgid
;
3143 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
3144 child_process
->name
= process
->name
;
3145 child_process
->brand
= process
->brand
;
3150 /* We stamp a newly created process as kernel_thread.
3151 * The thread should not be running yet. */
3152 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
3154 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3155 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3156 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3158 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3159 LttvProcessState
*process
;
3160 LttvExecutionState
*es
;
3163 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3164 s
->parent
.target_pid
= pid
;
3166 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3168 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3169 process
->execution_stack
=
3170 g_array_set_size(process
->execution_stack
, 1);
3171 es
= process
->state
=
3172 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3173 es
->t
= LTTV_STATE_SYSCALL
;
3175 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3180 static gboolean
process_exit(void *hook_data
, void *call_data
)
3182 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3183 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3184 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3186 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3187 LttvProcessState
*process
; // = ts->running_process[cpu];
3189 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3190 s
->parent
.target_pid
= pid
;
3192 // FIXME : Add this test in the "known state" section
3193 // g_assert(process->pid == pid);
3195 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3196 if(likely(process
!= NULL
)) {
3197 process
->state
->s
= LTTV_STATE_EXIT
;
3202 static gboolean
process_free(void *hook_data
, void *call_data
)
3204 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3205 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3206 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3207 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3209 LttvProcessState
*process
;
3211 /* PID of the process to release */
3212 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3213 s
->parent
.target_pid
= release_pid
;
3215 g_assert(release_pid
!= 0);
3217 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3218 if(likely(process
!= NULL
))
3219 exit_process(s
, process
);
3222 if(likely(process
!= NULL
)) {
3223 /* release_task is happening at kernel level : we can now safely release
3224 * the data structure of the process */
3225 //This test is fun, though, as it may happen that
3226 //at time t : CPU 0 : process_free
3227 //at time t+150ns : CPU 1 : schedule out
3228 //Clearly due to time imprecision, we disable it. (Mathieu)
3229 //If this weird case happen, we have no choice but to put the
3230 //Currently running process on the cpu to 0.
3231 //I re-enable it following time precision fixes. (Mathieu)
3232 //Well, in the case where an process is freed by a process on another CPU
3233 //and still scheduled, it happens that this is the schedchange that will
3234 //drop the last reference count. Do not free it here!
3235 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3237 for(i
=0; i
< num_cpus
; i
++) {
3238 //g_assert(process != ts->running_process[i]);
3239 if(process
== ts
->running_process
[i
]) {
3240 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3244 if(i
== num_cpus
) /* process is not scheduled */
3245 exit_process(s
, process
);
3252 static gboolean
process_exec(void *hook_data
, void *call_data
)
3254 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3255 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3256 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3257 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3260 LttvProcessState
*process
= ts
->running_process
[cpu
];
3262 #if 0//how to use a sequence that must be transformed in a string
3263 /* PID of the process to release */
3264 guint64 name_len
= ltt_event_field_element_number(e
,
3265 lttv_trace_get_hook_field(th
, 0));
3266 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3267 LttField
*child
= ltt_event_field_element_select(e
,
3268 lttv_trace_get_hook_field(th
, 0), 0);
3270 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3271 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3272 memcpy(null_term_name
, name_begin
, name_len
);
3273 null_term_name
[name_len
] = '\0';
3274 process
->name
= g_quark_from_string(null_term_name
);
3277 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3278 lttv_trace_get_hook_field(th
, 0)));
3279 process
->brand
= LTTV_STATE_UNBRANDED
;
3280 //g_free(null_term_name);
3284 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3286 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3287 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3288 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3289 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3292 LttvProcessState
*process
= ts
->running_process
[cpu
];
3294 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3295 process
->brand
= g_quark_from_string(name
);
3300 static gboolean
fs_open(void *hook_data
, void *call_data
)
3302 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3303 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3304 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3305 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3306 struct marker_field
*f
;
3310 LttvProcessState
*process
= ts
->running_process
[cpu
];
3312 f
= lttv_trace_get_hook_field(th
, 0);
3313 fd
= ltt_event_get_int(e
, f
);
3315 f
= lttv_trace_get_hook_field(th
, 1);
3316 filename
= ltt_event_get_string(e
, f
);
3318 g_hash_table_insert(process
->fds
, (gpointer
)(long)fd
,
3319 (gpointer
)(unsigned long)g_quark_from_string(filename
));
3324 static void print_stack(LttvProcessState
*process
)
3326 LttvExecutionState
*es
;
3329 g_debug("Execution stack for process %u %s:\n",
3330 process
->pid
, g_quark_to_string(process
->name
));
3332 for (i
= 0; i
< process
->execution_stack
->len
; i
++) {
3333 es
= &g_array_index(process
->execution_stack
,
3334 LttvExecutionState
, i
);
3335 g_debug("Depth %d mode %s submode %s status %s\n",
3336 i
, g_quark_to_string(es
->t
),
3337 g_quark_to_string(es
->n
),
3338 g_quark_to_string(es
->s
));
3343 static void fix_process(gpointer key
, gpointer value
, gpointer user_data
)
3345 LttvProcessState
*process
;
3346 LttvExecutionState
*es
;
3347 process
= (LttvProcessState
*)value
;
3348 LttTime
*timestamp
= (LttTime
*)user_data
;
3350 print_stack(process
);
3352 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3353 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3354 if(es
->t
== LTTV_STATE_MAYBE_SYSCALL
) {
3355 es
->t
= LTTV_STATE_SYSCALL
;
3356 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3357 es
->entry
= *timestamp
;
3358 es
->change
= *timestamp
;
3359 es
->cum_cpu_time
= ltt_time_zero
;
3360 if(es
->s
== LTTV_STATE_UNNAMED
)
3361 es
->s
= LTTV_STATE_WAIT
;
3364 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3365 if(es
->t
== LTTV_STATE_MAYBE_USER_MODE
) {
3366 es
->t
= LTTV_STATE_USER_MODE
;
3367 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3368 es
->entry
= *timestamp
;
3369 //g_assert(timestamp->tv_sec != 0);
3370 es
->change
= *timestamp
;
3371 es
->cum_cpu_time
= ltt_time_zero
;
3372 if(es
->s
== LTTV_STATE_UNNAMED
)
3373 es
->s
= LTTV_STATE_RUN
;
3375 if(process
->execution_stack
->len
== 1) {
3376 /* Still in bottom unknown mode, means we either:
3377 * - never did a system call
3378 * - are scheduled out from user mode.
3379 * May be either in user mode, syscall mode, running or waiting.*/
3380 /* CHECK : we may be tagging syscall mode when being user mode
3381 * (should be fixed now) */
3382 if (es
->s
== LTTV_STATE_WAIT_CPU
) {
3383 /* nothing to do: scheduled out from userspace */
3385 process
->execution_stack
=
3386 g_array_set_size(process
->execution_stack
, 2);
3387 es
= process
->state
= &g_array_index(process
->execution_stack
,
3388 LttvExecutionState
, 1);
3389 es
->t
= LTTV_STATE_SYSCALL
;
3390 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3391 es
->entry
= *timestamp
;
3392 //g_assert(timestamp->tv_sec != 0);
3393 es
->change
= *timestamp
;
3394 es
->cum_cpu_time
= ltt_time_zero
;
3395 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3396 es
->s
= LTTV_STATE_WAIT
;
3403 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3405 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3406 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3407 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3408 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3409 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3411 /* For all processes */
3412 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3413 /* else, if stack[0] is unknown, set to user mode, running */
3415 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3420 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3422 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3423 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3424 //It's slow : optimise later by doing this before reading trace.
3425 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3431 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3432 LttvProcessState
*process
= ts
->running_process
[cpu
];
3433 LttvProcessState
*parent_process
;
3434 struct marker_field
*f
;
3436 LttvExecutionState
*es
;
3440 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3441 s
->parent
.target_pid
= pid
;
3444 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3447 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3450 f
= lttv_trace_get_hook_field(th
, 3);
3451 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3453 //FIXME: type is rarely used, enum must match possible types.
3455 /* Skip mode 4th param */
3457 /* Skip submode 5th param */
3459 /* Skip status 6th param */
3462 f
= lttv_trace_get_hook_field(th
, 7);
3464 tgid
= ltt_event_get_unsigned(e
, f
);
3469 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3470 for(i
=0; i
<nb_cpus
; i
++) {
3471 process
= lttv_state_find_process(ts
, i
, pid
);
3472 g_assert(process
!= NULL
);
3474 process
->ppid
= parent_pid
;
3475 process
->tgid
= tgid
;
3476 process
->name
= g_quark_from_string(command
);
3477 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3478 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3482 /* The process might exist if a process was forked while performing the
3484 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3485 if(process
== NULL
) {
3486 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3487 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3488 pid
, tgid
, g_quark_from_string(command
),
3489 &s
->parent
.timestamp
);
3491 /* Keep the stack bottom : a running user mode */
3492 /* Disabled because of inconsistencies in the current statedump states. */
3493 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3494 /* Only keep the bottom
3495 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3496 /* Will cause expected trap when in fact being syscall (even after end of
3498 * Will cause expected interrupt when being syscall. (only before end of
3499 * statedump event) */
3500 // This will cause a "popping last state on stack, ignoring it."
3501 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3502 es
= process
->state
= &g_array_index(process
->execution_stack
,
3503 LttvExecutionState
, 0);
3504 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3505 es
->t
= LTTV_STATE_MAYBE_SYSCALL
;
3506 es
->s
= LTTV_STATE_UNNAMED
;
3507 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3511 /* User space process :
3512 * bottom : user mode
3513 * either currently running or scheduled out.
3514 * can be scheduled out because interrupted in (user mode or in syscall)
3515 * or because of an explicit call to the scheduler in syscall. Note that
3516 * the scheduler call comes after the irq_exit, so never in interrupt
3518 // temp workaround : set size to 1 : only have user mode bottom of stack.
3519 // will cause g_info message of expected syscall mode when in fact being
3520 // in user mode. Can also cause expected trap when in fact being user
3521 // mode in the event of a page fault reenabling interrupts in the handler.
3522 // Expected syscall and trap can also happen after the end of statedump
3523 // This will cause a "popping last state on stack, ignoring it."
3524 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3525 es
= process
->state
= &g_array_index(process
->execution_stack
,
3526 LttvExecutionState
, 0);
3527 es
->t
= LTTV_STATE_MAYBE_USER_MODE
;
3528 es
->s
= LTTV_STATE_UNNAMED
;
3529 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3536 es
= process
->state
= &g_array_index(process
->execution_stack
,
3537 LttvExecutionState
, 1);
3538 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3539 es
->s
= LTTV_STATE_UNNAMED
;
3540 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3544 /* The process has already been created :
3545 * Probably was forked while dumping the process state or
3546 * was simply scheduled in prior to get the state dump event.
3548 process
->ppid
= parent_pid
;
3549 process
->tgid
= tgid
;
3550 process
->name
= g_quark_from_string(command
);
3551 process
->type
= type
;
3552 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3554 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3555 if(type
== LTTV_STATE_KERNEL_THREAD
)
3556 es
->t
= LTTV_STATE_SYSCALL
;
3558 es
->t
= LTTV_STATE_USER_MODE
;
3561 /* Don't mess around with the stack, it will eventually become
3562 * ok after the end of state dump. */
3569 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3571 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3573 lttv_state_add_event_hooks(tss
);
3578 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3580 LttvTraceset
*traceset
= self
->parent
.ts
;
3582 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3586 LttvTracefileState
*tfs
;
3592 LttvAttributeValue val
;
3594 nb_trace
= lttv_traceset_number(traceset
);
3595 for(i
= 0 ; i
< nb_trace
; i
++) {
3596 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3598 /* Find the eventtype id for the following events and register the
3599 associated by id hooks. */
3601 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 20);
3602 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3605 lttv_trace_find_hook(ts
->parent
.t
,
3607 LTT_EVENT_SYSCALL_ENTRY
,
3608 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3609 syscall_entry
, NULL
, &hooks
);
3611 lttv_trace_find_hook(ts
->parent
.t
,
3613 LTT_EVENT_SYSCALL_EXIT
,
3615 syscall_exit
, NULL
, &hooks
);
3617 lttv_trace_find_hook(ts
->parent
.t
,
3619 LTT_EVENT_TRAP_ENTRY
,
3620 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3621 trap_entry
, NULL
, &hooks
);
3623 lttv_trace_find_hook(ts
->parent
.t
,
3625 LTT_EVENT_TRAP_EXIT
,
3627 trap_exit
, NULL
, &hooks
);
3629 lttv_trace_find_hook(ts
->parent
.t
,
3631 LTT_EVENT_PAGE_FAULT_ENTRY
,
3632 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3633 trap_entry
, NULL
, &hooks
);
3635 lttv_trace_find_hook(ts
->parent
.t
,
3637 LTT_EVENT_PAGE_FAULT_EXIT
,
3639 trap_exit
, NULL
, &hooks
);
3641 lttv_trace_find_hook(ts
->parent
.t
,
3643 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3644 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3645 trap_entry
, NULL
, &hooks
);
3647 lttv_trace_find_hook(ts
->parent
.t
,
3649 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3651 trap_exit
, NULL
, &hooks
);
3653 lttv_trace_find_hook(ts
->parent
.t
,
3655 LTT_EVENT_IRQ_ENTRY
,
3656 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3657 irq_entry
, NULL
, &hooks
);
3659 lttv_trace_find_hook(ts
->parent
.t
,
3663 irq_exit
, NULL
, &hooks
);
3665 lttv_trace_find_hook(ts
->parent
.t
,
3667 LTT_EVENT_SOFT_IRQ_RAISE
,
3668 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3669 soft_irq_raise
, NULL
, &hooks
);
3671 lttv_trace_find_hook(ts
->parent
.t
,
3673 LTT_EVENT_SOFT_IRQ_ENTRY
,
3674 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3675 soft_irq_entry
, NULL
, &hooks
);
3677 lttv_trace_find_hook(ts
->parent
.t
,
3679 LTT_EVENT_SOFT_IRQ_EXIT
,
3681 soft_irq_exit
, NULL
, &hooks
);
3683 lttv_trace_find_hook(ts
->parent
.t
,
3685 LTT_EVENT_SCHED_SCHEDULE
,
3686 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3687 LTT_FIELD_PREV_STATE
),
3688 schedchange
, NULL
, &hooks
);
3690 lttv_trace_find_hook(ts
->parent
.t
,
3692 LTT_EVENT_SCHED_TRY_WAKEUP
,
3693 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_CPU_ID
, LTT_FIELD_STATE
),
3694 sched_try_wakeup
, NULL
, &hooks
);
3696 lttv_trace_find_hook(ts
->parent
.t
,
3698 LTT_EVENT_PROCESS_FORK
,
3699 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3700 LTT_FIELD_CHILD_TGID
),
3701 process_fork
, NULL
, &hooks
);
3703 lttv_trace_find_hook(ts
->parent
.t
,
3705 LTT_EVENT_KTHREAD_CREATE
,
3706 FIELD_ARRAY(LTT_FIELD_PID
),
3707 process_kernel_thread
, NULL
, &hooks
);
3709 lttv_trace_find_hook(ts
->parent
.t
,
3711 LTT_EVENT_PROCESS_EXIT
,
3712 FIELD_ARRAY(LTT_FIELD_PID
),
3713 process_exit
, NULL
, &hooks
);
3715 lttv_trace_find_hook(ts
->parent
.t
,
3717 LTT_EVENT_PROCESS_FREE
,
3718 FIELD_ARRAY(LTT_FIELD_PID
),
3719 process_free
, NULL
, &hooks
);
3721 lttv_trace_find_hook(ts
->parent
.t
,
3724 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3725 process_exec
, NULL
, &hooks
);
3727 lttv_trace_find_hook(ts
->parent
.t
,
3728 LTT_CHANNEL_USERSPACE
,
3729 LTT_EVENT_THREAD_BRAND
,
3730 FIELD_ARRAY(LTT_FIELD_NAME
),
3731 thread_brand
, NULL
, &hooks
);
3733 /* statedump-related hooks */
3734 lttv_trace_find_hook(ts
->parent
.t
,
3735 LTT_CHANNEL_TASK_STATE
,
3736 LTT_EVENT_PROCESS_STATE
,
3737 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3738 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3739 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3740 enum_process_state
, NULL
, &hooks
);
3742 lttv_trace_find_hook(ts
->parent
.t
,
3743 LTT_CHANNEL_GLOBAL_STATE
,
3744 LTT_EVENT_STATEDUMP_END
,
3746 statedump_end
, NULL
, &hooks
);
3748 lttv_trace_find_hook(ts
->parent
.t
,
3749 LTT_CHANNEL_IRQ_STATE
,
3750 LTT_EVENT_LIST_INTERRUPT
,
3751 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3752 enum_interrupt
, NULL
, &hooks
);
3754 lttv_trace_find_hook(ts
->parent
.t
,
3756 LTT_EVENT_REQUEST_ISSUE
,
3757 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3758 bdev_request_issue
, NULL
, &hooks
);
3760 lttv_trace_find_hook(ts
->parent
.t
,
3762 LTT_EVENT_REQUEST_COMPLETE
,
3763 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3764 bdev_request_complete
, NULL
, &hooks
);
3766 lttv_trace_find_hook(ts
->parent
.t
,
3767 LTT_CHANNEL_USERSPACE
,
3768 LTT_EVENT_FUNCTION_ENTRY
,
3769 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3770 function_entry
, NULL
, &hooks
);
3772 lttv_trace_find_hook(ts
->parent
.t
,
3773 LTT_CHANNEL_USERSPACE
,
3774 LTT_EVENT_FUNCTION_EXIT
,
3775 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3776 function_exit
, NULL
, &hooks
);
3778 lttv_trace_find_hook(ts
->parent
.t
,
3779 LTT_CHANNEL_SYSCALL_STATE
,
3780 LTT_EVENT_SYS_CALL_TABLE
,
3781 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3782 dump_syscall
, NULL
, &hooks
);
3784 lttv_trace_find_hook(ts
->parent
.t
,
3785 LTT_CHANNEL_KPROBE_STATE
,
3786 LTT_EVENT_KPROBE_TABLE
,
3787 FIELD_ARRAY(LTT_FIELD_IP
, LTT_FIELD_SYMBOL
),
3788 dump_kprobe
, NULL
, &hooks
);
3790 lttv_trace_find_hook(ts
->parent
.t
,
3791 LTT_CHANNEL_SOFTIRQ_STATE
,
3792 LTT_EVENT_SOFTIRQ_VEC
,
3793 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3794 dump_softirq
, NULL
, &hooks
);
3796 lttv_trace_find_hook(ts
->parent
.t
,
3799 FIELD_ARRAY(LTT_FIELD_FD
, LTT_FIELD_FILENAME
),
3800 fs_open
, NULL
, &hooks
);
3802 /* Add these hooks to each event_by_id hooks list */
3804 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3806 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3808 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3809 LttvTracefileContext
*, j
));
3811 for(k
= 0 ; k
< hooks
->len
; k
++) {
3812 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3813 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3815 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3821 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3822 *(val
.v_pointer
) = hooks
;
3826 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3828 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3830 lttv_state_remove_event_hooks(tss
);
3835 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3837 LttvTraceset
*traceset
= self
->parent
.ts
;
3839 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3843 LttvTracefileState
*tfs
;
3849 LttvAttributeValue val
;
3851 nb_trace
= lttv_traceset_number(traceset
);
3852 for(i
= 0 ; i
< nb_trace
; i
++) {
3853 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3855 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3856 hooks
= *(val
.v_pointer
);
3858 /* Remove these hooks from each event_by_id hooks list */
3860 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3862 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3864 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3865 LttvTracefileContext
*, j
));
3867 for(k
= 0 ; k
< hooks
->len
; k
++) {
3868 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3869 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3870 lttv_hooks_remove_data(
3871 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3876 lttv_trace_hook_remove_all(&hooks
);
3877 g_array_free(hooks
, TRUE
);
3881 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3883 guint
*event_count
= (guint
*)hook_data
;
3885 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3886 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3891 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3893 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3895 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3897 LttvAttributeValue value
;
3899 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3900 LTTV_STATE_SAVED_STATES
);
3901 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3902 value
= lttv_attribute_add(saved_states_tree
,
3903 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3904 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3905 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3906 *(value
.v_time
) = self
->parent
.timestamp
;
3907 lttv_state_save(tcs
, saved_state_tree
);
3908 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3909 self
->parent
.timestamp
.tv_nsec
);
3911 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3916 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3918 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3920 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3925 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3933 static gboolean
block_start(void *hook_data
, void *call_data
)
3935 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3937 LttvTracefileState
*tfcs
;
3939 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3941 LttEventPosition
*ep
;
3943 guint i
, nb_block
, nb_event
, nb_tracefile
;
3947 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3949 LttvAttributeValue value
;
3951 ep
= ltt_event_position_new();
3953 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3955 /* Count the number of events added since the last block end in any
3958 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3960 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3961 LttvTracefileContext
, i
));
3962 ltt_event_position(tfcs
->parent
.e
, ep
);
3963 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3964 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3965 tfcs
->saved_position
= nb_event
;
3969 if(tcs
->nb_event
>= tcs
->save_interval
) {
3970 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3971 LTTV_STATE_SAVED_STATES
);
3972 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3973 value
= lttv_attribute_add(saved_states_tree
,
3974 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3975 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3976 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3977 *(value
.v_time
) = self
->parent
.timestamp
;
3978 lttv_state_save(tcs
, saved_state_tree
);
3980 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3981 self
->parent
.timestamp
.tv_nsec
);
3983 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3989 static gboolean
block_end(void *hook_data
, void *call_data
)
3991 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3993 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3997 LttEventPosition
*ep
;
3999 guint nb_block
, nb_event
;
4001 ep
= ltt_event_position_new();
4002 ltt_event_position(self
->parent
.e
, ep
);
4003 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
4004 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
4005 self
->saved_position
= 0;
4006 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4013 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4015 LttvTraceset
*traceset
= self
->parent
.ts
;
4017 guint i
, j
, nb_trace
, nb_tracefile
;
4021 LttvTracefileState
*tfs
;
4023 LttvTraceHook hook_start
, hook_end
;
4025 nb_trace
= lttv_traceset_number(traceset
);
4026 for(i
= 0 ; i
< nb_trace
; i
++) {
4027 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4029 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4030 NULL
, NULL
, block_start
, &hook_start
);
4031 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4032 NULL
, NULL
, block_end
, &hook_end
);
4034 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4036 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4038 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4039 LttvTracefileContext
, j
));
4040 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4041 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
4042 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4043 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
4049 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4051 LttvTraceset
*traceset
= self
->parent
.ts
;
4053 guint i
, j
, nb_trace
, nb_tracefile
;
4057 LttvTracefileState
*tfs
;
4060 nb_trace
= lttv_traceset_number(traceset
);
4061 for(i
= 0 ; i
< nb_trace
; i
++) {
4063 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4064 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4066 if(ts
->has_precomputed_states
) continue;
4068 guint
*event_count
= g_new(guint
, 1);
4071 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4073 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4074 LttvTracefileContext
*, j
));
4075 lttv_hooks_add(tfs
->parent
.event
,
4076 state_save_event_hook
,
4083 lttv_process_traceset_begin(&self
->parent
,
4084 NULL
, NULL
, NULL
, NULL
, NULL
);
4088 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
4090 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4092 lttv_state_save_add_event_hooks(tss
);
4099 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4101 LttvTraceset
*traceset
= self
->parent
.ts
;
4103 guint i
, j
, nb_trace
, nb_tracefile
;
4107 LttvTracefileState
*tfs
;
4109 LttvTraceHook hook_start
, hook_end
;
4111 nb_trace
= lttv_traceset_number(traceset
);
4112 for(i
= 0 ; i
< nb_trace
; i
++) {
4113 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
4115 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4116 NULL
, NULL
, block_start
, &hook_start
);
4118 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4119 NULL
, NULL
, block_end
, &hook_end
);
4121 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4123 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4125 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4126 LttvTracefileContext
, j
));
4127 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4128 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
4129 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4130 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
4136 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4138 LttvTraceset
*traceset
= self
->parent
.ts
;
4140 guint i
, j
, nb_trace
, nb_tracefile
;
4144 LttvTracefileState
*tfs
;
4146 LttvHooks
*after_trace
= lttv_hooks_new();
4148 lttv_hooks_add(after_trace
,
4149 state_save_after_trace_hook
,
4154 lttv_process_traceset_end(&self
->parent
,
4155 NULL
, after_trace
, NULL
, NULL
, NULL
);
4157 lttv_hooks_destroy(after_trace
);
4159 nb_trace
= lttv_traceset_number(traceset
);
4160 for(i
= 0 ; i
< nb_trace
; i
++) {
4162 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4163 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4165 if(ts
->has_precomputed_states
) continue;
4167 guint
*event_count
= NULL
;
4169 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4171 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4172 LttvTracefileContext
*, j
));
4173 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
4174 state_save_event_hook
);
4176 if(event_count
) g_free(event_count
);
4180 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
4182 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4184 lttv_state_save_remove_event_hooks(tss
);
4189 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
4191 LttvTraceset
*traceset
= self
->parent
.ts
;
4195 int min_pos
, mid_pos
, max_pos
;
4197 guint call_rest
= 0;
4199 LttvTraceState
*tcs
;
4201 LttvAttributeValue value
;
4203 LttvAttributeType type
;
4205 LttvAttributeName name
;
4209 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
4211 //g_tree_destroy(self->parent.pqueue);
4212 //self->parent.pqueue = g_tree_new(compare_tracefile);
4214 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
4216 nb_trace
= lttv_traceset_number(traceset
);
4217 for(i
= 0 ; i
< nb_trace
; i
++) {
4218 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4220 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4221 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4222 LTTV_STATE_SAVED_STATES
);
4225 if(saved_states_tree
) {
4226 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4227 mid_pos
= max_pos
/ 2;
4228 while(min_pos
< max_pos
) {
4229 type
= lttv_attribute_get(saved_states_tree
, mid_pos
,
4230 &name
, &value
, &is_named
);
4231 g_assert(type
== LTTV_GOBJECT
);
4232 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4233 type
= lttv_attribute_get_by_name(saved_state_tree
,
4234 LTTV_STATE_TIME
, &value
);
4235 g_assert(type
== LTTV_TIME
);
4236 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4238 closest_tree
= saved_state_tree
;
4240 else max_pos
= mid_pos
- 1;
4242 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4246 /* restore the closest earlier saved state */
4248 lttv_state_restore(tcs
, closest_tree
);
4252 /* There is no saved state, yet we want to have it. Restart at T0 */
4254 restore_init_state(tcs
);
4255 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4258 /* We want to seek quickly without restoring/updating the state */
4260 restore_init_state(tcs
);
4261 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4264 if(!call_rest
) g_info("NOT Calling restore");
4268 static void traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4273 static void traceset_state_finalize (LttvTracesetState
*self
)
4275 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4276 finalize(G_OBJECT(self
));
4280 static void traceset_state_class_init (LttvTracesetContextClass
*klass
)
4282 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4284 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4285 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4286 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4287 klass
->new_traceset_context
= new_traceset_context
;
4288 klass
->new_trace_context
= new_trace_context
;
4289 klass
->new_tracefile_context
= new_tracefile_context
;
4293 GType
lttv_traceset_state_get_type(void)
4295 static GType type
= 0;
4297 static const GTypeInfo info
= {
4298 sizeof (LttvTracesetStateClass
),
4299 NULL
, /* base_init */
4300 NULL
, /* base_finalize */
4301 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4302 NULL
, /* class_finalize */
4303 NULL
, /* class_data */
4304 sizeof (LttvTracesetState
),
4305 0, /* n_preallocs */
4306 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4307 NULL
/* value handling */
4310 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4317 static void trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4322 static void trace_state_finalize (LttvTraceState
*self
)
4324 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4325 finalize(G_OBJECT(self
));
4329 static void trace_state_class_init (LttvTraceStateClass
*klass
)
4331 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4333 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4334 klass
->state_save
= state_save
;
4335 klass
->state_restore
= state_restore
;
4336 klass
->state_saved_free
= state_saved_free
;
4340 GType
lttv_trace_state_get_type(void)
4342 static GType type
= 0;
4344 static const GTypeInfo info
= {
4345 sizeof (LttvTraceStateClass
),
4346 NULL
, /* base_init */
4347 NULL
, /* base_finalize */
4348 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4349 NULL
, /* class_finalize */
4350 NULL
, /* class_data */
4351 sizeof (LttvTraceState
),
4352 0, /* n_preallocs */
4353 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4354 NULL
/* value handling */
4357 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4358 "LttvTraceStateType", &info
, 0);
4364 static void tracefile_state_instance_init (GTypeInstance
*instance
,
4370 static void tracefile_state_finalize (LttvTracefileState
*self
)
4372 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4373 finalize(G_OBJECT(self
));
4377 static void tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4379 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4381 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4385 GType
lttv_tracefile_state_get_type(void)
4387 static GType type
= 0;
4389 static const GTypeInfo info
= {
4390 sizeof (LttvTracefileStateClass
),
4391 NULL
, /* base_init */
4392 NULL
, /* base_finalize */
4393 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4394 NULL
, /* class_finalize */
4395 NULL
, /* class_data */
4396 sizeof (LttvTracefileState
),
4397 0, /* n_preallocs */
4398 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4399 NULL
/* value handling */
4402 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4403 "LttvTracefileStateType", &info
, 0);
4409 static void module_init()
4411 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4412 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4413 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4414 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4415 LTTV_STATE_MAYBE_USER_MODE
= g_quark_from_string("MAYBE_USER_MODE");
4416 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4417 LTTV_STATE_MAYBE_SYSCALL
= g_quark_from_string("MAYBE_SYSCALL");
4418 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4419 LTTV_STATE_MAYBE_TRAP
= g_quark_from_string("MAYBE_TRAP");
4420 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4421 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4422 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4423 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4424 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4425 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4426 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4427 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4428 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4429 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4430 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4431 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4432 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4433 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4434 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4435 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4436 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4437 LTTV_STATE_EVENT
= g_quark_from_string("event");
4438 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4439 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4440 LTTV_STATE_TIME
= g_quark_from_string("time");
4441 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4442 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4443 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4444 g_quark_from_string("trace_state_use_count");
4445 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4446 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4447 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4448 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4449 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4450 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4452 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4453 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4454 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4455 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4456 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4457 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4458 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4459 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4460 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4461 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4462 LTT_CHANNEL_KPROBE_STATE
= g_quark_from_string("kprobe_state");
4463 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4464 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4465 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4466 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4467 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4469 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4470 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4471 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4472 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4473 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4474 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4475 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4476 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4477 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4478 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4479 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4480 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4481 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4482 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4483 LTT_EVENT_SCHED_TRY_WAKEUP
= g_quark_from_string("sched_try_wakeup");
4484 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4485 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4486 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4487 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4488 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4489 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4490 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4491 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4492 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4493 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4494 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4495 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4496 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4497 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4498 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4499 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4500 LTT_EVENT_KPROBE
= g_quark_from_string("kprobe");
4501 LTT_EVENT_OPEN
= g_quark_from_string("open");
4502 LTT_EVENT_READ
= g_quark_from_string("read");
4503 LTT_EVENT_POLL_EVENT
= g_quark_from_string("poll_event");
4505 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4506 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4507 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4508 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4509 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4510 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4511 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4512 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4513 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4514 LTT_FIELD_PID
= g_quark_from_string("pid");
4515 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4516 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4517 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4518 LTT_FIELD_NAME
= g_quark_from_string("name");
4519 LTT_FIELD_TYPE
= g_quark_from_string("type");
4520 LTT_FIELD_MODE
= g_quark_from_string("mode");
4521 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4522 LTT_FIELD_STATUS
= g_quark_from_string("status");
4523 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4524 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4525 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4526 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4527 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4528 LTT_FIELD_ACTION
= g_quark_from_string("action");
4529 LTT_FIELD_ID
= g_quark_from_string("id");
4530 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4531 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4532 LTT_FIELD_IP
= g_quark_from_string("ip");
4533 LTT_FIELD_FD
= g_quark_from_string("fd");
4534 LTT_FIELD_STATE
= g_quark_from_string("state");
4535 LTT_FIELD_CPU_ID
= g_quark_from_string("cpu_id");
4537 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4538 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4539 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4540 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4541 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4542 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4544 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4545 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4546 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4548 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4549 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4550 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4551 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4554 static void module_destroy()
4559 LTTV_MODULE("state", "State computation", \
4560 "Update the system state, possibly saving it at intervals", \
4561 module_init
, module_destroy
)