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
,
142 LTTV_STATE_MODE_UNKNOWN
,
143 LTTV_STATE_USER_MODE
,
150 LTTV_STATE_SUBMODE_UNKNOWN
,
151 LTTV_STATE_SUBMODE_NONE
;
155 LTTV_STATE_WAIT_FORK
,
164 LTTV_STATE_UNBRANDED
;
167 LTTV_STATE_USER_THREAD
,
168 LTTV_STATE_KERNEL_THREAD
;
186 LTTV_BDEV_BUSY_READING
,
187 LTTV_BDEV_BUSY_WRITING
;
190 LTTV_STATE_TRACEFILES
,
191 LTTV_STATE_PROCESSES
,
193 LTTV_STATE_RUNNING_PROCESS
,
195 LTTV_STATE_SAVED_STATES
,
196 LTTV_STATE_SAVED_STATES_TIME
,
199 LTTV_STATE_NAME_TABLES
,
200 LTTV_STATE_TRACE_STATE_USE_COUNT
,
201 LTTV_STATE_RESOURCE_CPUS
,
202 LTTV_STATE_RESOURCE_CPUS_COUNT
,
203 LTTV_STATE_RESOURCE_IRQS
,
204 LTTV_STATE_RESOURCE_SOFT_IRQS
,
205 LTTV_STATE_RESOURCE_TRAPS
,
206 LTTV_STATE_RESOURCE_BLKDEVS
;
208 static void create_max_time(LttvTraceState
*tcs
);
210 static void get_max_time(LttvTraceState
*tcs
);
212 static void free_max_time(LttvTraceState
*tcs
);
214 static void create_name_tables(LttvTraceState
*tcs
);
216 static void get_name_tables(LttvTraceState
*tcs
);
218 static void free_name_tables(LttvTraceState
*tcs
);
220 static void free_saved_state(LttvTraceState
*tcs
);
222 static void lttv_state_free_process_table(GHashTable
*processes
);
224 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
225 GPtrArray
*quarktable
);
227 /* Resource function prototypes */
228 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
229 static LttvBdevState
*bdevstate_new(void);
230 static void bdevstate_free(LttvBdevState
*);
231 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
232 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
235 #if (__WORDSIZE == 32)
236 guint
guint64_hash(gconstpointer key
)
238 guint64 ukey
= *(const guint64
*)key
;
240 return (guint
)ukey
^ (guint
)(ukey
>> 32);
243 gboolean
guint64_equal(gconstpointer a
, gconstpointer b
)
245 guint64 ua
= *(const guint64
*)a
;
246 guint64 ub
= *(const guint64
*)b
;
252 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
254 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
258 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
260 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
264 void lttv_state_state_saved_free(LttvTraceState
*self
,
265 LttvAttribute
*container
)
267 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
271 guint
process_hash(gconstpointer key
)
273 guint pid
= ((const LttvProcessState
*)key
)->pid
;
274 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
278 /* If the hash table hash function is well distributed,
279 * the process_equal should compare different pid */
280 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
282 const LttvProcessState
*process_a
, *process_b
;
285 process_a
= (const LttvProcessState
*)a
;
286 process_b
= (const LttvProcessState
*)b
;
288 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
289 else if(likely(process_a
->pid
== 0 &&
290 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
295 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
297 g_tree_destroy((GTree
*)value
);
300 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
302 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
303 g_hash_table_destroy(usertraces
);
306 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
311 static guint
check_expand(nb
, id
)
316 return max(id
+ 1, nb
* 2);
319 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
320 guint nb
, guint new_nb
)
322 /* Expand an incomplete table */
323 GQuark
*old_table
= *table
;
324 *table
= g_new(GQuark
, new_nb
);
325 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
329 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
330 guint new_nb
, const char *def_string
)
333 GString
*fe_name
= g_string_new("");
334 for(i
= nb
; i
< new_nb
; i
++) {
335 g_string_printf(fe_name
, "%s %d", def_string
, i
);
336 table
[i
] = g_quark_from_string(fe_name
->str
);
338 g_string_free(fe_name
, TRUE
);
341 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
343 LttvNameTables
*nt
= ts
->name_tables
;
346 new_nb
= check_expand(nt
->nb_syscalls
, id
);
347 if(likely(new_nb
== nt
->nb_syscalls
))
349 expand_name_table(ts
, &nt
->syscall_names
, nt
->nb_syscalls
, new_nb
);
350 fill_name_table(ts
, nt
->syscall_names
, nt
->nb_syscalls
, new_nb
, "syscall");
351 /* Update the table size */
352 nt
->nb_syscalls
= new_nb
;
355 static void expand_kprobe_table(LttvTraceState
*ts
, guint64 ip
, char *symbol
)
357 LttvNameTables
*nt
= ts
->name_tables
;
358 #if (__WORDSIZE == 32)
359 guint64
*ip_ptr
= g_new(guint64
, 1);
360 g_hash_table_insert(nt
->kprobe_hash
, ip_ptr
,
361 (gpointer
)(glong
)g_quark_from_string(symbol
));
363 g_hash_table_insert(nt
->kprobe_hash
, (gpointer
)ip
,
364 (gpointer
)(glong
)g_quark_from_string(symbol
));
368 static void expand_trap_table(LttvTraceState
*ts
, int id
)
370 LttvNameTables
*nt
= ts
->name_tables
;
371 LttvTrapState
*old_table
;
374 new_nb
= check_expand(nt
->nb_traps
, id
);
375 if(likely(new_nb
== nt
->nb_traps
))
378 expand_name_table(ts
, &nt
->trap_names
, nt
->nb_traps
, new_nb
);
379 fill_name_table(ts
, nt
->trap_names
, nt
->nb_traps
, new_nb
, "trap");
381 old_table
= ts
->trap_states
;
382 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
383 memcpy(ts
->trap_states
, old_table
, nt
->nb_traps
* sizeof(LttvTrapState
));
385 for(i
= nt
->nb_traps
; i
< new_nb
; i
++)
386 ts
->trap_states
[i
].running
= 0;
388 /* Update the table size */
389 nt
->nb_traps
= new_nb
;
392 static void expand_irq_table(LttvTraceState
*ts
, int id
)
394 LttvNameTables
*nt
= ts
->name_tables
;
395 LttvIRQState
*old_table
;
398 new_nb
= check_expand(nt
->nb_irqs
, id
);
399 if(likely(new_nb
== nt
->nb_irqs
))
402 expand_name_table(ts
, &nt
->irq_names
, nt
->nb_irqs
, new_nb
);
403 fill_name_table(ts
, nt
->irq_names
, nt
->nb_irqs
, new_nb
, "irq");
405 old_table
= ts
->irq_states
;
406 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
407 memcpy(ts
->irq_states
, old_table
, nt
->nb_irqs
* sizeof(LttvIRQState
));
409 for(i
= nt
->nb_irqs
; i
< new_nb
; i
++)
410 ts
->irq_states
[i
].mode_stack
=
411 g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
413 /* Update the table size */
414 nt
->nb_irqs
= new_nb
;
417 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
419 LttvNameTables
*nt
= ts
->name_tables
;
420 LttvSoftIRQState
*old_table
;
423 new_nb
= check_expand(nt
->nb_soft_irqs
, id
);
424 if(likely(new_nb
== nt
->nb_soft_irqs
))
427 expand_name_table(ts
, &nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
);
428 fill_name_table(ts
, nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
, "softirq");
430 old_table
= ts
->soft_irq_states
;
431 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
432 memcpy(ts
->soft_irq_states
, old_table
,
433 nt
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
435 for(i
= nt
->nb_soft_irqs
; i
< new_nb
; i
++)
436 ts
->soft_irq_states
[i
].running
= 0;
438 /* Update the table size */
439 nt
->nb_soft_irqs
= new_nb
;
443 restore_init_state(LttvTraceState
*self
)
445 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
447 //LttvTracefileState *tfcs;
449 LttTime start_time
, end_time
;
451 /* Free the process tables */
452 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
453 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
454 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
455 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
458 /* Seek time to beginning */
459 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
460 // closest. It's the tracecontext job to seek the trace to the beginning
461 // anyway : the init state might be used at the middle of the trace as well...
462 //g_tree_destroy(self->parent.ts_context->pqueue);
463 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
465 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
467 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
469 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
470 nb_irqs
= self
->name_tables
->nb_irqs
;
471 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
472 nb_traps
= self
->name_tables
->nb_traps
;
474 /* Put the per cpu running_process to beginning state : process 0. */
475 for(i
=0; i
< nb_cpus
; i
++) {
476 LttvExecutionState
*es
;
477 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
478 LTTV_STATE_UNNAMED
, &start_time
);
479 /* We are not sure is it's a kernel thread or normal thread, put the
480 * bottom stack state to unknown */
481 self
->running_process
[i
]->execution_stack
=
482 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
483 es
= self
->running_process
[i
]->state
=
484 &g_array_index(self
->running_process
[i
]->execution_stack
,
485 LttvExecutionState
, 0);
486 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
487 es
->s
= LTTV_STATE_UNNAMED
;
489 //self->running_process[i]->state->s = LTTV_STATE_RUN;
490 self
->running_process
[i
]->cpu
= i
;
492 /* reset cpu states */
493 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
494 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
495 if(self
->cpu_states
[i
].irq_stack
->len
)
496 g_array_remove_range(self
->cpu_states
[i
].irq_stack
, 0, self
->cpu_states
[i
].irq_stack
->len
);
497 if(self
->cpu_states
[i
].softirq_stack
->len
)
498 g_array_remove_range(self
->cpu_states
[i
].softirq_stack
, 0, self
->cpu_states
[i
].softirq_stack
->len
);
499 if(self
->cpu_states
[i
].trap_stack
->len
)
500 g_array_remove_range(self
->cpu_states
[i
].trap_stack
, 0, self
->cpu_states
[i
].trap_stack
->len
);
504 /* reset irq states */
505 for(i
=0; i
<nb_irqs
; i
++) {
506 if(self
->irq_states
[i
].mode_stack
->len
> 0)
507 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
510 /* reset softirq states */
511 for(i
=0; i
<nb_soft_irqs
; i
++) {
512 self
->soft_irq_states
[i
].pending
= 0;
513 self
->soft_irq_states
[i
].running
= 0;
516 /* reset trap states */
517 for(i
=0; i
<nb_traps
; i
++) {
518 self
->trap_states
[i
].running
= 0;
521 /* reset bdev states */
522 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
523 //g_hash_table_steal_all(self->bdev_states);
524 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
527 nb_tracefile
= self
->parent
.tracefiles
->len
;
529 for(i
= 0 ; i
< nb_tracefile
; i
++) {
531 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
532 LttvTracefileContext
*, i
));
533 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
534 // tfcs->saved_position = 0;
535 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
536 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
537 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
538 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
543 //static LttTime time_zero = {0,0};
545 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
548 const LttTime
*t1
= (const LttTime
*)a
;
549 const LttTime
*t2
= (const LttTime
*)b
;
551 return ltt_time_compare(*t1
, *t2
);
554 static void free_usertrace_key(gpointer data
)
559 #define MAX_STRING_LEN 4096
562 state_load_saved_states(LttvTraceState
*tcs
)
565 GPtrArray
*quarktable
;
566 const char *trace_path
;
570 tcs
->has_precomputed_states
= FALSE
;
574 gchar buf
[MAX_STRING_LEN
];
577 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
578 strncpy(path
, trace_path
, PATH_MAX
-1);
579 count
= strnlen(trace_path
, PATH_MAX
-1);
580 // quarktable : open, test
581 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
582 fp
= fopen(path
, "r");
584 quarktable
= g_ptr_array_sized_new(4096);
586 /* Index 0 is null */
588 if(hdr
== EOF
) return;
589 g_assert(hdr
== HDR_QUARKS
);
593 if(hdr
== EOF
) break;
594 g_assert(hdr
== HDR_QUARK
);
595 g_ptr_array_set_size(quarktable
, q
+1);
598 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
599 if(buf
[i
] == '\0' || feof(fp
)) break;
602 len
= strnlen(buf
, MAX_STRING_LEN
-1);
603 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
604 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
610 // saved_states : open, test
611 strncpy(path
, trace_path
, PATH_MAX
-1);
612 count
= strnlen(trace_path
, PATH_MAX
-1);
613 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
614 fp
= fopen(path
, "r");
618 if(hdr
!= HDR_TRACE
) goto end
;
620 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
622 tcs
->has_precomputed_states
= TRUE
;
627 /* Free the quarktable */
628 for(i
=0; i
<quarktable
->len
; i
++) {
629 string
= g_ptr_array_index (quarktable
, i
);
632 g_ptr_array_free(quarktable
, TRUE
);
637 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
639 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
642 LttvTraceContext
*tc
;
646 LttvTracefileState
*tfcs
;
648 LttvAttributeValue v
;
650 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
651 init((LttvTracesetContext
*)self
, ts
);
653 nb_trace
= lttv_traceset_number(ts
);
654 for(i
= 0 ; i
< nb_trace
; i
++) {
655 tc
= self
->parent
.traces
[i
];
656 tcs
= LTTV_TRACE_STATE(tc
);
657 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
658 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
662 if(*(v
.v_uint
) == 1) {
663 create_name_tables(tcs
);
664 create_max_time(tcs
);
666 get_name_tables(tcs
);
669 nb_tracefile
= tc
->tracefiles
->len
;
670 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
671 nb_irq
= tcs
->name_tables
->nb_irqs
;
672 tcs
->processes
= NULL
;
673 tcs
->usertraces
= NULL
;
674 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
676 /* init cpu resource stuff */
677 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
678 for(j
= 0; j
<nb_cpu
; j
++) {
679 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
680 tcs
->cpu_states
[j
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
681 tcs
->cpu_states
[j
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
682 tcs
->cpu_states
[j
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
683 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
686 /* init irq resource stuff */
687 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
688 for(j
= 0; j
<nb_irq
; j
++) {
689 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
690 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
693 /* init soft irq stuff */
694 /* the kernel has a statically fixed max of 32 softirqs */
695 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->name_tables
->nb_soft_irqs
);
697 /* init trap stuff */
698 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->name_tables
->nb_traps
);
700 /* init bdev resource stuff */
701 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
703 restore_init_state(tcs
);
704 for(j
= 0 ; j
< nb_tracefile
; j
++) {
706 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
707 LttvTracefileContext
*, j
));
708 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
709 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
710 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
711 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
712 /* It's a Usertrace */
713 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
714 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
715 GUINT_TO_POINTER(tid
));
716 if(!usertrace_tree
) {
717 usertrace_tree
= g_tree_new_full(compare_usertraces
,
718 NULL
, free_usertrace_key
, NULL
);
719 g_hash_table_insert(tcs
->usertraces
,
720 GUINT_TO_POINTER(tid
), usertrace_tree
);
722 LttTime
*timestamp
= g_new(LttTime
, 1);
723 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
724 ltt_tracefile_creation(tfcs
->parent
.tf
));
725 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
729 /* See if the trace has saved states */
730 state_load_saved_states(tcs
);
735 fini(LttvTracesetState
*self
)
741 //LttvTracefileState *tfcs;
743 LttvAttributeValue v
;
745 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
746 for(i
= 0 ; i
< nb_trace
; i
++) {
747 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
748 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
751 g_assert(*(v
.v_uint
) != 0);
754 if(*(v
.v_uint
) == 0) {
755 free_name_tables(tcs
);
757 free_saved_state(tcs
);
759 g_free(tcs
->running_process
);
760 tcs
->running_process
= NULL
;
761 lttv_state_free_process_table(tcs
->processes
);
762 lttv_state_free_usertraces(tcs
->usertraces
);
763 tcs
->processes
= NULL
;
764 tcs
->usertraces
= NULL
;
766 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
767 fini((LttvTracesetContext
*)self
);
771 static LttvTracesetContext
*
772 new_traceset_context(LttvTracesetContext
*self
)
774 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
778 static LttvTraceContext
*
779 new_trace_context(LttvTracesetContext
*self
)
781 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
785 static LttvTracefileContext
*
786 new_tracefile_context(LttvTracesetContext
*self
)
788 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
792 /* Write the process state of the trace */
794 static void write_process_state(gpointer key
, gpointer value
,
797 LttvProcessState
*process
;
799 LttvExecutionState
*es
;
801 FILE *fp
= (FILE *)user_data
;
806 process
= (LttvProcessState
*)value
;
808 " <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",
809 process
, process
->pid
, process
->tgid
, process
->ppid
,
810 g_quark_to_string(process
->type
),
811 process
->creation_time
.tv_sec
,
812 process
->creation_time
.tv_nsec
,
813 process
->insertion_time
.tv_sec
,
814 process
->insertion_time
.tv_nsec
,
815 g_quark_to_string(process
->name
),
816 g_quark_to_string(process
->brand
),
817 process
->cpu
, process
->free_events
);
819 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
820 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
821 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
822 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
823 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
824 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
825 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
828 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
829 address
= g_array_index(process
->user_stack
, guint64
, i
);
830 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n",
834 if(process
->usertrace
) {
835 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
836 g_quark_to_string(process
->usertrace
->tracefile_name
),
837 process
->usertrace
->cpu
);
841 fprintf(fp
, " </PROCESS>\n");
845 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
847 guint i
, nb_tracefile
, nb_block
, offset
;
850 LttvTracefileState
*tfcs
;
854 LttEventPosition
*ep
;
858 ep
= ltt_event_position_new();
860 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
862 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
864 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
865 for(i
=0;i
<nb_cpus
;i
++) {
866 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
867 i
, self
->running_process
[i
]->pid
);
870 nb_tracefile
= self
->parent
.tracefiles
->len
;
872 for(i
= 0 ; i
< nb_tracefile
; i
++) {
874 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
875 LttvTracefileContext
*, i
));
876 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
877 tfcs
->parent
.timestamp
.tv_sec
,
878 tfcs
->parent
.timestamp
.tv_nsec
);
879 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
880 if(e
== NULL
) fprintf(fp
,"/>\n");
882 ltt_event_position(e
, ep
);
883 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
884 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
889 fprintf(fp
,"</PROCESS_STATE>\n");
893 static void write_process_state_raw(gpointer key
, gpointer value
,
896 LttvProcessState
*process
;
898 LttvExecutionState
*es
;
900 FILE *fp
= (FILE *)user_data
;
905 process
= (LttvProcessState
*)value
;
906 fputc(HDR_PROCESS
, fp
);
907 //fwrite(&header, sizeof(header), 1, fp);
908 //fprintf(fp, "%s", g_quark_to_string(process->type));
910 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
911 //fprintf(fp, "%s", g_quark_to_string(process->name));
913 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
914 //fprintf(fp, "%s", g_quark_to_string(process->brand));
916 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
917 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
918 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
919 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
920 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
921 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
922 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
923 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
927 " <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",
928 process
, process
->pid
, process
->tgid
, process
->ppid
,
929 g_quark_to_string(process
->type
),
930 process
->creation_time
.tv_sec
,
931 process
->creation_time
.tv_nsec
,
932 process
->insertion_time
.tv_sec
,
933 process
->insertion_time
.tv_nsec
,
934 g_quark_to_string(process
->name
),
935 g_quark_to_string(process
->brand
),
939 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
940 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
943 //fprintf(fp, "%s", g_quark_to_string(es->t));
945 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
946 //fprintf(fp, "%s", g_quark_to_string(es->n));
948 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
949 //fprintf(fp, "%s", g_quark_to_string(es->s));
951 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
952 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
953 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
954 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
956 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
957 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
958 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
959 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
960 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
964 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
965 address
= g_array_index(process
->user_stack
, guint64
, i
);
966 fputc(HDR_USER_STACK
, fp
);
967 fwrite(&address
, sizeof(address
), 1, fp
);
969 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
974 if(process
->usertrace
) {
975 fputc(HDR_USERTRACE
, fp
);
976 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
978 fwrite(&process
->usertrace
->tracefile_name
,
979 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
980 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
982 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
983 g_quark_to_string(process
->usertrace
->tracefile_name
),
984 process
->usertrace
->cpu
);
991 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
993 guint i
, nb_tracefile
, nb_block
, offset
;
996 LttvTracefileState
*tfcs
;
1000 LttEventPosition
*ep
;
1004 ep
= ltt_event_position_new();
1006 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1007 fputc(HDR_PROCESS_STATE
, fp
);
1008 fwrite(&t
, sizeof(t
), 1, fp
);
1010 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
1012 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1013 for(i
=0;i
<nb_cpus
;i
++) {
1015 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
1016 fwrite(&self
->running_process
[i
]->pid
,
1017 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1018 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1019 // i, self->running_process[i]->pid);
1022 nb_tracefile
= self
->parent
.tracefiles
->len
;
1024 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1026 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1027 LttvTracefileContext
*, i
));
1028 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1029 // tfcs->parent.timestamp.tv_sec,
1030 // tfcs->parent.timestamp.tv_nsec);
1031 fputc(HDR_TRACEFILE
, fp
);
1032 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1033 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1034 * position following : end of trace */
1035 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1037 ltt_event_position(e
, ep
);
1038 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1039 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1041 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
1042 fwrite(&offset
, sizeof(offset
), 1, fp
);
1043 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
1050 /* Read process state from a file */
1052 /* Called because a HDR_PROCESS was found */
1053 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
1054 GPtrArray
*quarktable
)
1056 LttvExecutionState
*es
;
1057 LttvProcessState
*process
, *parent_process
;
1058 LttvProcessState tmp
;
1063 /* TODO : check return value */
1064 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1065 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1066 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1067 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1068 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1069 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1070 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1071 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1072 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1073 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1076 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1078 /* We must link to the parent */
1079 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1081 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1082 if(process
== NULL
) {
1083 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1085 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1086 &tmp
.creation_time
);
1089 process
->insertion_time
= tmp
.insertion_time
;
1090 process
->creation_time
= tmp
.creation_time
;
1091 process
->type
= g_quark_from_string(
1092 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1093 process
->tgid
= tmp
.tgid
;
1094 process
->ppid
= tmp
.ppid
;
1095 process
->brand
= g_quark_from_string(
1096 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1098 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1099 process
->free_events
= tmp
.free_events
;
1102 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1104 gint hdr
= fgetc(fp
);
1105 if(hdr
== EOF
) goto end_loop
;
1109 process
->execution_stack
=
1110 g_array_set_size(process
->execution_stack
,
1111 process
->execution_stack
->len
+ 1);
1112 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1113 process
->execution_stack
->len
-1);
1114 process
->state
= es
;
1116 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1117 es
->t
= g_quark_from_string(
1118 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1119 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1120 es
->n
= g_quark_from_string(
1121 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1122 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1123 es
->s
= g_quark_from_string(
1124 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1125 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1126 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1127 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1129 case HDR_USER_STACK
:
1130 process
->user_stack
= g_array_set_size(process
->user_stack
,
1131 process
->user_stack
->len
+ 1);
1132 address
= &g_array_index(process
->user_stack
, guint64
,
1133 process
->user_stack
->len
-1);
1134 fread(address
, sizeof(address
), 1, fp
);
1135 process
->current_function
= *address
;
1138 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1139 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1151 /* Called because a HDR_PROCESS_STATE was found */
1152 /* Append a saved state to the trace states */
1153 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1155 guint i
, nb_tracefile
, nb_block
, offset
;
1157 LttvTracefileState
*tfcs
;
1159 LttEventPosition
*ep
;
1167 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1169 LttvAttributeValue value
;
1170 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1171 ep
= ltt_event_position_new();
1173 restore_init_state(self
);
1175 fread(&t
, sizeof(t
), 1, fp
);
1178 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1180 if(hdr
== EOF
) goto end_loop
;
1184 /* Call read_process_state_raw */
1185 read_process_state_raw(self
, fp
, quarktable
);
1193 case HDR_USER_STACK
:
1195 case HDR_PROCESS_STATE
:
1201 g_error("Error while parsing saved state file : unknown data header %d",
1207 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1208 for(i
=0;i
<nb_cpus
;i
++) {
1211 g_assert(hdr
== HDR_CPU
);
1212 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1213 g_assert(i
== cpu_num
);
1214 fread(&self
->running_process
[i
]->pid
,
1215 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1218 nb_tracefile
= self
->parent
.tracefiles
->len
;
1220 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1222 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1223 LttvTracefileContext
*, i
));
1224 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1225 // tfcs->parent.timestamp.tv_sec,
1226 // tfcs->parent.timestamp.tv_nsec);
1227 g_tree_remove(pqueue
, &tfcs
->parent
);
1229 g_assert(hdr
== HDR_TRACEFILE
);
1230 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1231 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1232 * position following : end of trace */
1233 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1234 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1235 fread(&offset
, sizeof(offset
), 1, fp
);
1236 fread(&tsc
, sizeof(tsc
), 1, fp
);
1237 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1238 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1240 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1245 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1246 LTTV_STATE_SAVED_STATES
);
1247 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1248 value
= lttv_attribute_add(saved_states_tree
,
1249 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1250 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1251 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1252 *(value
.v_time
) = t
;
1253 lttv_state_save(self
, saved_state_tree
);
1254 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1257 *(self
->max_time_state_recomputed_in_seek
) = t
;
1261 /* Called when a HDR_TRACE is found */
1262 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1263 GPtrArray
*quarktable
)
1268 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1270 if(hdr
== EOF
) goto end_loop
;
1273 case HDR_PROCESS_STATE
:
1274 /* Call read_process_state_raw */
1275 lttv_state_read_raw(tcs
, fp
, quarktable
);
1283 case HDR_USER_STACK
:
1287 g_error("Error while parsing saved state file :"
1288 " unexpected data header %d",
1292 g_error("Error while parsing saved state file : unknown data header %d",
1297 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1298 restore_init_state(tcs
);
1299 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1305 /* Copy each process from an existing hash table to a new one */
1307 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1309 LttvProcessState
*process
, *new_process
;
1311 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1315 process
= (LttvProcessState
*)value
;
1316 new_process
= g_new(LttvProcessState
, 1);
1317 *new_process
= *process
;
1318 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1319 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1320 new_process
->execution_stack
=
1321 g_array_set_size(new_process
->execution_stack
,
1322 process
->execution_stack
->len
);
1323 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1324 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1325 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1327 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1328 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1329 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1330 sizeof(guint64
), 0);
1331 new_process
->user_stack
=
1332 g_array_set_size(new_process
->user_stack
,
1333 process
->user_stack
->len
);
1334 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1335 g_array_index(new_process
->user_stack
, guint64
, i
) =
1336 g_array_index(process
->user_stack
, guint64
, i
);
1338 new_process
->current_function
= process
->current_function
;
1340 /* fd hash table stuff */
1346 /* copy every item in the hash table */
1347 new_process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1349 g_hash_table_iter_init(&it
, process
->fds
);
1350 while (g_hash_table_iter_next (&it
, (void *)&key
, (void *)&value
)) {
1351 g_hash_table_insert(new_process
->fds
, key
, value
);
1355 /* When done creating the new process state, insert it in the
1357 g_hash_table_insert(new_processes
, new_process
, new_process
);
1361 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1363 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1365 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1366 return new_processes
;
1369 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1372 LttvCPUState
*retval
;
1374 retval
= g_new(LttvCPUState
, n
);
1376 for(i
=0; i
<n
; i
++) {
1377 retval
[i
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1378 g_array_set_size(retval
[i
].irq_stack
, states
[i
].irq_stack
->len
);
1379 for(j
=0; j
<states
[i
].irq_stack
->len
; j
++) {
1380 g_array_index(retval
[i
].irq_stack
, gint
, j
) = g_array_index(states
[i
].irq_stack
, gint
, j
);
1383 retval
[i
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1384 g_array_set_size(retval
[i
].softirq_stack
, states
[i
].softirq_stack
->len
);
1385 for(j
=0; j
<states
[i
].softirq_stack
->len
; j
++) {
1386 g_array_index(retval
[i
].softirq_stack
, gint
, j
) = g_array_index(states
[i
].softirq_stack
, gint
, j
);
1389 retval
[i
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1390 g_array_set_size(retval
[i
].trap_stack
, states
[i
].trap_stack
->len
);
1391 for(j
=0; j
<states
[i
].trap_stack
->len
; j
++) {
1392 g_array_index(retval
[i
].trap_stack
, gint
, j
) = g_array_index(states
[i
].trap_stack
, gint
, j
);
1395 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1396 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1397 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1398 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1405 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1409 for(i
=0; i
<n
; i
++) {
1410 g_array_free(states
[i
].mode_stack
, TRUE
);
1411 g_array_free(states
[i
].irq_stack
, TRUE
);
1412 g_array_free(states
[i
].softirq_stack
, TRUE
);
1413 g_array_free(states
[i
].trap_stack
, TRUE
);
1419 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1422 LttvIRQState
*retval
;
1424 retval
= g_new(LttvIRQState
, n
);
1426 for(i
=0; i
<n
; i
++) {
1427 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1428 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1429 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1430 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1437 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1441 for(i
=0; i
<n
; i
++) {
1442 g_array_free(states
[i
].mode_stack
, TRUE
);
1448 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1451 LttvSoftIRQState
*retval
;
1453 retval
= g_new(LttvSoftIRQState
, n
);
1455 for(i
=0; i
<n
; i
++) {
1456 retval
[i
].pending
= states
[i
].pending
;
1457 retval
[i
].running
= states
[i
].running
;
1463 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1468 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1471 LttvTrapState
*retval
;
1473 retval
= g_new(LttvTrapState
, n
);
1475 for(i
=0; i
<n
; i
++) {
1476 retval
[i
].running
= states
[i
].running
;
1482 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1487 /* bdevstate stuff */
1489 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1491 gint devcode_gint
= devcode
;
1492 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1494 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1495 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1497 gint
* key
= g_new(gint
, 1);
1499 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1507 static LttvBdevState
*bdevstate_new(void)
1509 LttvBdevState
*retval
;
1510 retval
= g_new(LttvBdevState
, 1);
1511 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1516 static void bdevstate_free(LttvBdevState
*bds
)
1518 g_array_free(bds
->mode_stack
, TRUE
);
1522 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1524 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1526 bdevstate_free(bds
);
1529 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1531 LttvBdevState
*retval
;
1533 retval
= bdevstate_new();
1534 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1539 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1541 //GHashTable *ht = (GHashTable *)u;
1542 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1543 LttvBdevState
*newbds
;
1545 newbds
= bdevstate_copy(bds
);
1547 g_hash_table_insert(u
, k
, newbds
);
1550 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1554 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1556 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1561 /* Free a hashtable and the LttvBdevState structures its values
1564 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1566 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1567 g_hash_table_destroy(ht
);
1570 /* The saved state for each trace contains a member "processes", which
1571 stores a copy of the process table, and a member "tracefiles" with
1572 one entry per tracefile. Each tracefile has a "process" member pointing
1573 to the current process and a "position" member storing the tracefile
1574 position (needed to seek to the current "next" event. */
1576 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1578 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1580 LttvTracefileState
*tfcs
;
1582 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1584 guint
*running_process
;
1586 LttvAttributeValue value
;
1588 LttEventPosition
*ep
;
1590 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1591 LTTV_STATE_TRACEFILES
);
1593 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1595 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1597 /* Add the currently running processes array */
1598 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1599 running_process
= g_new(guint
, nb_cpus
);
1600 for(i
=0;i
<nb_cpus
;i
++) {
1601 running_process
[i
] = self
->running_process
[i
]->pid
;
1603 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1605 *(value
.v_pointer
) = running_process
;
1607 g_info("State save");
1609 nb_tracefile
= self
->parent
.tracefiles
->len
;
1611 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1613 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1614 LttvTracefileContext
*, i
));
1615 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1616 value
= lttv_attribute_add(tracefiles_tree
, i
,
1618 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1620 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1622 *(value
.v_uint
) = tfcs
->process
->pid
;
1624 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1626 /* Only save the position if the tfs has not infinite time. */
1627 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1628 // && current_tfcs != tfcs) {
1629 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1630 *(value
.v_pointer
) = NULL
;
1632 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1633 ep
= ltt_event_position_new();
1634 ltt_event_position(e
, ep
);
1635 *(value
.v_pointer
) = ep
;
1637 guint nb_block
, offset
;
1640 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1641 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
, offset
,
1643 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1647 /* save the cpu state */
1649 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1651 *(value
.v_uint
) = nb_cpus
;
1653 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1655 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1658 /* save the irq state */
1659 nb_irqs
= self
->name_tables
->nb_irqs
;
1661 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1663 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1666 /* save the soft irq state */
1667 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1669 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1671 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1674 /* save the trap state */
1675 nb_traps
= self
->name_tables
->nb_traps
;
1677 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1679 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1682 /* save the blkdev states */
1683 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1685 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1689 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1691 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1693 LttvTracefileState
*tfcs
;
1695 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1697 guint
*running_process
;
1699 LttvAttributeType type
;
1701 LttvAttributeValue value
;
1703 LttvAttributeName name
;
1707 LttEventPosition
*ep
;
1709 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1712 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1713 LTTV_STATE_TRACEFILES
);
1715 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1717 g_assert(type
== LTTV_POINTER
);
1718 lttv_state_free_process_table(self
->processes
);
1719 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1721 /* Add the currently running processes array */
1722 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1723 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1725 g_assert(type
== LTTV_POINTER
);
1726 running_process
= *(value
.v_pointer
);
1727 for(i
=0;i
<nb_cpus
;i
++) {
1728 pid
= running_process
[i
];
1729 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1730 g_assert(self
->running_process
[i
] != NULL
);
1733 nb_tracefile
= self
->parent
.tracefiles
->len
;
1735 //g_tree_destroy(tsc->pqueue);
1736 //tsc->pqueue = g_tree_new(compare_tracefile);
1738 /* restore cpu resource states */
1739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1740 g_assert(type
== LTTV_POINTER
);
1741 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1742 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1744 /* restore irq resource states */
1745 nb_irqs
= self
->name_tables
->nb_irqs
;
1746 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1747 g_assert(type
== LTTV_POINTER
);
1748 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1749 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1751 /* restore soft irq resource states */
1752 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1753 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1754 g_assert(type
== LTTV_POINTER
);
1755 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1756 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1758 /* restore trap resource states */
1759 nb_traps
= self
->name_tables
->nb_traps
;
1760 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1761 g_assert(type
== LTTV_POINTER
);
1762 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1763 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1765 /* restore the blkdev states */
1766 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1767 g_assert(type
== LTTV_POINTER
);
1768 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1769 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1771 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1773 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1774 LttvTracefileContext
*, i
));
1775 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1776 g_assert(type
== LTTV_GOBJECT
);
1777 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1779 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1781 g_assert(type
== LTTV_UINT
);
1782 pid
= *(value
.v_uint
);
1783 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1785 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1787 g_assert(type
== LTTV_POINTER
);
1788 //g_assert(*(value.v_pointer) != NULL);
1789 ep
= *(value
.v_pointer
);
1790 g_assert(tfcs
->parent
.t_context
!= NULL
);
1792 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1794 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1795 g_tree_remove(tsc
->pqueue
, tfc
);
1798 retval
= ltt_tracefile_seek_position(tfc
->tf
, ep
);
1799 g_assert_cmpint(retval
, ==, 0);
1800 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1801 g_assert_cmpint(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
), !=, 0);
1802 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1803 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1805 tfc
->timestamp
= ltt_time_infinite
;
1811 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1813 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1815 LttvTracefileState
*tfcs
;
1817 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1819 guint
*running_process
;
1821 LttvAttributeType type
;
1823 LttvAttributeValue value
;
1825 LttvAttributeName name
;
1829 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1830 LTTV_STATE_TRACEFILES
);
1831 g_object_ref(G_OBJECT(tracefiles_tree
));
1832 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1834 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1836 g_assert(type
== LTTV_POINTER
);
1837 lttv_state_free_process_table(*(value
.v_pointer
));
1838 *(value
.v_pointer
) = NULL
;
1839 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1841 /* Free running processes array */
1842 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1844 g_assert(type
== LTTV_POINTER
);
1845 running_process
= *(value
.v_pointer
);
1846 g_free(running_process
);
1848 /* free cpu resource states */
1849 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1850 g_assert(type
== LTTV_UINT
);
1851 nb_cpus
= *value
.v_uint
;
1852 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1853 g_assert(type
== LTTV_POINTER
);
1854 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1856 /* free irq resource states */
1857 nb_irqs
= self
->name_tables
->nb_irqs
;
1858 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1859 g_assert(type
== LTTV_POINTER
);
1860 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1862 /* free softirq resource states */
1863 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1864 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1865 g_assert(type
== LTTV_POINTER
);
1866 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1868 /* free the blkdev states */
1869 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1870 g_assert(type
== LTTV_POINTER
);
1871 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1873 nb_tracefile
= self
->parent
.tracefiles
->len
;
1875 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1877 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1878 LttvTracefileContext
*, i
));
1879 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1880 g_assert(type
== LTTV_GOBJECT
);
1881 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1883 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1885 g_assert(type
== LTTV_POINTER
);
1886 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1888 g_object_unref(G_OBJECT(tracefiles_tree
));
1892 static void free_saved_state(LttvTraceState
*self
)
1896 LttvAttributeType type
;
1898 LttvAttributeValue value
;
1900 LttvAttributeName name
;
1904 LttvAttribute
*saved_states
;
1906 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1907 LTTV_STATE_SAVED_STATES
);
1909 nb
= lttv_attribute_get_number(saved_states
);
1910 for(i
= 0 ; i
< nb
; i
++) {
1911 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1912 g_assert(type
== LTTV_GOBJECT
);
1913 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1916 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1921 create_max_time(LttvTraceState
*tcs
)
1923 LttvAttributeValue v
;
1925 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1927 g_assert(*(v
.v_pointer
) == NULL
);
1928 *(v
.v_pointer
) = g_new(LttTime
,1);
1929 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1934 get_max_time(LttvTraceState
*tcs
)
1936 LttvAttributeValue v
;
1938 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1940 g_assert(*(v
.v_pointer
) != NULL
);
1941 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1946 free_max_time(LttvTraceState
*tcs
)
1948 LttvAttributeValue v
;
1950 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1952 g_free(*(v
.v_pointer
));
1953 *(v
.v_pointer
) = NULL
;
1957 create_name_tables(LttvTraceState
*tcs
)
1961 GString
*fe_name
= g_string_new("");
1963 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1965 LttvAttributeValue v
;
1969 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1971 g_assert(*(v
.v_pointer
) == NULL
);
1972 *(v
.v_pointer
) = name_tables
;
1974 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1976 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1978 LTT_EVENT_SYSCALL_ENTRY
,
1979 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1980 NULL
, NULL
, &hooks
)) {
1982 // th = lttv_trace_hook_get_first(&th);
1984 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1985 // nb = ltt_type_element_number(t);
1987 // name_tables->syscall_names = g_new(GQuark, nb);
1988 // name_tables->nb_syscalls = nb;
1990 // for(i = 0 ; i < nb ; i++) {
1991 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1992 // if(!name_tables->syscall_names[i]) {
1993 // GString *string = g_string_new("");
1994 // g_string_printf(string, "syscall %u", i);
1995 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1996 // g_string_free(string, TRUE);
2000 name_tables
->nb_syscalls
= 256;
2001 name_tables
->syscall_names
= g_new(GQuark
, 256);
2002 for(i
= 0 ; i
< 256 ; i
++) {
2003 g_string_printf(fe_name
, "syscall %d", i
);
2004 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2007 name_tables
->syscall_names
= NULL
;
2008 name_tables
->nb_syscalls
= 0;
2010 lttv_trace_hook_remove_all(&hooks
);
2012 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2014 LTT_EVENT_TRAP_ENTRY
,
2015 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2016 NULL
, NULL
, &hooks
) ||
2017 !lttv_trace_find_hook(tcs
->parent
.t
,
2019 LTT_EVENT_PAGE_FAULT_ENTRY
,
2020 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2021 NULL
, NULL
, &hooks
)) {
2023 // th = lttv_trace_hook_get_first(&th);
2025 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2026 // //nb = ltt_type_element_number(t);
2028 // name_tables->trap_names = g_new(GQuark, nb);
2029 // for(i = 0 ; i < nb ; i++) {
2030 // name_tables->trap_names[i] = g_quark_from_string(
2031 // ltt_enum_string_get(t, i));
2034 name_tables
->nb_traps
= 256;
2035 name_tables
->trap_names
= g_new(GQuark
, 256);
2036 for(i
= 0 ; i
< 256 ; i
++) {
2037 g_string_printf(fe_name
, "trap %d", i
);
2038 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2041 name_tables
->trap_names
= NULL
;
2042 name_tables
->nb_traps
= 0;
2044 lttv_trace_hook_remove_all(&hooks
);
2046 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2048 LTT_EVENT_IRQ_ENTRY
,
2049 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
2050 NULL
, NULL
, &hooks
)) {
2053 name_tables->irq_names = g_new(GQuark, nb);
2054 for(i = 0 ; i < nb ; i++) {
2055 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2059 name_tables
->nb_irqs
= 256;
2060 name_tables
->irq_names
= g_new(GQuark
, 256);
2061 for(i
= 0 ; i
< 256 ; i
++) {
2062 g_string_printf(fe_name
, "irq %d", i
);
2063 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2066 name_tables
->nb_irqs
= 0;
2067 name_tables
->irq_names
= NULL
;
2069 lttv_trace_hook_remove_all(&hooks
);
2071 name_tables->soft_irq_names = g_new(GQuark, nb);
2072 for(i = 0 ; i < nb ; i++) {
2073 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2077 /* the kernel is limited to 32 statically defined softirqs */
2078 name_tables
->nb_soft_irqs
= 32;
2079 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_soft_irqs
);
2080 for(i
= 0 ; i
< name_tables
->nb_soft_irqs
; i
++) {
2081 g_string_printf(fe_name
, "softirq %d", i
);
2082 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2084 g_array_free(hooks
, TRUE
);
2086 g_string_free(fe_name
, TRUE
);
2088 #if (__WORDSIZE == 32)
2089 name_tables
->kprobe_hash
= g_hash_table_new_full(guint64_hash
, guint64_equal
,
2092 name_tables
->kprobe_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2098 get_name_tables(LttvTraceState
*tcs
)
2100 LttvAttributeValue v
;
2102 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2104 g_assert(*(v
.v_pointer
) != NULL
);
2105 tcs
->name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2110 free_name_tables(LttvTraceState
*tcs
)
2112 LttvNameTables
*name_tables
;
2114 LttvAttributeValue v
;
2116 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2118 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2119 *(v
.v_pointer
) = NULL
;
2121 // g_free(name_tables->eventtype_names);
2122 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2123 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2124 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2125 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2126 g_hash_table_destroy(name_tables
->kprobe_hash
);
2127 g_free(name_tables
);
2130 #ifdef HASH_TABLE_DEBUG
2132 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2134 LttvProcessState
*process
= (LttvProcessState
*)value
;
2136 /* Test for process corruption */
2137 guint stack_len
= process
->execution_stack
->len
;
2140 static void hash_table_check(GHashTable
*table
)
2142 g_hash_table_foreach(table
, test_process
, NULL
);
2148 /* clears the stack and sets the state passed as argument */
2149 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2151 g_array_set_size(cpust
->mode_stack
, 1);
2152 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2155 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2157 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2158 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2161 static void cpu_pop_mode(LttvCPUState
*cpust
)
2163 if(cpust
->mode_stack
->len
<= 1)
2164 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2166 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2169 /* clears the stack and sets the state passed as argument */
2170 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2172 g_array_set_size(bdevst
->mode_stack
, 1);
2173 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2176 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2178 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2179 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2182 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2184 if(bdevst
->mode_stack
->len
<= 1)
2185 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2187 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2190 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2192 g_array_set_size(irqst
->mode_stack
, 1);
2193 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2196 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2198 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2199 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2202 static void irq_pop_mode(LttvIRQState
*irqst
)
2204 if(irqst
->mode_stack
->len
<= 1)
2205 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2207 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2210 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2213 LttvExecutionState
*es
;
2215 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2216 guint cpu
= tfs
->cpu
;
2218 #ifdef HASH_TABLE_DEBUG
2219 hash_table_check(ts
->processes
);
2221 LttvProcessState
*process
= ts
->running_process
[cpu
];
2223 guint depth
= process
->execution_stack
->len
;
2225 process
->execution_stack
=
2226 g_array_set_size(process
->execution_stack
, depth
+ 1);
2229 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2231 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2234 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2235 es
->cum_cpu_time
= ltt_time_zero
;
2236 es
->s
= process
->state
->s
;
2237 process
->state
= es
;
2241 * return 1 when empty, else 0 */
2242 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2243 LttvTracefileState
*tfs
)
2245 guint depth
= process
->execution_stack
->len
;
2251 process
->execution_stack
=
2252 g_array_set_size(process
->execution_stack
, depth
- 1);
2253 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2255 process
->state
->change
= tfs
->parent
.timestamp
;
2260 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2262 guint cpu
= tfs
->cpu
;
2263 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2264 LttvProcessState
*process
= ts
->running_process
[cpu
];
2266 guint depth
= process
->execution_stack
->len
;
2268 if(process
->state
->t
!= t
){
2269 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2270 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2271 g_info("process state has %s when pop_int is %s\n",
2272 g_quark_to_string(process
->state
->t
),
2273 g_quark_to_string(t
));
2274 g_info("{ %u, %u, %s, %s, %s }\n",
2277 g_quark_to_string(process
->name
),
2278 g_quark_to_string(process
->brand
),
2279 g_quark_to_string(process
->state
->s
));
2284 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2285 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2289 process
->execution_stack
=
2290 g_array_set_size(process
->execution_stack
, depth
- 1);
2291 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2293 process
->state
->change
= tfs
->parent
.timestamp
;
2296 struct search_result
{
2297 const LttTime
*time
; /* Requested time */
2298 LttTime
*best
; /* Best result */
2301 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2303 const LttTime
*elem_time
= (const LttTime
*)a
;
2304 /* Explicit non const cast */
2305 struct search_result
*res
= (struct search_result
*)b
;
2307 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2308 /* The usertrace was created before the schedchange */
2309 /* Get larger keys */
2311 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2312 /* The usertrace was created after the schedchange time */
2313 /* Get smaller keys */
2315 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2316 res
->best
= (LttTime
*)elem_time
;
2319 res
->best
= (LttTime
*)elem_time
;
2326 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2327 guint pid
, const LttTime
*timestamp
)
2329 LttvTracefileState
*tfs
= NULL
;
2330 struct search_result res
;
2331 /* Find the usertrace associated with a pid and time interval.
2332 * Search in the usertraces by PID (within a hash) and then, for each
2333 * corresponding element of the array, find the first one with creation
2334 * timestamp the lowest, but higher or equal to "timestamp". */
2335 res
.time
= timestamp
;
2337 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2338 GUINT_TO_POINTER(pid
));
2339 if(usertrace_tree
) {
2340 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2342 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2348 /* Return a new and initialized LttvProcessState structure */
2351 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2352 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2354 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2356 LttvExecutionState
*es
;
2361 process
->tgid
= tgid
;
2363 process
->name
= name
;
2364 process
->brand
= LTTV_STATE_UNBRANDED
;
2365 //process->last_cpu = tfs->cpu_name;
2366 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2367 process
->type
= LTTV_STATE_USER_THREAD
;
2368 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2369 process
->current_function
= 0; //function 0x0 by default.
2371 g_info("Process %u, core %p", process
->pid
, process
);
2372 g_hash_table_insert(tcs
->processes
, process
, process
);
2375 process
->ppid
= parent
->pid
;
2376 process
->creation_time
= *timestamp
;
2379 /* No parent. This process exists but we are missing all information about
2380 its creation. The birth time is set to zero but we remember the time of
2385 process
->creation_time
= ltt_time_zero
;
2388 process
->insertion_time
= *timestamp
;
2389 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2390 process
->creation_time
.tv_nsec
);
2391 process
->pid_time
= g_quark_from_string(buffer
);
2393 process
->free_events
= 0;
2394 //process->last_cpu = tfs->cpu_name;
2395 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2396 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2397 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2398 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2399 es
= process
->state
= &g_array_index(process
->execution_stack
,
2400 LttvExecutionState
, 0);
2401 es
->t
= LTTV_STATE_USER_MODE
;
2402 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2403 es
->entry
= *timestamp
;
2404 //g_assert(timestamp->tv_sec != 0);
2405 es
->change
= *timestamp
;
2406 es
->cum_cpu_time
= ltt_time_zero
;
2407 es
->s
= LTTV_STATE_RUN
;
2409 es
= process
->state
= &g_array_index(process
->execution_stack
,
2410 LttvExecutionState
, 1);
2411 es
->t
= LTTV_STATE_SYSCALL
;
2412 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2413 es
->entry
= *timestamp
;
2414 //g_assert(timestamp->tv_sec != 0);
2415 es
->change
= *timestamp
;
2416 es
->cum_cpu_time
= ltt_time_zero
;
2417 es
->s
= LTTV_STATE_WAIT_FORK
;
2419 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2420 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2421 sizeof(guint64
), 0);
2423 process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2428 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2431 LttvProcessState key
;
2432 LttvProcessState
*process
;
2436 process
= g_hash_table_lookup(ts
->processes
, &key
);
2441 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2442 const LttTime
*timestamp
)
2444 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2445 LttvExecutionState
*es
;
2447 /* Put ltt_time_zero creation time for unexisting processes */
2448 if(unlikely(process
== NULL
)) {
2449 process
= lttv_state_create_process(ts
,
2450 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2451 /* We are not sure is it's a kernel thread or normal thread, put the
2452 * bottom stack state to unknown */
2453 process
->execution_stack
=
2454 g_array_set_size(process
->execution_stack
, 1);
2455 process
->state
= es
=
2456 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2457 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2458 es
->s
= LTTV_STATE_UNNAMED
;
2463 /* FIXME : this function should be called when we receive an event telling that
2464 * release_task has been called in the kernel. In happens generally when
2465 * the parent waits for its child termination, but may also happens in special
2466 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2467 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2468 * of a killed thread group, but isn't the leader.
2470 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2472 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2473 LttvProcessState key
;
2475 /* Wait for both schedule with exit dead and process free to happen.
2476 * They can happen in any order. */
2477 if (++(process
->free_events
) < 2)
2480 key
.pid
= process
->pid
;
2481 key
.cpu
= process
->cpu
;
2482 g_hash_table_remove(ts
->processes
, &key
);
2483 g_array_free(process
->execution_stack
, TRUE
);
2484 g_array_free(process
->user_stack
, TRUE
);
2486 /* the following also clears the content */
2487 g_hash_table_destroy(process
->fds
);
2494 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2496 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2497 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2499 /* the following also clears the content */
2500 g_hash_table_destroy(((LttvProcessState
*)value
)->fds
);
2506 static void lttv_state_free_process_table(GHashTable
*processes
)
2508 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2509 g_hash_table_destroy(processes
);
2513 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2515 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2517 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2518 LttvProcessState
*process
= ts
->running_process
[cpu
];
2519 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2520 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2521 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2522 LttvExecutionSubmode submode
;
2523 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2525 guint syscall
= ltt_event_get_unsigned(e
, f
);
2526 expand_syscall_table(ts
, syscall
);
2527 submode
= nt
->syscall_names
[syscall
];
2528 /* There can be no system call from PID 0 : unknown state */
2529 if(process
->pid
!= 0)
2530 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2535 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2537 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2539 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2540 LttvProcessState
*process
= ts
->running_process
[cpu
];
2542 /* There can be no system call from PID 0 : unknown state */
2543 if(process
->pid
!= 0)
2544 pop_state(s
, LTTV_STATE_SYSCALL
);
2549 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2551 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2552 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2553 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2554 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2555 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2556 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2558 LttvExecutionSubmode submode
;
2560 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2562 expand_trap_table(ts
, trap
);
2564 submode
= nt
->trap_names
[trap
];
2566 push_state(s
, LTTV_STATE_TRAP
, submode
);
2568 /* update cpu status */
2569 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2571 /* update trap status */
2572 g_array_append_val(s
->cpu_state
->trap_stack
, trap
);
2573 ts
->trap_states
[trap
].running
++;
2578 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2580 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2581 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2583 pop_state(s
, LTTV_STATE_TRAP
);
2585 /* update cpu status */
2586 cpu_pop_mode(s
->cpu_state
);
2588 /* update trap status */
2589 if (s
->cpu_state
->trap_stack
->len
> 0) {
2590 gint last
= g_array_index(s
->cpu_state
->trap_stack
, gint
, s
->cpu_state
->trap_stack
->len
-1);
2591 if(ts
->trap_states
[last
].running
)
2592 ts
->trap_states
[last
].running
--;
2593 g_array_remove_index(s
->cpu_state
->trap_stack
, s
->cpu_state
->trap_stack
->len
-1);
2598 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2600 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2601 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2602 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2603 //guint8 ev_id = ltt_event_eventtype_id(e);
2604 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2605 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2606 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2608 LttvExecutionSubmode submode
;
2609 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2611 expand_irq_table(ts
, irq
);
2613 submode
= nt
->irq_names
[irq
];
2615 /* Do something with the info about being in user or system mode when int? */
2616 push_state(s
, LTTV_STATE_IRQ
, submode
);
2618 /* update cpu status */
2619 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2621 /* update irq status */
2622 g_array_append_val(s
->cpu_state
->irq_stack
, irq
);
2623 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2628 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2630 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2631 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2633 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2635 /* update cpu status */
2636 cpu_pop_mode(s
->cpu_state
);
2638 /* update softirq status */
2639 if (s
->cpu_state
->softirq_stack
->len
> 0) {
2640 gint last
= g_array_index(s
->cpu_state
->softirq_stack
, gint
, s
->cpu_state
->softirq_stack
->len
-1);
2641 if(ts
->soft_irq_states
[last
].running
)
2642 ts
->soft_irq_states
[last
].running
--;
2643 g_array_remove_index(s
->cpu_state
->softirq_stack
, s
->cpu_state
->softirq_stack
->len
-1);
2648 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2650 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2651 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2653 pop_state(s
, LTTV_STATE_IRQ
);
2655 /* update cpu status */
2656 cpu_pop_mode(s
->cpu_state
);
2658 /* update irq status */
2659 if (s
->cpu_state
->irq_stack
->len
> 0) {
2660 gint last
= g_array_index(s
->cpu_state
->irq_stack
, gint
, s
->cpu_state
->irq_stack
->len
-1);
2661 g_array_remove_index(s
->cpu_state
->irq_stack
, s
->cpu_state
->irq_stack
->len
-1);
2662 irq_pop_mode(&ts
->irq_states
[last
]);
2668 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2670 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2671 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2672 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2673 //guint8 ev_id = ltt_event_eventtype_id(e);
2674 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2675 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2676 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2678 LttvExecutionSubmode submode
;
2679 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2680 guint64 nb_softirqs
= nt
->nb_soft_irqs
;
2682 if(softirq
< nb_softirqs
) {
2683 submode
= nt
->soft_irq_names
[softirq
];
2685 /* Fixup an incomplete irq table */
2686 GString
*string
= g_string_new("");
2687 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2688 submode
= g_quark_from_string(string
->str
);
2689 g_string_free(string
, TRUE
);
2692 /* update softirq status */
2693 /* a soft irq raises are not cumulative */
2694 ts
->soft_irq_states
[softirq
].pending
=1;
2699 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2701 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2702 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2703 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2704 //guint8 ev_id = ltt_event_eventtype_id(e);
2705 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2706 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2707 LttvExecutionSubmode submode
;
2708 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2709 expand_soft_irq_table(ts
, softirq
);
2710 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2711 submode
= nt
->soft_irq_names
[softirq
];
2713 /* Do something with the info about being in user or system mode when int? */
2714 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2716 /* update cpu status */
2717 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2719 /* update softirq status */
2720 g_array_append_val(s
->cpu_state
->softirq_stack
, softirq
);
2721 if(ts
->soft_irq_states
[softirq
].pending
)
2722 ts
->soft_irq_states
[softirq
].pending
--;
2723 ts
->soft_irq_states
[softirq
].running
++;
2728 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2731 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2732 LttvNameTables
*nt
= ts
->name_tables
;
2733 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2734 //guint8 ev_id = ltt_event_eventtype_id(e);
2735 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2737 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2738 lttv_trace_get_hook_field(th
, 0)));
2739 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2741 expand_irq_table(ts
, irq
);
2742 nt
->irq_names
[irq
] = action
;
2748 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2750 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2751 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2752 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2753 //guint8 ev_id = ltt_event_eventtype_id(e);
2754 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2756 guint major
= ltt_event_get_long_unsigned(e
,
2757 lttv_trace_get_hook_field(th
, 0));
2758 guint minor
= ltt_event_get_long_unsigned(e
,
2759 lttv_trace_get_hook_field(th
, 1));
2760 guint oper
= ltt_event_get_long_unsigned(e
,
2761 lttv_trace_get_hook_field(th
, 2));
2762 guint16 devcode
= MKDEV(major
,minor
);
2764 /* have we seen this block device before? */
2765 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2768 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2770 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2775 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2777 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2778 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2779 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2780 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2782 guint major
= ltt_event_get_long_unsigned(e
,
2783 lttv_trace_get_hook_field(th
, 0));
2784 guint minor
= ltt_event_get_long_unsigned(e
,
2785 lttv_trace_get_hook_field(th
, 1));
2786 //guint oper = ltt_event_get_long_unsigned(e,
2787 // lttv_trace_get_hook_field(th, 2));
2788 guint16 devcode
= MKDEV(major
,minor
);
2790 /* have we seen this block device before? */
2791 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2793 /* update block device */
2794 bdev_pop_mode(bdev
);
2799 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2803 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2804 guint cpu
= tfs
->cpu
;
2805 LttvProcessState
*process
= ts
->running_process
[cpu
];
2807 guint depth
= process
->user_stack
->len
;
2809 process
->user_stack
=
2810 g_array_set_size(process
->user_stack
, depth
+ 1);
2812 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2813 *new_func
= funcptr
;
2814 process
->current_function
= funcptr
;
2817 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2819 guint cpu
= tfs
->cpu
;
2820 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2821 LttvProcessState
*process
= ts
->running_process
[cpu
];
2823 if(process
->current_function
!= funcptr
){
2824 g_info("Different functions (%lu.%09lu): ignore it\n",
2825 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2826 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2827 process
->current_function
, funcptr
);
2828 g_info("{ %u, %u, %s, %s, %s }\n",
2831 g_quark_to_string(process
->name
),
2832 g_quark_to_string(process
->brand
),
2833 g_quark_to_string(process
->state
->s
));
2836 guint depth
= process
->user_stack
->len
;
2839 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2840 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2844 process
->user_stack
=
2845 g_array_set_size(process
->user_stack
, depth
- 1);
2846 process
->current_function
=
2847 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2851 static gboolean
function_entry(void *hook_data
, void *call_data
)
2853 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2854 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2855 //guint8 ev_id = ltt_event_eventtype_id(e);
2856 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2857 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2858 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2860 push_function(s
, funcptr
);
2864 static gboolean
function_exit(void *hook_data
, void *call_data
)
2866 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2867 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2868 //guint8 ev_id = ltt_event_eventtype_id(e);
2869 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2870 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2871 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2873 pop_function(s
, funcptr
);
2877 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2879 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2880 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2881 LttvNameTables
*nt
= ts
->name_tables
;
2882 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2883 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2888 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2889 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2890 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2892 expand_syscall_table(ts
, id
);
2893 nt
->syscall_names
[id
] = g_quark_from_string(symbol
);
2898 static gboolean
dump_kprobe(void *hook_data
, void *call_data
)
2900 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2901 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2902 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2903 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2907 ip
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2908 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 1));
2910 expand_kprobe_table(ts
, ip
, symbol
);
2915 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2917 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2918 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2919 LttvNameTables
*nt
= ts
->name_tables
;
2920 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2921 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2926 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2927 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2928 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2930 expand_soft_irq_table(ts
, id
);
2931 nt
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2936 static gboolean
schedchange(void *hook_data
, void *call_data
)
2938 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2940 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2941 LttvProcessState
*process
= ts
->running_process
[cpu
];
2942 //LttvProcessState *old_process = ts->running_process[cpu];
2944 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2945 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2946 guint pid_in
, pid_out
;
2949 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2950 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2951 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2953 if(likely(process
!= NULL
)) {
2955 /* We could not know but it was not the idle process executing.
2956 This should only happen at the beginning, before the first schedule
2957 event, and when the initial information (current process for each CPU)
2958 is missing. It is not obvious how we could, after the fact, compensate
2959 the wrongly attributed statistics. */
2961 //This test only makes sense once the state is known and if there is no
2962 //missing events. We need to silently ignore schedchange coming after a
2963 //process_free, or it causes glitches. (FIXME)
2964 //if(unlikely(process->pid != pid_out)) {
2965 // g_assert(process->pid == 0);
2967 if(process
->pid
== 0
2968 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2970 /* Scheduling out of pid 0 at beginning of the trace :
2971 * we know for sure it is in syscall mode at this point. */
2972 g_assert(process
->execution_stack
->len
== 1);
2973 process
->state
->t
= LTTV_STATE_SYSCALL
;
2974 process
->state
->s
= LTTV_STATE_WAIT
;
2975 process
->state
->change
= s
->parent
.timestamp
;
2976 process
->state
->entry
= s
->parent
.timestamp
;
2979 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2980 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2981 process
->state
->change
= s
->parent
.timestamp
;
2983 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2984 else process
->state
->s
= LTTV_STATE_WAIT
;
2985 process
->state
->change
= s
->parent
.timestamp
;
2988 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2989 /* see sched.h for states */
2990 if (!exit_process(s
, process
)) {
2991 process
->state
->s
= LTTV_STATE_DEAD
;
2992 process
->state
->change
= s
->parent
.timestamp
;
2997 process
= ts
->running_process
[cpu
] =
2998 lttv_state_find_process_or_create(
2999 (LttvTraceState
*)s
->parent
.t_context
,
3001 &s
->parent
.timestamp
);
3002 process
->state
->s
= LTTV_STATE_RUN
;
3004 if(process
->usertrace
)
3005 process
->usertrace
->cpu
= cpu
;
3006 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3007 process
->state
->change
= s
->parent
.timestamp
;
3009 /* update cpu status */
3011 /* going to idle task */
3012 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
3014 /* scheduling a real task.
3015 * we must be careful here:
3016 * if we just schedule()'ed to a process that is
3017 * in a trap, we must put the cpu in trap mode
3019 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
3020 if(process
->state
->t
== LTTV_STATE_TRAP
)
3021 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
3027 static gboolean
process_fork(void *hook_data
, void *call_data
)
3029 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3030 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3031 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3033 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
3034 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
3035 //LttvProcessState *zombie_process;
3037 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3038 LttvProcessState
*process
= ts
->running_process
[cpu
];
3039 LttvProcessState
*child_process
;
3040 struct marker_field
*f
;
3043 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3046 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3047 s
->parent
.target_pid
= child_pid
;
3050 f
= lttv_trace_get_hook_field(th
, 2);
3052 child_tgid
= ltt_event_get_unsigned(e
, f
);
3056 /* Mathieu : it seems like the process might have been scheduled in before the
3057 * fork, and, in a rare case, might be the current process. This might happen
3058 * in a SMP case where we don't have enough precision on the clocks.
3060 * Test reenabled after precision fixes on time. (Mathieu) */
3062 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3064 if(unlikely(zombie_process
!= NULL
)) {
3065 /* Reutilisation of PID. Only now we are sure that the old PID
3066 * has been released. FIXME : should know when release_task happens instead.
3068 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3070 for(i
=0; i
< num_cpus
; i
++) {
3071 g_assert(zombie_process
!= ts
->running_process
[i
]);
3074 exit_process(s
, zombie_process
);
3077 g_assert(process
->pid
!= child_pid
);
3078 // FIXME : Add this test in the "known state" section
3079 // g_assert(process->pid == parent_pid);
3080 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3081 if(child_process
== NULL
) {
3082 child_process
= lttv_state_create_process(ts
, process
, cpu
,
3083 child_pid
, child_tgid
,
3084 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
3086 /* The process has already been created : due to time imprecision between
3087 * multiple CPUs : it has been scheduled in before creation. Note that we
3088 * shouldn't have this kind of imprecision.
3090 * Simply put a correct parent.
3092 g_error("Process %u has been created at [%lu.%09lu] "
3093 "and inserted at [%lu.%09lu] before \n"
3094 "fork on cpu %u[%lu.%09lu].\n"
3095 "Probably an unsynchronized TSC problem on the traced machine.",
3097 child_process
->creation_time
.tv_sec
,
3098 child_process
->creation_time
.tv_nsec
,
3099 child_process
->insertion_time
.tv_sec
,
3100 child_process
->insertion_time
.tv_nsec
,
3101 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
3102 //g_assert(0); /* This is a problematic case : the process has been created
3103 // before the fork event */
3104 child_process
->ppid
= process
->pid
;
3105 child_process
->tgid
= child_tgid
;
3107 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
3108 child_process
->name
= process
->name
;
3109 child_process
->brand
= process
->brand
;
3114 /* We stamp a newly created process as kernel_thread.
3115 * The thread should not be running yet. */
3116 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
3118 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3119 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3120 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3122 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3123 LttvProcessState
*process
;
3124 LttvExecutionState
*es
;
3127 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3128 s
->parent
.target_pid
= pid
;
3130 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3132 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3133 process
->execution_stack
=
3134 g_array_set_size(process
->execution_stack
, 1);
3135 es
= process
->state
=
3136 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3137 es
->t
= LTTV_STATE_SYSCALL
;
3139 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3144 static gboolean
process_exit(void *hook_data
, void *call_data
)
3146 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3147 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3148 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3150 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3151 LttvProcessState
*process
; // = ts->running_process[cpu];
3153 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3154 s
->parent
.target_pid
= pid
;
3156 // FIXME : Add this test in the "known state" section
3157 // g_assert(process->pid == pid);
3159 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3160 if(likely(process
!= NULL
)) {
3161 process
->state
->s
= LTTV_STATE_EXIT
;
3166 static gboolean
process_free(void *hook_data
, void *call_data
)
3168 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3169 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3170 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3171 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3173 LttvProcessState
*process
;
3175 /* PID of the process to release */
3176 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3177 s
->parent
.target_pid
= release_pid
;
3179 g_assert(release_pid
!= 0);
3181 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3182 if(likely(process
!= NULL
))
3183 exit_process(s
, process
);
3186 if(likely(process
!= NULL
)) {
3187 /* release_task is happening at kernel level : we can now safely release
3188 * the data structure of the process */
3189 //This test is fun, though, as it may happen that
3190 //at time t : CPU 0 : process_free
3191 //at time t+150ns : CPU 1 : schedule out
3192 //Clearly due to time imprecision, we disable it. (Mathieu)
3193 //If this weird case happen, we have no choice but to put the
3194 //Currently running process on the cpu to 0.
3195 //I re-enable it following time precision fixes. (Mathieu)
3196 //Well, in the case where an process is freed by a process on another CPU
3197 //and still scheduled, it happens that this is the schedchange that will
3198 //drop the last reference count. Do not free it here!
3199 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3201 for(i
=0; i
< num_cpus
; i
++) {
3202 //g_assert(process != ts->running_process[i]);
3203 if(process
== ts
->running_process
[i
]) {
3204 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3208 if(i
== num_cpus
) /* process is not scheduled */
3209 exit_process(s
, process
);
3216 static gboolean
process_exec(void *hook_data
, void *call_data
)
3218 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3219 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3220 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3221 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3224 LttvProcessState
*process
= ts
->running_process
[cpu
];
3226 #if 0//how to use a sequence that must be transformed in a string
3227 /* PID of the process to release */
3228 guint64 name_len
= ltt_event_field_element_number(e
,
3229 lttv_trace_get_hook_field(th
, 0));
3230 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3231 LttField
*child
= ltt_event_field_element_select(e
,
3232 lttv_trace_get_hook_field(th
, 0), 0);
3234 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3235 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3236 memcpy(null_term_name
, name_begin
, name_len
);
3237 null_term_name
[name_len
] = '\0';
3238 process
->name
= g_quark_from_string(null_term_name
);
3241 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3242 lttv_trace_get_hook_field(th
, 0)));
3243 process
->brand
= LTTV_STATE_UNBRANDED
;
3244 //g_free(null_term_name);
3248 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3250 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3251 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3252 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3253 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3256 LttvProcessState
*process
= ts
->running_process
[cpu
];
3258 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3259 process
->brand
= g_quark_from_string(name
);
3264 static gboolean
fs_open(void *hook_data
, void *call_data
)
3266 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3267 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3268 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3269 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3270 struct marker_field
*f
;
3274 LttvProcessState
*process
= ts
->running_process
[cpu
];
3276 f
= lttv_trace_get_hook_field(th
, 0);
3277 fd
= ltt_event_get_int(e
, f
);
3279 f
= lttv_trace_get_hook_field(th
, 1);
3280 filename
= ltt_event_get_string(e
, f
);
3282 g_hash_table_insert(process
->fds
, (gpointer
)(long)fd
,
3283 (gpointer
)(unsigned long)g_quark_from_string(filename
));
3288 static void fix_process(gpointer key
, gpointer value
,
3291 LttvProcessState
*process
;
3292 LttvExecutionState
*es
;
3293 process
= (LttvProcessState
*)value
;
3294 LttTime
*timestamp
= (LttTime
*)user_data
;
3296 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3297 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3298 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3299 es
->t
= LTTV_STATE_SYSCALL
;
3300 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3301 es
->entry
= *timestamp
;
3302 es
->change
= *timestamp
;
3303 es
->cum_cpu_time
= ltt_time_zero
;
3304 if(es
->s
== LTTV_STATE_UNNAMED
)
3305 es
->s
= LTTV_STATE_WAIT
;
3308 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3309 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3310 es
->t
= LTTV_STATE_USER_MODE
;
3311 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3312 es
->entry
= *timestamp
;
3313 //g_assert(timestamp->tv_sec != 0);
3314 es
->change
= *timestamp
;
3315 es
->cum_cpu_time
= ltt_time_zero
;
3316 if(es
->s
== LTTV_STATE_UNNAMED
)
3317 es
->s
= LTTV_STATE_RUN
;
3319 if(process
->execution_stack
->len
== 1) {
3320 /* Still in bottom unknown mode, means never did a system call
3321 * May be either in user mode, syscall mode, running or waiting.*/
3322 /* FIXME : we may be tagging syscall mode when being user mode */
3323 process
->execution_stack
=
3324 g_array_set_size(process
->execution_stack
, 2);
3325 es
= process
->state
= &g_array_index(process
->execution_stack
,
3326 LttvExecutionState
, 1);
3327 es
->t
= LTTV_STATE_SYSCALL
;
3328 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3329 es
->entry
= *timestamp
;
3330 //g_assert(timestamp->tv_sec != 0);
3331 es
->change
= *timestamp
;
3332 es
->cum_cpu_time
= ltt_time_zero
;
3333 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3334 es
->s
= LTTV_STATE_WAIT
;
3340 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3342 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3343 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3344 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3345 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3346 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3348 /* For all processes */
3349 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3350 /* else, if stack[0] is unknown, set to user mode, running */
3352 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3357 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3359 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3360 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3361 //It's slow : optimise later by doing this before reading trace.
3362 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3368 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3369 LttvProcessState
*process
= ts
->running_process
[cpu
];
3370 LttvProcessState
*parent_process
;
3371 struct marker_field
*f
;
3372 GQuark type
, mode
, submode
, status
;
3373 LttvExecutionState
*es
;
3377 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3378 s
->parent
.target_pid
= pid
;
3381 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3384 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3387 f
= lttv_trace_get_hook_field(th
, 3);
3388 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3390 //FIXME: type is rarely used, enum must match possible types.
3393 f
= lttv_trace_get_hook_field(th
, 4);
3394 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3397 f
= lttv_trace_get_hook_field(th
, 5);
3398 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3401 f
= lttv_trace_get_hook_field(th
, 6);
3402 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3405 f
= lttv_trace_get_hook_field(th
, 7);
3407 tgid
= ltt_event_get_unsigned(e
, f
);
3412 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3413 for(i
=0; i
<nb_cpus
; i
++) {
3414 process
= lttv_state_find_process(ts
, i
, pid
);
3415 g_assert(process
!= NULL
);
3417 process
->ppid
= parent_pid
;
3418 process
->tgid
= tgid
;
3419 process
->name
= g_quark_from_string(command
);
3421 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3422 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3426 /* The process might exist if a process was forked while performing the
3428 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3429 if(process
== NULL
) {
3430 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3431 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3432 pid
, tgid
, g_quark_from_string(command
),
3433 &s
->parent
.timestamp
);
3435 /* Keep the stack bottom : a running user mode */
3436 /* Disabled because of inconsistencies in the current statedump states. */
3437 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3438 /* Only keep the bottom
3439 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3440 /* Will cause expected trap when in fact being syscall (even after end of
3442 * Will cause expected interrupt when being syscall. (only before end of
3443 * statedump event) */
3444 // This will cause a "popping last state on stack, ignoring it."
3445 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3446 es
= process
->state
= &g_array_index(process
->execution_stack
,
3447 LttvExecutionState
, 0);
3448 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3449 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3450 es
->s
= LTTV_STATE_UNNAMED
;
3451 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3453 es
->t
= LTTV_STATE_SYSCALL
;
3458 /* User space process :
3459 * bottom : user mode
3460 * either currently running or scheduled out.
3461 * can be scheduled out because interrupted in (user mode or in syscall)
3462 * or because of an explicit call to the scheduler in syscall. Note that
3463 * the scheduler call comes after the irq_exit, so never in interrupt
3465 // temp workaround : set size to 1 : only have user mode bottom of stack.
3466 // will cause g_info message of expected syscall mode when in fact being
3467 // in user mode. Can also cause expected trap when in fact being user
3468 // mode in the event of a page fault reenabling interrupts in the handler.
3469 // Expected syscall and trap can also happen after the end of statedump
3470 // This will cause a "popping last state on stack, ignoring it."
3471 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3472 es
= process
->state
= &g_array_index(process
->execution_stack
,
3473 LttvExecutionState
, 0);
3474 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3475 es
->s
= LTTV_STATE_UNNAMED
;
3476 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3478 es
->t
= LTTV_STATE_USER_MODE
;
3486 es
= process
->state
= &g_array_index(process
->execution_stack
,
3487 LttvExecutionState
, 1);
3488 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3489 es
->s
= LTTV_STATE_UNNAMED
;
3490 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3494 /* The process has already been created :
3495 * Probably was forked while dumping the process state or
3496 * was simply scheduled in prior to get the state dump event.
3498 process
->ppid
= parent_pid
;
3499 process
->tgid
= tgid
;
3500 process
->name
= g_quark_from_string(command
);
3501 process
->type
= type
;
3503 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3505 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3506 if(type
== LTTV_STATE_KERNEL_THREAD
)
3507 es
->t
= LTTV_STATE_SYSCALL
;
3509 es
->t
= LTTV_STATE_USER_MODE
;
3512 /* Don't mess around with the stack, it will eventually become
3513 * ok after the end of state dump. */
3520 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3522 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3524 lttv_state_add_event_hooks(tss
);
3529 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3531 LttvTraceset
*traceset
= self
->parent
.ts
;
3533 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3537 LttvTracefileState
*tfs
;
3543 LttvAttributeValue val
;
3545 nb_trace
= lttv_traceset_number(traceset
);
3546 for(i
= 0 ; i
< nb_trace
; i
++) {
3547 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3549 /* Find the eventtype id for the following events and register the
3550 associated by id hooks. */
3552 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 20);
3553 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3556 lttv_trace_find_hook(ts
->parent
.t
,
3558 LTT_EVENT_SYSCALL_ENTRY
,
3559 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3560 syscall_entry
, NULL
, &hooks
);
3562 lttv_trace_find_hook(ts
->parent
.t
,
3564 LTT_EVENT_SYSCALL_EXIT
,
3566 syscall_exit
, NULL
, &hooks
);
3568 lttv_trace_find_hook(ts
->parent
.t
,
3570 LTT_EVENT_TRAP_ENTRY
,
3571 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3572 trap_entry
, NULL
, &hooks
);
3574 lttv_trace_find_hook(ts
->parent
.t
,
3576 LTT_EVENT_TRAP_EXIT
,
3578 trap_exit
, NULL
, &hooks
);
3580 lttv_trace_find_hook(ts
->parent
.t
,
3582 LTT_EVENT_PAGE_FAULT_ENTRY
,
3583 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3584 trap_entry
, NULL
, &hooks
);
3586 lttv_trace_find_hook(ts
->parent
.t
,
3588 LTT_EVENT_PAGE_FAULT_EXIT
,
3590 trap_exit
, NULL
, &hooks
);
3592 lttv_trace_find_hook(ts
->parent
.t
,
3594 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3595 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3596 trap_entry
, NULL
, &hooks
);
3598 lttv_trace_find_hook(ts
->parent
.t
,
3600 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3602 trap_exit
, NULL
, &hooks
);
3604 lttv_trace_find_hook(ts
->parent
.t
,
3606 LTT_EVENT_IRQ_ENTRY
,
3607 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3608 irq_entry
, NULL
, &hooks
);
3610 lttv_trace_find_hook(ts
->parent
.t
,
3614 irq_exit
, NULL
, &hooks
);
3616 lttv_trace_find_hook(ts
->parent
.t
,
3618 LTT_EVENT_SOFT_IRQ_RAISE
,
3619 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3620 soft_irq_raise
, NULL
, &hooks
);
3622 lttv_trace_find_hook(ts
->parent
.t
,
3624 LTT_EVENT_SOFT_IRQ_ENTRY
,
3625 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3626 soft_irq_entry
, NULL
, &hooks
);
3628 lttv_trace_find_hook(ts
->parent
.t
,
3630 LTT_EVENT_SOFT_IRQ_EXIT
,
3632 soft_irq_exit
, NULL
, &hooks
);
3634 lttv_trace_find_hook(ts
->parent
.t
,
3636 LTT_EVENT_SCHED_SCHEDULE
,
3637 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3638 LTT_FIELD_PREV_STATE
),
3639 schedchange
, NULL
, &hooks
);
3641 lttv_trace_find_hook(ts
->parent
.t
,
3643 LTT_EVENT_PROCESS_FORK
,
3644 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3645 LTT_FIELD_CHILD_TGID
),
3646 process_fork
, NULL
, &hooks
);
3648 lttv_trace_find_hook(ts
->parent
.t
,
3650 LTT_EVENT_KTHREAD_CREATE
,
3651 FIELD_ARRAY(LTT_FIELD_PID
),
3652 process_kernel_thread
, NULL
, &hooks
);
3654 lttv_trace_find_hook(ts
->parent
.t
,
3656 LTT_EVENT_PROCESS_EXIT
,
3657 FIELD_ARRAY(LTT_FIELD_PID
),
3658 process_exit
, NULL
, &hooks
);
3660 lttv_trace_find_hook(ts
->parent
.t
,
3662 LTT_EVENT_PROCESS_FREE
,
3663 FIELD_ARRAY(LTT_FIELD_PID
),
3664 process_free
, NULL
, &hooks
);
3666 lttv_trace_find_hook(ts
->parent
.t
,
3669 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3670 process_exec
, NULL
, &hooks
);
3672 lttv_trace_find_hook(ts
->parent
.t
,
3673 LTT_CHANNEL_USERSPACE
,
3674 LTT_EVENT_THREAD_BRAND
,
3675 FIELD_ARRAY(LTT_FIELD_NAME
),
3676 thread_brand
, NULL
, &hooks
);
3678 /* statedump-related hooks */
3679 lttv_trace_find_hook(ts
->parent
.t
,
3680 LTT_CHANNEL_TASK_STATE
,
3681 LTT_EVENT_PROCESS_STATE
,
3682 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3683 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3684 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3685 enum_process_state
, NULL
, &hooks
);
3687 lttv_trace_find_hook(ts
->parent
.t
,
3688 LTT_CHANNEL_GLOBAL_STATE
,
3689 LTT_EVENT_STATEDUMP_END
,
3691 statedump_end
, NULL
, &hooks
);
3693 lttv_trace_find_hook(ts
->parent
.t
,
3694 LTT_CHANNEL_IRQ_STATE
,
3695 LTT_EVENT_LIST_INTERRUPT
,
3696 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3697 enum_interrupt
, NULL
, &hooks
);
3699 lttv_trace_find_hook(ts
->parent
.t
,
3701 LTT_EVENT_REQUEST_ISSUE
,
3702 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3703 bdev_request_issue
, NULL
, &hooks
);
3705 lttv_trace_find_hook(ts
->parent
.t
,
3707 LTT_EVENT_REQUEST_COMPLETE
,
3708 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3709 bdev_request_complete
, NULL
, &hooks
);
3711 lttv_trace_find_hook(ts
->parent
.t
,
3712 LTT_CHANNEL_USERSPACE
,
3713 LTT_EVENT_FUNCTION_ENTRY
,
3714 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3715 function_entry
, NULL
, &hooks
);
3717 lttv_trace_find_hook(ts
->parent
.t
,
3718 LTT_CHANNEL_USERSPACE
,
3719 LTT_EVENT_FUNCTION_EXIT
,
3720 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3721 function_exit
, NULL
, &hooks
);
3723 lttv_trace_find_hook(ts
->parent
.t
,
3724 LTT_CHANNEL_SYSCALL_STATE
,
3725 LTT_EVENT_SYS_CALL_TABLE
,
3726 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3727 dump_syscall
, NULL
, &hooks
);
3729 lttv_trace_find_hook(ts
->parent
.t
,
3730 LTT_CHANNEL_KPROBE_STATE
,
3731 LTT_EVENT_KPROBE_TABLE
,
3732 FIELD_ARRAY(LTT_FIELD_IP
, LTT_FIELD_SYMBOL
),
3733 dump_kprobe
, NULL
, &hooks
);
3735 lttv_trace_find_hook(ts
->parent
.t
,
3736 LTT_CHANNEL_SOFTIRQ_STATE
,
3737 LTT_EVENT_SOFTIRQ_VEC
,
3738 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3739 dump_softirq
, NULL
, &hooks
);
3741 lttv_trace_find_hook(ts
->parent
.t
,
3744 FIELD_ARRAY(LTT_FIELD_FD
, LTT_FIELD_FILENAME
),
3745 fs_open
, NULL
, &hooks
);
3747 /* Add these hooks to each event_by_id hooks list */
3749 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3751 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3753 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3754 LttvTracefileContext
*, j
));
3756 for(k
= 0 ; k
< hooks
->len
; k
++) {
3757 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3758 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3760 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3766 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3767 *(val
.v_pointer
) = hooks
;
3771 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3773 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3775 lttv_state_remove_event_hooks(tss
);
3780 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3782 LttvTraceset
*traceset
= self
->parent
.ts
;
3784 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3788 LttvTracefileState
*tfs
;
3794 LttvAttributeValue val
;
3796 nb_trace
= lttv_traceset_number(traceset
);
3797 for(i
= 0 ; i
< nb_trace
; i
++) {
3798 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3800 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3801 hooks
= *(val
.v_pointer
);
3803 /* Remove these hooks from each event_by_id hooks list */
3805 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3807 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3809 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3810 LttvTracefileContext
*, j
));
3812 for(k
= 0 ; k
< hooks
->len
; k
++) {
3813 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3814 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3815 lttv_hooks_remove_data(
3816 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3821 lttv_trace_hook_remove_all(&hooks
);
3822 g_array_free(hooks
, TRUE
);
3826 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3828 guint
*event_count
= (guint
*)hook_data
;
3830 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3831 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3836 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3838 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3840 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3842 LttvAttributeValue value
;
3844 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3845 LTTV_STATE_SAVED_STATES
);
3846 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3847 value
= lttv_attribute_add(saved_states_tree
,
3848 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3849 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3850 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3851 *(value
.v_time
) = self
->parent
.timestamp
;
3852 lttv_state_save(tcs
, saved_state_tree
);
3853 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3854 self
->parent
.timestamp
.tv_nsec
);
3856 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3861 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3863 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3865 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3870 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3878 static gboolean
block_start(void *hook_data
, void *call_data
)
3880 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3882 LttvTracefileState
*tfcs
;
3884 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3886 LttEventPosition
*ep
;
3888 guint i
, nb_block
, nb_event
, nb_tracefile
;
3892 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3894 LttvAttributeValue value
;
3896 ep
= ltt_event_position_new();
3898 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3900 /* Count the number of events added since the last block end in any
3903 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3905 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3906 LttvTracefileContext
, i
));
3907 ltt_event_position(tfcs
->parent
.e
, ep
);
3908 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3909 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3910 tfcs
->saved_position
= nb_event
;
3914 if(tcs
->nb_event
>= tcs
->save_interval
) {
3915 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3916 LTTV_STATE_SAVED_STATES
);
3917 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3918 value
= lttv_attribute_add(saved_states_tree
,
3919 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3920 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3921 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3922 *(value
.v_time
) = self
->parent
.timestamp
;
3923 lttv_state_save(tcs
, saved_state_tree
);
3925 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3926 self
->parent
.timestamp
.tv_nsec
);
3928 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3934 static gboolean
block_end(void *hook_data
, void *call_data
)
3936 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3938 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3942 LttEventPosition
*ep
;
3944 guint nb_block
, nb_event
;
3946 ep
= ltt_event_position_new();
3947 ltt_event_position(self
->parent
.e
, ep
);
3948 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3949 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3950 self
->saved_position
= 0;
3951 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3958 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3960 LttvTraceset
*traceset
= self
->parent
.ts
;
3962 guint i
, j
, nb_trace
, nb_tracefile
;
3966 LttvTracefileState
*tfs
;
3968 LttvTraceHook hook_start
, hook_end
;
3970 nb_trace
= lttv_traceset_number(traceset
);
3971 for(i
= 0 ; i
< nb_trace
; i
++) {
3972 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3974 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3975 NULL
, NULL
, block_start
, &hook_start
);
3976 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3977 NULL
, NULL
, block_end
, &hook_end
);
3979 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3981 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3983 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3984 LttvTracefileContext
, j
));
3985 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3986 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3987 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3988 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3994 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3996 LttvTraceset
*traceset
= self
->parent
.ts
;
3998 guint i
, j
, nb_trace
, nb_tracefile
;
4002 LttvTracefileState
*tfs
;
4005 nb_trace
= lttv_traceset_number(traceset
);
4006 for(i
= 0 ; i
< nb_trace
; i
++) {
4008 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4009 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4011 if(ts
->has_precomputed_states
) continue;
4013 guint
*event_count
= g_new(guint
, 1);
4016 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4018 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4019 LttvTracefileContext
*, j
));
4020 lttv_hooks_add(tfs
->parent
.event
,
4021 state_save_event_hook
,
4028 lttv_process_traceset_begin(&self
->parent
,
4029 NULL
, NULL
, NULL
, NULL
, NULL
);
4033 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
4035 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4037 lttv_state_save_add_event_hooks(tss
);
4044 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4046 LttvTraceset
*traceset
= self
->parent
.ts
;
4048 guint i
, j
, nb_trace
, nb_tracefile
;
4052 LttvTracefileState
*tfs
;
4054 LttvTraceHook hook_start
, hook_end
;
4056 nb_trace
= lttv_traceset_number(traceset
);
4057 for(i
= 0 ; i
< nb_trace
; i
++) {
4058 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
4060 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4061 NULL
, NULL
, block_start
, &hook_start
);
4063 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4064 NULL
, NULL
, block_end
, &hook_end
);
4066 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4068 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4070 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4071 LttvTracefileContext
, j
));
4072 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4073 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
4074 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4075 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
4081 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4083 LttvTraceset
*traceset
= self
->parent
.ts
;
4085 guint i
, j
, nb_trace
, nb_tracefile
;
4089 LttvTracefileState
*tfs
;
4091 LttvHooks
*after_trace
= lttv_hooks_new();
4093 lttv_hooks_add(after_trace
,
4094 state_save_after_trace_hook
,
4099 lttv_process_traceset_end(&self
->parent
,
4100 NULL
, after_trace
, NULL
, NULL
, NULL
);
4102 lttv_hooks_destroy(after_trace
);
4104 nb_trace
= lttv_traceset_number(traceset
);
4105 for(i
= 0 ; i
< nb_trace
; i
++) {
4107 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4108 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4110 if(ts
->has_precomputed_states
) continue;
4112 guint
*event_count
= NULL
;
4114 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4116 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4117 LttvTracefileContext
*, j
));
4118 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
4119 state_save_event_hook
);
4121 if(event_count
) g_free(event_count
);
4125 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
4127 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4129 lttv_state_save_remove_event_hooks(tss
);
4134 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
4136 LttvTraceset
*traceset
= self
->parent
.ts
;
4140 int min_pos
, mid_pos
, max_pos
;
4142 guint call_rest
= 0;
4144 LttvTraceState
*tcs
;
4146 LttvAttributeValue value
;
4148 LttvAttributeType type
;
4150 LttvAttributeName name
;
4154 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
4156 //g_tree_destroy(self->parent.pqueue);
4157 //self->parent.pqueue = g_tree_new(compare_tracefile);
4159 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
4161 nb_trace
= lttv_traceset_number(traceset
);
4162 for(i
= 0 ; i
< nb_trace
; i
++) {
4163 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4165 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4166 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4167 LTTV_STATE_SAVED_STATES
);
4170 if(saved_states_tree
) {
4171 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4172 mid_pos
= max_pos
/ 2;
4173 while(min_pos
< max_pos
) {
4174 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
4176 g_assert(type
== LTTV_GOBJECT
);
4177 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4178 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
4180 g_assert(type
== LTTV_TIME
);
4181 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4183 closest_tree
= saved_state_tree
;
4185 else max_pos
= mid_pos
- 1;
4187 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4191 /* restore the closest earlier saved state */
4193 lttv_state_restore(tcs
, closest_tree
);
4197 /* There is no saved state, yet we want to have it. Restart at T0 */
4199 restore_init_state(tcs
);
4200 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4203 /* We want to seek quickly without restoring/updating the state */
4205 restore_init_state(tcs
);
4206 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4209 if(!call_rest
) g_info("NOT Calling restore");
4214 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4220 traceset_state_finalize (LttvTracesetState
*self
)
4222 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4223 finalize(G_OBJECT(self
));
4228 traceset_state_class_init (LttvTracesetContextClass
*klass
)
4230 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4232 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4233 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4234 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4235 klass
->new_traceset_context
= new_traceset_context
;
4236 klass
->new_trace_context
= new_trace_context
;
4237 klass
->new_tracefile_context
= new_tracefile_context
;
4242 lttv_traceset_state_get_type(void)
4244 static GType type
= 0;
4246 static const GTypeInfo info
= {
4247 sizeof (LttvTracesetStateClass
),
4248 NULL
, /* base_init */
4249 NULL
, /* base_finalize */
4250 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4251 NULL
, /* class_finalize */
4252 NULL
, /* class_data */
4253 sizeof (LttvTracesetState
),
4254 0, /* n_preallocs */
4255 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4256 NULL
/* value handling */
4259 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4267 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4273 trace_state_finalize (LttvTraceState
*self
)
4275 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4276 finalize(G_OBJECT(self
));
4281 trace_state_class_init (LttvTraceStateClass
*klass
)
4283 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4285 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4286 klass
->state_save
= state_save
;
4287 klass
->state_restore
= state_restore
;
4288 klass
->state_saved_free
= state_saved_free
;
4293 lttv_trace_state_get_type(void)
4295 static GType type
= 0;
4297 static const GTypeInfo info
= {
4298 sizeof (LttvTraceStateClass
),
4299 NULL
, /* base_init */
4300 NULL
, /* base_finalize */
4301 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4302 NULL
, /* class_finalize */
4303 NULL
, /* class_data */
4304 sizeof (LttvTraceState
),
4305 0, /* n_preallocs */
4306 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4307 NULL
/* value handling */
4310 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4311 "LttvTraceStateType", &info
, 0);
4318 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4324 tracefile_state_finalize (LttvTracefileState
*self
)
4326 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4327 finalize(G_OBJECT(self
));
4332 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4334 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4336 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4341 lttv_tracefile_state_get_type(void)
4343 static GType type
= 0;
4345 static const GTypeInfo info
= {
4346 sizeof (LttvTracefileStateClass
),
4347 NULL
, /* base_init */
4348 NULL
, /* base_finalize */
4349 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4350 NULL
, /* class_finalize */
4351 NULL
, /* class_data */
4352 sizeof (LttvTracefileState
),
4353 0, /* n_preallocs */
4354 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4355 NULL
/* value handling */
4358 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4359 "LttvTracefileStateType", &info
, 0);
4365 static void module_init()
4367 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4368 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4369 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4370 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4371 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4372 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4373 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4374 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4375 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4376 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4377 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4378 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4379 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4380 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4381 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4382 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4383 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4384 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4385 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4386 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4387 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4388 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4389 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4390 LTTV_STATE_EVENT
= g_quark_from_string("event");
4391 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4392 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4393 LTTV_STATE_TIME
= g_quark_from_string("time");
4394 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4395 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4396 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4397 g_quark_from_string("trace_state_use_count");
4398 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4399 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4400 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4401 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4402 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4403 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4405 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4406 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4407 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4408 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4409 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4410 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4411 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4412 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4413 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4414 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4415 LTT_CHANNEL_KPROBE_STATE
= g_quark_from_string("kprobe_state");
4416 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4417 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4418 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4419 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4420 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4422 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4423 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4424 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4425 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4426 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4427 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4428 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4429 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4430 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4431 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4432 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4433 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4434 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4435 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4436 LTT_EVENT_SCHED_TRY_WAKEUP
= g_quark_from_string("sched_try_wakeup");
4437 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4438 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4439 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4440 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4441 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4442 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4443 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4444 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4445 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4446 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4447 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4448 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4449 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4450 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4451 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4452 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4453 LTT_EVENT_KPROBE
= g_quark_from_string("kprobe");
4454 LTT_EVENT_OPEN
= g_quark_from_string("open");
4455 LTT_EVENT_READ
= g_quark_from_string("read");
4456 LTT_EVENT_POLL_EVENT
= g_quark_from_string("poll_event");
4458 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4459 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4460 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4461 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4462 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4463 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4464 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4465 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4466 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4467 LTT_FIELD_PID
= g_quark_from_string("pid");
4468 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4469 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4470 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4471 LTT_FIELD_NAME
= g_quark_from_string("name");
4472 LTT_FIELD_TYPE
= g_quark_from_string("type");
4473 LTT_FIELD_MODE
= g_quark_from_string("mode");
4474 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4475 LTT_FIELD_STATUS
= g_quark_from_string("status");
4476 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4477 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4478 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4479 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4480 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4481 LTT_FIELD_ACTION
= g_quark_from_string("action");
4482 LTT_FIELD_ID
= g_quark_from_string("id");
4483 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4484 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4485 LTT_FIELD_IP
= g_quark_from_string("ip");
4486 LTT_FIELD_FD
= g_quark_from_string("fd");
4488 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4489 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4490 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4491 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4492 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4493 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4495 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4496 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4497 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4499 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4500 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4501 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4502 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4505 static void module_destroy()
4510 LTTV_MODULE("state", "State computation", \
4511 "Update the system state, possibly saving it at intervals", \
4512 module_init
, module_destroy
)