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
];
583 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
584 strncpy(path
, trace_path
, PATH_MAX
-1);
585 count
= strnlen(trace_path
, PATH_MAX
-1);
586 // quarktable : open, test
587 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
588 fp
= fopen(path
, "r");
590 quarktable
= g_ptr_array_sized_new(4096);
592 /* Index 0 is null */
594 if(hdr
== EOF
) return;
595 g_assert(hdr
== HDR_QUARKS
);
599 if(hdr
== EOF
) break;
600 g_assert(hdr
== HDR_QUARK
);
601 g_ptr_array_set_size(quarktable
, q
+1);
604 res
= fread(&buf
[i
], sizeof(gchar
), 1, fp
);
606 if(buf
[i
] == '\0' || feof(fp
)) break;
609 len
= strnlen(buf
, MAX_STRING_LEN
-1);
610 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
611 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
617 // saved_states : open, test
618 strncpy(path
, trace_path
, PATH_MAX
-1);
619 count
= strnlen(trace_path
, PATH_MAX
-1);
620 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
621 fp
= fopen(path
, "r");
625 if(hdr
!= HDR_TRACE
) goto end
;
627 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
629 tcs
->has_precomputed_states
= TRUE
;
634 /* Free the quarktable */
635 for(i
=0; i
<quarktable
->len
; i
++) {
636 string
= g_ptr_array_index (quarktable
, i
);
639 g_ptr_array_free(quarktable
, TRUE
);
643 static void init(LttvTracesetState
*self
, LttvTraceset
*ts
)
645 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
648 LttvTraceContext
*tc
;
652 LttvTracefileState
*tfcs
;
654 LttvAttributeValue v
;
656 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
657 init((LttvTracesetContext
*)self
, ts
);
659 nb_trace
= lttv_traceset_number(ts
);
660 for(i
= 0 ; i
< nb_trace
; i
++) {
661 tc
= self
->parent
.traces
[i
];
662 tcs
= LTTV_TRACE_STATE(tc
);
663 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
664 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
668 if(*(v
.v_uint
) == 1) {
669 create_name_tables(tcs
);
670 create_max_time(tcs
);
672 get_name_tables(tcs
);
675 nb_tracefile
= tc
->tracefiles
->len
;
676 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
677 nb_irq
= tcs
->name_tables
->nb_irqs
;
678 tcs
->processes
= NULL
;
679 tcs
->usertraces
= NULL
;
680 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
682 /* init cpu resource stuff */
683 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
684 for(j
= 0; j
<nb_cpu
; j
++) {
685 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
686 tcs
->cpu_states
[j
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
687 tcs
->cpu_states
[j
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
688 tcs
->cpu_states
[j
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
689 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
692 /* init irq resource stuff */
693 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
694 for(j
= 0; j
<nb_irq
; j
++) {
695 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
696 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
699 /* init soft irq stuff */
700 /* the kernel has a statically fixed max of 32 softirqs */
701 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->name_tables
->nb_soft_irqs
);
703 /* init trap stuff */
704 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->name_tables
->nb_traps
);
706 /* init bdev resource stuff */
707 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
709 restore_init_state(tcs
);
710 for(j
= 0 ; j
< nb_tracefile
; j
++) {
712 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
713 LttvTracefileContext
*, j
));
714 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
715 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
716 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
717 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
718 /* It's a Usertrace */
719 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
720 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
721 GUINT_TO_POINTER(tid
));
722 if(!usertrace_tree
) {
723 usertrace_tree
= g_tree_new_full(compare_usertraces
,
724 NULL
, free_usertrace_key
, NULL
);
725 g_hash_table_insert(tcs
->usertraces
,
726 GUINT_TO_POINTER(tid
), usertrace_tree
);
728 LttTime
*timestamp
= g_new(LttTime
, 1);
729 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
730 ltt_tracefile_creation(tfcs
->parent
.tf
));
731 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
735 /* See if the trace has saved states */
736 state_load_saved_states(tcs
);
740 static void fini(LttvTracesetState
*self
)
746 //LttvTracefileState *tfcs;
748 LttvAttributeValue v
;
750 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
751 for(i
= 0 ; i
< nb_trace
; i
++) {
752 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
753 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
756 g_assert(*(v
.v_uint
) != 0);
759 if(*(v
.v_uint
) == 0) {
760 free_name_tables(tcs
);
762 free_saved_state(tcs
);
764 g_free(tcs
->running_process
);
765 tcs
->running_process
= NULL
;
766 lttv_state_free_process_table(tcs
->processes
);
767 lttv_state_free_usertraces(tcs
->usertraces
);
768 tcs
->processes
= NULL
;
769 tcs
->usertraces
= NULL
;
771 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
772 fini((LttvTracesetContext
*)self
);
776 static LttvTracesetContext
*new_traceset_context(LttvTracesetContext
*self
)
778 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
782 static LttvTraceContext
*new_trace_context(LttvTracesetContext
*self
)
784 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
788 static LttvTracefileContext
*new_tracefile_context(LttvTracesetContext
*self
)
790 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
794 /* Write the process state of the trace */
796 static void write_process_state(gpointer key
, gpointer value
,
799 LttvProcessState
*process
;
801 LttvExecutionState
*es
;
803 FILE *fp
= (FILE *)user_data
;
808 process
= (LttvProcessState
*)value
;
809 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",
810 process
, process
->pid
, process
->tgid
, process
->ppid
,
811 g_quark_to_string(process
->type
),
812 process
->creation_time
.tv_sec
,
813 process
->creation_time
.tv_nsec
,
814 process
->insertion_time
.tv_sec
,
815 process
->insertion_time
.tv_nsec
,
816 g_quark_to_string(process
->name
),
817 g_quark_to_string(process
->brand
),
818 process
->cpu
, process
->free_events
);
820 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
821 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
822 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
823 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
824 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
825 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
826 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
829 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
830 address
= g_array_index(process
->user_stack
, guint64
, i
);
831 fprintf(fp
, " <USER_STACK ADDRESS=\"%" PRIu64
"\"/>\n", address
);
834 if(process
->usertrace
) {
835 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
836 g_quark_to_string(process
->usertrace
->tracefile_name
),
837 process
->usertrace
->cpu
);
841 fprintf(fp
, " </PROCESS>\n");
845 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
847 guint i
, nb_tracefile
, nb_block
, offset
;
850 LttvTracefileState
*tfcs
;
854 LttEventPosition
*ep
;
858 ep
= ltt_event_position_new();
860 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
862 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
864 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
865 for(i
=0;i
<nb_cpus
;i
++) {
866 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
867 i
, self
->running_process
[i
]->pid
);
870 nb_tracefile
= self
->parent
.tracefiles
->len
;
872 for(i
= 0 ; i
< nb_tracefile
; i
++) {
874 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
875 LttvTracefileContext
*, i
));
876 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
877 tfcs
->parent
.timestamp
.tv_sec
,
878 tfcs
->parent
.timestamp
.tv_nsec
);
879 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
880 if(e
== NULL
) fprintf(fp
,"/>\n");
882 ltt_event_position(e
, ep
);
883 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
884 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%" PRIu64
"/>\n", nb_block
, offset
,
889 fprintf(fp
,"</PROCESS_STATE>\n");
893 static void write_process_state_raw(gpointer key
, gpointer value
,
896 LttvProcessState
*process
;
898 LttvExecutionState
*es
;
900 FILE *fp
= (FILE *)user_data
;
905 process
= (LttvProcessState
*)value
;
906 fputc(HDR_PROCESS
, fp
);
907 //fwrite(&header, sizeof(header), 1, fp);
908 //fprintf(fp, "%s", g_quark_to_string(process->type));
910 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
911 //fprintf(fp, "%s", g_quark_to_string(process->name));
913 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
914 //fprintf(fp, "%s", g_quark_to_string(process->brand));
916 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
917 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
918 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
919 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
920 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
921 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
922 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
923 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
926 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",
927 process
, process
->pid
, process
->tgid
, process
->ppid
,
928 g_quark_to_string(process
->type
),
929 process
->creation_time
.tv_sec
,
930 process
->creation_time
.tv_nsec
,
931 process
->insertion_time
.tv_sec
,
932 process
->insertion_time
.tv_nsec
,
933 g_quark_to_string(process
->name
),
934 g_quark_to_string(process
->brand
),
938 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
939 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
942 //fprintf(fp, "%s", g_quark_to_string(es->t));
944 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
945 //fprintf(fp, "%s", g_quark_to_string(es->n));
947 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
948 //fprintf(fp, "%s", g_quark_to_string(es->s));
950 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
951 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
952 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
953 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
955 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
956 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
957 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
958 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
959 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
963 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
964 address
= g_array_index(process
->user_stack
, guint64
, i
);
965 fputc(HDR_USER_STACK
, fp
);
966 fwrite(&address
, sizeof(address
), 1, fp
);
968 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n", address
);
972 if(process
->usertrace
) {
973 fputc(HDR_USERTRACE
, fp
);
974 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
976 fwrite(&process
->usertrace
->tracefile_name
,
977 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
978 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
980 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
981 g_quark_to_string(process
->usertrace
->tracefile_name
),
982 process
->usertrace
->cpu
);
989 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
991 guint i
, nb_tracefile
, nb_block
, offset
;
994 LttvTracefileState
*tfcs
;
998 LttEventPosition
*ep
;
1002 ep
= ltt_event_position_new();
1004 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
1005 fputc(HDR_PROCESS_STATE
, fp
);
1006 fwrite(&t
, sizeof(t
), 1, fp
);
1008 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
1010 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1011 for(i
=0;i
<nb_cpus
;i
++) {
1013 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
1014 fwrite(&self
->running_process
[i
]->pid
,
1015 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1016 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
1017 // i, self->running_process[i]->pid);
1020 nb_tracefile
= self
->parent
.tracefiles
->len
;
1022 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1024 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1025 LttvTracefileContext
*, i
));
1026 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1027 // tfcs->parent.timestamp.tv_sec,
1028 // tfcs->parent.timestamp.tv_nsec);
1029 fputc(HDR_TRACEFILE
, fp
);
1030 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1031 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1032 * position following : end of trace */
1033 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1035 ltt_event_position(e
, ep
);
1036 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1037 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
1039 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
1040 fwrite(&offset
, sizeof(offset
), 1, fp
);
1041 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
1048 /* Read process state from a file */
1050 /* Called because a HDR_PROCESS was found */
1051 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
1052 GPtrArray
*quarktable
)
1054 LttvExecutionState
*es
;
1055 LttvProcessState
*process
, *parent_process
;
1056 LttvProcessState tmp
;
1062 res
= fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
1063 res
+= fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
1064 res
+= fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
1065 res
+= fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
1066 res
+= fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
1067 res
+= fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
1068 res
+= fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
1069 res
+= fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
1070 res
+= fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
1071 res
+= fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
1072 g_assert(res
== 10);
1075 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
1077 /* We must link to the parent */
1078 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
1080 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
1081 if(process
== NULL
) {
1082 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
1084 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
1085 &tmp
.creation_time
);
1088 process
->insertion_time
= tmp
.insertion_time
;
1089 process
->creation_time
= tmp
.creation_time
;
1090 process
->type
= g_quark_from_string(
1091 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
1092 process
->tgid
= tmp
.tgid
;
1093 process
->ppid
= tmp
.ppid
;
1094 process
->brand
= g_quark_from_string(
1095 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
1097 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
1098 process
->free_events
= tmp
.free_events
;
1101 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1103 gint hdr
= fgetc(fp
);
1104 if(hdr
== EOF
) goto end_loop
;
1108 process
->execution_stack
=
1109 g_array_set_size(process
->execution_stack
,
1110 process
->execution_stack
->len
+ 1);
1111 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1112 process
->execution_stack
->len
-1);
1113 process
->state
= es
;
1115 res
= fread(&es
->t
, sizeof(es
->t
), 1, fp
);
1117 es
->t
= g_quark_from_string(
1118 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
1119 res
= fread(&es
->n
, sizeof(es
->n
), 1, fp
);
1121 es
->n
= g_quark_from_string(
1122 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
1123 res
= fread(&es
->s
, sizeof(es
->s
), 1, fp
);
1125 es
->s
= g_quark_from_string(
1126 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
1127 res
= fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
1128 res
+= fread(&es
->change
, sizeof(es
->change
), 1, fp
);
1129 res
+= fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
1133 case HDR_USER_STACK
:
1134 process
->user_stack
= g_array_set_size(process
->user_stack
,
1135 process
->user_stack
->len
+ 1);
1136 address
= &g_array_index(process
->user_stack
, guint64
,
1137 process
->user_stack
->len
-1);
1138 res
= fread(address
, sizeof(address
), 1, fp
);
1140 process
->current_function
= *address
;
1144 res
= fread(&tmpq
, sizeof(tmpq
), 1, fp
);
1145 res
+= fread(&process
->usertrace
->cpu
,
1146 sizeof(process
->usertrace
->cpu
), 1, fp
);
1160 /* Called because a HDR_PROCESS_STATE was found */
1161 /* Append a saved state to the trace states */
1162 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
1164 guint i
, nb_tracefile
, nb_block
, offset
;
1166 LttvTracefileState
*tfcs
;
1168 LttEventPosition
*ep
;
1177 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1179 LttvAttributeValue value
;
1180 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1181 ep
= ltt_event_position_new();
1183 restore_init_state(self
);
1185 res
= fread(&t
, sizeof(t
), 1, fp
);
1189 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1191 if(hdr
== EOF
) goto end_loop
;
1195 /* Call read_process_state_raw */
1196 read_process_state_raw(self
, fp
, quarktable
);
1204 case HDR_USER_STACK
:
1206 case HDR_PROCESS_STATE
:
1212 g_error("Error while parsing saved state file : unknown data header %d",
1218 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1219 for(i
=0;i
<nb_cpus
;i
++) {
1222 g_assert(hdr
== HDR_CPU
);
1223 res
= fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1225 g_assert(i
== cpu_num
);
1226 res
= fread(&self
->running_process
[i
]->pid
,
1227 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1231 nb_tracefile
= self
->parent
.tracefiles
->len
;
1233 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1235 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1236 LttvTracefileContext
*, i
));
1237 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1238 // tfcs->parent.timestamp.tv_sec,
1239 // tfcs->parent.timestamp.tv_nsec);
1240 g_tree_remove(pqueue
, &tfcs
->parent
);
1242 g_assert(hdr
== HDR_TRACEFILE
);
1243 res
= fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1245 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1246 * position following : end of trace */
1247 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1248 res
= fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1249 res
+= fread(&offset
, sizeof(offset
), 1, fp
);
1250 res
+= fread(&tsc
, sizeof(tsc
), 1, fp
);
1252 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1253 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1255 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1260 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1261 LTTV_STATE_SAVED_STATES
);
1262 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1263 value
= lttv_attribute_add(saved_states_tree
,
1264 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1265 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1266 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1267 *(value
.v_time
) = t
;
1268 lttv_state_save(self
, saved_state_tree
);
1269 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1272 *(self
->max_time_state_recomputed_in_seek
) = t
;
1276 /* Called when a HDR_TRACE is found */
1277 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1278 GPtrArray
*quarktable
)
1283 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1285 if(hdr
== EOF
) goto end_loop
;
1288 case HDR_PROCESS_STATE
:
1289 /* Call read_process_state_raw */
1290 lttv_state_read_raw(tcs
, fp
, quarktable
);
1298 case HDR_USER_STACK
:
1302 g_error("Error while parsing saved state file :"
1303 " unexpected data header %d",
1307 g_error("Error while parsing saved state file : unknown data header %d",
1312 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1313 restore_init_state(tcs
);
1314 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1320 /* Copy each process from an existing hash table to a new one */
1322 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1324 LttvProcessState
*process
, *new_process
;
1326 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1330 process
= (LttvProcessState
*)value
;
1331 new_process
= g_new(LttvProcessState
, 1);
1332 *new_process
= *process
;
1333 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1334 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1335 new_process
->execution_stack
=
1336 g_array_set_size(new_process
->execution_stack
,
1337 process
->execution_stack
->len
);
1338 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1339 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1340 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1342 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1343 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1344 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1345 sizeof(guint64
), 0);
1346 new_process
->user_stack
= g_array_set_size(new_process
->user_stack
,
1347 process
->user_stack
->len
);
1348 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1349 g_array_index(new_process
->user_stack
, guint64
, i
) =
1350 g_array_index(process
->user_stack
, guint64
, i
);
1352 new_process
->current_function
= process
->current_function
;
1354 /* fd hash table stuff */
1360 /* copy every item in the hash table */
1361 new_process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1363 g_hash_table_iter_init(&it
, process
->fds
);
1364 while (g_hash_table_iter_next (&it
, (void *)&key
, (void *)&value
)) {
1365 g_hash_table_insert(new_process
->fds
, key
, value
);
1369 /* When done creating the new process state, insert it in the
1371 g_hash_table_insert(new_processes
, new_process
, new_process
);
1375 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1377 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1379 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1380 return new_processes
;
1383 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1386 LttvCPUState
*retval
;
1388 retval
= g_new(LttvCPUState
, n
);
1390 for(i
=0; i
<n
; i
++) {
1391 retval
[i
].irq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1392 g_array_set_size(retval
[i
].irq_stack
, states
[i
].irq_stack
->len
);
1393 for(j
=0; j
<states
[i
].irq_stack
->len
; j
++) {
1394 g_array_index(retval
[i
].irq_stack
, gint
, j
) =
1395 g_array_index(states
[i
].irq_stack
, gint
, j
);
1398 retval
[i
].softirq_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1399 g_array_set_size(retval
[i
].softirq_stack
, states
[i
].softirq_stack
->len
);
1400 for(j
=0; j
<states
[i
].softirq_stack
->len
; j
++) {
1401 g_array_index(retval
[i
].softirq_stack
, gint
, j
) =
1402 g_array_index(states
[i
].softirq_stack
, gint
, j
);
1405 retval
[i
].trap_stack
= g_array_new(FALSE
, FALSE
, sizeof(gint
));
1406 g_array_set_size(retval
[i
].trap_stack
, states
[i
].trap_stack
->len
);
1407 for(j
=0; j
<states
[i
].trap_stack
->len
; j
++) {
1408 g_array_index(retval
[i
].trap_stack
, gint
, j
) =
1409 g_array_index(states
[i
].trap_stack
, gint
, j
);
1412 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1413 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1414 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1415 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1416 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1423 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1427 for(i
=0; i
<n
; i
++) {
1428 g_array_free(states
[i
].mode_stack
, TRUE
);
1429 g_array_free(states
[i
].irq_stack
, TRUE
);
1430 g_array_free(states
[i
].softirq_stack
, TRUE
);
1431 g_array_free(states
[i
].trap_stack
, TRUE
);
1437 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1440 LttvIRQState
*retval
;
1442 retval
= g_new(LttvIRQState
, n
);
1444 for(i
=0; i
<n
; i
++) {
1445 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1446 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1447 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1448 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) =
1449 g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1456 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1460 for(i
=0; i
<n
; i
++) {
1461 g_array_free(states
[i
].mode_stack
, TRUE
);
1467 static LttvSoftIRQState
*
1468 lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1471 LttvSoftIRQState
*retval
;
1473 retval
= g_new(LttvSoftIRQState
, n
);
1475 for(i
=0; i
<n
; i
++) {
1476 retval
[i
].pending
= states
[i
].pending
;
1477 retval
[i
].running
= states
[i
].running
;
1483 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1488 static LttvTrapState
*
1489 lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1492 LttvTrapState
*retval
;
1494 retval
= g_new(LttvTrapState
, n
);
1496 for(i
=0; i
<n
; i
++) {
1497 retval
[i
].running
= states
[i
].running
;
1503 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1508 /* bdevstate stuff */
1510 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint32 devcode
)
1512 gint devcode_gint
= devcode
;
1513 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1515 LttvBdevState
*bdevstate
= g_new(LttvBdevState
, 1);
1516 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1518 gint
* key
= g_new(gint
, 1);
1520 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1528 static LttvBdevState
*bdevstate_new(void)
1530 LttvBdevState
*retval
;
1531 retval
= g_new(LttvBdevState
, 1);
1532 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1537 static void bdevstate_free(LttvBdevState
*bds
)
1539 g_array_free(bds
->mode_stack
, TRUE
);
1543 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1545 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1547 bdevstate_free(bds
);
1550 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1552 LttvBdevState
*retval
;
1554 retval
= bdevstate_new();
1555 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
,
1556 bds
->mode_stack
->len
);
1561 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1563 //GHashTable *ht = (GHashTable *)u;
1564 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1565 LttvBdevState
*newbds
;
1567 newbds
= bdevstate_copy(bds
);
1569 g_hash_table_insert(u
, k
, newbds
);
1572 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1576 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1578 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1583 /* Free a hashtable and the LttvBdevState structures its values
1586 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1588 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1589 g_hash_table_destroy(ht
);
1592 /* The saved state for each trace contains a member "processes", which
1593 stores a copy of the process table, and a member "tracefiles" with
1594 one entry per tracefile. Each tracefile has a "process" member pointing
1595 to the current process and a "position" member storing the tracefile
1596 position (needed to seek to the current "next" event. */
1598 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1600 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1602 LttvTracefileState
*tfcs
;
1604 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1606 guint
*running_process
;
1608 LttvAttributeValue value
;
1610 LttEventPosition
*ep
;
1612 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1613 LTTV_STATE_TRACEFILES
);
1615 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1617 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1619 /* Add the currently running processes array */
1620 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1621 running_process
= g_new(guint
, nb_cpus
);
1622 for(i
=0;i
<nb_cpus
;i
++) {
1623 running_process
[i
] = self
->running_process
[i
]->pid
;
1625 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1627 *(value
.v_pointer
) = running_process
;
1629 g_info("State save");
1631 nb_tracefile
= self
->parent
.tracefiles
->len
;
1633 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1635 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1636 LttvTracefileContext
*, i
));
1637 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1638 value
= lttv_attribute_add(tracefiles_tree
, i
,
1640 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1642 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1644 *(value
.v_uint
) = tfcs
->process
->pid
;
1646 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1648 /* Only save the position if the tfs has not infinite time. */
1649 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1650 // && current_tfcs != tfcs) {
1651 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1652 *(value
.v_pointer
) = NULL
;
1654 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1655 ep
= ltt_event_position_new();
1656 ltt_event_position(e
, ep
);
1657 *(value
.v_pointer
) = ep
;
1659 guint nb_block
, offset
;
1662 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1663 g_info("Block %u offset %u tsc %" PRIu64
" time %lu.%lu", nb_block
,
1664 offset
, tsc
, tfcs
->parent
.timestamp
.tv_sec
,
1665 tfcs
->parent
.timestamp
.tv_nsec
);
1669 /* save the cpu state */
1671 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1673 *(value
.v_uint
) = nb_cpus
;
1675 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1677 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1680 /* save the irq state */
1681 nb_irqs
= self
->name_tables
->nb_irqs
;
1683 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1685 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1688 /* save the soft irq state */
1689 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1691 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1693 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1696 /* save the trap state */
1697 nb_traps
= self
->name_tables
->nb_traps
;
1699 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1701 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1704 /* save the blkdev states */
1705 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1707 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1711 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1713 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1715 LttvTracefileState
*tfcs
;
1717 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1719 guint
*running_process
;
1721 LttvAttributeType type
;
1723 LttvAttributeValue value
;
1725 LttvAttributeName name
;
1729 LttEventPosition
*ep
;
1731 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1734 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1735 LTTV_STATE_TRACEFILES
);
1737 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1739 g_assert(type
== LTTV_POINTER
);
1740 lttv_state_free_process_table(self
->processes
);
1741 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1743 /* Add the currently running processes array */
1744 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1745 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1747 g_assert(type
== LTTV_POINTER
);
1748 running_process
= *(value
.v_pointer
);
1749 for(i
=0;i
<nb_cpus
;i
++) {
1750 pid
= running_process
[i
];
1751 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1752 g_assert(self
->running_process
[i
] != NULL
);
1755 nb_tracefile
= self
->parent
.tracefiles
->len
;
1757 //g_tree_destroy(tsc->pqueue);
1758 //tsc->pqueue = g_tree_new(compare_tracefile);
1760 /* restore cpu resource states */
1761 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1762 g_assert(type
== LTTV_POINTER
);
1763 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1764 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1766 /* restore irq resource states */
1767 nb_irqs
= self
->name_tables
->nb_irqs
;
1768 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1769 g_assert(type
== LTTV_POINTER
);
1770 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1771 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1773 /* restore soft irq resource states */
1774 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1775 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1776 g_assert(type
== LTTV_POINTER
);
1777 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1778 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1780 /* restore trap resource states */
1781 nb_traps
= self
->name_tables
->nb_traps
;
1782 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1783 g_assert(type
== LTTV_POINTER
);
1784 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1785 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1787 /* restore the blkdev states */
1788 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1789 g_assert(type
== LTTV_POINTER
);
1790 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1791 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1793 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1795 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1796 LttvTracefileContext
*, i
));
1797 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1798 g_assert(type
== LTTV_GOBJECT
);
1799 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1801 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1803 g_assert(type
== LTTV_UINT
);
1804 pid
= *(value
.v_uint
);
1805 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1807 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1809 g_assert(type
== LTTV_POINTER
);
1810 //g_assert(*(value.v_pointer) != NULL);
1811 ep
= *(value
.v_pointer
);
1812 g_assert(tfcs
->parent
.t_context
!= NULL
);
1814 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1816 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1817 g_tree_remove(tsc
->pqueue
, tfc
);
1820 retval
= ltt_tracefile_seek_position(tfc
->tf
, ep
);
1821 g_assert_cmpint(retval
, ==, 0);
1822 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1823 g_assert_cmpint(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
),
1825 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1826 g_info("Restoring state for a tf at time %lu.%lu",
1827 tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1829 tfc
->timestamp
= ltt_time_infinite
;
1835 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1837 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1839 LttvTracefileState
*tfcs
;
1841 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1843 guint
*running_process
;
1845 LttvAttributeType type
;
1847 LttvAttributeValue value
;
1849 LttvAttributeName name
;
1853 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1854 LTTV_STATE_TRACEFILES
);
1855 g_object_ref(G_OBJECT(tracefiles_tree
));
1856 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1858 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1860 g_assert(type
== LTTV_POINTER
);
1861 lttv_state_free_process_table(*(value
.v_pointer
));
1862 *(value
.v_pointer
) = NULL
;
1863 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1865 /* Free running processes array */
1866 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1868 g_assert(type
== LTTV_POINTER
);
1869 running_process
= *(value
.v_pointer
);
1870 g_free(running_process
);
1872 /* free cpu resource states */
1873 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1874 g_assert(type
== LTTV_UINT
);
1875 nb_cpus
= *value
.v_uint
;
1876 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1877 g_assert(type
== LTTV_POINTER
);
1878 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1880 /* free irq resource states */
1881 nb_irqs
= self
->name_tables
->nb_irqs
;
1882 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1883 g_assert(type
== LTTV_POINTER
);
1884 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1886 /* free softirq resource states */
1887 nb_soft_irqs
= self
->name_tables
->nb_soft_irqs
;
1888 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1889 g_assert(type
== LTTV_POINTER
);
1890 lttv_state_free_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1892 /* free the blkdev states */
1893 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1894 g_assert(type
== LTTV_POINTER
);
1895 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1897 nb_tracefile
= self
->parent
.tracefiles
->len
;
1899 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1901 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1902 LttvTracefileContext
*, i
));
1903 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1904 g_assert(type
== LTTV_GOBJECT
);
1905 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1907 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1909 g_assert(type
== LTTV_POINTER
);
1910 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1912 g_object_unref(G_OBJECT(tracefiles_tree
));
1916 static void free_saved_state(LttvTraceState
*self
)
1920 LttvAttributeType type
;
1922 LttvAttributeValue value
;
1924 LttvAttributeName name
;
1928 LttvAttribute
*saved_states
;
1930 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1931 LTTV_STATE_SAVED_STATES
);
1933 nb
= lttv_attribute_get_number(saved_states
);
1934 for(i
= 0 ; i
< nb
; i
++) {
1935 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1936 g_assert(type
== LTTV_GOBJECT
);
1937 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1940 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1944 static void create_max_time(LttvTraceState
*tcs
)
1946 LttvAttributeValue v
;
1948 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1950 g_assert(*(v
.v_pointer
) == NULL
);
1951 *(v
.v_pointer
) = g_new(LttTime
,1);
1952 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1956 static void get_max_time(LttvTraceState
*tcs
)
1958 LttvAttributeValue v
;
1960 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1962 g_assert(*(v
.v_pointer
) != NULL
);
1963 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1967 static void free_max_time(LttvTraceState
*tcs
)
1969 LttvAttributeValue v
;
1971 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1973 g_free(*(v
.v_pointer
));
1974 *(v
.v_pointer
) = NULL
;
1977 static void create_name_tables(LttvTraceState
*tcs
)
1981 GString
*fe_name
= g_string_new("");
1983 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1985 LttvAttributeValue v
;
1989 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1991 g_assert(*(v
.v_pointer
) == NULL
);
1992 *(v
.v_pointer
) = name_tables
;
1994 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1996 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1998 LTT_EVENT_SYSCALL_ENTRY
,
1999 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
2000 NULL
, NULL
, &hooks
)) {
2002 // th = lttv_trace_hook_get_first(&th);
2004 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2005 // nb = ltt_type_element_number(t);
2007 // name_tables->syscall_names = g_new(GQuark, nb);
2008 // name_tables->nb_syscalls = nb;
2010 // for(i = 0 ; i < nb ; i++) {
2011 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
2012 // if(!name_tables->syscall_names[i]) {
2013 // GString *string = g_string_new("");
2014 // g_string_printf(string, "syscall %u", i);
2015 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
2016 // g_string_free(string, TRUE);
2020 name_tables
->nb_syscalls
= 256;
2021 name_tables
->syscall_names
= g_new(GQuark
, 256);
2022 for(i
= 0 ; i
< 256 ; i
++) {
2023 g_string_printf(fe_name
, "syscall %d", i
);
2024 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2027 name_tables
->syscall_names
= NULL
;
2028 name_tables
->nb_syscalls
= 0;
2030 lttv_trace_hook_remove_all(&hooks
);
2032 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2034 LTT_EVENT_TRAP_ENTRY
,
2035 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2036 NULL
, NULL
, &hooks
) ||
2037 !lttv_trace_find_hook(tcs
->parent
.t
,
2039 LTT_EVENT_PAGE_FAULT_ENTRY
,
2040 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
2041 NULL
, NULL
, &hooks
)) {
2043 // th = lttv_trace_hook_get_first(&th);
2045 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2046 // //nb = ltt_type_element_number(t);
2048 // name_tables->trap_names = g_new(GQuark, nb);
2049 // for(i = 0 ; i < nb ; i++) {
2050 // name_tables->trap_names[i] = g_quark_from_string(
2051 // ltt_enum_string_get(t, i));
2054 name_tables
->nb_traps
= 256;
2055 name_tables
->trap_names
= g_new(GQuark
, 256);
2056 for(i
= 0 ; i
< 256 ; i
++) {
2057 g_string_printf(fe_name
, "trap %d", i
);
2058 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2061 name_tables
->trap_names
= NULL
;
2062 name_tables
->nb_traps
= 0;
2064 lttv_trace_hook_remove_all(&hooks
);
2066 if(!lttv_trace_find_hook(tcs
->parent
.t
,
2068 LTT_EVENT_IRQ_ENTRY
,
2069 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
2070 NULL
, NULL
, &hooks
)) {
2073 name_tables->irq_names = g_new(GQuark, nb);
2074 for(i = 0 ; i < nb ; i++) {
2075 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2078 /* FIXME: LttvIRQState *irq_states should become a g_array */
2079 /* temp fix: increase from 256 to 512 default size */
2081 name_tables
->nb_irqs
= 512;
2082 name_tables
->irq_names
= g_new(GQuark
, 512);
2083 for(i
= 0 ; i
< 512 ; i
++) {
2084 g_string_printf(fe_name
, "irq %d", i
);
2085 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2088 name_tables
->nb_irqs
= 0;
2089 name_tables
->irq_names
= NULL
;
2091 lttv_trace_hook_remove_all(&hooks
);
2093 name_tables->soft_irq_names = g_new(GQuark, nb);
2094 for(i = 0 ; i < nb ; i++) {
2095 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2099 /* the kernel is limited to 32 statically defined softirqs */
2100 name_tables
->nb_soft_irqs
= 32;
2101 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_soft_irqs
);
2102 for(i
= 0 ; i
< name_tables
->nb_soft_irqs
; i
++) {
2103 g_string_printf(fe_name
, "softirq %d", i
);
2104 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2106 g_array_free(hooks
, TRUE
);
2108 g_string_free(fe_name
, TRUE
);
2110 #if (__WORDSIZE == 32)
2111 name_tables
->kprobe_hash
= g_hash_table_new_full(guint64_hash
, guint64_equal
,
2114 name_tables
->kprobe_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2119 static void get_name_tables(LttvTraceState
*tcs
)
2121 LttvAttributeValue v
;
2123 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2125 g_assert(*(v
.v_pointer
) != NULL
);
2126 tcs
->name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2130 static void free_name_tables(LttvTraceState
*tcs
)
2132 LttvNameTables
*name_tables
;
2134 LttvAttributeValue v
;
2136 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
2138 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
2139 *(v
.v_pointer
) = NULL
;
2141 // g_free(name_tables->eventtype_names);
2142 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
2143 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
2144 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
2145 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
2146 g_hash_table_destroy(name_tables
->kprobe_hash
);
2147 g_free(name_tables
);
2150 #ifdef HASH_TABLE_DEBUG
2152 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
2154 LttvProcessState
*process
= (LttvProcessState
*)value
;
2156 /* Test for process corruption */
2157 guint stack_len
= process
->execution_stack
->len
;
2160 static void hash_table_check(GHashTable
*table
)
2162 g_hash_table_foreach(table
, test_process
, NULL
);
2168 /* clears the stack and sets the state passed as argument */
2169 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2171 g_array_set_size(cpust
->mode_stack
, 1);
2172 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
2175 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
2177 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
2178 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
2181 static void cpu_pop_mode(LttvCPUState
*cpust
)
2183 if(cpust
->mode_stack
->len
<= 1)
2184 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
2186 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
2189 /* clears the stack and sets the state passed as argument */
2190 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2192 g_array_set_size(bdevst
->mode_stack
, 1);
2193 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
2196 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
2198 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
2199 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
2202 static void bdev_pop_mode(LttvBdevState
*bdevst
)
2204 if(bdevst
->mode_stack
->len
<= 1)
2205 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
2207 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
2210 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2212 g_array_set_size(irqst
->mode_stack
, 1);
2213 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
2216 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
2218 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
2219 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
2222 static void irq_pop_mode(LttvIRQState
*irqst
)
2224 if(irqst
->mode_stack
->len
<= 1)
2225 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
2227 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
2230 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
2233 LttvExecutionState
*es
;
2235 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2236 guint cpu
= tfs
->cpu
;
2238 #ifdef HASH_TABLE_DEBUG
2239 hash_table_check(ts
->processes
);
2241 LttvProcessState
*process
= ts
->running_process
[cpu
];
2243 guint depth
= process
->execution_stack
->len
;
2245 process
->execution_stack
=
2246 g_array_set_size(process
->execution_stack
, depth
+ 1);
2249 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2251 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2254 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2255 es
->cum_cpu_time
= ltt_time_zero
;
2256 es
->s
= process
->state
->s
;
2257 process
->state
= es
;
2261 * return 1 when empty, else 0 */
2263 lttv_state_pop_state_cleanup(LttvProcessState
*process
, LttvTracefileState
*tfs
)
2265 guint depth
= process
->execution_stack
->len
;
2271 process
->execution_stack
=
2272 g_array_set_size(process
->execution_stack
, depth
- 1);
2273 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2275 process
->state
->change
= tfs
->parent
.timestamp
;
2280 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2282 guint cpu
= tfs
->cpu
;
2283 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2284 LttvProcessState
*process
= ts
->running_process
[cpu
];
2286 guint depth
= process
->execution_stack
->len
;
2288 if(process
->state
->t
!= t
){
2289 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2290 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2291 g_info("process state has %s when pop_int is %s\n",
2292 g_quark_to_string(process
->state
->t
),
2293 g_quark_to_string(t
));
2294 g_info("{ %u, %u, %s, %s, %s }\n",
2297 g_quark_to_string(process
->name
),
2298 g_quark_to_string(process
->brand
),
2299 g_quark_to_string(process
->state
->s
));
2304 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2305 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2309 process
->execution_stack
=
2310 g_array_set_size(process
->execution_stack
, depth
- 1);
2311 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2313 process
->state
->change
= tfs
->parent
.timestamp
;
2316 struct search_result
{
2317 const LttTime
*time
; /* Requested time */
2318 LttTime
*best
; /* Best result */
2321 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2323 const LttTime
*elem_time
= (const LttTime
*)a
;
2324 /* Explicit non const cast */
2325 struct search_result
*res
= (struct search_result
*)b
;
2327 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2328 /* The usertrace was created before the schedchange */
2329 /* Get larger keys */
2331 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2332 /* The usertrace was created after the schedchange time */
2333 /* Get smaller keys */
2335 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2336 res
->best
= (LttTime
*)elem_time
;
2339 res
->best
= (LttTime
*)elem_time
;
2346 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2347 guint pid
, const LttTime
*timestamp
)
2349 LttvTracefileState
*tfs
= NULL
;
2350 struct search_result res
;
2351 /* Find the usertrace associated with a pid and time interval.
2352 * Search in the usertraces by PID (within a hash) and then, for each
2353 * corresponding element of the array, find the first one with creation
2354 * timestamp the lowest, but higher or equal to "timestamp". */
2355 res
.time
= timestamp
;
2357 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
,
2358 GUINT_TO_POINTER(pid
));
2359 if(usertrace_tree
) {
2360 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2362 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2368 /* Return a new and initialized LttvProcessState structure */
2370 LttvProcessState
*lttv_state_create_process(LttvTraceState
*tcs
,
2371 LttvProcessState
*parent
, guint cpu
, guint pid
,
2372 guint tgid
, GQuark name
, const LttTime
*timestamp
)
2374 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2376 LttvExecutionState
*es
;
2381 process
->tgid
= tgid
;
2383 process
->name
= name
;
2384 process
->brand
= LTTV_STATE_UNBRANDED
;
2385 //process->last_cpu = tfs->cpu_name;
2386 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2387 process
->type
= LTTV_STATE_USER_THREAD
;
2388 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2389 process
->current_function
= 0; //function 0x0 by default.
2391 g_info("Process %u, core %p", process
->pid
, process
);
2392 g_hash_table_insert(tcs
->processes
, process
, process
);
2395 process
->ppid
= parent
->pid
;
2396 process
->creation_time
= *timestamp
;
2399 /* No parent. This process exists but we are missing all information about
2400 its creation. The birth time is set to zero but we remember the time of
2405 process
->creation_time
= ltt_time_zero
;
2408 process
->insertion_time
= *timestamp
;
2409 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2410 process
->creation_time
.tv_nsec
);
2411 process
->pid_time
= g_quark_from_string(buffer
);
2413 process
->free_events
= 0;
2414 //process->last_cpu = tfs->cpu_name;
2415 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2416 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2417 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2418 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2419 es
= process
->state
= &g_array_index(process
->execution_stack
,
2420 LttvExecutionState
, 0);
2421 es
->t
= LTTV_STATE_USER_MODE
;
2422 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2423 es
->entry
= *timestamp
;
2424 //g_assert(timestamp->tv_sec != 0);
2425 es
->change
= *timestamp
;
2426 es
->cum_cpu_time
= ltt_time_zero
;
2427 es
->s
= LTTV_STATE_RUN
;
2429 es
= process
->state
= &g_array_index(process
->execution_stack
,
2430 LttvExecutionState
, 1);
2431 es
->t
= LTTV_STATE_SYSCALL
;
2432 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2433 es
->entry
= *timestamp
;
2434 //g_assert(timestamp->tv_sec != 0);
2435 es
->change
= *timestamp
;
2436 es
->cum_cpu_time
= ltt_time_zero
;
2437 es
->s
= LTTV_STATE_WAIT_FORK
;
2439 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2440 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2441 sizeof(guint64
), 0);
2443 process
->fds
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
2449 lttv_state_find_process(LttvTraceState
*ts
, guint cpu
, guint pid
)
2451 LttvProcessState key
;
2452 LttvProcessState
*process
;
2456 process
= g_hash_table_lookup(ts
->processes
, &key
);
2460 LttvProcessState
*lttv_state_find_process_or_create(LttvTraceState
*ts
,
2461 guint cpu
, guint pid
, const LttTime
*timestamp
)
2463 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2464 LttvExecutionState
*es
;
2466 /* Put ltt_time_zero creation time for unexisting processes */
2467 if(unlikely(process
== NULL
)) {
2468 process
= lttv_state_create_process(ts
,
2469 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2470 /* We are not sure is it's a kernel thread or normal thread, put the
2471 * bottom stack state to unknown */
2472 process
->execution_stack
=
2473 g_array_set_size(process
->execution_stack
, 1);
2474 process
->state
= es
=
2475 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2476 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2477 es
->s
= LTTV_STATE_UNNAMED
;
2482 /* FIXME : this function should be called when we receive an event telling that
2483 * release_task has been called in the kernel. In happens generally when
2484 * the parent waits for its child termination, but may also happens in special
2485 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2486 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2487 * of a killed thread group, but isn't the leader.
2489 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2491 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2492 LttvProcessState key
;
2494 /* Wait for both schedule with exit dead and process free to happen.
2495 * They can happen in any order. */
2496 if (++(process
->free_events
) < 2)
2499 key
.pid
= process
->pid
;
2500 key
.cpu
= process
->cpu
;
2501 g_hash_table_remove(ts
->processes
, &key
);
2502 g_array_free(process
->execution_stack
, TRUE
);
2503 g_array_free(process
->user_stack
, TRUE
);
2505 /* the following also clears the content */
2506 g_hash_table_destroy(process
->fds
);
2513 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2515 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2516 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2518 /* the following also clears the content */
2519 g_hash_table_destroy(((LttvProcessState
*)value
)->fds
);
2525 static void lttv_state_free_process_table(GHashTable
*processes
)
2527 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2528 g_hash_table_destroy(processes
);
2532 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2534 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2536 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2537 LttvProcessState
*process
= ts
->running_process
[cpu
];
2538 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2539 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2540 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2541 LttvExecutionSubmode submode
;
2542 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2544 guint syscall
= ltt_event_get_unsigned(e
, f
);
2545 expand_syscall_table(ts
, syscall
);
2546 submode
= nt
->syscall_names
[syscall
];
2547 /* There can be no system call from PID 0 : unknown state */
2548 if(process
->pid
!= 0)
2549 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2554 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2556 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2558 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2559 LttvProcessState
*process
= ts
->running_process
[cpu
];
2561 /* There can be no system call from PID 0 : unknown state */
2562 if(process
->pid
!= 0)
2563 pop_state(s
, LTTV_STATE_SYSCALL
);
2568 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2570 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2571 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2572 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2573 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2574 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2575 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2577 LttvExecutionSubmode submode
;
2579 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2581 expand_trap_table(ts
, trap
);
2583 submode
= nt
->trap_names
[trap
];
2585 push_state(s
, LTTV_STATE_TRAP
, submode
);
2587 /* update cpu status */
2588 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2590 /* update trap status */
2591 g_array_append_val(s
->cpu_state
->trap_stack
, trap
);
2592 ts
->trap_states
[trap
].running
++;
2597 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2599 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2600 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2602 pop_state(s
, LTTV_STATE_TRAP
);
2604 /* update cpu status */
2605 cpu_pop_mode(s
->cpu_state
);
2607 /* update trap status */
2608 if (s
->cpu_state
->trap_stack
->len
> 0) {
2609 gint last
= g_array_index(s
->cpu_state
->trap_stack
, gint
,
2610 s
->cpu_state
->trap_stack
->len
-1);
2611 if(ts
->trap_states
[last
].running
)
2612 ts
->trap_states
[last
].running
--;
2613 g_array_remove_index(s
->cpu_state
->trap_stack
,
2614 s
->cpu_state
->trap_stack
->len
-1);
2619 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2621 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2622 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2623 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2624 //guint8 ev_id = ltt_event_eventtype_id(e);
2625 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2626 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2627 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2629 LttvExecutionSubmode submode
;
2630 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2632 expand_irq_table(ts
, irq
);
2634 submode
= nt
->irq_names
[irq
];
2636 /* Do something with the info about being in user or system mode when int? */
2637 push_state(s
, LTTV_STATE_IRQ
, submode
);
2639 /* update cpu status */
2640 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2642 /* update irq status */
2643 g_array_append_val(s
->cpu_state
->irq_stack
, irq
);
2644 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2649 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2651 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2652 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2654 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2656 /* update cpu status */
2657 cpu_pop_mode(s
->cpu_state
);
2659 /* update softirq status */
2660 if (s
->cpu_state
->softirq_stack
->len
> 0) {
2661 gint last
= g_array_index(s
->cpu_state
->softirq_stack
, gint
, s
->cpu_state
->softirq_stack
->len
-1);
2662 if(ts
->soft_irq_states
[last
].running
)
2663 ts
->soft_irq_states
[last
].running
--;
2664 g_array_remove_index(s
->cpu_state
->softirq_stack
, s
->cpu_state
->softirq_stack
->len
-1);
2669 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2671 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2672 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2674 pop_state(s
, LTTV_STATE_IRQ
);
2676 /* update cpu status */
2677 cpu_pop_mode(s
->cpu_state
);
2679 /* update irq status */
2680 if (s
->cpu_state
->irq_stack
->len
> 0) {
2681 gint last
= g_array_index(s
->cpu_state
->irq_stack
, gint
, s
->cpu_state
->irq_stack
->len
-1);
2682 g_array_remove_index(s
->cpu_state
->irq_stack
, s
->cpu_state
->irq_stack
->len
-1);
2683 irq_pop_mode(&ts
->irq_states
[last
]);
2689 static gboolean
soft_irq_raise(void *hook_data
, void *call_data
)
2691 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2692 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2693 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2694 //guint8 ev_id = ltt_event_eventtype_id(e);
2695 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2696 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2697 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2699 LttvExecutionSubmode submode
;
2700 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2701 guint64 nb_softirqs
= nt
->nb_soft_irqs
;
2703 if(softirq
< nb_softirqs
) {
2704 submode
= nt
->soft_irq_names
[softirq
];
2706 /* Fixup an incomplete irq table */
2707 GString
*string
= g_string_new("");
2708 g_string_printf(string
, "softirq %" PRIu64
, softirq
);
2709 submode
= g_quark_from_string(string
->str
);
2710 g_string_free(string
, TRUE
);
2713 /* update softirq status */
2714 /* a soft irq raises are not cumulative */
2715 ts
->soft_irq_states
[softirq
].pending
=1;
2720 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2722 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2723 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2724 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2725 //guint8 ev_id = ltt_event_eventtype_id(e);
2726 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2727 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2728 LttvExecutionSubmode submode
;
2729 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2730 expand_soft_irq_table(ts
, softirq
);
2731 LttvNameTables
*nt
= ((LttvTraceState
*)(s
->parent
.t_context
))->name_tables
;
2732 submode
= nt
->soft_irq_names
[softirq
];
2734 /* Do something with the info about being in user or system mode when int? */
2735 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2737 /* update cpu status */
2738 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2740 /* update softirq status */
2741 g_array_append_val(s
->cpu_state
->softirq_stack
, softirq
);
2742 if(ts
->soft_irq_states
[softirq
].pending
)
2743 ts
->soft_irq_states
[softirq
].pending
--;
2744 ts
->soft_irq_states
[softirq
].running
++;
2749 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2751 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2752 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2753 LttvNameTables
*nt
= ts
->name_tables
;
2754 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2755 //guint8 ev_id = ltt_event_eventtype_id(e);
2756 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2758 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2759 lttv_trace_get_hook_field(th
, 0)));
2760 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2762 expand_irq_table(ts
, irq
);
2763 nt
->irq_names
[irq
] = action
;
2769 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2771 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2772 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2773 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2774 //guint8 ev_id = ltt_event_eventtype_id(e);
2775 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2777 guint major
= ltt_event_get_long_unsigned(e
,
2778 lttv_trace_get_hook_field(th
, 0));
2779 guint minor
= ltt_event_get_long_unsigned(e
,
2780 lttv_trace_get_hook_field(th
, 1));
2781 guint oper
= ltt_event_get_long_unsigned(e
,
2782 lttv_trace_get_hook_field(th
, 2));
2783 guint32 devcode
= MKDEV(major
,minor
);
2785 /* have we seen this block device before? */
2786 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2789 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2791 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2796 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2798 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2799 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2800 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2801 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2803 guint major
= ltt_event_get_long_unsigned(e
,
2804 lttv_trace_get_hook_field(th
, 0));
2805 guint minor
= ltt_event_get_long_unsigned(e
,
2806 lttv_trace_get_hook_field(th
, 1));
2807 //guint oper = ltt_event_get_long_unsigned(e,
2808 // lttv_trace_get_hook_field(th, 2));
2809 guint32 devcode
= MKDEV(major
,minor
);
2811 /* have we seen this block device before? */
2812 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2814 /* update block device */
2815 bdev_pop_mode(bdev
);
2820 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2824 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2825 guint cpu
= tfs
->cpu
;
2826 LttvProcessState
*process
= ts
->running_process
[cpu
];
2828 guint depth
= process
->user_stack
->len
;
2830 process
->user_stack
=
2831 g_array_set_size(process
->user_stack
, depth
+ 1);
2833 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2834 *new_func
= funcptr
;
2835 process
->current_function
= funcptr
;
2838 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2840 guint cpu
= tfs
->cpu
;
2841 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2842 LttvProcessState
*process
= ts
->running_process
[cpu
];
2844 if(process
->current_function
!= funcptr
){
2845 g_info("Different functions (%lu.%09lu): ignore it\n",
2846 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2847 g_info("process state has %" PRIu64
" when pop_function is %" PRIu64
"\n",
2848 process
->current_function
, funcptr
);
2849 g_info("{ %u, %u, %s, %s, %s }\n",
2852 g_quark_to_string(process
->name
),
2853 g_quark_to_string(process
->brand
),
2854 g_quark_to_string(process
->state
->s
));
2857 guint depth
= process
->user_stack
->len
;
2860 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2861 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2865 process
->user_stack
=
2866 g_array_set_size(process
->user_stack
, depth
- 1);
2867 process
->current_function
=
2868 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2872 static gboolean
function_entry(void *hook_data
, void *call_data
)
2874 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2875 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2876 //guint8 ev_id = ltt_event_eventtype_id(e);
2877 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2878 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2879 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2881 push_function(s
, funcptr
);
2885 static gboolean
function_exit(void *hook_data
, void *call_data
)
2887 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2888 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2889 //guint8 ev_id = ltt_event_eventtype_id(e);
2890 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2891 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2892 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2894 pop_function(s
, funcptr
);
2898 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2900 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2901 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2902 LttvNameTables
*nt
= ts
->name_tables
;
2903 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2904 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2909 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2910 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2911 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2913 expand_syscall_table(ts
, id
);
2914 nt
->syscall_names
[id
] = g_quark_from_string(symbol
);
2919 static gboolean
dump_kprobe(void *hook_data
, void *call_data
)
2921 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2922 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2923 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2924 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2928 ip
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2929 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 1));
2931 expand_kprobe_table(ts
, ip
, symbol
);
2936 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2938 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2939 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2940 LttvNameTables
*nt
= ts
->name_tables
;
2941 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2942 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2947 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2948 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2949 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2951 expand_soft_irq_table(ts
, id
);
2952 nt
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2957 static gboolean
sched_try_wakeup(void *hook_data
, void *call_data
)
2959 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2960 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2961 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2962 LttvProcessState
*process
;
2966 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
2967 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2969 process
= lttv_state_find_process_or_create(
2970 (LttvTraceState
*)s
->parent
.t_context
,
2971 woken_cpu
, woken_pid
,
2972 &s
->parent
.timestamp
);
2974 if (process
->state
->s
== LTTV_STATE_WAIT
|| process
->state
->s
== LTTV_STATE_WAIT_FORK
)
2976 process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2977 process
->state
->change
= s
->parent
.timestamp
;
2980 g_debug("Wakeup: process %d on CPU %u\n", woken_pid
, woken_cpu
);
2985 static gboolean
schedchange(void *hook_data
, void *call_data
)
2987 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2989 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2990 LttvProcessState
*process
= ts
->running_process
[cpu
];
2991 //LttvProcessState *old_process = ts->running_process[cpu];
2993 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2994 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2995 guint pid_in
, pid_out
;
2998 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2999 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3000 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
3002 if(likely(process
!= NULL
)) {
3004 /* We could not know but it was not the idle process executing.
3005 This should only happen at the beginning, before the first schedule
3006 event, and when the initial information (current process for each CPU)
3007 is missing. It is not obvious how we could, after the fact, compensate
3008 the wrongly attributed statistics. */
3010 //This test only makes sense once the state is known and if there is no
3011 //missing events. We need to silently ignore schedchange coming after a
3012 //process_free, or it causes glitches. (FIXME)
3013 //if(unlikely(process->pid != pid_out)) {
3014 // g_assert(process->pid == 0);
3016 if(process
->pid
== 0
3017 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3019 /* Scheduling out of pid 0 at beginning of the trace :
3020 * we know for sure it is in syscall mode at this point. */
3021 g_assert(process
->execution_stack
->len
== 1);
3022 process
->state
->t
= LTTV_STATE_SYSCALL
;
3023 process
->state
->s
= LTTV_STATE_WAIT
;
3024 process
->state
->change
= s
->parent
.timestamp
;
3025 process
->state
->entry
= s
->parent
.timestamp
;
3028 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
3029 process
->state
->s
= LTTV_STATE_ZOMBIE
;
3030 process
->state
->change
= s
->parent
.timestamp
;
3032 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
3033 else process
->state
->s
= LTTV_STATE_WAIT
;
3034 process
->state
->change
= s
->parent
.timestamp
;
3037 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
3038 /* see sched.h for states */
3039 if (!exit_process(s
, process
)) {
3040 process
->state
->s
= LTTV_STATE_DEAD
;
3041 process
->state
->change
= s
->parent
.timestamp
;
3046 process
= ts
->running_process
[cpu
] = lttv_state_find_process_or_create(
3047 (LttvTraceState
*)s
->parent
.t_context
,
3049 &s
->parent
.timestamp
);
3050 process
->state
->s
= LTTV_STATE_RUN
;
3052 if(process
->usertrace
)
3053 process
->usertrace
->cpu
= cpu
;
3054 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3055 process
->state
->change
= s
->parent
.timestamp
;
3057 /* update cpu status */
3059 /* going to idle task */
3060 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
3062 /* scheduling a real task.
3063 * we must be careful here:
3064 * if we just schedule()'ed to a process that is
3065 * in a trap, we must put the cpu in trap mode
3067 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
3068 if(process
->state
->t
== LTTV_STATE_TRAP
)
3069 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
3075 static gboolean
process_fork(void *hook_data
, void *call_data
)
3077 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3078 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3079 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3081 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
3082 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
3083 //LttvProcessState *zombie_process;
3085 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3086 LttvProcessState
*process
= ts
->running_process
[cpu
];
3087 LttvProcessState
*child_process
;
3088 struct marker_field
*f
;
3091 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3094 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3095 s
->parent
.target_pid
= child_pid
;
3098 f
= lttv_trace_get_hook_field(th
, 2);
3100 child_tgid
= ltt_event_get_unsigned(e
, f
);
3104 /* Mathieu : it seems like the process might have been scheduled in before the
3105 * fork, and, in a rare case, might be the current process. This might happen
3106 * in a SMP case where we don't have enough precision on the clocks.
3108 * Test reenabled after precision fixes on time. (Mathieu) */
3110 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3112 if(unlikely(zombie_process
!= NULL
)) {
3113 /* Reutilisation of PID. Only now we are sure that the old PID
3114 * has been released. FIXME : should know when release_task happens instead.
3116 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3118 for(i
=0; i
< num_cpus
; i
++) {
3119 g_assert(zombie_process
!= ts
->running_process
[i
]);
3122 exit_process(s
, zombie_process
);
3125 g_assert(process
->pid
!= child_pid
);
3126 // FIXME : Add this test in the "known state" section
3127 // g_assert(process->pid == parent_pid);
3128 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
3129 if(child_process
== NULL
) {
3130 child_process
= lttv_state_create_process(ts
, process
, cpu
,
3131 child_pid
, child_tgid
,
3132 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
3134 /* The process has already been created : due to time imprecision between
3135 * multiple CPUs : it has been scheduled in before creation. Note that we
3136 * shouldn't have this kind of imprecision.
3138 * Simply put a correct parent.
3140 g_error("Process %u has been created at [%lu.%09lu] "
3141 "and inserted at [%lu.%09lu] before \n"
3142 "fork on cpu %u[%lu.%09lu].\n"
3143 "Probably an unsynchronized TSC problem on the traced machine.",
3145 child_process
->creation_time
.tv_sec
,
3146 child_process
->creation_time
.tv_nsec
,
3147 child_process
->insertion_time
.tv_sec
,
3148 child_process
->insertion_time
.tv_nsec
,
3149 cpu
, ltt_event_time(e
).tv_sec
, ltt_event_time(e
).tv_nsec
);
3150 //g_assert(0); /* This is a problematic case : the process has been created
3151 // before the fork event */
3152 child_process
->ppid
= process
->pid
;
3153 child_process
->tgid
= child_tgid
;
3155 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
3156 child_process
->name
= process
->name
;
3157 child_process
->brand
= process
->brand
;
3162 /* We stamp a newly created process as kernel_thread.
3163 * The thread should not be running yet. */
3164 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
3166 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3167 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3168 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3170 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3171 LttvProcessState
*process
;
3172 LttvExecutionState
*es
;
3175 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3176 s
->parent
.target_pid
= pid
;
3178 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
3180 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
3181 process
->execution_stack
=
3182 g_array_set_size(process
->execution_stack
, 1);
3183 es
= process
->state
=
3184 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3185 es
->t
= LTTV_STATE_SYSCALL
;
3187 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3192 static gboolean
process_exit(void *hook_data
, void *call_data
)
3194 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3195 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3196 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3198 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3199 LttvProcessState
*process
; // = ts->running_process[cpu];
3201 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3202 s
->parent
.target_pid
= pid
;
3204 // FIXME : Add this test in the "known state" section
3205 // g_assert(process->pid == pid);
3207 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3208 if(likely(process
!= NULL
)) {
3209 process
->state
->s
= LTTV_STATE_EXIT
;
3214 static gboolean
process_free(void *hook_data
, void *call_data
)
3216 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3217 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3218 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3219 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3221 LttvProcessState
*process
;
3223 /* PID of the process to release */
3224 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3225 s
->parent
.target_pid
= release_pid
;
3227 g_assert(release_pid
!= 0);
3229 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
3230 if(likely(process
!= NULL
))
3231 exit_process(s
, process
);
3234 if(likely(process
!= NULL
)) {
3235 /* release_task is happening at kernel level : we can now safely release
3236 * the data structure of the process */
3237 //This test is fun, though, as it may happen that
3238 //at time t : CPU 0 : process_free
3239 //at time t+150ns : CPU 1 : schedule out
3240 //Clearly due to time imprecision, we disable it. (Mathieu)
3241 //If this weird case happen, we have no choice but to put the
3242 //Currently running process on the cpu to 0.
3243 //I re-enable it following time precision fixes. (Mathieu)
3244 //Well, in the case where an process is freed by a process on another CPU
3245 //and still scheduled, it happens that this is the schedchange that will
3246 //drop the last reference count. Do not free it here!
3247 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3249 for(i
=0; i
< num_cpus
; i
++) {
3250 //g_assert(process != ts->running_process[i]);
3251 if(process
== ts
->running_process
[i
]) {
3252 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3256 if(i
== num_cpus
) /* process is not scheduled */
3257 exit_process(s
, process
);
3264 static gboolean
process_exec(void *hook_data
, void *call_data
)
3266 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3267 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3268 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3269 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3272 LttvProcessState
*process
= ts
->running_process
[cpu
];
3274 #if 0//how to use a sequence that must be transformed in a string
3275 /* PID of the process to release */
3276 guint64 name_len
= ltt_event_field_element_number(e
,
3277 lttv_trace_get_hook_field(th
, 0));
3278 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3279 LttField
*child
= ltt_event_field_element_select(e
,
3280 lttv_trace_get_hook_field(th
, 0), 0);
3282 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3283 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3284 memcpy(null_term_name
, name_begin
, name_len
);
3285 null_term_name
[name_len
] = '\0';
3286 process
->name
= g_quark_from_string(null_term_name
);
3289 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3290 lttv_trace_get_hook_field(th
, 0)));
3291 process
->brand
= LTTV_STATE_UNBRANDED
;
3292 //g_free(null_term_name);
3296 static gboolean
thread_brand(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
;
3304 LttvProcessState
*process
= ts
->running_process
[cpu
];
3306 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3307 process
->brand
= g_quark_from_string(name
);
3312 static gboolean
fs_open(void *hook_data
, void *call_data
)
3314 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3315 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3316 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3317 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3318 struct marker_field
*f
;
3322 LttvProcessState
*process
= ts
->running_process
[cpu
];
3324 f
= lttv_trace_get_hook_field(th
, 0);
3325 fd
= ltt_event_get_int(e
, f
);
3327 f
= lttv_trace_get_hook_field(th
, 1);
3328 filename
= ltt_event_get_string(e
, f
);
3330 g_hash_table_insert(process
->fds
, (gpointer
)(long)fd
,
3331 (gpointer
)(unsigned long)g_quark_from_string(filename
));
3336 static void print_stack(LttvProcessState
*process
)
3338 LttvExecutionState
*es
;
3341 g_debug("Execution stack for process %u %s:\n",
3342 process
->pid
, g_quark_to_string(process
->name
));
3344 for (i
= 0; i
< process
->execution_stack
->len
; i
++) {
3345 es
= &g_array_index(process
->execution_stack
,
3346 LttvExecutionState
, i
);
3347 g_debug("Depth %d mode %s submode %s status %s\n",
3348 i
, g_quark_to_string(es
->t
),
3349 g_quark_to_string(es
->n
),
3350 g_quark_to_string(es
->s
));
3355 static void fix_process(gpointer key
, gpointer value
, gpointer user_data
)
3357 LttvProcessState
*process
;
3358 LttvExecutionState
*es
;
3359 process
= (LttvProcessState
*)value
;
3360 LttTime
*timestamp
= (LttTime
*)user_data
;
3362 print_stack(process
);
3364 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3365 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3366 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3367 es
->t
= LTTV_STATE_SYSCALL
;
3368 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3369 es
->entry
= *timestamp
;
3370 es
->change
= *timestamp
;
3371 es
->cum_cpu_time
= ltt_time_zero
;
3372 if(es
->s
== LTTV_STATE_UNNAMED
)
3373 es
->s
= LTTV_STATE_WAIT
;
3376 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3377 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3378 es
->t
= LTTV_STATE_USER_MODE
;
3379 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3380 es
->entry
= *timestamp
;
3381 //g_assert(timestamp->tv_sec != 0);
3382 es
->change
= *timestamp
;
3383 es
->cum_cpu_time
= ltt_time_zero
;
3384 if(es
->s
== LTTV_STATE_UNNAMED
)
3385 es
->s
= LTTV_STATE_RUN
;
3387 if(process
->execution_stack
->len
== 1) {
3388 /* Still in bottom unknown mode, means we either:
3389 * - never did a system call
3390 * - are scheduled out from user mode.
3391 * May be either in user mode, syscall mode, running or waiting.*/
3392 /* CHECK : we may be tagging syscall mode when being user mode
3393 * (should be fixed now) */
3394 if (es
->s
== LTTV_STATE_WAIT_CPU
) {
3395 /* nothing to do: scheduled out from userspace */
3397 process
->execution_stack
=
3398 g_array_set_size(process
->execution_stack
, 2);
3399 es
= process
->state
= &g_array_index(process
->execution_stack
,
3400 LttvExecutionState
, 1);
3401 es
->t
= LTTV_STATE_SYSCALL
;
3402 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3403 es
->entry
= *timestamp
;
3404 //g_assert(timestamp->tv_sec != 0);
3405 es
->change
= *timestamp
;
3406 es
->cum_cpu_time
= ltt_time_zero
;
3407 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3408 es
->s
= LTTV_STATE_WAIT
;
3415 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3417 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3418 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3419 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3420 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3421 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3423 /* For all processes */
3424 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3425 /* else, if stack[0] is unknown, set to user mode, running */
3427 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3432 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3435 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3436 //It's slow : optimise later by doing this before reading trace.
3437 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3443 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3444 LttvProcessState
*process
= ts
->running_process
[cpu
];
3445 LttvProcessState
*parent_process
;
3446 struct marker_field
*f
;
3447 GQuark type
, mode
, submode
, status
;
3448 LttvExecutionState
*es
;
3452 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3453 s
->parent
.target_pid
= pid
;
3456 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3459 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3462 f
= lttv_trace_get_hook_field(th
, 3);
3463 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3465 //FIXME: type is rarely used, enum must match possible types.
3468 f
= lttv_trace_get_hook_field(th
, 4);
3469 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3472 f
= lttv_trace_get_hook_field(th
, 5);
3473 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3476 f
= lttv_trace_get_hook_field(th
, 6);
3477 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3480 f
= lttv_trace_get_hook_field(th
, 7);
3482 tgid
= ltt_event_get_unsigned(e
, f
);
3487 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3488 for(i
=0; i
<nb_cpus
; i
++) {
3489 process
= lttv_state_find_process(ts
, i
, pid
);
3490 g_assert(process
!= NULL
);
3492 process
->ppid
= parent_pid
;
3493 process
->tgid
= tgid
;
3494 process
->name
= g_quark_from_string(command
);
3495 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3496 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3500 /* The process might exist if a process was forked while performing the
3502 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3503 if(process
== NULL
) {
3504 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3505 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3506 pid
, tgid
, g_quark_from_string(command
),
3507 &s
->parent
.timestamp
);
3509 /* Keep the stack bottom : a running user mode */
3510 /* Disabled because of inconsistencies in the current statedump states. */
3511 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3512 /* Only keep the bottom
3513 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3514 /* Will cause expected trap when in fact being syscall (even after end of
3516 * Will cause expected interrupt when being syscall. (only before end of
3517 * statedump event) */
3518 // This will cause a "popping last state on stack, ignoring it."
3519 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3520 es
= process
->state
= &g_array_index(process
->execution_stack
,
3521 LttvExecutionState
, 0);
3522 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3523 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3524 es
->s
= LTTV_STATE_UNNAMED
;
3525 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3527 es
->t
= LTTV_STATE_SYSCALL
;
3532 /* User space process :
3533 * bottom : user mode
3534 * either currently running or scheduled out.
3535 * can be scheduled out because interrupted in (user mode or in syscall)
3536 * or because of an explicit call to the scheduler in syscall. Note that
3537 * the scheduler call comes after the irq_exit, so never in interrupt
3539 // temp workaround : set size to 1 : only have user mode bottom of stack.
3540 // will cause g_info message of expected syscall mode when in fact being
3541 // in user mode. Can also cause expected trap when in fact being user
3542 // mode in the event of a page fault reenabling interrupts in the handler.
3543 // Expected syscall and trap can also happen after the end of statedump
3544 // This will cause a "popping last state on stack, ignoring it."
3545 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3546 es
= process
->state
= &g_array_index(process
->execution_stack
,
3547 LttvExecutionState
, 0);
3548 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3549 es
->s
= LTTV_STATE_UNNAMED
;
3550 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3552 es
->t
= LTTV_STATE_USER_MODE
;
3560 es
= process
->state
= &g_array_index(process
->execution_stack
,
3561 LttvExecutionState
, 1);
3562 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3563 es
->s
= LTTV_STATE_UNNAMED
;
3564 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3568 /* The process has already been created :
3569 * Probably was forked while dumping the process state or
3570 * was simply scheduled in prior to get the state dump event.
3572 process
->ppid
= parent_pid
;
3573 process
->tgid
= tgid
;
3574 process
->name
= g_quark_from_string(command
);
3575 process
->type
= type
;
3576 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3578 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3579 if(type
== LTTV_STATE_KERNEL_THREAD
)
3580 es
->t
= LTTV_STATE_SYSCALL
;
3582 es
->t
= LTTV_STATE_USER_MODE
;
3585 /* Don't mess around with the stack, it will eventually become
3586 * ok after the end of state dump. */
3593 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3595 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3597 lttv_state_add_event_hooks(tss
);
3602 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3604 LttvTraceset
*traceset
= self
->parent
.ts
;
3606 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3610 LttvTracefileState
*tfs
;
3616 LttvAttributeValue val
;
3618 nb_trace
= lttv_traceset_number(traceset
);
3619 for(i
= 0 ; i
< nb_trace
; i
++) {
3620 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3622 /* Find the eventtype id for the following events and register the
3623 associated by id hooks. */
3625 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 20);
3626 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3629 lttv_trace_find_hook(ts
->parent
.t
,
3631 LTT_EVENT_SYSCALL_ENTRY
,
3632 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3633 syscall_entry
, NULL
, &hooks
);
3635 lttv_trace_find_hook(ts
->parent
.t
,
3637 LTT_EVENT_SYSCALL_EXIT
,
3639 syscall_exit
, NULL
, &hooks
);
3641 lttv_trace_find_hook(ts
->parent
.t
,
3643 LTT_EVENT_TRAP_ENTRY
,
3644 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3645 trap_entry
, NULL
, &hooks
);
3647 lttv_trace_find_hook(ts
->parent
.t
,
3649 LTT_EVENT_TRAP_EXIT
,
3651 trap_exit
, NULL
, &hooks
);
3653 lttv_trace_find_hook(ts
->parent
.t
,
3655 LTT_EVENT_PAGE_FAULT_ENTRY
,
3656 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3657 trap_entry
, NULL
, &hooks
);
3659 lttv_trace_find_hook(ts
->parent
.t
,
3661 LTT_EVENT_PAGE_FAULT_EXIT
,
3663 trap_exit
, NULL
, &hooks
);
3665 lttv_trace_find_hook(ts
->parent
.t
,
3667 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
,
3668 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3669 trap_entry
, NULL
, &hooks
);
3671 lttv_trace_find_hook(ts
->parent
.t
,
3673 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
,
3675 trap_exit
, NULL
, &hooks
);
3677 lttv_trace_find_hook(ts
->parent
.t
,
3679 LTT_EVENT_IRQ_ENTRY
,
3680 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3681 irq_entry
, NULL
, &hooks
);
3683 lttv_trace_find_hook(ts
->parent
.t
,
3687 irq_exit
, NULL
, &hooks
);
3689 lttv_trace_find_hook(ts
->parent
.t
,
3691 LTT_EVENT_SOFT_IRQ_RAISE
,
3692 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3693 soft_irq_raise
, NULL
, &hooks
);
3695 lttv_trace_find_hook(ts
->parent
.t
,
3697 LTT_EVENT_SOFT_IRQ_ENTRY
,
3698 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3699 soft_irq_entry
, NULL
, &hooks
);
3701 lttv_trace_find_hook(ts
->parent
.t
,
3703 LTT_EVENT_SOFT_IRQ_EXIT
,
3705 soft_irq_exit
, NULL
, &hooks
);
3707 lttv_trace_find_hook(ts
->parent
.t
,
3709 LTT_EVENT_SCHED_SCHEDULE
,
3710 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3711 LTT_FIELD_PREV_STATE
),
3712 schedchange
, NULL
, &hooks
);
3714 lttv_trace_find_hook(ts
->parent
.t
,
3716 LTT_EVENT_SCHED_TRY_WAKEUP
,
3717 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_CPU_ID
, LTT_FIELD_STATE
),
3718 sched_try_wakeup
, NULL
, &hooks
);
3720 lttv_trace_find_hook(ts
->parent
.t
,
3722 LTT_EVENT_PROCESS_FORK
,
3723 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3724 LTT_FIELD_CHILD_TGID
),
3725 process_fork
, NULL
, &hooks
);
3727 lttv_trace_find_hook(ts
->parent
.t
,
3729 LTT_EVENT_KTHREAD_CREATE
,
3730 FIELD_ARRAY(LTT_FIELD_PID
),
3731 process_kernel_thread
, NULL
, &hooks
);
3733 lttv_trace_find_hook(ts
->parent
.t
,
3735 LTT_EVENT_PROCESS_EXIT
,
3736 FIELD_ARRAY(LTT_FIELD_PID
),
3737 process_exit
, NULL
, &hooks
);
3739 lttv_trace_find_hook(ts
->parent
.t
,
3741 LTT_EVENT_PROCESS_FREE
,
3742 FIELD_ARRAY(LTT_FIELD_PID
),
3743 process_free
, NULL
, &hooks
);
3745 lttv_trace_find_hook(ts
->parent
.t
,
3748 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3749 process_exec
, NULL
, &hooks
);
3751 lttv_trace_find_hook(ts
->parent
.t
,
3752 LTT_CHANNEL_USERSPACE
,
3753 LTT_EVENT_THREAD_BRAND
,
3754 FIELD_ARRAY(LTT_FIELD_NAME
),
3755 thread_brand
, NULL
, &hooks
);
3757 /* statedump-related hooks */
3758 lttv_trace_find_hook(ts
->parent
.t
,
3759 LTT_CHANNEL_TASK_STATE
,
3760 LTT_EVENT_PROCESS_STATE
,
3761 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3762 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3763 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3764 enum_process_state
, NULL
, &hooks
);
3766 lttv_trace_find_hook(ts
->parent
.t
,
3767 LTT_CHANNEL_GLOBAL_STATE
,
3768 LTT_EVENT_STATEDUMP_END
,
3770 statedump_end
, NULL
, &hooks
);
3772 lttv_trace_find_hook(ts
->parent
.t
,
3773 LTT_CHANNEL_IRQ_STATE
,
3774 LTT_EVENT_LIST_INTERRUPT
,
3775 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3776 enum_interrupt
, NULL
, &hooks
);
3778 lttv_trace_find_hook(ts
->parent
.t
,
3780 LTT_EVENT_REQUEST_ISSUE
,
3781 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3782 bdev_request_issue
, NULL
, &hooks
);
3784 lttv_trace_find_hook(ts
->parent
.t
,
3786 LTT_EVENT_REQUEST_COMPLETE
,
3787 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3788 bdev_request_complete
, NULL
, &hooks
);
3790 lttv_trace_find_hook(ts
->parent
.t
,
3791 LTT_CHANNEL_USERSPACE
,
3792 LTT_EVENT_FUNCTION_ENTRY
,
3793 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3794 function_entry
, NULL
, &hooks
);
3796 lttv_trace_find_hook(ts
->parent
.t
,
3797 LTT_CHANNEL_USERSPACE
,
3798 LTT_EVENT_FUNCTION_EXIT
,
3799 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3800 function_exit
, NULL
, &hooks
);
3802 lttv_trace_find_hook(ts
->parent
.t
,
3803 LTT_CHANNEL_SYSCALL_STATE
,
3804 LTT_EVENT_SYS_CALL_TABLE
,
3805 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3806 dump_syscall
, NULL
, &hooks
);
3808 lttv_trace_find_hook(ts
->parent
.t
,
3809 LTT_CHANNEL_KPROBE_STATE
,
3810 LTT_EVENT_KPROBE_TABLE
,
3811 FIELD_ARRAY(LTT_FIELD_IP
, LTT_FIELD_SYMBOL
),
3812 dump_kprobe
, NULL
, &hooks
);
3814 lttv_trace_find_hook(ts
->parent
.t
,
3815 LTT_CHANNEL_SOFTIRQ_STATE
,
3816 LTT_EVENT_SOFTIRQ_VEC
,
3817 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3818 dump_softirq
, NULL
, &hooks
);
3820 lttv_trace_find_hook(ts
->parent
.t
,
3823 FIELD_ARRAY(LTT_FIELD_FD
, LTT_FIELD_FILENAME
),
3824 fs_open
, NULL
, &hooks
);
3826 /* Add these hooks to each event_by_id hooks list */
3828 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3830 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3832 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3833 LttvTracefileContext
*, j
));
3835 for(k
= 0 ; k
< hooks
->len
; k
++) {
3836 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3837 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3839 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3845 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3846 *(val
.v_pointer
) = hooks
;
3850 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3852 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3854 lttv_state_remove_event_hooks(tss
);
3859 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3861 LttvTraceset
*traceset
= self
->parent
.ts
;
3863 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3867 LttvTracefileState
*tfs
;
3873 LttvAttributeValue val
;
3875 nb_trace
= lttv_traceset_number(traceset
);
3876 for(i
= 0 ; i
< nb_trace
; i
++) {
3877 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3879 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3880 hooks
= *(val
.v_pointer
);
3882 /* Remove these hooks from each event_by_id hooks list */
3884 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3886 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3888 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3889 LttvTracefileContext
*, j
));
3891 for(k
= 0 ; k
< hooks
->len
; k
++) {
3892 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3893 if (th
->mdata
== tfs
->parent
.tf
->mdata
)
3894 lttv_hooks_remove_data(
3895 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3900 lttv_trace_hook_remove_all(&hooks
);
3901 g_array_free(hooks
, TRUE
);
3905 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3907 guint
*event_count
= (guint
*)hook_data
;
3909 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3910 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3915 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3917 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3919 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3921 LttvAttributeValue value
;
3923 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3924 LTTV_STATE_SAVED_STATES
);
3925 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3926 value
= lttv_attribute_add(saved_states_tree
,
3927 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3928 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3929 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3930 *(value
.v_time
) = self
->parent
.timestamp
;
3931 lttv_state_save(tcs
, saved_state_tree
);
3932 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3933 self
->parent
.timestamp
.tv_nsec
);
3935 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3940 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3942 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3944 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3949 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3957 static gboolean
block_start(void *hook_data
, void *call_data
)
3959 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3961 LttvTracefileState
*tfcs
;
3963 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3965 LttEventPosition
*ep
;
3967 guint i
, nb_block
, nb_event
, nb_tracefile
;
3971 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3973 LttvAttributeValue value
;
3975 ep
= ltt_event_position_new();
3977 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3979 /* Count the number of events added since the last block end in any
3982 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3984 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3985 LttvTracefileContext
, i
));
3986 ltt_event_position(tfcs
->parent
.e
, ep
);
3987 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3988 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3989 tfcs
->saved_position
= nb_event
;
3993 if(tcs
->nb_event
>= tcs
->save_interval
) {
3994 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3995 LTTV_STATE_SAVED_STATES
);
3996 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3997 value
= lttv_attribute_add(saved_states_tree
,
3998 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3999 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
4000 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
4001 *(value
.v_time
) = self
->parent
.timestamp
;
4002 lttv_state_save(tcs
, saved_state_tree
);
4004 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
4005 self
->parent
.timestamp
.tv_nsec
);
4007 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4013 static gboolean
block_end(void *hook_data
, void *call_data
)
4015 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
4017 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
4021 LttEventPosition
*ep
;
4023 guint nb_block
, nb_event
;
4025 ep
= ltt_event_position_new();
4026 ltt_event_position(self
->parent
.e
, ep
);
4027 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
4028 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
4029 self
->saved_position
= 0;
4030 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
4037 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4039 LttvTraceset
*traceset
= self
->parent
.ts
;
4041 guint i
, j
, nb_trace
, nb_tracefile
;
4045 LttvTracefileState
*tfs
;
4047 LttvTraceHook hook_start
, hook_end
;
4049 nb_trace
= lttv_traceset_number(traceset
);
4050 for(i
= 0 ; i
< nb_trace
; i
++) {
4051 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4053 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4054 NULL
, NULL
, block_start
, &hook_start
);
4055 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4056 NULL
, NULL
, block_end
, &hook_end
);
4058 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4060 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4062 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4063 LttvTracefileContext
, j
));
4064 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4065 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
4066 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
4067 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
4073 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
4075 LttvTraceset
*traceset
= self
->parent
.ts
;
4077 guint i
, j
, nb_trace
, nb_tracefile
;
4081 LttvTracefileState
*tfs
;
4084 nb_trace
= lttv_traceset_number(traceset
);
4085 for(i
= 0 ; i
< nb_trace
; i
++) {
4087 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4088 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4090 if(ts
->has_precomputed_states
) continue;
4092 guint
*event_count
= g_new(guint
, 1);
4095 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4097 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4098 LttvTracefileContext
*, j
));
4099 lttv_hooks_add(tfs
->parent
.event
,
4100 state_save_event_hook
,
4107 lttv_process_traceset_begin(&self
->parent
,
4108 NULL
, NULL
, NULL
, NULL
, NULL
);
4112 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
4114 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4116 lttv_state_save_add_event_hooks(tss
);
4123 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4125 LttvTraceset
*traceset
= self
->parent
.ts
;
4127 guint i
, j
, nb_trace
, nb_tracefile
;
4131 LttvTracefileState
*tfs
;
4133 LttvTraceHook hook_start
, hook_end
;
4135 nb_trace
= lttv_traceset_number(traceset
);
4136 for(i
= 0 ; i
< nb_trace
; i
++) {
4137 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
4139 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
4140 NULL
, NULL
, block_start
, &hook_start
);
4142 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
4143 NULL
, NULL
, block_end
, &hook_end
);
4145 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4147 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4149 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
4150 LttvTracefileContext
, j
));
4151 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4152 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
4153 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4154 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
4160 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
4162 LttvTraceset
*traceset
= self
->parent
.ts
;
4164 guint i
, j
, nb_trace
, nb_tracefile
;
4168 LttvTracefileState
*tfs
;
4170 LttvHooks
*after_trace
= lttv_hooks_new();
4172 lttv_hooks_add(after_trace
,
4173 state_save_after_trace_hook
,
4178 lttv_process_traceset_end(&self
->parent
,
4179 NULL
, after_trace
, NULL
, NULL
, NULL
);
4181 lttv_hooks_destroy(after_trace
);
4183 nb_trace
= lttv_traceset_number(traceset
);
4184 for(i
= 0 ; i
< nb_trace
; i
++) {
4186 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
4187 nb_tracefile
= ts
->parent
.tracefiles
->len
;
4189 if(ts
->has_precomputed_states
) continue;
4191 guint
*event_count
= NULL
;
4193 for(j
= 0 ; j
< nb_tracefile
; j
++) {
4195 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
4196 LttvTracefileContext
*, j
));
4197 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
4198 state_save_event_hook
);
4200 if(event_count
) g_free(event_count
);
4204 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
4206 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
4208 lttv_state_save_remove_event_hooks(tss
);
4213 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
4215 LttvTraceset
*traceset
= self
->parent
.ts
;
4219 int min_pos
, mid_pos
, max_pos
;
4221 guint call_rest
= 0;
4223 LttvTraceState
*tcs
;
4225 LttvAttributeValue value
;
4227 LttvAttributeType type
;
4229 LttvAttributeName name
;
4233 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
= NULL
;
4235 //g_tree_destroy(self->parent.pqueue);
4236 //self->parent.pqueue = g_tree_new(compare_tracefile);
4238 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
4240 nb_trace
= lttv_traceset_number(traceset
);
4241 for(i
= 0 ; i
< nb_trace
; i
++) {
4242 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
4244 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
4245 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
4246 LTTV_STATE_SAVED_STATES
);
4249 if(saved_states_tree
) {
4250 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
4251 mid_pos
= max_pos
/ 2;
4252 while(min_pos
< max_pos
) {
4253 type
= lttv_attribute_get(saved_states_tree
, mid_pos
,
4254 &name
, &value
, &is_named
);
4255 g_assert(type
== LTTV_GOBJECT
);
4256 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
4257 type
= lttv_attribute_get_by_name(saved_state_tree
,
4258 LTTV_STATE_TIME
, &value
);
4259 g_assert(type
== LTTV_TIME
);
4260 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
4262 closest_tree
= saved_state_tree
;
4264 else max_pos
= mid_pos
- 1;
4266 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
4270 /* restore the closest earlier saved state */
4272 lttv_state_restore(tcs
, closest_tree
);
4276 /* There is no saved state, yet we want to have it. Restart at T0 */
4278 restore_init_state(tcs
);
4279 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
4282 /* We want to seek quickly without restoring/updating the state */
4284 restore_init_state(tcs
);
4285 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
4288 if(!call_rest
) g_info("NOT Calling restore");
4292 static void traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4297 static void traceset_state_finalize (LttvTracesetState
*self
)
4299 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
4300 finalize(G_OBJECT(self
));
4304 static void traceset_state_class_init (LttvTracesetContextClass
*klass
)
4306 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4308 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
4309 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
4310 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
4311 klass
->new_traceset_context
= new_traceset_context
;
4312 klass
->new_trace_context
= new_trace_context
;
4313 klass
->new_tracefile_context
= new_tracefile_context
;
4317 GType
lttv_traceset_state_get_type(void)
4319 static GType type
= 0;
4321 static const GTypeInfo info
= {
4322 sizeof (LttvTracesetStateClass
),
4323 NULL
, /* base_init */
4324 NULL
, /* base_finalize */
4325 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
4326 NULL
, /* class_finalize */
4327 NULL
, /* class_data */
4328 sizeof (LttvTracesetState
),
4329 0, /* n_preallocs */
4330 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
4331 NULL
/* value handling */
4334 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4341 static void trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4346 static void trace_state_finalize (LttvTraceState
*self
)
4348 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4349 finalize(G_OBJECT(self
));
4353 static void trace_state_class_init (LttvTraceStateClass
*klass
)
4355 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4357 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4358 klass
->state_save
= state_save
;
4359 klass
->state_restore
= state_restore
;
4360 klass
->state_saved_free
= state_saved_free
;
4364 GType
lttv_trace_state_get_type(void)
4366 static GType type
= 0;
4368 static const GTypeInfo info
= {
4369 sizeof (LttvTraceStateClass
),
4370 NULL
, /* base_init */
4371 NULL
, /* base_finalize */
4372 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4373 NULL
, /* class_finalize */
4374 NULL
, /* class_data */
4375 sizeof (LttvTraceState
),
4376 0, /* n_preallocs */
4377 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4378 NULL
/* value handling */
4381 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4382 "LttvTraceStateType", &info
, 0);
4388 static void tracefile_state_instance_init (GTypeInstance
*instance
,
4394 static void tracefile_state_finalize (LttvTracefileState
*self
)
4396 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4397 finalize(G_OBJECT(self
));
4401 static void tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4403 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4405 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4409 GType
lttv_tracefile_state_get_type(void)
4411 static GType type
= 0;
4413 static const GTypeInfo info
= {
4414 sizeof (LttvTracefileStateClass
),
4415 NULL
, /* base_init */
4416 NULL
, /* base_finalize */
4417 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4418 NULL
, /* class_finalize */
4419 NULL
, /* class_data */
4420 sizeof (LttvTracefileState
),
4421 0, /* n_preallocs */
4422 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4423 NULL
/* value handling */
4426 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4427 "LttvTracefileStateType", &info
, 0);
4433 static void module_init()
4435 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4436 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4437 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4438 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4439 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4440 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4441 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4442 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4443 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4444 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4445 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4446 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4447 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4448 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4449 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4450 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4451 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4452 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4453 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4454 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4455 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4456 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4457 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4458 LTTV_STATE_EVENT
= g_quark_from_string("event");
4459 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4460 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4461 LTTV_STATE_TIME
= g_quark_from_string("time");
4462 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4463 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4464 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4465 g_quark_from_string("trace_state_use_count");
4466 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4467 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4468 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4469 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4470 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4471 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4473 LTT_CHANNEL_FD_STATE
= g_quark_from_string("fd_state");
4474 LTT_CHANNEL_GLOBAL_STATE
= g_quark_from_string("global_state");
4475 LTT_CHANNEL_IRQ_STATE
= g_quark_from_string("irq_state");
4476 LTT_CHANNEL_MODULE_STATE
= g_quark_from_string("module_state");
4477 LTT_CHANNEL_NETIF_STATE
= g_quark_from_string("netif_state");
4478 LTT_CHANNEL_SOFTIRQ_STATE
= g_quark_from_string("softirq_state");
4479 LTT_CHANNEL_SWAP_STATE
= g_quark_from_string("swap_state");
4480 LTT_CHANNEL_SYSCALL_STATE
= g_quark_from_string("syscall_state");
4481 LTT_CHANNEL_TASK_STATE
= g_quark_from_string("task_state");
4482 LTT_CHANNEL_VM_STATE
= g_quark_from_string("vm_state");
4483 LTT_CHANNEL_KPROBE_STATE
= g_quark_from_string("kprobe_state");
4484 LTT_CHANNEL_FS
= g_quark_from_string("fs");
4485 LTT_CHANNEL_KERNEL
= g_quark_from_string("kernel");
4486 LTT_CHANNEL_MM
= g_quark_from_string("mm");
4487 LTT_CHANNEL_USERSPACE
= g_quark_from_string("userspace");
4488 LTT_CHANNEL_BLOCK
= g_quark_from_string("block");
4490 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4491 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4492 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4493 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4494 LTT_EVENT_PAGE_FAULT_ENTRY
= g_quark_from_string("page_fault_entry");
4495 LTT_EVENT_PAGE_FAULT_EXIT
= g_quark_from_string("page_fault_exit");
4496 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
= g_quark_from_string("page_fault_nosem_entry");
4497 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
= g_quark_from_string("page_fault_nosem_exit");
4498 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4499 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4500 LTT_EVENT_SOFT_IRQ_RAISE
= g_quark_from_string("softirq_raise");
4501 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4502 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4503 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4504 LTT_EVENT_SCHED_TRY_WAKEUP
= g_quark_from_string("sched_try_wakeup");
4505 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4506 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4507 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4508 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4509 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4510 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4511 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4512 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4513 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4514 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4515 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4516 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4517 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4518 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4519 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4520 LTT_EVENT_KPROBE_TABLE
= g_quark_from_string("kprobe_table");
4521 LTT_EVENT_KPROBE
= g_quark_from_string("kprobe");
4522 LTT_EVENT_OPEN
= g_quark_from_string("open");
4523 LTT_EVENT_READ
= g_quark_from_string("read");
4524 LTT_EVENT_POLL_EVENT
= g_quark_from_string("poll_event");
4526 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4527 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4528 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4529 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4530 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4531 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4532 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4533 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4534 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4535 LTT_FIELD_PID
= g_quark_from_string("pid");
4536 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4537 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4538 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4539 LTT_FIELD_NAME
= g_quark_from_string("name");
4540 LTT_FIELD_TYPE
= g_quark_from_string("type");
4541 LTT_FIELD_MODE
= g_quark_from_string("mode");
4542 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4543 LTT_FIELD_STATUS
= g_quark_from_string("status");
4544 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4545 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4546 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4547 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4548 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4549 LTT_FIELD_ACTION
= g_quark_from_string("action");
4550 LTT_FIELD_ID
= g_quark_from_string("id");
4551 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4552 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4553 LTT_FIELD_IP
= g_quark_from_string("ip");
4554 LTT_FIELD_FD
= g_quark_from_string("fd");
4555 LTT_FIELD_STATE
= g_quark_from_string("state");
4556 LTT_FIELD_CPU_ID
= g_quark_from_string("cpu_id");
4558 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4559 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4560 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4561 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4562 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4563 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4565 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4566 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4567 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4569 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4570 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4571 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4572 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4575 static void module_destroy()
4580 LTTV_MODULE("state", "State computation", \
4581 "Update the system state, possibly saving it at intervals", \
4582 module_init
, module_destroy
)