1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
31 #include <ltt/marker-desc.h>
34 #include <ltt/ltt-private.h>
39 * usertrace is there only to be able to update the current CPU of the
40 * usertraces when there is a schedchange. it is a way to link the ProcessState
41 * to the associated usertrace. Link only created upon thread creation.
43 * The cpu id is necessary : it gives us back the current ProcessState when we
44 * are considering data from the usertrace.
47 #define PREALLOCATED_EXECUTION_STACK 10
53 LTT_CHANNEL_GLOBAL_STATE
,
54 LTT_CHANNEL_IRQ_STATE
,
55 LTT_CHANNEL_MODULE_STATE
,
56 LTT_CHANNEL_NETIF_STATE
,
57 LTT_CHANNEL_SOFTIRQ_STATE
,
58 LTT_CHANNEL_SWAP_STATE
,
59 LTT_CHANNEL_SYSCALL_STATE
,
60 LTT_CHANNEL_TASK_STATE
,
62 LTT_CHANNEL_KPROBE_STATE
,
66 LTT_CHANNEL_USERSPACE
,
72 LTT_EVENT_SYSCALL_ENTRY
,
73 LTT_EVENT_SYSCALL_EXIT
,
74 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
75 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
76 LTT_EVENT_PAGE_FAULT_ENTRY
,
77 LTT_EVENT_PAGE_FAULT_EXIT
,
82 LTT_EVENT_SOFT_IRQ_RAISE
,
83 LTT_EVENT_SOFT_IRQ_ENTRY
,
84 LTT_EVENT_SOFT_IRQ_EXIT
,
85 LTT_EVENT_SCHED_SCHEDULE
,
86 LTT_EVENT_SCHED_TRY_WAKEUP
,
87 LTT_EVENT_PROCESS_FORK
,
88 LTT_EVENT_KTHREAD_CREATE
,
89 LTT_EVENT_PROCESS_EXIT
,
90 LTT_EVENT_PROCESS_FREE
,
92 LTT_EVENT_PROCESS_STATE
,
93 LTT_EVENT_STATEDUMP_END
,
94 LTT_EVENT_FUNCTION_ENTRY
,
95 LTT_EVENT_FUNCTION_EXIT
,
96 LTT_EVENT_THREAD_BRAND
,
97 LTT_EVENT_REQUEST_ISSUE
,
98 LTT_EVENT_REQUEST_COMPLETE
,
99 LTT_EVENT_LIST_INTERRUPT
,
100 LTT_EVENT_SYS_CALL_TABLE
,
101 LTT_EVENT_SOFTIRQ_VEC
,
102 LTT_EVENT_KPROBE_TABLE
,
106 LTT_EVENT_POLL_EVENT
;
111 LTT_FIELD_SYSCALL_ID
,
114 LTT_FIELD_SOFT_IRQ_ID
,
117 LTT_FIELD_PREV_STATE
,
118 LTT_FIELD_PARENT_PID
,
122 LTT_FIELD_CHILD_TGID
,
144 LTTV_STATE_MODE_UNKNOWN
,
145 LTTV_STATE_USER_MODE
,
152 LTTV_STATE_SUBMODE_UNKNOWN
,
153 LTTV_STATE_SUBMODE_NONE
;
157 LTTV_STATE_WAIT_FORK
,
166 LTTV_STATE_UNBRANDED
;
169 LTTV_STATE_USER_THREAD
,
170 LTTV_STATE_KERNEL_THREAD
;
188 LTTV_BDEV_BUSY_READING
,
189 LTTV_BDEV_BUSY_WRITING
;
192 LTTV_STATE_TRACEFILES
,
193 LTTV_STATE_PROCESSES
,
195 LTTV_STATE_RUNNING_PROCESS
,
197 LTTV_STATE_SAVED_STATES
,
198 LTTV_STATE_SAVED_STATES_TIME
,
201 LTTV_STATE_NAME_TABLES
,
202 LTTV_STATE_TRACE_STATE_USE_COUNT
,
203 LTTV_STATE_RESOURCE_CPUS
,
204 LTTV_STATE_RESOURCE_CPUS_COUNT
,
205 LTTV_STATE_RESOURCE_IRQS
,
206 LTTV_STATE_RESOURCE_SOFT_IRQS
,
207 LTTV_STATE_RESOURCE_TRAPS
,
208 LTTV_STATE_RESOURCE_BLKDEVS
;
210 static void create_max_time(LttvTraceState
*tcs
);
212 static void get_max_time(LttvTraceState
*tcs
);
214 static void free_max_time(LttvTraceState
*tcs
);
216 static void create_name_tables(LttvTraceState
*tcs
);
218 static void get_name_tables(LttvTraceState
*tcs
);
220 static void free_name_tables(LttvTraceState
*tcs
);
222 static void free_saved_state(LttvTraceState
*tcs
);
224 static void lttv_state_free_process_table(GHashTable
*processes
);
226 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
227 GPtrArray
*quarktable
);
229 /* Resource function prototypes */
230 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
);
231 static LttvBdevState
*bdevstate_new(void);
232 static void bdevstate_free(LttvBdevState
*);
233 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
234 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
237 #if (__WORDSIZE == 32)
238 guint
guint64_hash(gconstpointer key
)
240 guint64 ukey
= *(const guint64
*)key
;
242 return (guint
)ukey
^ (guint
)(ukey
>> 32);
245 gboolean
guint64_equal(gconstpointer a
, gconstpointer b
)
247 guint64 ua
= *(const guint64
*)a
;
248 guint64 ub
= *(const guint64
*)b
;
254 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
256 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
260 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
262 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
266 void lttv_state_state_saved_free(LttvTraceState
*self
,
267 LttvAttribute
*container
)
269 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
273 guint
process_hash(gconstpointer key
)
275 guint pid
= ((const LttvProcessState
*)key
)->pid
;
276 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
280 /* If the hash table hash function is well distributed,
281 * the process_equal should compare different pid */
282 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
284 const LttvProcessState
*process_a
, *process_b
;
287 process_a
= (const LttvProcessState
*)a
;
288 process_b
= (const LttvProcessState
*)b
;
290 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
291 else if(likely(process_a
->pid
== 0 &&
292 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
297 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
299 g_tree_destroy((GTree
*)value
);
302 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
304 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
305 g_hash_table_destroy(usertraces
);
308 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
313 static guint
check_expand(nb
, id
)
318 return max(id
+ 1, nb
* 2);
321 static void expand_name_table(LttvTraceState
*ts
, GQuark
**table
,
322 guint nb
, guint new_nb
)
324 /* Expand an incomplete table */
325 GQuark
*old_table
= *table
;
326 *table
= g_new(GQuark
, new_nb
);
327 memcpy(*table
, old_table
, nb
* sizeof(GQuark
));
331 static void fill_name_table(LttvTraceState
*ts
, GQuark
*table
, guint nb
,
332 guint new_nb
, const char *def_string
)
335 GString
*fe_name
= g_string_new("");
336 for(i
= nb
; i
< new_nb
; i
++) {
337 g_string_printf(fe_name
, "%s %d", def_string
, i
);
338 table
[i
] = g_quark_from_string(fe_name
->str
);
340 g_string_free(fe_name
, TRUE
);
343 static void expand_syscall_table(LttvTraceState
*ts
, int id
)
345 LttvNameTables
*nt
= ts
->name_tables
;
348 new_nb
= check_expand(nt
->nb_syscalls
, id
);
349 if(likely(new_nb
== nt
->nb_syscalls
))
351 expand_name_table(ts
, &nt
->syscall_names
, nt
->nb_syscalls
, new_nb
);
352 fill_name_table(ts
, nt
->syscall_names
, nt
->nb_syscalls
, new_nb
, "syscall");
353 /* Update the table size */
354 nt
->nb_syscalls
= new_nb
;
357 static void expand_kprobe_table(LttvTraceState
*ts
, guint64 ip
, char *symbol
)
359 LttvNameTables
*nt
= ts
->name_tables
;
360 #if (__WORDSIZE == 32)
361 guint64
*ip_ptr
= g_new(guint64
, 1);
362 g_hash_table_insert(nt
->kprobe_hash
, ip_ptr
,
363 (gpointer
)(glong
)g_quark_from_string(symbol
));
365 g_hash_table_insert(nt
->kprobe_hash
, (gpointer
)ip
,
366 (gpointer
)(glong
)g_quark_from_string(symbol
));
370 static void expand_trap_table(LttvTraceState
*ts
, int id
)
372 LttvNameTables
*nt
= ts
->name_tables
;
373 LttvTrapState
*old_table
;
376 new_nb
= check_expand(nt
->nb_traps
, id
);
377 if(likely(new_nb
== nt
->nb_traps
))
380 expand_name_table(ts
, &nt
->trap_names
, nt
->nb_traps
, new_nb
);
381 fill_name_table(ts
, nt
->trap_names
, nt
->nb_traps
, new_nb
, "trap");
383 old_table
= ts
->trap_states
;
384 ts
->trap_states
= g_new(LttvTrapState
, new_nb
);
385 memcpy(ts
->trap_states
, old_table
, nt
->nb_traps
* sizeof(LttvTrapState
));
387 for(i
= nt
->nb_traps
; i
< new_nb
; i
++)
388 ts
->trap_states
[i
].running
= 0;
390 /* Update the table size */
391 nt
->nb_traps
= new_nb
;
394 static void expand_irq_table(LttvTraceState
*ts
, int id
)
396 LttvNameTables
*nt
= ts
->name_tables
;
397 LttvIRQState
*old_table
;
400 new_nb
= check_expand(nt
->nb_irqs
, id
);
401 if(likely(new_nb
== nt
->nb_irqs
))
404 expand_name_table(ts
, &nt
->irq_names
, nt
->nb_irqs
, new_nb
);
405 fill_name_table(ts
, nt
->irq_names
, nt
->nb_irqs
, new_nb
, "irq");
407 old_table
= ts
->irq_states
;
408 ts
->irq_states
= g_new(LttvIRQState
, new_nb
);
409 memcpy(ts
->irq_states
, old_table
, nt
->nb_irqs
* sizeof(LttvIRQState
));
411 for(i
= nt
->nb_irqs
; i
< new_nb
; i
++)
412 ts
->irq_states
[i
].mode_stack
=
413 g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
415 /* Update the table size */
416 nt
->nb_irqs
= new_nb
;
419 static void expand_soft_irq_table(LttvTraceState
*ts
, int id
)
421 LttvNameTables
*nt
= ts
->name_tables
;
422 LttvSoftIRQState
*old_table
;
425 new_nb
= check_expand(nt
->nb_soft_irqs
, id
);
426 if(likely(new_nb
== nt
->nb_soft_irqs
))
429 expand_name_table(ts
, &nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
);
430 fill_name_table(ts
, nt
->soft_irq_names
, nt
->nb_soft_irqs
, new_nb
, "softirq");
432 old_table
= ts
->soft_irq_states
;
433 ts
->soft_irq_states
= g_new(LttvSoftIRQState
, new_nb
);
434 memcpy(ts
->soft_irq_states
, old_table
,
435 nt
->nb_soft_irqs
* sizeof(LttvSoftIRQState
));
437 for(i
= nt
->nb_soft_irqs
; i
< new_nb
; i
++)
438 ts
->soft_irq_states
[i
].running
= 0;
440 /* Update the table size */
441 nt
->nb_soft_irqs
= new_nb
;
444 static void restore_init_state(LttvTraceState
*self
)
446 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
448 //LttvTracefileState *tfcs;
450 LttTime start_time
, end_time
;
452 /* Free the process tables */
453 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
454 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
455 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
456 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
459 /* Seek time to beginning */
460 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
461 // closest. It's the tracecontext job to seek the trace to the beginning
462 // anyway : the init state might be used at the middle of the trace as well...
463 //g_tree_destroy(self->parent.ts_context->pqueue);
464 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
466 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
468 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
470 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
471 nb_irqs
= self
->name_tables
->nb_irqs
;
472 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
473 nb_traps
= self
->name_tables
->nb_traps
;
475 /* Put the per cpu running_process to beginning state : process 0. */
476 for(i
=0; i
< nb_cpus
; i
++) {
477 LttvExecutionState
*es
;
478 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
479 LTTV_STATE_UNNAMED
, &start_time
);
480 /* We are not sure is it's a kernel thread or normal thread, put the
481 * bottom stack state to unknown */
482 self
->running_process
[i
]->execution_stack
=
483 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
484 es
= self
->running_process
[i
]->state
=
485 &g_array_index(self
->running_process
[i
]->execution_stack
,
486 LttvExecutionState
, 0);
487 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
488 es
->s
= LTTV_STATE_UNNAMED
;
490 //self->running_process[i]->state->s = LTTV_STATE_RUN;
491 self
->running_process
[i
]->cpu
= i
;
493 /* reset cpu states */
494 if(self
->cpu_states
[i
].mode_stack
->len
> 0) {
495 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0,
496 self
->cpu_states
[i
].mode_stack
->len
);
497 if(self
->cpu_states
[i
].irq_stack
->len
)
498 g_array_remove_range(self
->cpu_states
[i
].irq_stack
, 0,
499 self
->cpu_states
[i
].irq_stack
->len
);
500 if(self
->cpu_states
[i
].softirq_stack
->len
)
501 g_array_remove_range(self
->cpu_states
[i
].softirq_stack
, 0,
502 self
->cpu_states
[i
].softirq_stack
->len
);
503 if(self
->cpu_states
[i
].trap_stack
->len
)
504 g_array_remove_range(self
->cpu_states
[i
].trap_stack
, 0,
505 self
->cpu_states
[i
].trap_stack
->len
);
509 /* reset irq states */
510 for(i
=0; i
<nb_irqs
; i
++) {
511 if(self
->irq_states
[i
].mode_stack
->len
> 0)
512 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0,
513 self
->irq_states
[i
].mode_stack
->len
);
516 /* reset softirq states */
517 for(i
=0; i
<nb_soft_irqs
; i
++) {
518 self
->soft_irq_states
[i
].pending
= 0;
519 self
->soft_irq_states
[i
].running
= 0;
522 /* reset trap states */
523 for(i
=0; i
<nb_traps
; i
++) {
524 self
->trap_states
[i
].running
= 0;
527 /* reset bdev states */
528 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
529 //g_hash_table_steal_all(self->bdev_states);
530 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
533 nb_tracefile
= self
->parent
.tracefiles
->len
;
535 for(i
= 0 ; i
< nb_tracefile
; i
++) {
537 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
538 LttvTracefileContext
*, i
));
539 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
540 // tfcs->saved_position = 0;
541 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
542 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
543 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
544 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
549 //static LttTime time_zero = {0,0};
551 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
554 const LttTime
*t1
= (const LttTime
*)a
;
555 const LttTime
*t2
= (const LttTime
*)b
;
557 return ltt_time_compare(*t1
, *t2
);
560 static void free_usertrace_key(gpointer data
)
565 #define MAX_STRING_LEN 4096
567 static void state_load_saved_states(LttvTraceState
*tcs
)
570 GPtrArray
*quarktable
;
571 const char *trace_path
;
575 tcs
->has_precomputed_states
= FALSE
;
579 gchar buf
[MAX_STRING_LEN
];
582 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
583 strncpy(path
, trace_path
, PATH_MAX
-1);
584 count
= strnlen(trace_path
, PATH_MAX
-1);
585 // quarktable : open, test
586 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
587 fp
= fopen(path
, "r");
589 quarktable
= g_ptr_array_sized_new(4096);
591 /* Index 0 is null */
593 if(hdr
== EOF
) return;
594 g_assert(hdr
== HDR_QUARKS
);
598 if(hdr
== EOF
) break;
599 g_assert(hdr
== HDR_QUARK
);
600 g_ptr_array_set_size(quarktable
, q
+1);
603 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
604 if(buf
[i
] == '\0' || feof(fp
)) break;
607 len
= strnlen(buf
, MAX_STRING_LEN
-1);
608 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
609 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
615 // saved_states : open, test
616 strncpy(path
, trace_path
, PATH_MAX
-1);
617 count
= strnlen(trace_path
, PATH_MAX
-1);
618 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
619 fp
= fopen(path
, "r");
623 if(hdr
!= HDR_TRACE
) goto end
;
625 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
627 tcs
->has_precomputed_states
= TRUE
;
632 /* Free the quarktable */
633 for(i
=0; i
<quarktable
->len
; i
++) {
634 string
= g_ptr_array_index (quarktable
, i
);
637 g_ptr_array_free(quarktable
, TRUE
);
641 static void init(LttvTracesetState
*self
, LttvTraceset
*ts
)
643 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
646 LttvTraceContext
*tc
;
650 LttvTracefileState
*tfcs
;
652 LttvAttributeValue v
;
654 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
655 init((LttvTracesetContext
*)self
, ts
);
657 nb_trace
= lttv_traceset_number(ts
);
658 for(i
= 0 ; i
< nb_trace
; i
++) {
659 tc
= self
->parent
.traces
[i
];
660 tcs
= LTTV_TRACE_STATE(tc
);
661 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
662 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
666 if(*(v
.v_uint
) == 1) {
667 create_name_tables(tcs
);
668 create_max_time(tcs
);
670 get_name_tables(tcs
);
673 nb_tracefile
= tc
->tracefiles
->len
;
674 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
675 nb_irq
= tcs
->name_tables
->nb_irqs
;
676 tcs
->processes
= NULL
;
677 tcs
->usertraces
= NULL
;
678 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
680 /* init cpu resource stuff */
681 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
682 for(j
= 0; j
<nb_cpu
; j
++) {
683 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
684 tcs
->cpu_states
[j
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
685 tcs
->cpu_states
[j
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
686 tcs
->cpu_states
[j
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
687 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
690 /* init irq resource stuff */
691 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
692 for(j
= 0; j
<nb_irq
; j
++) {
693 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
694 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
697 /* init soft irq stuff */
698 /* the kernel has a statically fixed max of 32 softirqs */
699 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->name_tables
->nb_soft_irqs
);
701 /* init trap stuff */
702 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->name_tables
->nb_traps
);
704 /* init bdev resource stuff */
705 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
707 restore_init_state(tcs
);
708 for(j
= 0 ; j
< nb_tracefile
; j
++) {
710 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
711 LttvTracefileContext
*, j
));
712 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
713 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
714 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
715 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
716 /* It's a Usertrace */
717 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
718 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
719 GUINT_TO_POINTER(tid
));
720 if(!usertrace_tree
) {
721 usertrace_tree
= g_tree_new_full(compare_usertraces
,
722 NULL
, free_usertrace_key
, NULL
);
723 g_hash_table_insert(tcs
->usertraces
,
724 GUINT_TO_POINTER(tid
), usertrace_tree
);
726 LttTime
*timestamp
= g_new(LttTime
, 1);
727 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
728 ltt_tracefile_creation(tfcs
->parent
.tf
));
729 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
733 /* See if the trace has saved states */
734 state_load_saved_states(tcs
);
738 static void fini(LttvTracesetState
*self
)
744 //LttvTracefileState *tfcs;
746 LttvAttributeValue v
;
748 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
749 for(i
= 0 ; i
< nb_trace
; i
++) {
750 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
751 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
754 g_assert(*(v
.v_uint
) != 0);
757 if(*(v
.v_uint
) == 0) {
758 free_name_tables(tcs
);
760 free_saved_state(tcs
);
762 g_free(tcs
->running_process
);
763 tcs
->running_process
= NULL
;
764 lttv_state_free_process_table(tcs
->processes
);
765 lttv_state_free_usertraces(tcs
->usertraces
);
766 tcs
->processes
= NULL
;
767 tcs
->usertraces
= NULL
;
769 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
770 fini((LttvTracesetContext
*)self
);
774 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
776 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
780 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
782 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
786 static LttvTracefileContext
*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
;
807 fprintf(fp
," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" FREE_EVENTS=\"%u\">\n",
808 process
, process
->pid
, process
->tgid
, process
->ppid
,
809 g_quark_to_string(process
->type
),
810 process
->creation_time
.tv_sec
,
811 process
->creation_time
.tv_nsec
,
812 process
->insertion_time
.tv_sec
,
813 process
->insertion_time
.tv_nsec
,
814 g_quark_to_string(process
->name
),
815 g_quark_to_string(process
->brand
),
816 process
->cpu
, process
->free_events
);
818 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
819 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
820 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
821 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
822 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
823 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
824 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
827 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
828 address
= g_array_index(process
->user_stack
, guint64
, i
);
829 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n", address
);
832 if(process
->usertrace
) {
833 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
834 g_quark_to_string(process
->usertrace
->tracefile_name
),
835 process
->usertrace
->cpu
);
839 fprintf(fp
, " </PROCESS>\n");
843 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
845 guint i
, nb_tracefile
, nb_block
, offset
;
848 LttvTracefileState
*tfcs
;
852 LttEventPosition
*ep
;
856 ep
= ltt_event_position_new();
858 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
860 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
862 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
863 for(i
=0;i
<nb_cpus
;i
++) {
864 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
865 i
, self
->running_process
[i
]->pid
);
868 nb_tracefile
= self
->parent
.tracefiles
->len
;
870 for(i
= 0 ; i
< nb_tracefile
; i
++) {
872 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
873 LttvTracefileContext
*, i
));
874 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
875 tfcs
->parent
.timestamp
.tv_sec
,
876 tfcs
->parent
.timestamp
.tv_nsec
);
877 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
878 if(e
== NULL
) fprintf(fp
,"/>\n");
880 ltt_event_position(e
, ep
);
881 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
882 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
887 fprintf(fp
,"</PROCESS_STATE>\n");
891 static void write_process_state_raw(gpointer key
, gpointer value
,
894 LttvProcessState
*process
;
896 LttvExecutionState
*es
;
898 FILE *fp
= (FILE *)user_data
;
903 process
= (LttvProcessState
*)value
;
904 fputc(HDR_PROCESS
, fp
);
905 //fwrite(&header, sizeof(header), 1, fp);
906 //fprintf(fp, "%s", g_quark_to_string(process->type));
908 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
909 //fprintf(fp, "%s", g_quark_to_string(process->name));
911 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
912 //fprintf(fp, "%s", g_quark_to_string(process->brand));
914 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
915 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
916 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
917 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
918 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
919 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
920 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
921 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
924 fprintf(fp
," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
925 process
, process
->pid
, process
->tgid
, process
->ppid
,
926 g_quark_to_string(process
->type
),
927 process
->creation_time
.tv_sec
,
928 process
->creation_time
.tv_nsec
,
929 process
->insertion_time
.tv_sec
,
930 process
->insertion_time
.tv_nsec
,
931 g_quark_to_string(process
->name
),
932 g_quark_to_string(process
->brand
),
936 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
937 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
940 //fprintf(fp, "%s", g_quark_to_string(es->t));
942 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
943 //fprintf(fp, "%s", g_quark_to_string(es->n));
945 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
946 //fprintf(fp, "%s", g_quark_to_string(es->s));
948 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
949 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
950 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
951 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
953 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
954 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
955 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
956 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
957 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
961 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
962 address
= g_array_index(process
->user_stack
, guint64
, i
);
963 fputc(HDR_USER_STACK
, fp
);
964 fwrite(&address
, sizeof(address
), 1, fp
);
966 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n", address
);
970 if(process
->usertrace
) {
971 fputc(HDR_USERTRACE
, fp
);
972 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
974 fwrite(&process
->usertrace
->tracefile_name
,
975 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
976 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
978 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
979 g_quark_to_string(process
->usertrace
->tracefile_name
),
980 process
->usertrace
->cpu
);
987 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
989 guint i
, nb_tracefile
, nb_block
, offset
;
992 LttvTracefileState
*tfcs
;
996 LttEventPosition
*ep
;
1000 ep
= ltt_event_position_new();
1002 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1003 fputc(HDR_PROCESS_STATE
, fp
);
1004 fwrite(&t
, sizeof(t
), 1, fp
);
1006 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
1008 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1009 for(i
=0;i
<nb_cpus
;i
++) {
1011 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
1012 fwrite(&self
->running_process
[i
]->pid
,
1013 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1014 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1015 // i, self->running_process[i]->pid);
1018 nb_tracefile
= self
->parent
.tracefiles
->len
;
1020 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1022 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1023 LttvTracefileContext
*, i
));
1024 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1025 // tfcs->parent.timestamp.tv_sec,
1026 // tfcs->parent.timestamp.tv_nsec);
1027 fputc(HDR_TRACEFILE
, fp
);
1028 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1029 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1030 * position following : end of trace */
1031 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1033 ltt_event_position(e
, ep
);
1034 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1035 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1037 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
1038 fwrite(&offset
, sizeof(offset
), 1, fp
);
1039 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
1046 /* Read process state from a file */
1048 /* Called because a HDR_PROCESS was found */
1049 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
1050 GPtrArray
*quarktable
)
1052 LttvExecutionState
*es
;
1053 LttvProcessState
*process
, *parent_process
;
1054 LttvProcessState tmp
;
1059 /* TODO : check return value */
1060 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1061 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1062 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1063 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1064 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1065 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1066 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1067 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1068 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1069 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1072 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1074 /* We must link to the parent */
1075 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1077 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1078 if(process
== NULL
) {
1079 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1081 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1082 &tmp
.creation_time
);
1085 process
->insertion_time
= tmp
.insertion_time
;
1086 process
->creation_time
= tmp
.creation_time
;
1087 process
->type
= g_quark_from_string(
1088 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1089 process
->tgid
= tmp
.tgid
;
1090 process
->ppid
= tmp
.ppid
;
1091 process
->brand
= g_quark_from_string(
1092 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1094 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1095 process
->free_events
= tmp
.free_events
;
1098 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1100 gint hdr
= fgetc(fp
);
1101 if(hdr
== EOF
) goto end_loop
;
1105 process
->execution_stack
=
1106 g_array_set_size(process
->execution_stack
,
1107 process
->execution_stack
->len
+ 1);
1108 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1109 process
->execution_stack
->len
-1);
1110 process
->state
= es
;
1112 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1113 es
->t
= g_quark_from_string(
1114 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1115 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1116 es
->n
= g_quark_from_string(
1117 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1118 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1119 es
->s
= g_quark_from_string(
1120 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1121 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1122 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1123 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1126 case HDR_USER_STACK
:
1127 process
->user_stack
= g_array_set_size(process
->user_stack
,
1128 process
->user_stack
->len
+ 1);
1129 address
= &g_array_index(process
->user_stack
, guint64
,
1130 process
->user_stack
->len
-1);
1131 fread(address
, sizeof(address
), 1, fp
);
1132 process
->current_function
= *address
;
1136 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1137 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
1150 /* Called because a HDR_PROCESS_STATE was found */
1151 /* Append a saved state to the trace states */
1152 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1154 guint i
, nb_tracefile
, nb_block
, offset
;
1156 LttvTracefileState
*tfcs
;
1158 LttEventPosition
*ep
;
1166 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1168 LttvAttributeValue value
;
1169 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1170 ep
= ltt_event_position_new();
1172 restore_init_state(self
);
1174 fread(&t
, sizeof(t
), 1, fp
);
1177 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1179 if(hdr
== EOF
) goto end_loop
;
1183 /* Call read_process_state_raw */
1184 read_process_state_raw(self
, fp
, quarktable
);
1192 case HDR_USER_STACK
:
1194 case HDR_PROCESS_STATE
:
1200 g_error("Error while parsing saved state file : unknown data header %d",
1206 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1207 for(i
=0;i
<nb_cpus
;i
++) {
1210 g_assert(hdr
== HDR_CPU
);
1211 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1212 g_assert(i
== cpu_num
);
1213 fread(&self
->running_process
[i
]->pid
,
1214 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1217 nb_tracefile
= self
->parent
.tracefiles
->len
;
1219 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1221 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1222 LttvTracefileContext
*, i
));
1223 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1224 // tfcs->parent.timestamp.tv_sec,
1225 // tfcs->parent.timestamp.tv_nsec);
1226 g_tree_remove(pqueue
, &tfcs
->parent
);
1228 g_assert(hdr
== HDR_TRACEFILE
);
1229 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1230 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1231 * position following : end of trace */
1232 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1233 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1234 fread(&offset
, sizeof(offset
), 1, fp
);
1235 fread(&tsc
, sizeof(tsc
), 1, fp
);
1236 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1237 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1239 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1244 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1245 LTTV_STATE_SAVED_STATES
);
1246 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1247 value
= lttv_attribute_add(saved_states_tree
,
1248 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1249 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1250 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1251 *(value
.v_time
) = t
;
1252 lttv_state_save(self
, saved_state_tree
);
1253 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1256 *(self
->max_time_state_recomputed_in_seek
) = t
;
1260 /* Called when a HDR_TRACE is found */
1261 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1262 GPtrArray
*quarktable
)
1267 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1269 if(hdr
== EOF
) goto end_loop
;
1272 case HDR_PROCESS_STATE
:
1273 /* Call read_process_state_raw */
1274 lttv_state_read_raw(tcs
, fp
, quarktable
);
1282 case HDR_USER_STACK
:
1286 g_error("Error while parsing saved state file :"
1287 " unexpected data header %d",
1291 g_error("Error while parsing saved state file : unknown data header %d",
1296 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1297 restore_init_state(tcs
);
1298 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1304 /* Copy each process from an existing hash table to a new one */
1306 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1308 LttvProcessState
*process
, *new_process
;
1310 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1314 process
= (LttvProcessState
*)value
;
1315 new_process
= g_new(LttvProcessState
, 1);
1316 *new_process
= *process
;
1317 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1318 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1319 new_process
->execution_stack
=
1320 g_array_set_size(new_process
->execution_stack
,
1321 process
->execution_stack
->len
);
1322 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1323 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1324 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1326 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1327 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1328 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1329 sizeof(guint64
), 0);
1330 new_process
->user_stack
= g_array_set_size(new_process
->user_stack
,
1331 process
->user_stack
->len
);
1332 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1333 g_array_index(new_process
->user_stack
, guint64
, i
) =
1334 g_array_index(process
->user_stack
, guint64
, i
);
1336 new_process
->current_function
= process
->current_function
;
1338 /* fd hash table stuff */
1344 /* copy every item in the hash table */
1345 new_process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1347 g_hash_table_iter_init(&it
, process
->fds
);
1348 while (g_hash_table_iter_next (&it
, (void *)&key
, (void *)&value
)) {
1349 g_hash_table_insert(new_process
->fds
, key
, value
);
1353 /* When done creating the new process state, insert it in the
1355 g_hash_table_insert(new_processes
, new_process
, new_process
);
1359 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1361 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1363 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1364 return new_processes
;
1367 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1370 LttvCPUState
*retval
;
1372 retval
= g_new(LttvCPUState
, n
);
1374 for(i
=0; i
<n
; i
++) {
1375 retval
[i
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1376 g_array_set_size(retval
[i
].irq_stack
, states
[i
].irq_stack
->len
);
1377 for(j
=0; j
<states
[i
].irq_stack
->len
; j
++) {
1378 g_array_index(retval
[i
].irq_stack
, gint
, j
) =
1379 g_array_index(states
[i
].irq_stack
, gint
, j
);
1382 retval
[i
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1383 g_array_set_size(retval
[i
].softirq_stack
, states
[i
].softirq_stack
->len
);
1384 for(j
=0; j
<states
[i
].softirq_stack
->len
; j
++) {
1385 g_array_index(retval
[i
].softirq_stack
, gint
, j
) =
1386 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
) =
1393 g_array_index(states
[i
].trap_stack
, gint
, j
);
1396 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1397 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1398 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1399 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1400 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1407 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1411 for(i
=0; i
<n
; i
++) {
1412 g_array_free(states
[i
].mode_stack
, TRUE
);
1413 g_array_free(states
[i
].irq_stack
, TRUE
);
1414 g_array_free(states
[i
].softirq_stack
, TRUE
);
1415 g_array_free(states
[i
].trap_stack
, TRUE
);
1421 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1424 LttvIRQState
*retval
;
1426 retval
= g_new(LttvIRQState
, n
);
1428 for(i
=0; i
<n
; i
++) {
1429 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1430 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1431 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1432 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1433 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1440 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1444 for(i
=0; i
<n
; i
++) {
1445 g_array_free(states
[i
].mode_stack
, TRUE
);
1451 static LttvSoftIRQState
*
1452 lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1455 LttvSoftIRQState
*retval
;
1457 retval
= g_new(LttvSoftIRQState
, n
);
1459 for(i
=0; i
<n
; i
++) {
1460 retval
[i
].pending
= states
[i
].pending
;
1461 retval
[i
].running
= states
[i
].running
;
1467 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1472 static LttvTrapState
*
1473 lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1476 LttvTrapState
*retval
;
1478 retval
= g_new(LttvTrapState
, n
);
1480 for(i
=0; i
<n
; i
++) {
1481 retval
[i
].running
= states
[i
].running
;
1487 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1492 /* bdevstate stuff */
1494 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
)
1496 gint devcode_gint
= devcode
;
1497 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1499 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1500 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1502 gint
* key
= g_new(gint
, 1);
1504 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1512 static LttvBdevState
*bdevstate_new(void)
1514 LttvBdevState
*retval
;
1515 retval
= g_new(LttvBdevState
, 1);
1516 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1521 static void bdevstate_free(LttvBdevState
*bds
)
1523 g_array_free(bds
->mode_stack
, TRUE
);
1527 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1529 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1531 bdevstate_free(bds
);
1534 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1536 LttvBdevState
*retval
;
1538 retval
= bdevstate_new();
1539 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
,
1540 bds
->mode_stack
->len
);
1545 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1547 //GHashTable *ht = (GHashTable *)u;
1548 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1549 LttvBdevState
*newbds
;
1551 newbds
= bdevstate_copy(bds
);
1553 g_hash_table_insert(u
, k
, newbds
);
1556 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1560 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1562 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1567 /* Free a hashtable and the LttvBdevState structures its values
1570 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1572 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1573 g_hash_table_destroy(ht
);
1576 /* The saved state for each trace contains a member "processes", which
1577 stores a copy of the process table, and a member "tracefiles" with
1578 one entry per tracefile. Each tracefile has a "process" member pointing
1579 to the current process and a "position" member storing the tracefile
1580 position (needed to seek to the current "next" event. */
1582 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1584 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1586 LttvTracefileState
*tfcs
;
1588 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1590 guint
*running_process
;
1592 LttvAttributeValue value
;
1594 LttEventPosition
*ep
;
1596 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1597 LTTV_STATE_TRACEFILES
);
1599 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1601 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1603 /* Add the currently running processes array */
1604 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1605 running_process
= g_new(guint
, nb_cpus
);
1606 for(i
=0;i
<nb_cpus
;i
++) {
1607 running_process
[i
] = self
->running_process
[i
]->pid
;
1609 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1611 *(value
.v_pointer
) = running_process
;
1613 g_info("State save");
1615 nb_tracefile
= self
->parent
.tracefiles
->len
;
1617 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1619 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1620 LttvTracefileContext
*, i
));
1621 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1622 value
= lttv_attribute_add(tracefiles_tree
, i
,
1624 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1626 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1628 *(value
.v_uint
) = tfcs
->process
->pid
;
1630 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1632 /* Only save the position if the tfs has not infinite time. */
1633 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1634 // && current_tfcs != tfcs) {
1635 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1636 *(value
.v_pointer
) = NULL
;
1638 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1639 ep
= ltt_event_position_new();
1640 ltt_event_position(e
, ep
);
1641 *(value
.v_pointer
) = ep
;
1643 guint nb_block
, offset
;
1646 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1647 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
,
1648 offset
, tsc
, tfcs
->parent
.timestamp
.tv_sec
,
1649 tfcs
->parent
.timestamp
.tv_nsec
);
1653 /* save the cpu state */
1655 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1657 *(value
.v_uint
) = nb_cpus
;
1659 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1661 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1664 /* save the irq state */
1665 nb_irqs
= self
->name_tables
->nb_irqs
;
1667 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1669 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1672 /* save the soft irq state */
1673 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1675 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1677 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1680 /* save the trap state */
1681 nb_traps
= self
->name_tables
->nb_traps
;
1683 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1685 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1688 /* save the blkdev states */
1689 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1691 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1695 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1697 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1699 LttvTracefileState
*tfcs
;
1701 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1703 guint
*running_process
;
1705 LttvAttributeType type
;
1707 LttvAttributeValue value
;
1709 LttvAttributeName name
;
1713 LttEventPosition
*ep
;
1715 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1718 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1719 LTTV_STATE_TRACEFILES
);
1721 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1723 g_assert(type
== LTTV_POINTER
);
1724 lttv_state_free_process_table(self
->processes
);
1725 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1727 /* Add the currently running processes array */
1728 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1729 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1731 g_assert(type
== LTTV_POINTER
);
1732 running_process
= *(value
.v_pointer
);
1733 for(i
=0;i
<nb_cpus
;i
++) {
1734 pid
= running_process
[i
];
1735 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1736 g_assert(self
->running_process
[i
] != NULL
);
1739 nb_tracefile
= self
->parent
.tracefiles
->len
;
1741 //g_tree_destroy(tsc->pqueue);
1742 //tsc->pqueue = g_tree_new(compare_tracefile);
1744 /* restore cpu resource states */
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1746 g_assert(type
== LTTV_POINTER
);
1747 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1748 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1750 /* restore irq resource states */
1751 nb_irqs
= self
->name_tables
->nb_irqs
;
1752 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1753 g_assert(type
== LTTV_POINTER
);
1754 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1755 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1757 /* restore soft irq resource states */
1758 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1759 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1760 g_assert(type
== LTTV_POINTER
);
1761 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1762 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1764 /* restore trap resource states */
1765 nb_traps
= self
->name_tables
->nb_traps
;
1766 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1767 g_assert(type
== LTTV_POINTER
);
1768 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1769 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1771 /* restore the blkdev states */
1772 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1773 g_assert(type
== LTTV_POINTER
);
1774 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1775 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1777 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1779 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1780 LttvTracefileContext
*, i
));
1781 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1782 g_assert(type
== LTTV_GOBJECT
);
1783 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1785 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1787 g_assert(type
== LTTV_UINT
);
1788 pid
= *(value
.v_uint
);
1789 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1791 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1793 g_assert(type
== LTTV_POINTER
);
1794 //g_assert(*(value.v_pointer) != NULL);
1795 ep
= *(value
.v_pointer
);
1796 g_assert(tfcs
->parent
.t_context
!= NULL
);
1798 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1800 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1801 g_tree_remove(tsc
->pqueue
, tfc
);
1804 retval
= ltt_tracefile_seek_position(tfc
->tf
, ep
);
1805 g_assert_cmpint(retval
, ==, 0);
1806 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1807 g_assert_cmpint(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
),
1809 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1810 g_info("Restoring state for a tf at time %lu.%lu",
1811 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1813 tfc
->timestamp
= ltt_time_infinite
;
1819 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1821 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1823 LttvTracefileState
*tfcs
;
1825 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1827 guint
*running_process
;
1829 LttvAttributeType type
;
1831 LttvAttributeValue value
;
1833 LttvAttributeName name
;
1837 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1838 LTTV_STATE_TRACEFILES
);
1839 g_object_ref(G_OBJECT(tracefiles_tree
));
1840 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1842 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1844 g_assert(type
== LTTV_POINTER
);
1845 lttv_state_free_process_table(*(value
.v_pointer
));
1846 *(value
.v_pointer
) = NULL
;
1847 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1849 /* Free running processes array */
1850 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1852 g_assert(type
== LTTV_POINTER
);
1853 running_process
= *(value
.v_pointer
);
1854 g_free(running_process
);
1856 /* free cpu resource states */
1857 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1858 g_assert(type
== LTTV_UINT
);
1859 nb_cpus
= *value
.v_uint
;
1860 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1861 g_assert(type
== LTTV_POINTER
);
1862 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1864 /* free irq resource states */
1865 nb_irqs
= self
->name_tables
->nb_irqs
;
1866 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1867 g_assert(type
== LTTV_POINTER
);
1868 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1870 /* free softirq resource states */
1871 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1872 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1873 g_assert(type
== LTTV_POINTER
);
1874 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1876 /* free the blkdev states */
1877 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1878 g_assert(type
== LTTV_POINTER
);
1879 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1881 nb_tracefile
= self
->parent
.tracefiles
->len
;
1883 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1885 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1886 LttvTracefileContext
*, i
));
1887 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1888 g_assert(type
== LTTV_GOBJECT
);
1889 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1891 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1893 g_assert(type
== LTTV_POINTER
);
1894 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1896 g_object_unref(G_OBJECT(tracefiles_tree
));
1900 static void free_saved_state(LttvTraceState
*self
)
1904 LttvAttributeType type
;
1906 LttvAttributeValue value
;
1908 LttvAttributeName name
;
1912 LttvAttribute
*saved_states
;
1914 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1915 LTTV_STATE_SAVED_STATES
);
1917 nb
= lttv_attribute_get_number(saved_states
);
1918 for(i
= 0 ; i
< nb
; i
++) {
1919 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1920 g_assert(type
== LTTV_GOBJECT
);
1921 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1924 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1928 static void create_max_time(LttvTraceState
*tcs
)
1930 LttvAttributeValue v
;
1932 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1934 g_assert(*(v
.v_pointer
) == NULL
);
1935 *(v
.v_pointer
) = g_new(LttTime
,1);
1936 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1940 static void get_max_time(LttvTraceState
*tcs
)
1942 LttvAttributeValue v
;
1944 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1946 g_assert(*(v
.v_pointer
) != NULL
);
1947 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1951 static void free_max_time(LttvTraceState
*tcs
)
1953 LttvAttributeValue v
;
1955 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1957 g_free(*(v
.v_pointer
));
1958 *(v
.v_pointer
) = NULL
;
1961 static void create_name_tables(LttvTraceState
*tcs
)
1965 GString
*fe_name
= g_string_new("");
1967 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1969 LttvAttributeValue v
;
1973 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1975 g_assert(*(v
.v_pointer
) == NULL
);
1976 *(v
.v_pointer
) = name_tables
;
1978 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1980 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1982 LTT_EVENT_SYSCALL_ENTRY
,
1983 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1984 NULL
, NULL
, &hooks
)) {
1986 // th = lttv_trace_hook_get_first(&th);
1988 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1989 // nb = ltt_type_element_number(t);
1991 // name_tables->syscall_names = g_new(GQuark, nb);
1992 // name_tables->nb_syscalls = nb;
1994 // for(i = 0 ; i < nb ; i++) {
1995 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1996 // if(!name_tables->syscall_names[i]) {
1997 // GString *string = g_string_new("");
1998 // g_string_printf(string, "syscall %u", i);
1999 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
2000 // g_string_free(string, TRUE);
2004 name_tables
->nb_syscalls
= 256;
2005 name_tables
->syscall_names
= g_new(GQuark
, 256);
2006 for(i
= 0 ; i
< 256 ; i
++) {
2007 g_string_printf(fe_name
, "syscall %d", i
);
2008 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2011 name_tables
->syscall_names
= NULL
;
2012 name_tables
->nb_syscalls
= 0;
2014 lttv_trace_hook_remove_all(&hooks
);
2016 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2018 LTT_EVENT_TRAP_ENTRY
,
2019 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2020 NULL
, NULL
, &hooks
) ||
2021 !lttv_trace_find_hook(tcs
->parent
.t
,
2023 LTT_EVENT_PAGE_FAULT_ENTRY
,
2024 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2025 NULL
, NULL
, &hooks
)) {
2027 // th = lttv_trace_hook_get_first(&th);
2029 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2030 // //nb = ltt_type_element_number(t);
2032 // name_tables->trap_names = g_new(GQuark, nb);
2033 // for(i = 0 ; i < nb ; i++) {
2034 // name_tables->trap_names[i] = g_quark_from_string(
2035 // ltt_enum_string_get(t, i));
2038 name_tables
->nb_traps
= 256;
2039 name_tables
->trap_names
= g_new(GQuark
, 256);
2040 for(i
= 0 ; i
< 256 ; i
++) {
2041 g_string_printf(fe_name
, "trap %d", i
);
2042 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2045 name_tables
->trap_names
= NULL
;
2046 name_tables
->nb_traps
= 0;
2048 lttv_trace_hook_remove_all(&hooks
);
2050 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2052 LTT_EVENT_IRQ_ENTRY
,
2053 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
2054 NULL
, NULL
, &hooks
)) {
2057 name_tables->irq_names = g_new(GQuark, nb);
2058 for(i = 0 ; i < nb ; i++) {
2059 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2062 /* FIXME: LttvIRQState *irq_states should become a g_array */
2063 /* temp fix: increase from 256 to 512 default size */
2065 name_tables
->nb_irqs
= 512;
2066 name_tables
->irq_names
= g_new(GQuark
, 512);
2067 for(i
= 0 ; i
< 512 ; i
++) {
2068 g_string_printf(fe_name
, "irq %d", i
);
2069 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2072 name_tables
->nb_irqs
= 0;
2073 name_tables
->irq_names
= NULL
;
2075 lttv_trace_hook_remove_all(&hooks
);
2077 name_tables->soft_irq_names = g_new(GQuark, nb);
2078 for(i = 0 ; i < nb ; i++) {
2079 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2083 /* the kernel is limited to 32 statically defined softirqs */
2084 name_tables
->nb_soft_irqs
= 32;
2085 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_soft_irqs
);
2086 for(i
= 0 ; i
< name_tables
->nb_soft_irqs
; i
++) {
2087 g_string_printf(fe_name
, "softirq %d", i
);
2088 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2090 g_array_free(hooks
, TRUE
);
2092 g_string_free(fe_name
, TRUE
);
2094 #if (__WORDSIZE == 32)
2095 name_tables
->kprobe_hash
= g_hash_table_new_full(guint64_hash
, guint64_equal
,
2098 name_tables
->kprobe_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2103 static void get_name_tables(LttvTraceState
*tcs
)
2105 LttvAttributeValue v
;
2107 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2109 g_assert(*(v
.v_pointer
) != NULL
);
2110 tcs
->name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2114 static void free_name_tables(LttvTraceState
*tcs
)
2116 LttvNameTables
*name_tables
;
2118 LttvAttributeValue v
;
2120 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2122 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2123 *(v
.v_pointer
) = NULL
;
2125 // g_free(name_tables->eventtype_names);
2126 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2127 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2128 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2129 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2130 g_hash_table_destroy(name_tables
->kprobe_hash
);
2131 g_free(name_tables
);
2134 #ifdef HASH_TABLE_DEBUG
2136 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2138 LttvProcessState
*process
= (LttvProcessState
*)value
;
2140 /* Test for process corruption */
2141 guint stack_len
= process
->execution_stack
->len
;
2144 static void hash_table_check(GHashTable
*table
)
2146 g_hash_table_foreach(table
, test_process
, NULL
);
2152 /* clears the stack and sets the state passed as argument */
2153 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2155 g_array_set_size(cpust
->mode_stack
, 1);
2156 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2159 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2161 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2162 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2165 static void cpu_pop_mode(LttvCPUState
*cpust
)
2167 if(cpust
->mode_stack
->len
<= 1)
2168 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2170 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2173 /* clears the stack and sets the state passed as argument */
2174 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2176 g_array_set_size(bdevst
->mode_stack
, 1);
2177 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2180 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2182 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2183 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2186 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2188 if(bdevst
->mode_stack
->len
<= 1)
2189 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2191 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2194 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2196 g_array_set_size(irqst
->mode_stack
, 1);
2197 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2200 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2202 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2203 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2206 static void irq_pop_mode(LttvIRQState
*irqst
)
2208 if(irqst
->mode_stack
->len
<= 1)
2209 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2211 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2214 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2217 LttvExecutionState
*es
;
2219 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2220 guint cpu
= tfs
->cpu
;
2222 #ifdef HASH_TABLE_DEBUG
2223 hash_table_check(ts
->processes
);
2225 LttvProcessState
*process
= ts
->running_process
[cpu
];
2227 guint depth
= process
->execution_stack
->len
;
2229 process
->execution_stack
=
2230 g_array_set_size(process
->execution_stack
, depth
+ 1);
2233 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2235 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2238 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2239 es
->cum_cpu_time
= ltt_time_zero
;
2240 es
->s
= process
->state
->s
;
2241 process
->state
= es
;
2245 * return 1 when empty, else 0 */
2247 lttv_state_pop_state_cleanup(LttvProcessState
*process
, LttvTracefileState
*tfs
)
2249 guint depth
= process
->execution_stack
->len
;
2255 process
->execution_stack
=
2256 g_array_set_size(process
->execution_stack
, depth
- 1);
2257 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2259 process
->state
->change
= tfs
->parent
.timestamp
;
2264 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2266 guint cpu
= tfs
->cpu
;
2267 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2268 LttvProcessState
*process
= ts
->running_process
[cpu
];
2270 guint depth
= process
->execution_stack
->len
;
2272 if(process
->state
->t
!= t
){
2273 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2274 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2275 g_info("process state has %s when pop_int is %s\n",
2276 g_quark_to_string(process
->state
->t
),
2277 g_quark_to_string(t
));
2278 g_info("{ %u, %u, %s, %s, %s }\n",
2281 g_quark_to_string(process
->name
),
2282 g_quark_to_string(process
->brand
),
2283 g_quark_to_string(process
->state
->s
));
2288 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2289 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2293 process
->execution_stack
=
2294 g_array_set_size(process
->execution_stack
, depth
- 1);
2295 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2297 process
->state
->change
= tfs
->parent
.timestamp
;
2300 struct search_result
{
2301 const LttTime
*time
; /* Requested time */
2302 LttTime
*best
; /* Best result */
2305 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2307 const LttTime
*elem_time
= (const LttTime
*)a
;
2308 /* Explicit non const cast */
2309 struct search_result
*res
= (struct search_result
*)b
;
2311 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2312 /* The usertrace was created before the schedchange */
2313 /* Get larger keys */
2315 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2316 /* The usertrace was created after the schedchange time */
2317 /* Get smaller keys */
2319 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2320 res
->best
= (LttTime
*)elem_time
;
2323 res
->best
= (LttTime
*)elem_time
;
2330 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2331 guint pid
, const LttTime
*timestamp
)
2333 LttvTracefileState
*tfs
= NULL
;
2334 struct search_result res
;
2335 /* Find the usertrace associated with a pid and time interval.
2336 * Search in the usertraces by PID (within a hash) and then, for each
2337 * corresponding element of the array, find the first one with creation
2338 * timestamp the lowest, but higher or equal to "timestamp". */
2339 res
.time
= timestamp
;
2341 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2342 GUINT_TO_POINTER(pid
));
2343 if(usertrace_tree
) {
2344 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2346 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2352 /* Return a new and initialized LttvProcessState structure */
2354 LttvProcessState
*lttv_state_create_process(LttvTraceState
*tcs
,
2355 LttvProcessState
*parent
, guint cpu
, guint pid
,
2356 guint tgid
, GQuark name
, const LttTime
*timestamp
)
2358 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2360 LttvExecutionState
*es
;
2365 process
->tgid
= tgid
;
2367 process
->name
= name
;
2368 process
->brand
= LTTV_STATE_UNBRANDED
;
2369 //process->last_cpu = tfs->cpu_name;
2370 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2371 process
->type
= LTTV_STATE_USER_THREAD
;
2372 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2373 process
->current_function
= 0; //function 0x0 by default.
2375 g_info("Process %u, core %p", process
->pid
, process
);
2376 g_hash_table_insert(tcs
->processes
, process
, process
);
2379 process
->ppid
= parent
->pid
;
2380 process
->creation_time
= *timestamp
;
2383 /* No parent. This process exists but we are missing all information about
2384 its creation. The birth time is set to zero but we remember the time of
2389 process
->creation_time
= ltt_time_zero
;
2392 process
->insertion_time
= *timestamp
;
2393 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2394 process
->creation_time
.tv_nsec
);
2395 process
->pid_time
= g_quark_from_string(buffer
);
2397 process
->free_events
= 0;
2398 //process->last_cpu = tfs->cpu_name;
2399 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2400 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2401 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2402 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2403 es
= process
->state
= &g_array_index(process
->execution_stack
,
2404 LttvExecutionState
, 0);
2405 es
->t
= LTTV_STATE_USER_MODE
;
2406 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2407 es
->entry
= *timestamp
;
2408 //g_assert(timestamp->tv_sec != 0);
2409 es
->change
= *timestamp
;
2410 es
->cum_cpu_time
= ltt_time_zero
;
2411 es
->s
= LTTV_STATE_RUN
;
2413 es
= process
->state
= &g_array_index(process
->execution_stack
,
2414 LttvExecutionState
, 1);
2415 es
->t
= LTTV_STATE_SYSCALL
;
2416 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2417 es
->entry
= *timestamp
;
2418 //g_assert(timestamp->tv_sec != 0);
2419 es
->change
= *timestamp
;
2420 es
->cum_cpu_time
= ltt_time_zero
;
2421 es
->s
= LTTV_STATE_WAIT_FORK
;
2423 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2424 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2425 sizeof(guint64
), 0);
2427 process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2433 lttv_state_find_process(LttvTraceState
*ts
, guint cpu
, guint pid
)
2435 LttvProcessState key
;
2436 LttvProcessState
*process
;
2440 process
= g_hash_table_lookup(ts
->processes
, &key
);
2444 LttvProcessState
*lttv_state_find_process_or_create(LttvTraceState
*ts
,
2445 guint cpu
, guint pid
, const LttTime
*timestamp
)
2447 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2448 LttvExecutionState
*es
;
2450 /* Put ltt_time_zero creation time for unexisting processes */
2451 if(unlikely(process
== NULL
)) {
2452 process
= lttv_state_create_process(ts
,
2453 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2454 /* We are not sure is it's a kernel thread or normal thread, put the
2455 * bottom stack state to unknown */
2456 process
->execution_stack
=
2457 g_array_set_size(process
->execution_stack
, 1);
2458 process
->state
= es
=
2459 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2460 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2461 es
->s
= LTTV_STATE_UNNAMED
;
2466 /* FIXME : this function should be called when we receive an event telling that
2467 * release_task has been called in the kernel. In happens generally when
2468 * the parent waits for its child termination, but may also happens in special
2469 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2470 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2471 * of a killed thread group, but isn't the leader.
2473 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2475 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2476 LttvProcessState key
;
2478 /* Wait for both schedule with exit dead and process free to happen.
2479 * They can happen in any order. */
2480 if (++(process
->free_events
) < 2)
2483 key
.pid
= process
->pid
;
2484 key
.cpu
= process
->cpu
;
2485 g_hash_table_remove(ts
->processes
, &key
);
2486 g_array_free(process
->execution_stack
, TRUE
);
2487 g_array_free(process
->user_stack
, TRUE
);
2489 /* the following also clears the content */
2490 g_hash_table_destroy(process
->fds
);
2497 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2499 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2500 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2502 /* the following also clears the content */
2503 g_hash_table_destroy(((LttvProcessState
*)value
)->fds
);
2509 static void lttv_state_free_process_table(GHashTable
*processes
)
2511 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2512 g_hash_table_destroy(processes
);
2516 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2518 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2520 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2521 LttvProcessState
*process
= ts
->running_process
[cpu
];
2522 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2523 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2524 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2525 LttvExecutionSubmode submode
;
2526 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2528 guint syscall
= ltt_event_get_unsigned(e
, f
);
2529 expand_syscall_table(ts
, syscall
);
2530 submode
= nt
->syscall_names
[syscall
];
2531 /* There can be no system call from PID 0 : unknown state */
2532 if(process
->pid
!= 0)
2533 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2538 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2540 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2542 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2543 LttvProcessState
*process
= ts
->running_process
[cpu
];
2545 /* There can be no system call from PID 0 : unknown state */
2546 if(process
->pid
!= 0)
2547 pop_state(s
, LTTV_STATE_SYSCALL
);
2552 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2554 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2555 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2556 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2557 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2558 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2559 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2561 LttvExecutionSubmode submode
;
2563 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2565 expand_trap_table(ts
, trap
);
2567 submode
= nt
->trap_names
[trap
];
2569 push_state(s
, LTTV_STATE_TRAP
, submode
);
2571 /* update cpu status */
2572 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2574 /* update trap status */
2575 g_array_append_val(s
->cpu_state
->trap_stack
, trap
);
2576 ts
->trap_states
[trap
].running
++;
2581 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2583 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2584 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2586 pop_state(s
, LTTV_STATE_TRAP
);
2588 /* update cpu status */
2589 cpu_pop_mode(s
->cpu_state
);
2591 /* update trap status */
2592 if (s
->cpu_state
->trap_stack
->len
> 0) {
2593 gint last
= g_array_index(s
->cpu_state
->trap_stack
, gint
,
2594 s
->cpu_state
->trap_stack
->len
-1);
2595 if(ts
->trap_states
[last
].running
)
2596 ts
->trap_states
[last
].running
--;
2597 g_array_remove_index(s
->cpu_state
->trap_stack
,
2598 s
->cpu_state
->trap_stack
->len
-1);
2603 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2605 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2606 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2607 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2608 //guint8 ev_id = ltt_event_eventtype_id(e);
2609 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2610 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2611 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2613 LttvExecutionSubmode submode
;
2614 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2616 expand_irq_table(ts
, irq
);
2618 submode
= nt
->irq_names
[irq
];
2620 /* Do something with the info about being in user or system mode when int? */
2621 push_state(s
, LTTV_STATE_IRQ
, submode
);
2623 /* update cpu status */
2624 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2626 /* update irq status */
2627 g_array_append_val(s
->cpu_state
->irq_stack
, irq
);
2628 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2633 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2635 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2636 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2638 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2640 /* update cpu status */
2641 cpu_pop_mode(s
->cpu_state
);
2643 /* update softirq status */
2644 if (s
->cpu_state
->softirq_stack
->len
> 0) {
2645 gint last
= g_array_index(s
->cpu_state
->softirq_stack
, gint
, s
->cpu_state
->softirq_stack
->len
-1);
2646 if(ts
->soft_irq_states
[last
].running
)
2647 ts
->soft_irq_states
[last
].running
--;
2648 g_array_remove_index(s
->cpu_state
->softirq_stack
, s
->cpu_state
->softirq_stack
->len
-1);
2653 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2655 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2656 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2658 pop_state(s
, LTTV_STATE_IRQ
);
2660 /* update cpu status */
2661 cpu_pop_mode(s
->cpu_state
);
2663 /* update irq status */
2664 if (s
->cpu_state
->irq_stack
->len
> 0) {
2665 gint last
= g_array_index(s
->cpu_state
->irq_stack
, gint
, s
->cpu_state
->irq_stack
->len
-1);
2666 g_array_remove_index(s
->cpu_state
->irq_stack
, s
->cpu_state
->irq_stack
->len
-1);
2667 irq_pop_mode(&ts
->irq_states
[last
]);
2673 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2675 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2676 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2677 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2678 //guint8 ev_id = ltt_event_eventtype_id(e);
2679 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2680 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2681 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2683 LttvExecutionSubmode submode
;
2684 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2685 guint64 nb_softirqs
= nt
->nb_soft_irqs
;
2687 if(softirq
< nb_softirqs
) {
2688 submode
= nt
->soft_irq_names
[softirq
];
2690 /* Fixup an incomplete irq table */
2691 GString
*string
= g_string_new("");
2692 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2693 submode
= g_quark_from_string(string
->str
);
2694 g_string_free(string
, TRUE
);
2697 /* update softirq status */
2698 /* a soft irq raises are not cumulative */
2699 ts
->soft_irq_states
[softirq
].pending
=1;
2704 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2706 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2707 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2708 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2709 //guint8 ev_id = ltt_event_eventtype_id(e);
2710 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2711 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2712 LttvExecutionSubmode submode
;
2713 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2714 expand_soft_irq_table(ts
, softirq
);
2715 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2716 submode
= nt
->soft_irq_names
[softirq
];
2718 /* Do something with the info about being in user or system mode when int? */
2719 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2721 /* update cpu status */
2722 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2724 /* update softirq status */
2725 g_array_append_val(s
->cpu_state
->softirq_stack
, softirq
);
2726 if(ts
->soft_irq_states
[softirq
].pending
)
2727 ts
->soft_irq_states
[softirq
].pending
--;
2728 ts
->soft_irq_states
[softirq
].running
++;
2733 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2735 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2736 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2737 LttvNameTables
*nt
= ts
->name_tables
;
2738 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2739 //guint8 ev_id = ltt_event_eventtype_id(e);
2740 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2742 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2743 lttv_trace_get_hook_field(th
, 0)));
2744 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2746 expand_irq_table(ts
, irq
);
2747 nt
->irq_names
[irq
] = action
;
2753 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2755 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2756 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2757 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2758 //guint8 ev_id = ltt_event_eventtype_id(e);
2759 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2761 guint major
= ltt_event_get_long_unsigned(e
,
2762 lttv_trace_get_hook_field(th
, 0));
2763 guint minor
= ltt_event_get_long_unsigned(e
,
2764 lttv_trace_get_hook_field(th
, 1));
2765 guint oper
= ltt_event_get_long_unsigned(e
,
2766 lttv_trace_get_hook_field(th
, 2));
2767 guint32 devcode
= MKDEV(major
,minor
);
2769 /* have we seen this block device before? */
2770 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2773 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2775 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2780 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2782 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2783 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2784 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2785 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2787 guint major
= ltt_event_get_long_unsigned(e
,
2788 lttv_trace_get_hook_field(th
, 0));
2789 guint minor
= ltt_event_get_long_unsigned(e
,
2790 lttv_trace_get_hook_field(th
, 1));
2791 //guint oper = ltt_event_get_long_unsigned(e,
2792 // lttv_trace_get_hook_field(th, 2));
2793 guint32 devcode
= MKDEV(major
,minor
);
2795 /* have we seen this block device before? */
2796 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2798 /* update block device */
2799 bdev_pop_mode(bdev
);
2804 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2808 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2809 guint cpu
= tfs
->cpu
;
2810 LttvProcessState
*process
= ts
->running_process
[cpu
];
2812 guint depth
= process
->user_stack
->len
;
2814 process
->user_stack
=
2815 g_array_set_size(process
->user_stack
, depth
+ 1);
2817 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2818 *new_func
= funcptr
;
2819 process
->current_function
= funcptr
;
2822 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2824 guint cpu
= tfs
->cpu
;
2825 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2826 LttvProcessState
*process
= ts
->running_process
[cpu
];
2828 if(process
->current_function
!= funcptr
){
2829 g_info("Different functions (%lu.%09lu): ignore it\n",
2830 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2831 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2832 process
->current_function
, funcptr
);
2833 g_info("{ %u, %u, %s, %s, %s }\n",
2836 g_quark_to_string(process
->name
),
2837 g_quark_to_string(process
->brand
),
2838 g_quark_to_string(process
->state
->s
));
2841 guint depth
= process
->user_stack
->len
;
2844 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2845 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2849 process
->user_stack
=
2850 g_array_set_size(process
->user_stack
, depth
- 1);
2851 process
->current_function
=
2852 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2856 static gboolean
function_entry(void *hook_data
, void *call_data
)
2858 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2859 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2860 //guint8 ev_id = ltt_event_eventtype_id(e);
2861 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2862 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2863 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2865 push_function(s
, funcptr
);
2869 static gboolean
function_exit(void *hook_data
, void *call_data
)
2871 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2872 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2873 //guint8 ev_id = ltt_event_eventtype_id(e);
2874 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2875 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2876 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2878 pop_function(s
, funcptr
);
2882 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2884 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2885 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2886 LttvNameTables
*nt
= ts
->name_tables
;
2887 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2888 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2893 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2894 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2895 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2897 expand_syscall_table(ts
, id
);
2898 nt
->syscall_names
[id
] = g_quark_from_string(symbol
);
2903 static gboolean
dump_kprobe(void *hook_data
, void *call_data
)
2905 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2906 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2907 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2908 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2912 ip
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2913 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 1));
2915 expand_kprobe_table(ts
, ip
, symbol
);
2920 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2922 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2923 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2924 LttvNameTables
*nt
= ts
->name_tables
;
2925 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2926 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2931 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2932 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2933 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2935 expand_soft_irq_table(ts
, id
);
2936 nt
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2941 static gboolean
sched_try_wakeup(void *hook_data
, void *call_data
)
2943 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2944 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2945 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2946 LttvProcessState
*process
;
2950 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
2951 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2953 process
= lttv_state_find_process_or_create(
2954 (LttvTraceState
*)s
->parent
.t_context
,
2955 woken_cpu
, woken_pid
,
2956 &s
->parent
.timestamp
);
2958 if (process
->state
->s
== LTTV_STATE_WAIT
|| process
->state
->s
== LTTV_STATE_WAIT_FORK
)
2960 process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2961 process
->state
->change
= s
->parent
.timestamp
;
2964 g_debug("Wakeup: process %d on CPU %u\n", woken_pid
, woken_cpu
);
2969 static gboolean
schedchange(void *hook_data
, void *call_data
)
2971 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2973 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2974 LttvProcessState
*process
= ts
->running_process
[cpu
];
2975 //LttvProcessState *old_process = ts->running_process[cpu];
2977 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2978 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2979 guint pid_in
, pid_out
;
2982 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2983 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2984 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2986 if(likely(process
!= NULL
)) {
2988 /* We could not know but it was not the idle process executing.
2989 This should only happen at the beginning, before the first schedule
2990 event, and when the initial information (current process for each CPU)
2991 is missing. It is not obvious how we could, after the fact, compensate
2992 the wrongly attributed statistics. */
2994 //This test only makes sense once the state is known and if there is no
2995 //missing events. We need to silently ignore schedchange coming after a
2996 //process_free, or it causes glitches. (FIXME)
2997 //if(unlikely(process->pid != pid_out)) {
2998 // g_assert(process->pid == 0);
3000 if(process
->pid
== 0
3001 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3003 /* Scheduling out of pid 0 at beginning of the trace :
3004 * we know for sure it is in syscall mode at this point. */
3005 g_assert(process
->execution_stack
->len
== 1);
3006 process
->state
->t
= LTTV_STATE_SYSCALL
;
3007 process
->state
->s
= LTTV_STATE_WAIT
;
3008 process
->state
->change
= s
->parent
.timestamp
;
3009 process
->state
->entry
= s
->parent
.timestamp
;
3012 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
3013 process
->state
->s
= LTTV_STATE_ZOMBIE
;
3014 process
->state
->change
= s
->parent
.timestamp
;
3016 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
3017 else process
->state
->s
= LTTV_STATE_WAIT
;
3018 process
->state
->change
= s
->parent
.timestamp
;
3021 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
3022 /* see sched.h for states */
3023 if (!exit_process(s
, process
)) {
3024 process
->state
->s
= LTTV_STATE_DEAD
;
3025 process
->state
->change
= s
->parent
.timestamp
;
3030 process
= ts
->running_process
[cpu
] = lttv_state_find_process_or_create(
3031 (LttvTraceState
*)s
->parent
.t_context
,
3033 &s
->parent
.timestamp
);
3034 process
->state
->s
= LTTV_STATE_RUN
;
3036 if(process
->usertrace
)
3037 process
->usertrace
->cpu
= cpu
;
3038 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3039 process
->state
->change
= s
->parent
.timestamp
;
3041 /* update cpu status */
3043 /* going to idle task */
3044 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
3046 /* scheduling a real task.
3047 * we must be careful here:
3048 * if we just schedule()'ed to a process that is
3049 * in a trap, we must put the cpu in trap mode
3051 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
3052 if(process
->state
->t
== LTTV_STATE_TRAP
)
3053 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
3059 static gboolean
process_fork(void *hook_data
, void *call_data
)
3061 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3062 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3063 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3065 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
3066 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
3067 //LttvProcessState *zombie_process;
3069 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3070 LttvProcessState
*process
= ts
->running_process
[cpu
];
3071 LttvProcessState
*child_process
;
3072 struct marker_field
*f
;
3075 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3078 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3079 s
->parent
.target_pid
= child_pid
;
3082 f
= lttv_trace_get_hook_field(th
, 2);
3084 child_tgid
= ltt_event_get_unsigned(e
, f
);
3088 /* Mathieu : it seems like the process might have been scheduled in before the
3089 * fork, and, in a rare case, might be the current process. This might happen
3090 * in a SMP case where we don't have enough precision on the clocks.
3092 * Test reenabled after precision fixes on time. (Mathieu) */
3094 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3096 if(unlikely(zombie_process
!= NULL
)) {
3097 /* Reutilisation of PID. Only now we are sure that the old PID
3098 * has been released. FIXME : should know when release_task happens instead.
3100 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3102 for(i
=0; i
< num_cpus
; i
++) {
3103 g_assert(zombie_process
!= ts
->running_process
[i
]);
3106 exit_process(s
, zombie_process
);
3109 g_assert(process
->pid
!= child_pid
);
3110 // FIXME : Add this test in the "known state" section
3111 // g_assert(process->pid == parent_pid);
3112 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3113 if(child_process
== NULL
) {
3114 child_process
= lttv_state_create_process(ts
, process
, cpu
,
3115 child_pid
, child_tgid
,
3116 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
3118 /* The process has already been created : due to time imprecision between
3119 * multiple CPUs : it has been scheduled in before creation. Note that we
3120 * shouldn't have this kind of imprecision.
3122 * Simply put a correct parent.
3124 g_error("Process %u has been created at [%lu.%09lu] "
3125 "and inserted at [%lu.%09lu] before \n"
3126 "fork on cpu %u[%lu.%09lu].\n"
3127 "Probably an unsynchronized TSC problem on the traced machine.",
3129 child_process
->creation_time
.tv_sec
,
3130 child_process
->creation_time
.tv_nsec
,
3131 child_process
->insertion_time
.tv_sec
,
3132 child_process
->insertion_time
.tv_nsec
,
3133 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
3134 //g_assert(0); /* This is a problematic case : the process has been created
3135 // before the fork event */
3136 child_process
->ppid
= process
->pid
;
3137 child_process
->tgid
= child_tgid
;
3139 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
3140 child_process
->name
= process
->name
;
3141 child_process
->brand
= process
->brand
;
3146 /* We stamp a newly created process as kernel_thread.
3147 * The thread should not be running yet. */
3148 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
3150 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3151 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3152 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3154 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3155 LttvProcessState
*process
;
3156 LttvExecutionState
*es
;
3159 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3160 s
->parent
.target_pid
= pid
;
3162 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3164 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3165 process
->execution_stack
=
3166 g_array_set_size(process
->execution_stack
, 1);
3167 es
= process
->state
=
3168 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3169 es
->t
= LTTV_STATE_SYSCALL
;
3171 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3176 static gboolean
process_exit(void *hook_data
, void *call_data
)
3178 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3179 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3180 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3182 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3183 LttvProcessState
*process
; // = ts->running_process[cpu];
3185 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3186 s
->parent
.target_pid
= pid
;
3188 // FIXME : Add this test in the "known state" section
3189 // g_assert(process->pid == pid);
3191 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3192 if(likely(process
!= NULL
)) {
3193 process
->state
->s
= LTTV_STATE_EXIT
;
3198 static gboolean
process_free(void *hook_data
, void *call_data
)
3200 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3201 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3202 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3203 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3205 LttvProcessState
*process
;
3207 /* PID of the process to release */
3208 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3209 s
->parent
.target_pid
= release_pid
;
3211 g_assert(release_pid
!= 0);
3213 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3214 if(likely(process
!= NULL
))
3215 exit_process(s
, process
);
3218 if(likely(process
!= NULL
)) {
3219 /* release_task is happening at kernel level : we can now safely release
3220 * the data structure of the process */
3221 //This test is fun, though, as it may happen that
3222 //at time t : CPU 0 : process_free
3223 //at time t+150ns : CPU 1 : schedule out
3224 //Clearly due to time imprecision, we disable it. (Mathieu)
3225 //If this weird case happen, we have no choice but to put the
3226 //Currently running process on the cpu to 0.
3227 //I re-enable it following time precision fixes. (Mathieu)
3228 //Well, in the case where an process is freed by a process on another CPU
3229 //and still scheduled, it happens that this is the schedchange that will
3230 //drop the last reference count. Do not free it here!
3231 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3233 for(i
=0; i
< num_cpus
; i
++) {
3234 //g_assert(process != ts->running_process[i]);
3235 if(process
== ts
->running_process
[i
]) {
3236 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3240 if(i
== num_cpus
) /* process is not scheduled */
3241 exit_process(s
, process
);
3248 static gboolean
process_exec(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 #if 0//how to use a sequence that must be transformed in a string
3259 /* PID of the process to release */
3260 guint64 name_len
= ltt_event_field_element_number(e
,
3261 lttv_trace_get_hook_field(th
, 0));
3262 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3263 LttField
*child
= ltt_event_field_element_select(e
,
3264 lttv_trace_get_hook_field(th
, 0), 0);
3266 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3267 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3268 memcpy(null_term_name
, name_begin
, name_len
);
3269 null_term_name
[name_len
] = '\0';
3270 process
->name
= g_quark_from_string(null_term_name
);
3273 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3274 lttv_trace_get_hook_field(th
, 0)));
3275 process
->brand
= LTTV_STATE_UNBRANDED
;
3276 //g_free(null_term_name);
3280 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3282 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3283 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3284 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3285 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3288 LttvProcessState
*process
= ts
->running_process
[cpu
];
3290 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3291 process
->brand
= g_quark_from_string(name
);
3296 static gboolean
fs_open(void *hook_data
, void *call_data
)
3298 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3299 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3300 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3301 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3302 struct marker_field
*f
;
3306 LttvProcessState
*process
= ts
->running_process
[cpu
];
3308 f
= lttv_trace_get_hook_field(th
, 0);
3309 fd
= ltt_event_get_int(e
, f
);
3311 f
= lttv_trace_get_hook_field(th
, 1);
3312 filename
= ltt_event_get_string(e
, f
);
3314 g_hash_table_insert(process
->fds
, (gpointer
)(long)fd
,
3315 (gpointer
)(unsigned long)g_quark_from_string(filename
));
3320 static void print_stack(LttvProcessState
*process
)
3322 LttvExecutionState
*es
;
3325 g_debug("Execution stack for process %u %s:\n",
3326 process
->pid
, g_quark_to_string(process
->name
));
3328 for (i
= 0; i
< process
->execution_stack
->len
; i
++) {
3329 es
= &g_array_index(process
->execution_stack
,
3330 LttvExecutionState
, i
);
3331 g_debug("Depth %d mode %s submode %s status %s\n",
3332 i
, g_quark_to_string(es
->t
),
3333 g_quark_to_string(es
->n
),
3334 g_quark_to_string(es
->s
));
3339 static void fix_process(gpointer key
, gpointer value
, gpointer user_data
)
3341 LttvProcessState
*process
;
3342 LttvExecutionState
*es
;
3343 process
= (LttvProcessState
*)value
;
3344 LttTime
*timestamp
= (LttTime
*)user_data
;
3346 print_stack(process
);
3348 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3349 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3350 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3351 es
->t
= LTTV_STATE_SYSCALL
;
3352 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3353 es
->entry
= *timestamp
;
3354 es
->change
= *timestamp
;
3355 es
->cum_cpu_time
= ltt_time_zero
;
3356 if(es
->s
== LTTV_STATE_UNNAMED
)
3357 es
->s
= LTTV_STATE_WAIT
;
3360 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3361 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3362 es
->t
= LTTV_STATE_USER_MODE
;
3363 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3364 es
->entry
= *timestamp
;
3365 //g_assert(timestamp->tv_sec != 0);
3366 es
->change
= *timestamp
;
3367 es
->cum_cpu_time
= ltt_time_zero
;
3368 if(es
->s
== LTTV_STATE_UNNAMED
)
3369 es
->s
= LTTV_STATE_RUN
;
3371 if(process
->execution_stack
->len
== 1) {
3372 /* Still in bottom unknown mode, means we either:
3373 * - never did a system call
3374 * - are scheduled out from user mode.
3375 * May be either in user mode, syscall mode, running or waiting.*/
3376 /* CHECK : we may be tagging syscall mode when being user mode
3377 * (should be fixed now) */
3378 if (es
->s
== LTTV_STATE_WAIT_CPU
) {
3379 /* nothing to do: scheduled out from userspace */
3381 process
->execution_stack
=
3382 g_array_set_size(process
->execution_stack
, 2);
3383 es
= process
->state
= &g_array_index(process
->execution_stack
,
3384 LttvExecutionState
, 1);
3385 es
->t
= LTTV_STATE_SYSCALL
;
3386 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3387 es
->entry
= *timestamp
;
3388 //g_assert(timestamp->tv_sec != 0);
3389 es
->change
= *timestamp
;
3390 es
->cum_cpu_time
= ltt_time_zero
;
3391 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3392 es
->s
= LTTV_STATE_WAIT
;
3399 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3401 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3402 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3403 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3404 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3405 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3407 /* For all processes */
3408 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3409 /* else, if stack[0] is unknown, set to user mode, running */
3411 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3416 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3418 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3419 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3420 //It's slow : optimise later by doing this before reading trace.
3421 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3427 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3428 LttvProcessState
*process
= ts
->running_process
[cpu
];
3429 LttvProcessState
*parent_process
;
3430 struct marker_field
*f
;
3431 GQuark type
, mode
, submode
, status
;
3432 LttvExecutionState
*es
;
3436 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3437 s
->parent
.target_pid
= pid
;
3440 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3443 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3446 f
= lttv_trace_get_hook_field(th
, 3);
3447 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3449 //FIXME: type is rarely used, enum must match possible types.
3452 f
= lttv_trace_get_hook_field(th
, 4);
3453 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3456 f
= lttv_trace_get_hook_field(th
, 5);
3457 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3460 f
= lttv_trace_get_hook_field(th
, 6);
3461 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3464 f
= lttv_trace_get_hook_field(th
, 7);
3466 tgid
= ltt_event_get_unsigned(e
, f
);
3471 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3472 for(i
=0; i
<nb_cpus
; i
++) {
3473 process
= lttv_state_find_process(ts
, i
, pid
);
3474 g_assert(process
!= NULL
);
3476 process
->ppid
= parent_pid
;
3477 process
->tgid
= tgid
;
3478 process
->name
= g_quark_from_string(command
);
3479 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3480 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3484 /* The process might exist if a process was forked while performing the
3486 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3487 if(process
== NULL
) {
3488 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3489 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3490 pid
, tgid
, g_quark_from_string(command
),
3491 &s
->parent
.timestamp
);
3493 /* Keep the stack bottom : a running user mode */
3494 /* Disabled because of inconsistencies in the current statedump states. */
3495 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3496 /* Only keep the bottom
3497 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3498 /* Will cause expected trap when in fact being syscall (even after end of
3500 * Will cause expected interrupt when being syscall. (only before end of
3501 * statedump event) */
3502 // This will cause a "popping last state on stack, ignoring it."
3503 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3504 es
= process
->state
= &g_array_index(process
->execution_stack
,
3505 LttvExecutionState
, 0);
3506 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3507 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3508 es
->s
= LTTV_STATE_UNNAMED
;
3509 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3511 es
->t
= LTTV_STATE_SYSCALL
;
3516 /* User space process :
3517 * bottom : user mode
3518 * either currently running or scheduled out.
3519 * can be scheduled out because interrupted in (user mode or in syscall)
3520 * or because of an explicit call to the scheduler in syscall. Note that
3521 * the scheduler call comes after the irq_exit, so never in interrupt
3523 // temp workaround : set size to 1 : only have user mode bottom of stack.
3524 // will cause g_info message of expected syscall mode when in fact being
3525 // in user mode. Can also cause expected trap when in fact being user
3526 // mode in the event of a page fault reenabling interrupts in the handler.
3527 // Expected syscall and trap can also happen after the end of statedump
3528 // This will cause a "popping last state on stack, ignoring it."
3529 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3530 es
= process
->state
= &g_array_index(process
->execution_stack
,
3531 LttvExecutionState
, 0);
3532 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3533 es
->s
= LTTV_STATE_UNNAMED
;
3534 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3536 es
->t
= LTTV_STATE_USER_MODE
;
3544 es
= process
->state
= &g_array_index(process
->execution_stack
,
3545 LttvExecutionState
, 1);
3546 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3547 es
->s
= LTTV_STATE_UNNAMED
;
3548 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3552 /* The process has already been created :
3553 * Probably was forked while dumping the process state or
3554 * was simply scheduled in prior to get the state dump event.
3556 process
->ppid
= parent_pid
;
3557 process
->tgid
= tgid
;
3558 process
->name
= g_quark_from_string(command
);
3559 process
->type
= type
;
3560 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3562 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3563 if(type
== LTTV_STATE_KERNEL_THREAD
)
3564 es
->t
= LTTV_STATE_SYSCALL
;
3566 es
->t
= LTTV_STATE_USER_MODE
;
3569 /* Don't mess around with the stack, it will eventually become
3570 * ok after the end of state dump. */
3577 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3579 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3581 lttv_state_add_event_hooks(tss
);
3586 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3588 LttvTraceset
*traceset
= self
->parent
.ts
;
3590 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3594 LttvTracefileState
*tfs
;
3600 LttvAttributeValue val
;
3602 nb_trace
= lttv_traceset_number(traceset
);
3603 for(i
= 0 ; i
< nb_trace
; i
++) {
3604 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3606 /* Find the eventtype id for the following events and register the
3607 associated by id hooks. */
3609 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 20);
3610 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3613 lttv_trace_find_hook(ts
->parent
.t
,
3615 LTT_EVENT_SYSCALL_ENTRY
,
3616 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3617 syscall_entry
, NULL
, &hooks
);
3619 lttv_trace_find_hook(ts
->parent
.t
,
3621 LTT_EVENT_SYSCALL_EXIT
,
3623 syscall_exit
, NULL
, &hooks
);
3625 lttv_trace_find_hook(ts
->parent
.t
,
3627 LTT_EVENT_TRAP_ENTRY
,
3628 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3629 trap_entry
, NULL
, &hooks
);
3631 lttv_trace_find_hook(ts
->parent
.t
,
3633 LTT_EVENT_TRAP_EXIT
,
3635 trap_exit
, NULL
, &hooks
);
3637 lttv_trace_find_hook(ts
->parent
.t
,
3639 LTT_EVENT_PAGE_FAULT_ENTRY
,
3640 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3641 trap_entry
, NULL
, &hooks
);
3643 lttv_trace_find_hook(ts
->parent
.t
,
3645 LTT_EVENT_PAGE_FAULT_EXIT
,
3647 trap_exit
, NULL
, &hooks
);
3649 lttv_trace_find_hook(ts
->parent
.t
,
3651 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3652 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3653 trap_entry
, NULL
, &hooks
);
3655 lttv_trace_find_hook(ts
->parent
.t
,
3657 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3659 trap_exit
, NULL
, &hooks
);
3661 lttv_trace_find_hook(ts
->parent
.t
,
3663 LTT_EVENT_IRQ_ENTRY
,
3664 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3665 irq_entry
, NULL
, &hooks
);
3667 lttv_trace_find_hook(ts
->parent
.t
,
3671 irq_exit
, NULL
, &hooks
);
3673 lttv_trace_find_hook(ts
->parent
.t
,
3675 LTT_EVENT_SOFT_IRQ_RAISE
,
3676 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3677 soft_irq_raise
, NULL
, &hooks
);
3679 lttv_trace_find_hook(ts
->parent
.t
,
3681 LTT_EVENT_SOFT_IRQ_ENTRY
,
3682 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3683 soft_irq_entry
, NULL
, &hooks
);
3685 lttv_trace_find_hook(ts
->parent
.t
,
3687 LTT_EVENT_SOFT_IRQ_EXIT
,
3689 soft_irq_exit
, NULL
, &hooks
);
3691 lttv_trace_find_hook(ts
->parent
.t
,
3693 LTT_EVENT_SCHED_SCHEDULE
,
3694 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3695 LTT_FIELD_PREV_STATE
),
3696 schedchange
, NULL
, &hooks
);
3698 lttv_trace_find_hook(ts
->parent
.t
,
3700 LTT_EVENT_SCHED_TRY_WAKEUP
,
3701 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_CPU_ID
, LTT_FIELD_STATE
),
3702 sched_try_wakeup
, NULL
, &hooks
);
3704 lttv_trace_find_hook(ts
->parent
.t
,
3706 LTT_EVENT_PROCESS_FORK
,
3707 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3708 LTT_FIELD_CHILD_TGID
),
3709 process_fork
, NULL
, &hooks
);
3711 lttv_trace_find_hook(ts
->parent
.t
,
3713 LTT_EVENT_KTHREAD_CREATE
,
3714 FIELD_ARRAY(LTT_FIELD_PID
),
3715 process_kernel_thread
, NULL
, &hooks
);
3717 lttv_trace_find_hook(ts
->parent
.t
,
3719 LTT_EVENT_PROCESS_EXIT
,
3720 FIELD_ARRAY(LTT_FIELD_PID
),
3721 process_exit
, NULL
, &hooks
);
3723 lttv_trace_find_hook(ts
->parent
.t
,
3725 LTT_EVENT_PROCESS_FREE
,
3726 FIELD_ARRAY(LTT_FIELD_PID
),
3727 process_free
, NULL
, &hooks
);
3729 lttv_trace_find_hook(ts
->parent
.t
,
3732 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3733 process_exec
, NULL
, &hooks
);
3735 lttv_trace_find_hook(ts
->parent
.t
,
3736 LTT_CHANNEL_USERSPACE
,
3737 LTT_EVENT_THREAD_BRAND
,
3738 FIELD_ARRAY(LTT_FIELD_NAME
),
3739 thread_brand
, NULL
, &hooks
);
3741 /* statedump-related hooks */
3742 lttv_trace_find_hook(ts
->parent
.t
,
3743 LTT_CHANNEL_TASK_STATE
,
3744 LTT_EVENT_PROCESS_STATE
,
3745 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3746 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3747 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3748 enum_process_state
, NULL
, &hooks
);
3750 lttv_trace_find_hook(ts
->parent
.t
,
3751 LTT_CHANNEL_GLOBAL_STATE
,
3752 LTT_EVENT_STATEDUMP_END
,
3754 statedump_end
, NULL
, &hooks
);
3756 lttv_trace_find_hook(ts
->parent
.t
,
3757 LTT_CHANNEL_IRQ_STATE
,
3758 LTT_EVENT_LIST_INTERRUPT
,
3759 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3760 enum_interrupt
, NULL
, &hooks
);
3762 lttv_trace_find_hook(ts
->parent
.t
,
3764 LTT_EVENT_REQUEST_ISSUE
,
3765 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3766 bdev_request_issue
, NULL
, &hooks
);
3768 lttv_trace_find_hook(ts
->parent
.t
,
3770 LTT_EVENT_REQUEST_COMPLETE
,
3771 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3772 bdev_request_complete
, NULL
, &hooks
);
3774 lttv_trace_find_hook(ts
->parent
.t
,
3775 LTT_CHANNEL_USERSPACE
,
3776 LTT_EVENT_FUNCTION_ENTRY
,
3777 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3778 function_entry
, NULL
, &hooks
);
3780 lttv_trace_find_hook(ts
->parent
.t
,
3781 LTT_CHANNEL_USERSPACE
,
3782 LTT_EVENT_FUNCTION_EXIT
,
3783 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3784 function_exit
, NULL
, &hooks
);
3786 lttv_trace_find_hook(ts
->parent
.t
,
3787 LTT_CHANNEL_SYSCALL_STATE
,
3788 LTT_EVENT_SYS_CALL_TABLE
,
3789 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3790 dump_syscall
, NULL
, &hooks
);
3792 lttv_trace_find_hook(ts
->parent
.t
,
3793 LTT_CHANNEL_KPROBE_STATE
,
3794 LTT_EVENT_KPROBE_TABLE
,
3795 FIELD_ARRAY(LTT_FIELD_IP
, LTT_FIELD_SYMBOL
),
3796 dump_kprobe
, NULL
, &hooks
);
3798 lttv_trace_find_hook(ts
->parent
.t
,
3799 LTT_CHANNEL_SOFTIRQ_STATE
,
3800 LTT_EVENT_SOFTIRQ_VEC
,
3801 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3802 dump_softirq
, NULL
, &hooks
);
3804 lttv_trace_find_hook(ts
->parent
.t
,
3807 FIELD_ARRAY(LTT_FIELD_FD
, LTT_FIELD_FILENAME
),
3808 fs_open
, NULL
, &hooks
);
3810 /* Add these hooks to each event_by_id hooks list */
3812 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3814 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3816 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3817 LttvTracefileContext
*, j
));
3819 for(k
= 0 ; k
< hooks
->len
; k
++) {
3820 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3821 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3823 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3829 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3830 *(val
.v_pointer
) = hooks
;
3834 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3836 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3838 lttv_state_remove_event_hooks(tss
);
3843 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3845 LttvTraceset
*traceset
= self
->parent
.ts
;
3847 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3851 LttvTracefileState
*tfs
;
3857 LttvAttributeValue val
;
3859 nb_trace
= lttv_traceset_number(traceset
);
3860 for(i
= 0 ; i
< nb_trace
; i
++) {
3861 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3863 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3864 hooks
= *(val
.v_pointer
);
3866 /* Remove these hooks from each event_by_id hooks list */
3868 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3870 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3872 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3873 LttvTracefileContext
*, j
));
3875 for(k
= 0 ; k
< hooks
->len
; k
++) {
3876 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3877 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3878 lttv_hooks_remove_data(
3879 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3884 lttv_trace_hook_remove_all(&hooks
);
3885 g_array_free(hooks
, TRUE
);
3889 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3891 guint
*event_count
= (guint
*)hook_data
;
3893 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3894 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3899 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3901 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3903 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3905 LttvAttributeValue value
;
3907 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3908 LTTV_STATE_SAVED_STATES
);
3909 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3910 value
= lttv_attribute_add(saved_states_tree
,
3911 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3912 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3913 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3914 *(value
.v_time
) = self
->parent
.timestamp
;
3915 lttv_state_save(tcs
, saved_state_tree
);
3916 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3917 self
->parent
.timestamp
.tv_nsec
);
3919 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3924 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3926 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3928 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3933 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3941 static gboolean
block_start(void *hook_data
, void *call_data
)
3943 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3945 LttvTracefileState
*tfcs
;
3947 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3949 LttEventPosition
*ep
;
3951 guint i
, nb_block
, nb_event
, nb_tracefile
;
3955 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3957 LttvAttributeValue value
;
3959 ep
= ltt_event_position_new();
3961 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3963 /* Count the number of events added since the last block end in any
3966 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3968 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3969 LttvTracefileContext
, i
));
3970 ltt_event_position(tfcs
->parent
.e
, ep
);
3971 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3972 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3973 tfcs
->saved_position
= nb_event
;
3977 if(tcs
->nb_event
>= tcs
->save_interval
) {
3978 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3979 LTTV_STATE_SAVED_STATES
);
3980 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3981 value
= lttv_attribute_add(saved_states_tree
,
3982 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3983 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3984 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3985 *(value
.v_time
) = self
->parent
.timestamp
;
3986 lttv_state_save(tcs
, saved_state_tree
);
3988 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3989 self
->parent
.timestamp
.tv_nsec
);
3991 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3997 static gboolean
block_end(void *hook_data
, void *call_data
)
3999 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
4001 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
4005 LttEventPosition
*ep
;
4007 guint nb_block
, nb_event
;
4009 ep
= ltt_event_position_new();
4010 ltt_event_position(self
->parent
.e
, ep
);
4011 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
4012 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
4013 self
->saved_position
= 0;
4014 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4021 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4023 LttvTraceset
*traceset
= self
->parent
.ts
;
4025 guint i
, j
, nb_trace
, nb_tracefile
;
4029 LttvTracefileState
*tfs
;
4031 LttvTraceHook hook_start
, hook_end
;
4033 nb_trace
= lttv_traceset_number(traceset
);
4034 for(i
= 0 ; i
< nb_trace
; i
++) {
4035 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4037 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4038 NULL
, NULL
, block_start
, &hook_start
);
4039 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4040 NULL
, NULL
, block_end
, &hook_end
);
4042 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4044 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4046 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4047 LttvTracefileContext
, j
));
4048 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4049 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
4050 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4051 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
4057 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4059 LttvTraceset
*traceset
= self
->parent
.ts
;
4061 guint i
, j
, nb_trace
, nb_tracefile
;
4065 LttvTracefileState
*tfs
;
4068 nb_trace
= lttv_traceset_number(traceset
);
4069 for(i
= 0 ; i
< nb_trace
; i
++) {
4071 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4072 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4074 if(ts
->has_precomputed_states
) continue;
4076 guint
*event_count
= g_new(guint
, 1);
4079 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4081 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4082 LttvTracefileContext
*, j
));
4083 lttv_hooks_add(tfs
->parent
.event
,
4084 state_save_event_hook
,
4091 lttv_process_traceset_begin(&self
->parent
,
4092 NULL
, NULL
, NULL
, NULL
, NULL
);
4096 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
4098 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4100 lttv_state_save_add_event_hooks(tss
);
4107 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4109 LttvTraceset
*traceset
= self
->parent
.ts
;
4111 guint i
, j
, nb_trace
, nb_tracefile
;
4115 LttvTracefileState
*tfs
;
4117 LttvTraceHook hook_start
, hook_end
;
4119 nb_trace
= lttv_traceset_number(traceset
);
4120 for(i
= 0 ; i
< nb_trace
; i
++) {
4121 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
4123 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4124 NULL
, NULL
, block_start
, &hook_start
);
4126 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4127 NULL
, NULL
, block_end
, &hook_end
);
4129 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4131 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4133 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4134 LttvTracefileContext
, j
));
4135 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4136 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
4137 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4138 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
4144 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4146 LttvTraceset
*traceset
= self
->parent
.ts
;
4148 guint i
, j
, nb_trace
, nb_tracefile
;
4152 LttvTracefileState
*tfs
;
4154 LttvHooks
*after_trace
= lttv_hooks_new();
4156 lttv_hooks_add(after_trace
,
4157 state_save_after_trace_hook
,
4162 lttv_process_traceset_end(&self
->parent
,
4163 NULL
, after_trace
, NULL
, NULL
, NULL
);
4165 lttv_hooks_destroy(after_trace
);
4167 nb_trace
= lttv_traceset_number(traceset
);
4168 for(i
= 0 ; i
< nb_trace
; i
++) {
4170 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4171 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4173 if(ts
->has_precomputed_states
) continue;
4175 guint
*event_count
= NULL
;
4177 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4179 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4180 LttvTracefileContext
*, j
));
4181 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
4182 state_save_event_hook
);
4184 if(event_count
) g_free(event_count
);
4188 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
4190 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4192 lttv_state_save_remove_event_hooks(tss
);
4197 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
4199 LttvTraceset
*traceset
= self
->parent
.ts
;
4203 int min_pos
, mid_pos
, max_pos
;
4205 guint call_rest
= 0;
4207 LttvTraceState
*tcs
;
4209 LttvAttributeValue value
;
4211 LttvAttributeType type
;
4213 LttvAttributeName name
;
4217 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
4219 //g_tree_destroy(self->parent.pqueue);
4220 //self->parent.pqueue = g_tree_new(compare_tracefile);
4222 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
4224 nb_trace
= lttv_traceset_number(traceset
);
4225 for(i
= 0 ; i
< nb_trace
; i
++) {
4226 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4228 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4229 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4230 LTTV_STATE_SAVED_STATES
);
4233 if(saved_states_tree
) {
4234 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4235 mid_pos
= max_pos
/ 2;
4236 while(min_pos
< max_pos
) {
4237 type
= lttv_attribute_get(saved_states_tree
, mid_pos
,
4238 &name
, &value
, &is_named
);
4239 g_assert(type
== LTTV_GOBJECT
);
4240 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4241 type
= lttv_attribute_get_by_name(saved_state_tree
,
4242 LTTV_STATE_TIME
, &value
);
4243 g_assert(type
== LTTV_TIME
);
4244 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4246 closest_tree
= saved_state_tree
;
4248 else max_pos
= mid_pos
- 1;
4250 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4254 /* restore the closest earlier saved state */
4256 lttv_state_restore(tcs
, closest_tree
);
4260 /* There is no saved state, yet we want to have it. Restart at T0 */
4262 restore_init_state(tcs
);
4263 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4266 /* We want to seek quickly without restoring/updating the state */
4268 restore_init_state(tcs
);
4269 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4272 if(!call_rest
) g_info("NOT Calling restore");
4276 static void traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4281 static void traceset_state_finalize (LttvTracesetState
*self
)
4283 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4284 finalize(G_OBJECT(self
));
4288 static void traceset_state_class_init (LttvTracesetContextClass
*klass
)
4290 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4292 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4293 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4294 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4295 klass
->new_traceset_context
= new_traceset_context
;
4296 klass
->new_trace_context
= new_trace_context
;
4297 klass
->new_tracefile_context
= new_tracefile_context
;
4301 GType
lttv_traceset_state_get_type(void)
4303 static GType type
= 0;
4305 static const GTypeInfo info
= {
4306 sizeof (LttvTracesetStateClass
),
4307 NULL
, /* base_init */
4308 NULL
, /* base_finalize */
4309 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4310 NULL
, /* class_finalize */
4311 NULL
, /* class_data */
4312 sizeof (LttvTracesetState
),
4313 0, /* n_preallocs */
4314 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4315 NULL
/* value handling */
4318 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4325 static void trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4330 static void trace_state_finalize (LttvTraceState
*self
)
4332 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4333 finalize(G_OBJECT(self
));
4337 static void trace_state_class_init (LttvTraceStateClass
*klass
)
4339 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4341 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4342 klass
->state_save
= state_save
;
4343 klass
->state_restore
= state_restore
;
4344 klass
->state_saved_free
= state_saved_free
;
4348 GType
lttv_trace_state_get_type(void)
4350 static GType type
= 0;
4352 static const GTypeInfo info
= {
4353 sizeof (LttvTraceStateClass
),
4354 NULL
, /* base_init */
4355 NULL
, /* base_finalize */
4356 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4357 NULL
, /* class_finalize */
4358 NULL
, /* class_data */
4359 sizeof (LttvTraceState
),
4360 0, /* n_preallocs */
4361 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4362 NULL
/* value handling */
4365 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4366 "LttvTraceStateType", &info
, 0);
4372 static void tracefile_state_instance_init (GTypeInstance
*instance
,
4378 static void tracefile_state_finalize (LttvTracefileState
*self
)
4380 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4381 finalize(G_OBJECT(self
));
4385 static void tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4387 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4389 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4393 GType
lttv_tracefile_state_get_type(void)
4395 static GType type
= 0;
4397 static const GTypeInfo info
= {
4398 sizeof (LttvTracefileStateClass
),
4399 NULL
, /* base_init */
4400 NULL
, /* base_finalize */
4401 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4402 NULL
, /* class_finalize */
4403 NULL
, /* class_data */
4404 sizeof (LttvTracefileState
),
4405 0, /* n_preallocs */
4406 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4407 NULL
/* value handling */
4410 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4411 "LttvTracefileStateType", &info
, 0);
4417 static void module_init()
4419 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4420 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4421 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4422 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4423 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4424 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4425 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4426 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4427 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4428 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4429 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4430 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4431 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4432 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4433 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4434 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4435 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4436 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4437 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4438 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4439 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4440 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4441 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4442 LTTV_STATE_EVENT
= g_quark_from_string("event");
4443 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4444 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4445 LTTV_STATE_TIME
= g_quark_from_string("time");
4446 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4447 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4448 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4449 g_quark_from_string("trace_state_use_count");
4450 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4451 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4452 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4453 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4454 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4455 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4457 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4458 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4459 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4460 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4461 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4462 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4463 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4464 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4465 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4466 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4467 LTT_CHANNEL_KPROBE_STATE
= g_quark_from_string("kprobe_state");
4468 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4469 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4470 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4471 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4472 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4474 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4475 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4476 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4477 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4478 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4479 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4480 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4481 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4482 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4483 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4484 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4485 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4486 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4487 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4488 LTT_EVENT_SCHED_TRY_WAKEUP
= g_quark_from_string("sched_try_wakeup");
4489 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4490 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4491 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4492 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4493 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4494 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4495 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4496 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4497 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4498 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4499 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4500 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4501 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4502 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4503 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4504 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4505 LTT_EVENT_KPROBE
= g_quark_from_string("kprobe");
4506 LTT_EVENT_OPEN
= g_quark_from_string("open");
4507 LTT_EVENT_READ
= g_quark_from_string("read");
4508 LTT_EVENT_POLL_EVENT
= g_quark_from_string("poll_event");
4510 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4511 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4512 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4513 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4514 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4515 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4516 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4517 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4518 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4519 LTT_FIELD_PID
= g_quark_from_string("pid");
4520 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4521 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4522 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4523 LTT_FIELD_NAME
= g_quark_from_string("name");
4524 LTT_FIELD_TYPE
= g_quark_from_string("type");
4525 LTT_FIELD_MODE
= g_quark_from_string("mode");
4526 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4527 LTT_FIELD_STATUS
= g_quark_from_string("status");
4528 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4529 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4530 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4531 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4532 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4533 LTT_FIELD_ACTION
= g_quark_from_string("action");
4534 LTT_FIELD_ID
= g_quark_from_string("id");
4535 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4536 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4537 LTT_FIELD_IP
= g_quark_from_string("ip");
4538 LTT_FIELD_FD
= g_quark_from_string("fd");
4539 LTT_FIELD_STATE
= g_quark_from_string("state");
4540 LTT_FIELD_CPU_ID
= g_quark_from_string("cpu_id");
4542 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4543 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4544 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4545 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4546 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4547 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4549 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4550 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4551 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4553 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4554 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4555 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4556 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4559 static void module_destroy()
4564 LTTV_MODULE("state", "State computation", \
4565 "Update the system state, possibly saving it at intervals", \
4566 module_init
, module_destroy
)