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>
38 * usertrace is there only to be able to update the current CPU of the
39 * usertraces when there is a schedchange. it is a way to link the ProcessState
40 * to the associated usertrace. Link only created upon thread creation.
42 * The cpu id is necessary : it gives us back the current ProcessState when we
43 * are considering data from the usertrace.
46 #define PREALLOCATED_EXECUTION_STACK 10
48 /* Facilities Quarks */
52 LTT_FACILITY_KERNEL_ARCH
,
55 LTT_FACILITY_USER_GENERIC
,
57 LTT_FACILITY_STATEDUMP
;
62 LTT_EVENT_SYSCALL_ENTRY
,
63 LTT_EVENT_SYSCALL_EXIT
,
68 LTT_EVENT_SOFT_IRQ_ENTRY
,
69 LTT_EVENT_SOFT_IRQ_EXIT
,
70 LTT_EVENT_SCHED_SCHEDULE
,
71 LTT_EVENT_PROCESS_FORK
,
72 LTT_EVENT_KTHREAD_CREATE
,
73 LTT_EVENT_PROCESS_EXIT
,
74 LTT_EVENT_PROCESS_FREE
,
76 LTT_EVENT_PROCESS_STATE
,
77 LTT_EVENT_STATEDUMP_END
,
78 LTT_EVENT_FUNCTION_ENTRY
,
79 LTT_EVENT_FUNCTION_EXIT
,
80 LTT_EVENT_THREAD_BRAND
,
81 LTT_EVENT_REQUEST_ISSUE
,
82 LTT_EVENT_REQUEST_COMPLETE
,
83 LTT_EVENT_LIST_INTERRUPT
,
84 LTT_EVENT_SYS_CALL_TABLE
,
85 LTT_EVENT_SOFTIRQ_VEC
;
93 LTT_FIELD_SOFT_IRQ_ID
,
101 LTT_FIELD_CHILD_TGID
,
119 LTTV_STATE_MODE_UNKNOWN
,
120 LTTV_STATE_USER_MODE
,
127 LTTV_STATE_SUBMODE_UNKNOWN
,
128 LTTV_STATE_SUBMODE_NONE
;
132 LTTV_STATE_WAIT_FORK
,
141 LTTV_STATE_UNBRANDED
;
144 LTTV_STATE_USER_THREAD
,
145 LTTV_STATE_KERNEL_THREAD
;
163 LTTV_BDEV_BUSY_READING
,
164 LTTV_BDEV_BUSY_WRITING
;
167 LTTV_STATE_TRACEFILES
,
168 LTTV_STATE_PROCESSES
,
170 LTTV_STATE_RUNNING_PROCESS
,
172 LTTV_STATE_SAVED_STATES
,
173 LTTV_STATE_SAVED_STATES_TIME
,
176 LTTV_STATE_NAME_TABLES
,
177 LTTV_STATE_TRACE_STATE_USE_COUNT
,
178 LTTV_STATE_RESOURCE_CPUS
,
179 LTTV_STATE_RESOURCE_CPUS_COUNT
,
180 LTTV_STATE_RESOURCE_IRQS
,
181 LTTV_STATE_RESOURCE_SOFT_IRQS
,
182 LTTV_STATE_RESOURCE_TRAPS
,
183 LTTV_STATE_RESOURCE_BLKDEVS
;
185 static void create_max_time(LttvTraceState
*tcs
);
187 static void get_max_time(LttvTraceState
*tcs
);
189 static void free_max_time(LttvTraceState
*tcs
);
191 static void create_name_tables(LttvTraceState
*tcs
);
193 static void get_name_tables(LttvTraceState
*tcs
);
195 static void free_name_tables(LttvTraceState
*tcs
);
197 static void free_saved_state(LttvTraceState
*tcs
);
199 static void lttv_state_free_process_table(GHashTable
*processes
);
201 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
202 GPtrArray
*quarktable
);
204 /* Resource function prototypes */
205 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
206 static LttvBdevState
*bdevstate_new(void);
207 static void bdevstate_free(LttvBdevState
*);
208 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
209 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
212 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
214 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
218 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
220 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
224 void lttv_state_state_saved_free(LttvTraceState
*self
,
225 LttvAttribute
*container
)
227 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
231 guint
process_hash(gconstpointer key
)
233 guint pid
= ((const LttvProcessState
*)key
)->pid
;
234 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
238 /* If the hash table hash function is well distributed,
239 * the process_equal should compare different pid */
240 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
242 const LttvProcessState
*process_a
, *process_b
;
245 process_a
= (const LttvProcessState
*)a
;
246 process_b
= (const LttvProcessState
*)b
;
248 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
249 else if(likely(process_a
->pid
== 0 &&
250 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
255 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
257 g_tree_destroy((GTree
*)value
);
260 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
262 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
263 g_hash_table_destroy(usertraces
);
266 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
272 restore_init_state(LttvTraceState
*self
)
274 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
276 //LttvTracefileState *tfcs;
278 LttTime start_time
, end_time
;
280 /* Free the process tables */
281 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
282 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
283 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
284 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
287 /* Seek time to beginning */
288 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
289 // closest. It's the tracecontext job to seek the trace to the beginning
290 // anyway : the init state might be used at the middle of the trace as well...
291 //g_tree_destroy(self->parent.ts_context->pqueue);
292 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
294 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
296 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
298 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
299 nb_irqs
= self
->nb_irqs
;
300 nb_soft_irqs
= self
->nb_soft_irqs
;
301 nb_traps
= self
->nb_traps
;
303 /* Put the per cpu running_process to beginning state : process 0. */
304 for(i
=0; i
< nb_cpus
; i
++) {
305 LttvExecutionState
*es
;
306 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
307 LTTV_STATE_UNNAMED
, &start_time
);
308 /* We are not sure is it's a kernel thread or normal thread, put the
309 * bottom stack state to unknown */
310 self
->running_process
[i
]->execution_stack
=
311 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
312 es
= self
->running_process
[i
]->state
=
313 &g_array_index(self
->running_process
[i
]->execution_stack
,
314 LttvExecutionState
, 0);
315 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
316 es
->s
= LTTV_STATE_UNNAMED
;
318 //self->running_process[i]->state->s = LTTV_STATE_RUN;
319 self
->running_process
[i
]->cpu
= i
;
321 /* reset cpu states */
322 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
323 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
326 /* reset irq states */
327 for(i
=0; i
<nb_irqs
; i
++) {
328 if(self
->irq_states
[i
].mode_stack
->len
> 0)
329 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
332 /* reset softirq states */
333 for(i
=0; i
<nb_soft_irqs
; i
++) {
334 self
->soft_irq_states
[i
].running
= 0;
337 /* reset trap states */
338 for(i
=0; i
<nb_traps
; i
++) {
339 self
->trap_states
[i
].running
= 0;
342 /* reset bdev states */
343 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
344 //g_hash_table_steal_all(self->bdev_states);
345 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
348 nb_tracefile
= self
->parent
.tracefiles
->len
;
350 for(i
= 0 ; i
< nb_tracefile
; i
++) {
352 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
353 LttvTracefileContext
*, i
));
354 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
355 // tfcs->saved_position = 0;
356 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
357 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
358 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
359 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
364 //static LttTime time_zero = {0,0};
366 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
369 const LttTime
*t1
= (const LttTime
*)a
;
370 const LttTime
*t2
= (const LttTime
*)b
;
372 return ltt_time_compare(*t1
, *t2
);
375 static void free_usertrace_key(gpointer data
)
380 #define MAX_STRING_LEN 4096
383 state_load_saved_states(LttvTraceState
*tcs
)
386 GPtrArray
*quarktable
;
387 const char *trace_path
;
391 tcs
->has_precomputed_states
= FALSE
;
395 gchar buf
[MAX_STRING_LEN
];
398 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
399 strncpy(path
, trace_path
, PATH_MAX
-1);
400 count
= strnlen(trace_path
, PATH_MAX
-1);
401 // quarktable : open, test
402 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
403 fp
= fopen(path
, "r");
405 quarktable
= g_ptr_array_sized_new(4096);
407 /* Index 0 is null */
409 if(hdr
== EOF
) return;
410 g_assert(hdr
== HDR_QUARKS
);
414 if(hdr
== EOF
) break;
415 g_assert(hdr
== HDR_QUARK
);
416 g_ptr_array_set_size(quarktable
, q
+1);
419 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
420 if(buf
[i
] == '\0' || feof(fp
)) break;
423 len
= strnlen(buf
, MAX_STRING_LEN
-1);
424 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
425 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
431 // saved_states : open, test
432 strncpy(path
, trace_path
, PATH_MAX
-1);
433 count
= strnlen(trace_path
, PATH_MAX
-1);
434 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
435 fp
= fopen(path
, "r");
439 if(hdr
!= HDR_TRACE
) goto end
;
441 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
443 tcs
->has_precomputed_states
= TRUE
;
448 /* Free the quarktable */
449 for(i
=0; i
<quarktable
->len
; i
++) {
450 string
= g_ptr_array_index (quarktable
, i
);
453 g_ptr_array_free(quarktable
, TRUE
);
458 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
460 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
463 LttvTraceContext
*tc
;
467 LttvTracefileState
*tfcs
;
469 LttvAttributeValue v
;
471 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
472 init((LttvTracesetContext
*)self
, ts
);
474 nb_trace
= lttv_traceset_number(ts
);
475 for(i
= 0 ; i
< nb_trace
; i
++) {
476 tc
= self
->parent
.traces
[i
];
477 tcs
= LTTV_TRACE_STATE(tc
);
478 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
479 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
483 if(*(v
.v_uint
) == 1) {
484 create_name_tables(tcs
);
485 create_max_time(tcs
);
487 get_name_tables(tcs
);
490 nb_tracefile
= tc
->tracefiles
->len
;
491 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
492 nb_irq
= tcs
->nb_irqs
;
493 tcs
->processes
= NULL
;
494 tcs
->usertraces
= NULL
;
495 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
497 /* init cpu resource stuff */
498 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
499 for(j
= 0; j
<nb_cpu
; j
++) {
500 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
501 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
504 /* init irq resource stuff */
505 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
506 for(j
= 0; j
<nb_irq
; j
++) {
507 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
508 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
511 /* init soft irq stuff */
512 /* the kernel has a statically fixed max of 32 softirqs */
513 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
515 /* init trap stuff */
516 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
518 /* init bdev resource stuff */
519 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
521 restore_init_state(tcs
);
522 for(j
= 0 ; j
< nb_tracefile
; j
++) {
524 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
525 LttvTracefileContext
*, j
));
526 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
527 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
528 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
529 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
530 /* It's a Usertrace */
531 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
532 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
534 if(!usertrace_tree
) {
535 usertrace_tree
= g_tree_new_full(compare_usertraces
,
536 NULL
, free_usertrace_key
, NULL
);
537 g_hash_table_insert(tcs
->usertraces
,
538 (gpointer
)tid
, usertrace_tree
);
540 LttTime
*timestamp
= g_new(LttTime
, 1);
541 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
542 ltt_tracefile_creation(tfcs
->parent
.tf
));
543 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
547 /* See if the trace has saved states */
548 state_load_saved_states(tcs
);
553 fini(LttvTracesetState
*self
)
559 //LttvTracefileState *tfcs;
561 LttvAttributeValue v
;
563 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
564 for(i
= 0 ; i
< nb_trace
; i
++) {
565 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
566 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
569 g_assert(*(v
.v_uint
) != 0);
572 if(*(v
.v_uint
) == 0) {
573 free_name_tables(tcs
);
575 free_saved_state(tcs
);
577 g_free(tcs
->running_process
);
578 tcs
->running_process
= NULL
;
579 lttv_state_free_process_table(tcs
->processes
);
580 lttv_state_free_usertraces(tcs
->usertraces
);
581 tcs
->processes
= NULL
;
582 tcs
->usertraces
= NULL
;
584 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
585 fini((LttvTracesetContext
*)self
);
589 static LttvTracesetContext
*
590 new_traceset_context(LttvTracesetContext
*self
)
592 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
596 static LttvTraceContext
*
597 new_trace_context(LttvTracesetContext
*self
)
599 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
603 static LttvTracefileContext
*
604 new_tracefile_context(LttvTracesetContext
*self
)
606 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
610 /* Write the process state of the trace */
612 static void write_process_state(gpointer key
, gpointer value
,
615 LttvProcessState
*process
;
617 LttvExecutionState
*es
;
619 FILE *fp
= (FILE *)user_data
;
624 process
= (LttvProcessState
*)value
;
626 " <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",
627 process
, process
->pid
, process
->tgid
, process
->ppid
,
628 g_quark_to_string(process
->type
),
629 process
->creation_time
.tv_sec
,
630 process
->creation_time
.tv_nsec
,
631 process
->insertion_time
.tv_sec
,
632 process
->insertion_time
.tv_nsec
,
633 g_quark_to_string(process
->name
),
634 g_quark_to_string(process
->brand
),
635 process
->cpu
, process
->free_events
);
637 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
638 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
639 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
640 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
641 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
642 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
643 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
646 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
647 address
= g_array_index(process
->user_stack
, guint64
, i
);
648 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
652 if(process
->usertrace
) {
653 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
654 g_quark_to_string(process
->usertrace
->tracefile_name
),
655 process
->usertrace
->cpu
);
659 fprintf(fp
, " </PROCESS>\n");
663 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
665 guint i
, nb_tracefile
, nb_block
, offset
;
668 LttvTracefileState
*tfcs
;
672 LttEventPosition
*ep
;
676 ep
= ltt_event_position_new();
678 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
680 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
682 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
683 for(i
=0;i
<nb_cpus
;i
++) {
684 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
685 i
, self
->running_process
[i
]->pid
);
688 nb_tracefile
= self
->parent
.tracefiles
->len
;
690 for(i
= 0 ; i
< nb_tracefile
; i
++) {
692 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
693 LttvTracefileContext
*, i
));
694 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
695 tfcs
->parent
.timestamp
.tv_sec
,
696 tfcs
->parent
.timestamp
.tv_nsec
);
697 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
698 if(e
== NULL
) fprintf(fp
,"/>\n");
700 ltt_event_position(e
, ep
);
701 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
702 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
707 fprintf(fp
,"</PROCESS_STATE>\n");
711 static void write_process_state_raw(gpointer key
, gpointer value
,
714 LttvProcessState
*process
;
716 LttvExecutionState
*es
;
718 FILE *fp
= (FILE *)user_data
;
723 process
= (LttvProcessState
*)value
;
724 fputc(HDR_PROCESS
, fp
);
725 //fwrite(&header, sizeof(header), 1, fp);
726 //fprintf(fp, "%s", g_quark_to_string(process->type));
728 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
729 //fprintf(fp, "%s", g_quark_to_string(process->name));
731 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
732 //fprintf(fp, "%s", g_quark_to_string(process->brand));
734 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
735 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
736 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
737 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
738 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
739 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
740 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
741 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
745 " <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",
746 process
, process
->pid
, process
->tgid
, process
->ppid
,
747 g_quark_to_string(process
->type
),
748 process
->creation_time
.tv_sec
,
749 process
->creation_time
.tv_nsec
,
750 process
->insertion_time
.tv_sec
,
751 process
->insertion_time
.tv_nsec
,
752 g_quark_to_string(process
->name
),
753 g_quark_to_string(process
->brand
),
757 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
758 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
761 //fprintf(fp, "%s", g_quark_to_string(es->t));
763 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
764 //fprintf(fp, "%s", g_quark_to_string(es->n));
766 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
767 //fprintf(fp, "%s", g_quark_to_string(es->s));
769 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
770 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
771 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
772 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
774 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
775 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
776 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
777 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
778 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
782 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
783 address
= g_array_index(process
->user_stack
, guint64
, i
);
784 fputc(HDR_USER_STACK
, fp
);
785 fwrite(&address
, sizeof(address
), 1, fp
);
787 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
792 if(process
->usertrace
) {
793 fputc(HDR_USERTRACE
, fp
);
794 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
796 fwrite(&process
->usertrace
->tracefile_name
,
797 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
798 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
800 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
801 g_quark_to_string(process
->usertrace
->tracefile_name
),
802 process
->usertrace
->cpu
);
809 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
811 guint i
, nb_tracefile
, nb_block
, offset
;
814 LttvTracefileState
*tfcs
;
818 LttEventPosition
*ep
;
822 ep
= ltt_event_position_new();
824 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
825 fputc(HDR_PROCESS_STATE
, fp
);
826 fwrite(&t
, sizeof(t
), 1, fp
);
828 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
830 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
831 for(i
=0;i
<nb_cpus
;i
++) {
833 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
834 fwrite(&self
->running_process
[i
]->pid
,
835 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
836 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
837 // i, self->running_process[i]->pid);
840 nb_tracefile
= self
->parent
.tracefiles
->len
;
842 for(i
= 0 ; i
< nb_tracefile
; i
++) {
844 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
845 LttvTracefileContext
*, i
));
846 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
847 // tfcs->parent.timestamp.tv_sec,
848 // tfcs->parent.timestamp.tv_nsec);
849 fputc(HDR_TRACEFILE
, fp
);
850 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
851 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
852 * position following : end of trace */
853 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
855 ltt_event_position(e
, ep
);
856 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
857 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
859 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
860 fwrite(&offset
, sizeof(offset
), 1, fp
);
861 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
868 /* Read process state from a file */
870 /* Called because a HDR_PROCESS was found */
871 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
872 GPtrArray
*quarktable
)
874 LttvExecutionState
*es
;
875 LttvProcessState
*process
, *parent_process
;
876 LttvProcessState tmp
;
881 /* TODO : check return value */
882 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
883 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
884 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
885 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
886 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
887 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
888 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
889 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
890 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
891 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
894 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
896 /* We must link to the parent */
897 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
899 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
900 if(process
== NULL
) {
901 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
903 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
907 process
->insertion_time
= tmp
.insertion_time
;
908 process
->creation_time
= tmp
.creation_time
;
909 process
->type
= g_quark_from_string(
910 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
911 process
->tgid
= tmp
.tgid
;
912 process
->ppid
= tmp
.ppid
;
913 process
->brand
= g_quark_from_string(
914 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
916 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
917 process
->free_events
= tmp
.free_events
;
920 if(feof(fp
) || ferror(fp
)) goto end_loop
;
922 gint hdr
= fgetc(fp
);
923 if(hdr
== EOF
) goto end_loop
;
927 process
->execution_stack
=
928 g_array_set_size(process
->execution_stack
,
929 process
->execution_stack
->len
+ 1);
930 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
931 process
->execution_stack
->len
-1);
934 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
935 es
->t
= g_quark_from_string(
936 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
937 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
938 es
->n
= g_quark_from_string(
939 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
940 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
941 es
->s
= g_quark_from_string(
942 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
943 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
944 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
945 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
948 process
->user_stack
= g_array_set_size(process
->user_stack
,
949 process
->user_stack
->len
+ 1);
950 address
= &g_array_index(process
->user_stack
, guint64
,
951 process
->user_stack
->len
-1);
952 fread(address
, sizeof(address
), 1, fp
);
953 process
->current_function
= *address
;
956 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
957 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
969 /* Called because a HDR_PROCESS_STATE was found */
970 /* Append a saved state to the trace states */
971 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
973 guint i
, nb_tracefile
, nb_block
, offset
;
975 LttvTracefileState
*tfcs
;
977 LttEventPosition
*ep
;
985 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
987 LttvAttributeValue value
;
988 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
989 ep
= ltt_event_position_new();
991 restore_init_state(self
);
993 fread(&t
, sizeof(t
), 1, fp
);
996 if(feof(fp
) || ferror(fp
)) goto end_loop
;
998 if(hdr
== EOF
) goto end_loop
;
1002 /* Call read_process_state_raw */
1003 read_process_state_raw(self
, fp
, quarktable
);
1011 case HDR_USER_STACK
:
1013 case HDR_PROCESS_STATE
:
1019 g_error("Error while parsing saved state file : unknown data header %d",
1025 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1026 for(i
=0;i
<nb_cpus
;i
++) {
1029 g_assert(hdr
== HDR_CPU
);
1030 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1031 g_assert(i
== cpu_num
);
1032 fread(&self
->running_process
[i
]->pid
,
1033 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1036 nb_tracefile
= self
->parent
.tracefiles
->len
;
1038 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1040 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1041 LttvTracefileContext
*, i
));
1042 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1043 // tfcs->parent.timestamp.tv_sec,
1044 // tfcs->parent.timestamp.tv_nsec);
1045 g_tree_remove(pqueue
, &tfcs
->parent
);
1047 g_assert(hdr
== HDR_TRACEFILE
);
1048 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1049 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1050 * position following : end of trace */
1051 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1052 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1053 fread(&offset
, sizeof(offset
), 1, fp
);
1054 fread(&tsc
, sizeof(tsc
), 1, fp
);
1055 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1056 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1058 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1063 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1064 LTTV_STATE_SAVED_STATES
);
1065 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1066 value
= lttv_attribute_add(saved_states_tree
,
1067 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1068 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1069 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1070 *(value
.v_time
) = t
;
1071 lttv_state_save(self
, saved_state_tree
);
1072 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1075 *(self
->max_time_state_recomputed_in_seek
) = t
;
1079 /* Called when a HDR_TRACE is found */
1080 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1081 GPtrArray
*quarktable
)
1086 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1088 if(hdr
== EOF
) goto end_loop
;
1091 case HDR_PROCESS_STATE
:
1092 /* Call read_process_state_raw */
1093 lttv_state_read_raw(tcs
, fp
, quarktable
);
1101 case HDR_USER_STACK
:
1105 g_error("Error while parsing saved state file :"
1106 " unexpected data header %d",
1110 g_error("Error while parsing saved state file : unknown data header %d",
1115 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1116 restore_init_state(tcs
);
1117 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1123 /* Copy each process from an existing hash table to a new one */
1125 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1127 LttvProcessState
*process
, *new_process
;
1129 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1133 process
= (LttvProcessState
*)value
;
1134 new_process
= g_new(LttvProcessState
, 1);
1135 *new_process
= *process
;
1136 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1137 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1138 new_process
->execution_stack
=
1139 g_array_set_size(new_process
->execution_stack
,
1140 process
->execution_stack
->len
);
1141 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1142 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1143 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1145 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1146 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1147 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1148 sizeof(guint64
), 0);
1149 new_process
->user_stack
=
1150 g_array_set_size(new_process
->user_stack
,
1151 process
->user_stack
->len
);
1152 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1153 g_array_index(new_process
->user_stack
, guint64
, i
) =
1154 g_array_index(process
->user_stack
, guint64
, i
);
1156 new_process
->current_function
= process
->current_function
;
1157 g_hash_table_insert(new_processes
, new_process
, new_process
);
1161 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1163 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1165 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1166 return new_processes
;
1169 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1172 LttvCPUState
*retval
;
1174 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1176 for(i
=0; i
<n
; i
++) {
1177 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1178 retval
[i
].last_irq
= states
[i
].last_irq
;
1179 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1180 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1181 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1188 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1192 for(i
=0; i
<n
; i
++) {
1193 g_array_free(states
[i
].mode_stack
, TRUE
);
1199 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1202 LttvIRQState
*retval
;
1204 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1206 for(i
=0; i
<n
; i
++) {
1207 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1208 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1209 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1210 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1217 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1221 for(i
=0; i
<n
; i
++) {
1222 g_array_free(states
[i
].mode_stack
, TRUE
);
1228 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1231 LttvSoftIRQState
*retval
;
1233 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1235 for(i
=0; i
<n
; i
++) {
1236 retval
[i
].running
= states
[i
].running
;
1242 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1247 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1250 LttvTrapState
*retval
;
1252 retval
= g_malloc(n
*sizeof(LttvTrapState
));
1254 for(i
=0; i
<n
; i
++) {
1255 retval
[i
].running
= states
[i
].running
;
1261 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1266 /* bdevstate stuff */
1268 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1270 gint devcode_gint
= devcode
;
1271 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1273 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1274 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1276 gint
* key
= g_malloc(sizeof(gint
));
1278 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1286 static LttvBdevState
*bdevstate_new(void)
1288 LttvBdevState
*retval
;
1289 retval
= g_malloc(sizeof(LttvBdevState
));
1290 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1295 static void bdevstate_free(LttvBdevState
*bds
)
1297 g_array_free(bds
->mode_stack
, TRUE
);
1301 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1303 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1305 bdevstate_free(bds
);
1308 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1310 LttvBdevState
*retval
;
1312 retval
= bdevstate_new();
1313 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1318 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1320 //GHashTable *ht = (GHashTable *)u;
1321 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1322 LttvBdevState
*newbds
;
1324 newbds
= bdevstate_copy(bds
);
1326 g_hash_table_insert(u
, k
, newbds
);
1329 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1333 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1335 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1340 /* Free a hashtable and the LttvBdevState structures its values
1343 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1345 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1346 g_hash_table_destroy(ht
);
1349 /* The saved state for each trace contains a member "processes", which
1350 stores a copy of the process table, and a member "tracefiles" with
1351 one entry per tracefile. Each tracefile has a "process" member pointing
1352 to the current process and a "position" member storing the tracefile
1353 position (needed to seek to the current "next" event. */
1355 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1357 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1359 LttvTracefileState
*tfcs
;
1361 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1363 guint
*running_process
;
1365 LttvAttributeValue value
;
1367 LttEventPosition
*ep
;
1369 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1370 LTTV_STATE_TRACEFILES
);
1372 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1374 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1376 /* Add the currently running processes array */
1377 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1378 running_process
= g_new(guint
, nb_cpus
);
1379 for(i
=0;i
<nb_cpus
;i
++) {
1380 running_process
[i
] = self
->running_process
[i
]->pid
;
1382 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1384 *(value
.v_pointer
) = running_process
;
1386 g_info("State save");
1388 nb_tracefile
= self
->parent
.tracefiles
->len
;
1390 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1392 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1393 LttvTracefileContext
*, i
));
1394 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1395 value
= lttv_attribute_add(tracefiles_tree
, i
,
1397 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1399 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1401 *(value
.v_uint
) = tfcs
->process
->pid
;
1403 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1405 /* Only save the position if the tfs has not infinite time. */
1406 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1407 // && current_tfcs != tfcs) {
1408 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1409 *(value
.v_pointer
) = NULL
;
1411 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1412 ep
= ltt_event_position_new();
1413 ltt_event_position(e
, ep
);
1414 *(value
.v_pointer
) = ep
;
1416 guint nb_block
, offset
;
1419 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1420 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1422 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1426 /* save the cpu state */
1428 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1430 *(value
.v_uint
) = nb_cpus
;
1432 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1434 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1437 /* save the irq state */
1438 nb_irqs
= self
->nb_irqs
;
1440 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1442 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1445 /* save the soft irq state */
1446 nb_soft_irqs
= self
->nb_soft_irqs
;
1448 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1450 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1453 /* save the trap state */
1454 nb_traps
= self
->nb_traps
;
1456 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1458 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1461 /* save the blkdev states */
1462 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1464 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1468 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1470 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1472 LttvTracefileState
*tfcs
;
1474 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1476 guint
*running_process
;
1478 LttvAttributeType type
;
1480 LttvAttributeValue value
;
1482 LttvAttributeName name
;
1486 LttEventPosition
*ep
;
1488 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1490 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1491 LTTV_STATE_TRACEFILES
);
1493 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1495 g_assert(type
== LTTV_POINTER
);
1496 lttv_state_free_process_table(self
->processes
);
1497 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1499 /* Add the currently running processes array */
1500 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1501 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1503 g_assert(type
== LTTV_POINTER
);
1504 running_process
= *(value
.v_pointer
);
1505 for(i
=0;i
<nb_cpus
;i
++) {
1506 pid
= running_process
[i
];
1507 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1508 g_assert(self
->running_process
[i
] != NULL
);
1511 nb_tracefile
= self
->parent
.tracefiles
->len
;
1513 //g_tree_destroy(tsc->pqueue);
1514 //tsc->pqueue = g_tree_new(compare_tracefile);
1516 /* restore cpu resource states */
1517 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1518 g_assert(type
== LTTV_POINTER
);
1519 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1520 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1522 /* restore irq resource states */
1523 nb_irqs
= self
->nb_irqs
;
1524 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1525 g_assert(type
== LTTV_POINTER
);
1526 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1527 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1529 /* restore soft irq resource states */
1530 nb_soft_irqs
= self
->nb_soft_irqs
;
1531 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1532 g_assert(type
== LTTV_POINTER
);
1533 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1534 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1536 /* restore trap resource states */
1537 nb_traps
= self
->nb_traps
;
1538 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1539 g_assert(type
== LTTV_POINTER
);
1540 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1541 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1543 /* restore the blkdev states */
1544 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1545 g_assert(type
== LTTV_POINTER
);
1546 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1547 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1549 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1551 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1552 LttvTracefileContext
*, i
));
1553 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1554 g_assert(type
== LTTV_GOBJECT
);
1555 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1557 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1559 g_assert(type
== LTTV_UINT
);
1560 pid
= *(value
.v_uint
);
1561 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1563 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1565 g_assert(type
== LTTV_POINTER
);
1566 //g_assert(*(value.v_pointer) != NULL);
1567 ep
= *(value
.v_pointer
);
1568 g_assert(tfcs
->parent
.t_context
!= NULL
);
1570 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1572 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1573 g_tree_remove(tsc
->pqueue
, tfc
);
1576 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1577 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1578 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1579 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1580 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1582 tfc
->timestamp
= ltt_time_infinite
;
1588 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1590 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1592 LttvTracefileState
*tfcs
;
1594 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1596 guint
*running_process
;
1598 LttvAttributeType type
;
1600 LttvAttributeValue value
;
1602 LttvAttributeName name
;
1606 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1607 LTTV_STATE_TRACEFILES
);
1608 g_object_ref(G_OBJECT(tracefiles_tree
));
1609 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1611 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1613 g_assert(type
== LTTV_POINTER
);
1614 lttv_state_free_process_table(*(value
.v_pointer
));
1615 *(value
.v_pointer
) = NULL
;
1616 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1618 /* Free running processes array */
1619 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1621 g_assert(type
== LTTV_POINTER
);
1622 running_process
= *(value
.v_pointer
);
1623 g_free(running_process
);
1625 /* free cpu resource states */
1626 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1627 g_assert(type
== LTTV_UINT
);
1628 nb_cpus
= *value
.v_uint
;
1629 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1630 g_assert(type
== LTTV_POINTER
);
1631 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1633 /* free irq resource states */
1634 nb_irqs
= self
->nb_irqs
;
1635 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1636 g_assert(type
== LTTV_POINTER
);
1637 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1639 /* free the blkdev states */
1640 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1641 g_assert(type
== LTTV_POINTER
);
1642 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1644 nb_tracefile
= self
->parent
.tracefiles
->len
;
1646 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1648 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1649 LttvTracefileContext
*, i
));
1650 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1651 g_assert(type
== LTTV_GOBJECT
);
1652 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1654 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1656 g_assert(type
== LTTV_POINTER
);
1657 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1659 g_object_unref(G_OBJECT(tracefiles_tree
));
1663 static void free_saved_state(LttvTraceState
*self
)
1667 LttvAttributeType type
;
1669 LttvAttributeValue value
;
1671 LttvAttributeName name
;
1675 LttvAttribute
*saved_states
;
1677 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1678 LTTV_STATE_SAVED_STATES
);
1680 nb
= lttv_attribute_get_number(saved_states
);
1681 for(i
= 0 ; i
< nb
; i
++) {
1682 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1683 g_assert(type
== LTTV_GOBJECT
);
1684 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1687 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1692 create_max_time(LttvTraceState
*tcs
)
1694 LttvAttributeValue v
;
1696 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1698 g_assert(*(v
.v_pointer
) == NULL
);
1699 *(v
.v_pointer
) = g_new(LttTime
,1);
1700 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1705 get_max_time(LttvTraceState
*tcs
)
1707 LttvAttributeValue v
;
1709 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1711 g_assert(*(v
.v_pointer
) != NULL
);
1712 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1717 free_max_time(LttvTraceState
*tcs
)
1719 LttvAttributeValue v
;
1721 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1723 g_free(*(v
.v_pointer
));
1724 *(v
.v_pointer
) = NULL
;
1728 typedef struct _LttvNameTables
{
1729 // FIXME GQuark *eventtype_names;
1730 GQuark
*syscall_names
;
1736 GQuark
*soft_irq_names
;
1742 create_name_tables(LttvTraceState
*tcs
)
1746 GString
*fe_name
= g_string_new("");
1748 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1750 LttvAttributeValue v
;
1754 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1756 g_assert(*(v
.v_pointer
) == NULL
);
1757 *(v
.v_pointer
) = name_tables
;
1759 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1761 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1762 LTT_FACILITY_KERNEL_ARCH
,
1763 LTT_EVENT_SYSCALL_ENTRY
,
1764 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1765 NULL
, NULL
, &hooks
)) {
1767 // th = lttv_trace_hook_get_first(&th);
1769 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1770 // nb = ltt_type_element_number(t);
1772 // name_tables->syscall_names = g_new(GQuark, nb);
1773 // name_tables->nb_syscalls = nb;
1775 // for(i = 0 ; i < nb ; i++) {
1776 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1777 // if(!name_tables->syscall_names[i]) {
1778 // GString *string = g_string_new("");
1779 // g_string_printf(string, "syscall %u", i);
1780 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1781 // g_string_free(string, TRUE);
1785 name_tables
->nb_syscalls
= 256;
1786 name_tables
->syscall_names
= g_new(GQuark
, 256);
1787 for(i
= 0 ; i
< 256 ; i
++) {
1788 g_string_printf(fe_name
, "syscall %d", i
);
1789 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1792 name_tables
->syscall_names
= NULL
;
1793 name_tables
->nb_syscalls
= 0;
1795 lttv_trace_hook_remove_all(&hooks
);
1797 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1798 LTT_FACILITY_KERNEL_ARCH
,
1799 LTT_EVENT_TRAP_ENTRY
,
1800 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1801 NULL
, NULL
, &hooks
)) {
1803 // th = lttv_trace_hook_get_first(&th);
1805 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1806 // //nb = ltt_type_element_number(t);
1808 // name_tables->trap_names = g_new(GQuark, nb);
1809 // for(i = 0 ; i < nb ; i++) {
1810 // name_tables->trap_names[i] = g_quark_from_string(
1811 // ltt_enum_string_get(t, i));
1814 name_tables
->nb_traps
= 256;
1815 name_tables
->trap_names
= g_new(GQuark
, 256);
1816 for(i
= 0 ; i
< 256 ; i
++) {
1817 g_string_printf(fe_name
, "trap %d", i
);
1818 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1821 name_tables
->trap_names
= NULL
;
1822 name_tables
->nb_traps
= 0;
1824 lttv_trace_hook_remove_all(&hooks
);
1826 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1827 LTT_FACILITY_KERNEL
,
1828 LTT_EVENT_IRQ_ENTRY
,
1829 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1830 NULL
, NULL
, &hooks
)) {
1833 name_tables->irq_names = g_new(GQuark, nb);
1834 for(i = 0 ; i < nb ; i++) {
1835 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1839 name_tables
->nb_irqs
= 256;
1840 name_tables
->irq_names
= g_new(GQuark
, 256);
1841 for(i
= 0 ; i
< 256 ; i
++) {
1842 g_string_printf(fe_name
, "irq %d", i
);
1843 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1846 name_tables
->nb_irqs
= 0;
1847 name_tables
->irq_names
= NULL
;
1849 lttv_trace_hook_remove_all(&hooks
);
1851 name_tables->soft_irq_names = g_new(GQuark, nb);
1852 for(i = 0 ; i < nb ; i++) {
1853 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1857 /* the kernel is limited to 32 statically defined softirqs */
1858 name_tables
->nb_softirqs
= 32;
1859 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1860 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1861 g_string_printf(fe_name
, "softirq %d", i
);
1862 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1864 g_array_free(hooks
, TRUE
);
1866 g_string_free(fe_name
, TRUE
);
1871 get_name_tables(LttvTraceState
*tcs
)
1873 LttvNameTables
*name_tables
;
1875 LttvAttributeValue v
;
1877 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1879 g_assert(*(v
.v_pointer
) != NULL
);
1880 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1881 //tcs->eventtype_names = name_tables->eventtype_names;
1882 tcs
->syscall_names
= name_tables
->syscall_names
;
1883 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1884 tcs
->trap_names
= name_tables
->trap_names
;
1885 tcs
->nb_traps
= name_tables
->nb_traps
;
1886 tcs
->irq_names
= name_tables
->irq_names
;
1887 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1888 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1889 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1894 free_name_tables(LttvTraceState
*tcs
)
1896 LttvNameTables
*name_tables
;
1898 LttvAttributeValue v
;
1900 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1902 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1903 *(v
.v_pointer
) = NULL
;
1905 // g_free(name_tables->eventtype_names);
1906 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1907 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1908 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1909 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1910 if(name_tables
) g_free(name_tables
);
1913 #ifdef HASH_TABLE_DEBUG
1915 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1917 LttvProcessState
*process
= (LttvProcessState
*)value
;
1919 /* Test for process corruption */
1920 guint stack_len
= process
->execution_stack
->len
;
1923 static void hash_table_check(GHashTable
*table
)
1925 g_hash_table_foreach(table
, test_process
, NULL
);
1931 /* clears the stack and sets the state passed as argument */
1932 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1934 g_array_set_size(cpust
->mode_stack
, 1);
1935 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1938 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1940 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1941 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1944 static void cpu_pop_mode(LttvCPUState
*cpust
)
1946 if(cpust
->mode_stack
->len
<= 1)
1947 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1949 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1952 /* clears the stack and sets the state passed as argument */
1953 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1955 g_array_set_size(bdevst
->mode_stack
, 1);
1956 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1959 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1961 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1962 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1965 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1967 if(bdevst
->mode_stack
->len
<= 1)
1968 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1970 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1973 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1975 g_array_set_size(irqst
->mode_stack
, 1);
1976 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1979 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1981 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1982 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1985 static void irq_pop_mode(LttvIRQState
*irqst
)
1987 if(irqst
->mode_stack
->len
<= 1)
1988 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1990 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1993 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1996 LttvExecutionState
*es
;
1998 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1999 guint cpu
= tfs
->cpu
;
2001 #ifdef HASH_TABLE_DEBUG
2002 hash_table_check(ts
->processes
);
2004 LttvProcessState
*process
= ts
->running_process
[cpu
];
2006 guint depth
= process
->execution_stack
->len
;
2008 process
->execution_stack
=
2009 g_array_set_size(process
->execution_stack
, depth
+ 1);
2012 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2014 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2017 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2018 es
->cum_cpu_time
= ltt_time_zero
;
2019 es
->s
= process
->state
->s
;
2020 process
->state
= es
;
2024 * return 1 when empty, else 0 */
2025 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2026 LttvTracefileState
*tfs
)
2028 guint depth
= process
->execution_stack
->len
;
2034 process
->execution_stack
=
2035 g_array_set_size(process
->execution_stack
, depth
- 1);
2036 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2038 process
->state
->change
= tfs
->parent
.timestamp
;
2043 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2045 guint cpu
= tfs
->cpu
;
2046 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2047 LttvProcessState
*process
= ts
->running_process
[cpu
];
2049 guint depth
= process
->execution_stack
->len
;
2051 if(process
->state
->t
!= t
){
2052 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2053 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2054 g_info("process state has %s when pop_int is %s\n",
2055 g_quark_to_string(process
->state
->t
),
2056 g_quark_to_string(t
));
2057 g_info("{ %u, %u, %s, %s, %s }\n",
2060 g_quark_to_string(process
->name
),
2061 g_quark_to_string(process
->brand
),
2062 g_quark_to_string(process
->state
->s
));
2067 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2068 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2072 process
->execution_stack
=
2073 g_array_set_size(process
->execution_stack
, depth
- 1);
2074 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2076 process
->state
->change
= tfs
->parent
.timestamp
;
2079 struct search_result
{
2080 const LttTime
*time
; /* Requested time */
2081 LttTime
*best
; /* Best result */
2084 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2086 const LttTime
*elem_time
= (const LttTime
*)a
;
2087 /* Explicit non const cast */
2088 struct search_result
*res
= (struct search_result
*)b
;
2090 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2091 /* The usertrace was created before the schedchange */
2092 /* Get larger keys */
2094 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2095 /* The usertrace was created after the schedchange time */
2096 /* Get smaller keys */
2098 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2099 res
->best
= (LttTime
*)elem_time
;
2102 res
->best
= (LttTime
*)elem_time
;
2109 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2110 guint pid
, const LttTime
*timestamp
)
2112 LttvTracefileState
*tfs
= NULL
;
2113 struct search_result res
;
2114 /* Find the usertrace associated with a pid and time interval.
2115 * Search in the usertraces by PID (within a hash) and then, for each
2116 * corresponding element of the array, find the first one with creation
2117 * timestamp the lowest, but higher or equal to "timestamp". */
2118 res
.time
= timestamp
;
2120 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2121 if(usertrace_tree
) {
2122 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2124 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2132 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2133 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2135 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2137 LttvExecutionState
*es
;
2142 process
->tgid
= tgid
;
2144 process
->name
= name
;
2145 process
->brand
= LTTV_STATE_UNBRANDED
;
2146 //process->last_cpu = tfs->cpu_name;
2147 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2148 process
->type
= LTTV_STATE_USER_THREAD
;
2149 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2150 process
->current_function
= 0; //function 0x0 by default.
2152 g_info("Process %u, core %p", process
->pid
, process
);
2153 g_hash_table_insert(tcs
->processes
, process
, process
);
2156 process
->ppid
= parent
->pid
;
2157 process
->creation_time
= *timestamp
;
2160 /* No parent. This process exists but we are missing all information about
2161 its creation. The birth time is set to zero but we remember the time of
2166 process
->creation_time
= ltt_time_zero
;
2169 process
->insertion_time
= *timestamp
;
2170 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2171 process
->creation_time
.tv_nsec
);
2172 process
->pid_time
= g_quark_from_string(buffer
);
2174 process
->free_events
= 0;
2175 //process->last_cpu = tfs->cpu_name;
2176 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2177 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2178 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2179 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2180 es
= process
->state
= &g_array_index(process
->execution_stack
,
2181 LttvExecutionState
, 0);
2182 es
->t
= LTTV_STATE_USER_MODE
;
2183 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2184 es
->entry
= *timestamp
;
2185 //g_assert(timestamp->tv_sec != 0);
2186 es
->change
= *timestamp
;
2187 es
->cum_cpu_time
= ltt_time_zero
;
2188 es
->s
= LTTV_STATE_RUN
;
2190 es
= process
->state
= &g_array_index(process
->execution_stack
,
2191 LttvExecutionState
, 1);
2192 es
->t
= LTTV_STATE_SYSCALL
;
2193 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2194 es
->entry
= *timestamp
;
2195 //g_assert(timestamp->tv_sec != 0);
2196 es
->change
= *timestamp
;
2197 es
->cum_cpu_time
= ltt_time_zero
;
2198 es
->s
= LTTV_STATE_WAIT_FORK
;
2200 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2201 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2202 sizeof(guint64
), 0);
2207 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2210 LttvProcessState key
;
2211 LttvProcessState
*process
;
2215 process
= g_hash_table_lookup(ts
->processes
, &key
);
2220 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2221 const LttTime
*timestamp
)
2223 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2224 LttvExecutionState
*es
;
2226 /* Put ltt_time_zero creation time for unexisting processes */
2227 if(unlikely(process
== NULL
)) {
2228 process
= lttv_state_create_process(ts
,
2229 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2230 /* We are not sure is it's a kernel thread or normal thread, put the
2231 * bottom stack state to unknown */
2232 process
->execution_stack
=
2233 g_array_set_size(process
->execution_stack
, 1);
2234 process
->state
= es
=
2235 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2236 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2237 es
->s
= LTTV_STATE_UNNAMED
;
2242 /* FIXME : this function should be called when we receive an event telling that
2243 * release_task has been called in the kernel. In happens generally when
2244 * the parent waits for its child terminaison, but may also happen in special
2245 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2246 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2247 * of a killed thread group, but isn't the leader.
2249 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2251 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2252 LttvProcessState key
;
2254 /* Wait for both schedule with exit dead and process free to happen.
2255 * They can happen in any order. */
2256 if (++(process
->free_events
) < 2)
2259 key
.pid
= process
->pid
;
2260 key
.cpu
= process
->cpu
;
2261 g_hash_table_remove(ts
->processes
, &key
);
2262 g_array_free(process
->execution_stack
, TRUE
);
2263 g_array_free(process
->user_stack
, TRUE
);
2269 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2271 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2272 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2277 static void lttv_state_free_process_table(GHashTable
*processes
)
2279 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2280 g_hash_table_destroy(processes
);
2284 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2286 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2288 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2289 LttvProcessState
*process
= ts
->running_process
[cpu
];
2290 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2291 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2292 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2294 LttvExecutionSubmode submode
;
2296 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2297 guint syscall
= ltt_event_get_unsigned(e
, f
);
2299 if(nb_syscalls
<= syscall
) {
2300 /* Fixup an incomplete syscall table */
2301 GQuark
*old_names
= ts
->syscall_names
;
2302 guint new_nb_syscalls
= max(syscall
+ 1, ts
->nb_syscalls
* 2);
2304 GString
*fe_name
= g_string_new("");
2305 ts
->syscall_names
= g_new(GQuark
, new_nb_syscalls
);
2306 memcpy(ts
->syscall_names
, old_names
,
2307 ts
->nb_syscalls
* sizeof(GQuark
));
2308 for(i
= ts
->nb_syscalls
; i
< new_nb_syscalls
; i
++) {
2309 g_string_printf(fe_name
, "syscall %d", i
);
2310 ts
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2312 g_string_free(fe_name
, TRUE
);
2313 ts
->nb_syscalls
= new_nb_syscalls
;
2315 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[syscall
];
2316 /* There can be no system call from PID 0 : unknown state */
2317 if(process
->pid
!= 0)
2318 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2323 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2325 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2327 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2328 LttvProcessState
*process
= ts
->running_process
[cpu
];
2330 /* There can be no system call from PID 0 : unknown state */
2331 if(process
->pid
!= 0)
2332 pop_state(s
, LTTV_STATE_SYSCALL
);
2337 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2339 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2340 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2341 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2342 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2343 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2345 LttvExecutionSubmode submode
;
2347 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2349 if (unlikely(ts
->nb_traps
<= trap
)) {
2350 /* Fixup an incomplete trap table */
2351 GQuark
*old_names
= ts
->trap_names
;
2352 guint new_nb_traps
= max(trap
+ 1, ts
->nb_traps
* 2);
2354 GString
*fe_name
= g_string_new("");
2355 ts
->trap_names
= g_new(GQuark
, new_nb_traps
);
2356 memcpy(ts
->trap_names
, old_names
,
2357 ts
->nb_traps
* sizeof(GQuark
));
2358 for(i
= ts
->nb_traps
; i
< new_nb_traps
; i
++) {
2359 g_string_printf(fe_name
, "trap %d", i
);
2360 ts
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
2362 g_string_free(fe_name
, TRUE
);
2363 ts
->nb_traps
= new_nb_traps
;
2365 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2367 push_state(s
, LTTV_STATE_TRAP
, submode
);
2369 /* update cpu status */
2370 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2372 /* update trap status */
2373 s
->cpu_state
->last_trap
= trap
;
2374 ts
->trap_states
[trap
].running
++;
2379 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2381 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2382 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2383 guint trap
= s
->cpu_state
->last_trap
;
2385 pop_state(s
, LTTV_STATE_TRAP
);
2387 /* update cpu status */
2388 cpu_pop_mode(s
->cpu_state
);
2390 /* update trap status */
2391 if(ts
->trap_states
[trap
].running
)
2392 ts
->trap_states
[trap
].running
--;
2397 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2399 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2400 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2401 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2402 //guint8 ev_id = ltt_event_eventtype_id(e);
2403 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2404 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2406 LttvExecutionSubmode submode
;
2407 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2409 if (unlikely(ts
->nb_irqs
<= irq
)) {
2410 /* Fixup an incomplete irq table */
2411 GQuark
*old_names
= ts
->irq_names
;
2412 guint new_nb_irqs
= max(irq
+ 1, ts
->nb_irqs
* 2);
2414 GString
*fe_name
= g_string_new("");
2415 ts
->irq_names
= g_new(GQuark
, new_nb_irqs
);
2416 memcpy(ts
->irq_names
, old_names
,
2417 ts
->nb_irqs
* sizeof(GQuark
));
2418 for(i
= ts
->nb_irqs
; i
< new_nb_irqs
; i
++) {
2419 g_string_printf(fe_name
, "irq %d", i
);
2420 ts
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2422 g_string_free(fe_name
, TRUE
);
2423 ts
->nb_irqs
= new_nb_irqs
;
2425 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2427 /* Do something with the info about being in user or system mode when int? */
2428 push_state(s
, LTTV_STATE_IRQ
, submode
);
2430 /* update cpu status */
2431 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2433 /* update irq status */
2434 s
->cpu_state
->last_irq
= irq
;
2435 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2440 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2442 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2443 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2444 guint softirq
= s
->cpu_state
->last_soft_irq
;
2446 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2448 /* update softirq status */
2449 if(ts
->soft_irq_states
[softirq
].running
)
2450 ts
->soft_irq_states
[softirq
].running
--;
2452 /* update cpu status */
2453 cpu_pop_mode(s
->cpu_state
);
2458 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2460 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2461 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2463 pop_state(s
, LTTV_STATE_IRQ
);
2465 /* update cpu status */
2466 cpu_pop_mode(s
->cpu_state
);
2468 /* update irq status */
2469 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2474 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2476 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2477 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2478 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2479 //guint8 ev_id = ltt_event_eventtype_id(e);
2480 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2481 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2483 LttvExecutionSubmode submode
;
2484 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2485 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2487 if (unlikely(nb_softirqs
<= softirq
)) {
2488 /* Fixup an incomplete softirq table */
2489 GQuark
*old_names
= ts
->soft_irq_names
;
2490 guint new_nb_soft_irqs
= max(softirq
+ 1, ts
->nb_soft_irqs
* 2);
2492 GString
*fe_name
= g_string_new("");
2493 ts
->soft_irq_names
= g_new(GQuark
, new_nb_soft_irqs
);
2494 memcpy(ts
->soft_irq_names
, old_names
,
2495 ts
->nb_soft_irqs
* sizeof(GQuark
));
2496 for(i
= ts
->nb_soft_irqs
; i
< new_nb_soft_irqs
; i
++) {
2497 g_string_printf(fe_name
, "softirq %d", i
);
2498 ts
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2500 g_string_free(fe_name
, TRUE
);
2501 ts
->nb_soft_irqs
= new_nb_soft_irqs
;
2503 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2505 /* Do something with the info about being in user or system mode when int? */
2506 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2508 /* update cpu status */
2509 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2511 /* update softirq status */
2512 s
->cpu_state
->last_soft_irq
= softirq
;
2513 ts
->soft_irq_states
[softirq
].running
++;
2518 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2520 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2521 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2522 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2523 //guint8 ev_id = ltt_event_eventtype_id(e);
2524 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2526 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2527 lttv_trace_get_hook_field(th
, 0)));
2528 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2530 if (ts
->nb_irqs
<= irq
) {
2531 GQuark
*old_names
= ts
->irq_names
;
2532 guint new_nb_irqs
= max(irq
+ 1, ts
->nb_irqs
* 2);
2534 GString
*fe_name
= g_string_new("");
2535 ts
->irq_names
= g_new(GQuark
, new_nb_irqs
);
2536 memcpy(ts
->irq_names
, old_names
,
2537 ts
->nb_irqs
* sizeof(GQuark
));
2538 for(i
= ts
->nb_irqs
; i
< new_nb_irqs
; i
++) {
2539 g_string_printf(fe_name
, "irq %d", i
);
2540 ts
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2542 g_string_free(fe_name
, TRUE
);
2543 ts
->nb_irqs
= new_nb_irqs
;
2545 ts
->irq_names
[irq
] = action
;
2551 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2553 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2554 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2555 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2556 //guint8 ev_id = ltt_event_eventtype_id(e);
2557 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2559 guint major
= ltt_event_get_long_unsigned(e
,
2560 lttv_trace_get_hook_field(th
, 0));
2561 guint minor
= ltt_event_get_long_unsigned(e
,
2562 lttv_trace_get_hook_field(th
, 1));
2563 guint oper
= ltt_event_get_long_unsigned(e
,
2564 lttv_trace_get_hook_field(th
, 2));
2565 guint16 devcode
= MKDEV(major
,minor
);
2567 /* have we seen this block device before? */
2568 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2571 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2573 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2578 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2580 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2581 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2582 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2583 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2585 guint major
= ltt_event_get_long_unsigned(e
,
2586 lttv_trace_get_hook_field(th
, 0));
2587 guint minor
= ltt_event_get_long_unsigned(e
,
2588 lttv_trace_get_hook_field(th
, 1));
2589 //guint oper = ltt_event_get_long_unsigned(e,
2590 // lttv_trace_get_hook_field(th, 2));
2591 guint16 devcode
= MKDEV(major
,minor
);
2593 /* have we seen this block device before? */
2594 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2596 /* update block device */
2597 bdev_pop_mode(bdev
);
2602 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2606 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2607 guint cpu
= tfs
->cpu
;
2608 LttvProcessState
*process
= ts
->running_process
[cpu
];
2610 guint depth
= process
->user_stack
->len
;
2612 process
->user_stack
=
2613 g_array_set_size(process
->user_stack
, depth
+ 1);
2615 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2616 *new_func
= funcptr
;
2617 process
->current_function
= funcptr
;
2620 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2622 guint cpu
= tfs
->cpu
;
2623 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2624 LttvProcessState
*process
= ts
->running_process
[cpu
];
2626 if(process
->current_function
!= funcptr
){
2627 g_info("Different functions (%lu.%09lu): ignore it\n",
2628 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2629 g_info("process state has %llu when pop_function is %llu\n",
2630 process
->current_function
, funcptr
);
2631 g_info("{ %u, %u, %s, %s, %s }\n",
2634 g_quark_to_string(process
->name
),
2635 g_quark_to_string(process
->brand
),
2636 g_quark_to_string(process
->state
->s
));
2639 guint depth
= process
->user_stack
->len
;
2642 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2643 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2647 process
->user_stack
=
2648 g_array_set_size(process
->user_stack
, depth
- 1);
2649 process
->current_function
=
2650 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2654 static gboolean
function_entry(void *hook_data
, void *call_data
)
2656 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2657 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2658 //guint8 ev_id = ltt_event_eventtype_id(e);
2659 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2660 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2661 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2663 push_function(s
, funcptr
);
2667 static gboolean
function_exit(void *hook_data
, void *call_data
)
2669 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2670 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2671 //guint8 ev_id = ltt_event_eventtype_id(e);
2672 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2673 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2674 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2676 pop_function(s
, funcptr
);
2680 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2682 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2683 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2684 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2685 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2690 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2691 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2692 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2694 if (ts
->nb_syscalls
<= id
) {
2695 GQuark
*old_names
= ts
->syscall_names
;
2696 guint new_nb_syscalls
= max(id
+ 1, ts
->nb_syscalls
* 2);
2698 GString
*fe_name
= g_string_new("");
2699 ts
->syscall_names
= g_new(GQuark
, new_nb_syscalls
);
2700 memcpy(ts
->syscall_names
, old_names
,
2701 ts
->nb_syscalls
* sizeof(GQuark
));
2702 for(i
= ts
->nb_syscalls
; i
< new_nb_syscalls
; i
++) {
2703 g_string_printf(fe_name
, "syscall %d", i
);
2704 ts
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2706 g_string_free(fe_name
, TRUE
);
2707 ts
->nb_syscalls
= new_nb_syscalls
;
2709 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2714 static gboolean
dump_softirq(void *hook_data
, void *call_data
)
2716 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2717 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2718 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2719 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2724 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2725 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2726 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2728 if (ts
->nb_soft_irqs
<= id
) {
2729 /* Fixup an incomplete softirq table */
2730 GQuark
*old_names
= ts
->soft_irq_names
;
2731 guint new_nb_soft_irqs
= max(id
+ 1, ts
->nb_soft_irqs
* 2);
2733 GString
*fe_name
= g_string_new("");
2734 ts
->soft_irq_names
= g_new(GQuark
, new_nb_soft_irqs
);
2735 memcpy(ts
->soft_irq_names
, old_names
,
2736 ts
->nb_soft_irqs
* sizeof(GQuark
));
2737 for(i
= ts
->nb_soft_irqs
; i
< new_nb_soft_irqs
; i
++) {
2738 g_string_printf(fe_name
, "softirq %d", i
);
2739 ts
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
2741 g_string_free(fe_name
, TRUE
);
2742 ts
->nb_soft_irqs
= new_nb_soft_irqs
;
2745 ts
->soft_irq_names
[id
] = g_quark_from_string(symbol
);
2750 static gboolean
schedchange(void *hook_data
, void *call_data
)
2752 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2754 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2755 LttvProcessState
*process
= ts
->running_process
[cpu
];
2756 //LttvProcessState *old_process = ts->running_process[cpu];
2758 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2759 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2760 guint pid_in
, pid_out
;
2763 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2764 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2765 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2767 if(likely(process
!= NULL
)) {
2769 /* We could not know but it was not the idle process executing.
2770 This should only happen at the beginning, before the first schedule
2771 event, and when the initial information (current process for each CPU)
2772 is missing. It is not obvious how we could, after the fact, compensate
2773 the wrongly attributed statistics. */
2775 //This test only makes sense once the state is known and if there is no
2776 //missing events. We need to silently ignore schedchange coming after a
2777 //process_free, or it causes glitches. (FIXME)
2778 //if(unlikely(process->pid != pid_out)) {
2779 // g_assert(process->pid == 0);
2781 if(process
->pid
== 0
2782 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2784 /* Scheduling out of pid 0 at beginning of the trace :
2785 * we know for sure it is in syscall mode at this point. */
2786 g_assert(process
->execution_stack
->len
== 1);
2787 process
->state
->t
= LTTV_STATE_SYSCALL
;
2788 process
->state
->s
= LTTV_STATE_WAIT
;
2789 process
->state
->change
= s
->parent
.timestamp
;
2790 process
->state
->entry
= s
->parent
.timestamp
;
2793 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2794 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2795 process
->state
->change
= s
->parent
.timestamp
;
2797 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2798 else process
->state
->s
= LTTV_STATE_WAIT
;
2799 process
->state
->change
= s
->parent
.timestamp
;
2802 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2803 /* see sched.h for states */
2804 if (!exit_process(s
, process
)) {
2805 process
->state
->s
= LTTV_STATE_DEAD
;
2806 process
->state
->change
= s
->parent
.timestamp
;
2811 process
= ts
->running_process
[cpu
] =
2812 lttv_state_find_process_or_create(
2813 (LttvTraceState
*)s
->parent
.t_context
,
2815 &s
->parent
.timestamp
);
2816 process
->state
->s
= LTTV_STATE_RUN
;
2818 if(process
->usertrace
)
2819 process
->usertrace
->cpu
= cpu
;
2820 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2821 process
->state
->change
= s
->parent
.timestamp
;
2823 /* update cpu status */
2825 /* going to idle task */
2826 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2828 /* scheduling a real task.
2829 * we must be careful here:
2830 * if we just schedule()'ed to a process that is
2831 * in a trap, we must put the cpu in trap mode
2833 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2834 if(process
->state
->t
== LTTV_STATE_TRAP
)
2835 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2841 static gboolean
process_fork(void *hook_data
, void *call_data
)
2843 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2844 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2845 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2847 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2848 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2849 //LttvProcessState *zombie_process;
2851 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2852 LttvProcessState
*process
= ts
->running_process
[cpu
];
2853 LttvProcessState
*child_process
;
2854 struct marker_field
*f
;
2857 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2860 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2861 s
->parent
.target_pid
= child_pid
;
2864 f
= lttv_trace_get_hook_field(th
, 2);
2866 child_tgid
= ltt_event_get_unsigned(e
, f
);
2870 /* Mathieu : it seems like the process might have been scheduled in before the
2871 * fork, and, in a rare case, might be the current process. This might happen
2872 * in a SMP case where we don't have enough precision on the clocks.
2874 * Test reenabled after precision fixes on time. (Mathieu) */
2876 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2878 if(unlikely(zombie_process
!= NULL
)) {
2879 /* Reutilisation of PID. Only now we are sure that the old PID
2880 * has been released. FIXME : should know when release_task happens instead.
2882 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2884 for(i
=0; i
< num_cpus
; i
++) {
2885 g_assert(zombie_process
!= ts
->running_process
[i
]);
2888 exit_process(s
, zombie_process
);
2891 g_assert(process
->pid
!= child_pid
);
2892 // FIXME : Add this test in the "known state" section
2893 // g_assert(process->pid == parent_pid);
2894 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2895 if(child_process
== NULL
) {
2896 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2897 child_pid
, child_tgid
,
2898 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2900 /* The process has already been created : due to time imprecision between
2901 * multiple CPUs : it has been scheduled in before creation. Note that we
2902 * shouldn't have this kind of imprecision.
2904 * Simply put a correct parent.
2906 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2907 //g_assert(0); /* This is a problematic case : the process has been created
2908 // before the fork event */
2909 child_process
->ppid
= process
->pid
;
2910 child_process
->tgid
= child_tgid
;
2912 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2913 child_process
->name
= process
->name
;
2914 child_process
->brand
= process
->brand
;
2919 /* We stamp a newly created process as kernel_thread.
2920 * The thread should not be running yet. */
2921 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2923 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2924 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2925 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2927 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2928 LttvProcessState
*process
;
2929 LttvExecutionState
*es
;
2932 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2933 s
->parent
.target_pid
= pid
;
2935 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2937 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2938 process
->execution_stack
=
2939 g_array_set_size(process
->execution_stack
, 1);
2940 es
= process
->state
=
2941 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2942 es
->t
= LTTV_STATE_SYSCALL
;
2944 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2949 static gboolean
process_exit(void *hook_data
, void *call_data
)
2951 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2952 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2953 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2955 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2956 LttvProcessState
*process
; // = ts->running_process[cpu];
2958 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2959 s
->parent
.target_pid
= pid
;
2961 // FIXME : Add this test in the "known state" section
2962 // g_assert(process->pid == pid);
2964 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2965 if(likely(process
!= NULL
)) {
2966 process
->state
->s
= LTTV_STATE_EXIT
;
2971 static gboolean
process_free(void *hook_data
, void *call_data
)
2973 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2974 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2975 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2976 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2978 LttvProcessState
*process
;
2980 /* PID of the process to release */
2981 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2982 s
->parent
.target_pid
= release_pid
;
2984 g_assert(release_pid
!= 0);
2986 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2987 if(likely(process
!= NULL
))
2988 exit_process(s
, process
);
2991 if(likely(process
!= NULL
)) {
2992 /* release_task is happening at kernel level : we can now safely release
2993 * the data structure of the process */
2994 //This test is fun, though, as it may happen that
2995 //at time t : CPU 0 : process_free
2996 //at time t+150ns : CPU 1 : schedule out
2997 //Clearly due to time imprecision, we disable it. (Mathieu)
2998 //If this weird case happen, we have no choice but to put the
2999 //Currently running process on the cpu to 0.
3000 //I re-enable it following time precision fixes. (Mathieu)
3001 //Well, in the case where an process is freed by a process on another CPU
3002 //and still scheduled, it happens that this is the schedchange that will
3003 //drop the last reference count. Do not free it here!
3004 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3006 for(i
=0; i
< num_cpus
; i
++) {
3007 //g_assert(process != ts->running_process[i]);
3008 if(process
== ts
->running_process
[i
]) {
3009 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3013 if(i
== num_cpus
) /* process is not scheduled */
3014 exit_process(s
, process
);
3021 static gboolean
process_exec(void *hook_data
, void *call_data
)
3023 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3024 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3025 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3026 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3029 LttvProcessState
*process
= ts
->running_process
[cpu
];
3031 #if 0//how to use a sequence that must be transformed in a string
3032 /* PID of the process to release */
3033 guint64 name_len
= ltt_event_field_element_number(e
,
3034 lttv_trace_get_hook_field(th
, 0));
3035 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3036 LttField
*child
= ltt_event_field_element_select(e
,
3037 lttv_trace_get_hook_field(th
, 0), 0);
3039 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
3040 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
3041 memcpy(null_term_name
, name_begin
, name_len
);
3042 null_term_name
[name_len
] = '\0';
3043 process
->name
= g_quark_from_string(null_term_name
);
3046 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
3047 lttv_trace_get_hook_field(th
, 0)));
3048 process
->brand
= LTTV_STATE_UNBRANDED
;
3049 //g_free(null_term_name);
3053 static gboolean
thread_brand(void *hook_data
, void *call_data
)
3055 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3056 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3057 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3058 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3061 LttvProcessState
*process
= ts
->running_process
[cpu
];
3063 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
3064 process
->brand
= g_quark_from_string(name
);
3069 static void fix_process(gpointer key
, gpointer value
,
3072 LttvProcessState
*process
;
3073 LttvExecutionState
*es
;
3074 process
= (LttvProcessState
*)value
;
3075 LttTime
*timestamp
= (LttTime
*)user_data
;
3077 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
3078 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3079 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3080 es
->t
= LTTV_STATE_SYSCALL
;
3081 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3082 es
->entry
= *timestamp
;
3083 es
->change
= *timestamp
;
3084 es
->cum_cpu_time
= ltt_time_zero
;
3085 if(es
->s
== LTTV_STATE_UNNAMED
)
3086 es
->s
= LTTV_STATE_WAIT
;
3089 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3090 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3091 es
->t
= LTTV_STATE_USER_MODE
;
3092 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3093 es
->entry
= *timestamp
;
3094 //g_assert(timestamp->tv_sec != 0);
3095 es
->change
= *timestamp
;
3096 es
->cum_cpu_time
= ltt_time_zero
;
3097 if(es
->s
== LTTV_STATE_UNNAMED
)
3098 es
->s
= LTTV_STATE_RUN
;
3100 if(process
->execution_stack
->len
== 1) {
3101 /* Still in bottom unknown mode, means never did a system call
3102 * May be either in user mode, syscall mode, running or waiting.*/
3103 /* FIXME : we may be tagging syscall mode when being user mode */
3104 process
->execution_stack
=
3105 g_array_set_size(process
->execution_stack
, 2);
3106 es
= process
->state
= &g_array_index(process
->execution_stack
,
3107 LttvExecutionState
, 1);
3108 es
->t
= LTTV_STATE_SYSCALL
;
3109 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3110 es
->entry
= *timestamp
;
3111 //g_assert(timestamp->tv_sec != 0);
3112 es
->change
= *timestamp
;
3113 es
->cum_cpu_time
= ltt_time_zero
;
3114 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3115 es
->s
= LTTV_STATE_WAIT
;
3121 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3123 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3124 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3125 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3126 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3127 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3129 /* For all processes */
3130 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3131 /* else, if stack[0] is unknown, set to user mode, running */
3133 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3138 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3140 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3141 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3142 //It's slow : optimise later by doing this before reading trace.
3143 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3149 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3150 LttvProcessState
*process
= ts
->running_process
[cpu
];
3151 LttvProcessState
*parent_process
;
3152 struct marker_field
*f
;
3153 GQuark type
, mode
, submode
, status
;
3154 LttvExecutionState
*es
;
3158 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3159 s
->parent
.target_pid
= pid
;
3162 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3165 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3168 f
= lttv_trace_get_hook_field(th
, 3);
3169 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3171 //FIXME: type is rarely used, enum must match possible types.
3174 f
= lttv_trace_get_hook_field(th
, 4);
3175 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3178 f
= lttv_trace_get_hook_field(th
, 5);
3179 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3182 f
= lttv_trace_get_hook_field(th
, 6);
3183 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3186 f
= lttv_trace_get_hook_field(th
, 7);
3188 tgid
= ltt_event_get_unsigned(e
, f
);
3193 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3194 for(i
=0; i
<nb_cpus
; i
++) {
3195 process
= lttv_state_find_process(ts
, i
, pid
);
3196 g_assert(process
!= NULL
);
3198 process
->ppid
= parent_pid
;
3199 process
->tgid
= tgid
;
3200 process
->name
= g_quark_from_string(command
);
3202 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3203 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3207 /* The process might exist if a process was forked while performing the
3209 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3210 if(process
== NULL
) {
3211 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3212 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3213 pid
, tgid
, g_quark_from_string(command
),
3214 &s
->parent
.timestamp
);
3216 /* Keep the stack bottom : a running user mode */
3217 /* Disabled because of inconsistencies in the current statedump states. */
3218 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3219 /* Only keep the bottom
3220 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3221 /* Will cause expected trap when in fact being syscall (even after end of
3223 * Will cause expected interrupt when being syscall. (only before end of
3224 * statedump event) */
3225 // This will cause a "popping last state on stack, ignoring it."
3226 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3227 es
= process
->state
= &g_array_index(process
->execution_stack
,
3228 LttvExecutionState
, 0);
3229 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3230 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3231 es
->s
= LTTV_STATE_UNNAMED
;
3232 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3234 es
->t
= LTTV_STATE_SYSCALL
;
3239 /* User space process :
3240 * bottom : user mode
3241 * either currently running or scheduled out.
3242 * can be scheduled out because interrupted in (user mode or in syscall)
3243 * or because of an explicit call to the scheduler in syscall. Note that
3244 * the scheduler call comes after the irq_exit, so never in interrupt
3246 // temp workaround : set size to 1 : only have user mode bottom of stack.
3247 // will cause g_info message of expected syscall mode when in fact being
3248 // in user mode. Can also cause expected trap when in fact being user
3249 // mode in the event of a page fault reenabling interrupts in the handler.
3250 // Expected syscall and trap can also happen after the end of statedump
3251 // This will cause a "popping last state on stack, ignoring it."
3252 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3253 es
= process
->state
= &g_array_index(process
->execution_stack
,
3254 LttvExecutionState
, 0);
3255 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3256 es
->s
= LTTV_STATE_UNNAMED
;
3257 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3259 es
->t
= LTTV_STATE_USER_MODE
;
3267 es
= process
->state
= &g_array_index(process
->execution_stack
,
3268 LttvExecutionState
, 1);
3269 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3270 es
->s
= LTTV_STATE_UNNAMED
;
3271 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3275 /* The process has already been created :
3276 * Probably was forked while dumping the process state or
3277 * was simply scheduled in prior to get the state dump event.
3279 process
->ppid
= parent_pid
;
3280 process
->tgid
= tgid
;
3281 process
->name
= g_quark_from_string(command
);
3282 process
->type
= type
;
3284 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3286 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3287 if(type
== LTTV_STATE_KERNEL_THREAD
)
3288 es
->t
= LTTV_STATE_SYSCALL
;
3290 es
->t
= LTTV_STATE_USER_MODE
;
3293 /* Don't mess around with the stack, it will eventually become
3294 * ok after the end of state dump. */
3301 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3303 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3305 lttv_state_add_event_hooks(tss
);
3310 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3312 LttvTraceset
*traceset
= self
->parent
.ts
;
3314 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3318 LttvTracefileState
*tfs
;
3324 LttvAttributeValue val
;
3326 nb_trace
= lttv_traceset_number(traceset
);
3327 for(i
= 0 ; i
< nb_trace
; i
++) {
3328 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3330 /* Find the eventtype id for the following events and register the
3331 associated by id hooks. */
3333 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3334 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3337 lttv_trace_find_hook(ts
->parent
.t
,
3338 LTT_FACILITY_KERNEL_ARCH
,
3339 LTT_EVENT_SYSCALL_ENTRY
,
3340 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3341 syscall_entry
, NULL
, &hooks
);
3343 lttv_trace_find_hook(ts
->parent
.t
,
3344 LTT_FACILITY_KERNEL_ARCH
,
3345 LTT_EVENT_SYSCALL_EXIT
,
3347 syscall_exit
, NULL
, &hooks
);
3349 lttv_trace_find_hook(ts
->parent
.t
,
3350 LTT_FACILITY_KERNEL_ARCH
,
3351 LTT_EVENT_TRAP_ENTRY
,
3352 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3353 trap_entry
, NULL
, &hooks
);
3355 lttv_trace_find_hook(ts
->parent
.t
,
3356 LTT_FACILITY_KERNEL_ARCH
,
3357 LTT_EVENT_TRAP_EXIT
,
3359 trap_exit
, NULL
, &hooks
);
3361 lttv_trace_find_hook(ts
->parent
.t
,
3362 LTT_FACILITY_KERNEL
,
3363 LTT_EVENT_IRQ_ENTRY
,
3364 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3365 irq_entry
, NULL
, &hooks
);
3367 lttv_trace_find_hook(ts
->parent
.t
,
3368 LTT_FACILITY_KERNEL
,
3371 irq_exit
, NULL
, &hooks
);
3373 lttv_trace_find_hook(ts
->parent
.t
,
3374 LTT_FACILITY_KERNEL
,
3375 LTT_EVENT_SOFT_IRQ_ENTRY
,
3376 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3377 soft_irq_entry
, NULL
, &hooks
);
3379 lttv_trace_find_hook(ts
->parent
.t
,
3380 LTT_FACILITY_KERNEL
,
3381 LTT_EVENT_SOFT_IRQ_EXIT
,
3383 soft_irq_exit
, NULL
, &hooks
);
3385 lttv_trace_find_hook(ts
->parent
.t
,
3386 LTT_FACILITY_KERNEL
,
3387 LTT_EVENT_SCHED_SCHEDULE
,
3388 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3389 LTT_FIELD_PREV_STATE
),
3390 schedchange
, NULL
, &hooks
);
3392 lttv_trace_find_hook(ts
->parent
.t
,
3393 LTT_FACILITY_KERNEL
,
3394 LTT_EVENT_PROCESS_FORK
,
3395 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3396 LTT_FIELD_CHILD_TGID
),
3397 process_fork
, NULL
, &hooks
);
3399 lttv_trace_find_hook(ts
->parent
.t
,
3400 LTT_FACILITY_KERNEL_ARCH
,
3401 LTT_EVENT_KTHREAD_CREATE
,
3402 FIELD_ARRAY(LTT_FIELD_PID
),
3403 process_kernel_thread
, NULL
, &hooks
);
3405 lttv_trace_find_hook(ts
->parent
.t
,
3406 LTT_FACILITY_KERNEL
,
3407 LTT_EVENT_PROCESS_EXIT
,
3408 FIELD_ARRAY(LTT_FIELD_PID
),
3409 process_exit
, NULL
, &hooks
);
3411 lttv_trace_find_hook(ts
->parent
.t
,
3412 LTT_FACILITY_KERNEL
,
3413 LTT_EVENT_PROCESS_FREE
,
3414 FIELD_ARRAY(LTT_FIELD_PID
),
3415 process_free
, NULL
, &hooks
);
3417 lttv_trace_find_hook(ts
->parent
.t
,
3420 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3421 process_exec
, NULL
, &hooks
);
3423 lttv_trace_find_hook(ts
->parent
.t
,
3424 LTT_FACILITY_USER_GENERIC
,
3425 LTT_EVENT_THREAD_BRAND
,
3426 FIELD_ARRAY(LTT_FIELD_NAME
),
3427 thread_brand
, NULL
, &hooks
);
3429 /* statedump-related hooks */
3430 lttv_trace_find_hook(ts
->parent
.t
,
3432 LTT_EVENT_PROCESS_STATE
,
3433 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3434 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3435 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3436 enum_process_state
, NULL
, &hooks
);
3438 lttv_trace_find_hook(ts
->parent
.t
,
3440 LTT_EVENT_STATEDUMP_END
,
3442 statedump_end
, NULL
, &hooks
);
3444 lttv_trace_find_hook(ts
->parent
.t
,
3446 LTT_EVENT_LIST_INTERRUPT
,
3447 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3448 enum_interrupt
, NULL
, &hooks
);
3450 lttv_trace_find_hook(ts
->parent
.t
,
3452 LTT_EVENT_REQUEST_ISSUE
,
3453 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3454 bdev_request_issue
, NULL
, &hooks
);
3456 lttv_trace_find_hook(ts
->parent
.t
,
3458 LTT_EVENT_REQUEST_COMPLETE
,
3459 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3460 bdev_request_complete
, NULL
, &hooks
);
3462 lttv_trace_find_hook(ts
->parent
.t
,
3463 LTT_FACILITY_USER_GENERIC
,
3464 LTT_EVENT_FUNCTION_ENTRY
,
3465 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3466 function_entry
, NULL
, &hooks
);
3468 lttv_trace_find_hook(ts
->parent
.t
,
3469 LTT_FACILITY_USER_GENERIC
,
3470 LTT_EVENT_FUNCTION_EXIT
,
3471 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3472 function_exit
, NULL
, &hooks
);
3474 lttv_trace_find_hook(ts
->parent
.t
,
3475 LTT_FACILITY_STATEDUMP
,
3476 LTT_EVENT_SYS_CALL_TABLE
,
3477 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3478 dump_syscall
, NULL
, &hooks
);
3480 lttv_trace_find_hook(ts
->parent
.t
,
3481 LTT_FACILITY_STATEDUMP
,
3482 LTT_EVENT_SOFTIRQ_VEC
,
3483 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3484 dump_softirq
, NULL
, &hooks
);
3486 /* Add these hooks to each event_by_id hooks list */
3488 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3490 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3492 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3493 LttvTracefileContext
*, j
));
3495 for(k
= 0 ; k
< hooks
->len
; k
++) {
3496 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3498 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3504 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3505 *(val
.v_pointer
) = hooks
;
3509 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3511 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3513 lttv_state_remove_event_hooks(tss
);
3518 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3520 LttvTraceset
*traceset
= self
->parent
.ts
;
3522 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3526 LttvTracefileState
*tfs
;
3532 LttvAttributeValue val
;
3534 nb_trace
= lttv_traceset_number(traceset
);
3535 for(i
= 0 ; i
< nb_trace
; i
++) {
3536 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3538 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3539 hooks
= *(val
.v_pointer
);
3541 /* Remove these hooks from each event_by_id hooks list */
3543 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3545 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3547 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3548 LttvTracefileContext
*, j
));
3550 for(k
= 0 ; k
< hooks
->len
; k
++) {
3551 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3552 lttv_hooks_remove_data(
3553 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3558 lttv_trace_hook_remove_all(&hooks
);
3559 g_array_free(hooks
, TRUE
);
3563 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3565 guint
*event_count
= (guint
*)hook_data
;
3567 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3568 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3573 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3575 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3577 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3579 LttvAttributeValue value
;
3581 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3582 LTTV_STATE_SAVED_STATES
);
3583 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3584 value
= lttv_attribute_add(saved_states_tree
,
3585 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3586 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3587 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3588 *(value
.v_time
) = self
->parent
.timestamp
;
3589 lttv_state_save(tcs
, saved_state_tree
);
3590 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3591 self
->parent
.timestamp
.tv_nsec
);
3593 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3598 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3600 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3602 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3607 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3615 static gboolean
block_start(void *hook_data
, void *call_data
)
3617 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3619 LttvTracefileState
*tfcs
;
3621 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3623 LttEventPosition
*ep
;
3625 guint i
, nb_block
, nb_event
, nb_tracefile
;
3629 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3631 LttvAttributeValue value
;
3633 ep
= ltt_event_position_new();
3635 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3637 /* Count the number of events added since the last block end in any
3640 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3642 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3643 LttvTracefileContext
, i
));
3644 ltt_event_position(tfcs
->parent
.e
, ep
);
3645 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3646 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3647 tfcs
->saved_position
= nb_event
;
3651 if(tcs
->nb_event
>= tcs
->save_interval
) {
3652 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3653 LTTV_STATE_SAVED_STATES
);
3654 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3655 value
= lttv_attribute_add(saved_states_tree
,
3656 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3657 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3658 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3659 *(value
.v_time
) = self
->parent
.timestamp
;
3660 lttv_state_save(tcs
, saved_state_tree
);
3662 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3663 self
->parent
.timestamp
.tv_nsec
);
3665 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3671 static gboolean
block_end(void *hook_data
, void *call_data
)
3673 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3675 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3679 LttEventPosition
*ep
;
3681 guint nb_block
, nb_event
;
3683 ep
= ltt_event_position_new();
3684 ltt_event_position(self
->parent
.e
, ep
);
3685 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3686 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3687 self
->saved_position
= 0;
3688 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3695 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3697 LttvTraceset
*traceset
= self
->parent
.ts
;
3699 guint i
, j
, nb_trace
, nb_tracefile
;
3703 LttvTracefileState
*tfs
;
3705 LttvTraceHook hook_start
, hook_end
;
3707 nb_trace
= lttv_traceset_number(traceset
);
3708 for(i
= 0 ; i
< nb_trace
; i
++) {
3709 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3711 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3712 NULL
, NULL
, block_start
, &hook_start
);
3713 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3714 NULL
, NULL
, block_end
, &hook_end
);
3716 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3718 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3720 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3721 LttvTracefileContext
, j
));
3722 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3723 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3724 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3725 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3731 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3733 LttvTraceset
*traceset
= self
->parent
.ts
;
3735 guint i
, j
, nb_trace
, nb_tracefile
;
3739 LttvTracefileState
*tfs
;
3742 nb_trace
= lttv_traceset_number(traceset
);
3743 for(i
= 0 ; i
< nb_trace
; i
++) {
3745 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3746 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3748 if(ts
->has_precomputed_states
) continue;
3750 guint
*event_count
= g_new(guint
, 1);
3753 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3755 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3756 LttvTracefileContext
*, j
));
3757 lttv_hooks_add(tfs
->parent
.event
,
3758 state_save_event_hook
,
3765 lttv_process_traceset_begin(&self
->parent
,
3766 NULL
, NULL
, NULL
, NULL
, NULL
);
3770 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3772 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3774 lttv_state_save_add_event_hooks(tss
);
3781 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3783 LttvTraceset
*traceset
= self
->parent
.ts
;
3785 guint i
, j
, nb_trace
, nb_tracefile
;
3789 LttvTracefileState
*tfs
;
3791 LttvTraceHook hook_start
, hook_end
;
3793 nb_trace
= lttv_traceset_number(traceset
);
3794 for(i
= 0 ; i
< nb_trace
; i
++) {
3795 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3797 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3798 NULL
, NULL
, block_start
, &hook_start
);
3800 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3801 NULL
, NULL
, block_end
, &hook_end
);
3803 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3805 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3807 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3808 LttvTracefileContext
, j
));
3809 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3810 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3811 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3812 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3818 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3820 LttvTraceset
*traceset
= self
->parent
.ts
;
3822 guint i
, j
, nb_trace
, nb_tracefile
;
3826 LttvTracefileState
*tfs
;
3828 LttvHooks
*after_trace
= lttv_hooks_new();
3830 lttv_hooks_add(after_trace
,
3831 state_save_after_trace_hook
,
3836 lttv_process_traceset_end(&self
->parent
,
3837 NULL
, after_trace
, NULL
, NULL
, NULL
);
3839 lttv_hooks_destroy(after_trace
);
3841 nb_trace
= lttv_traceset_number(traceset
);
3842 for(i
= 0 ; i
< nb_trace
; i
++) {
3844 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3845 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3847 if(ts
->has_precomputed_states
) continue;
3849 guint
*event_count
= NULL
;
3851 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3853 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3854 LttvTracefileContext
*, j
));
3855 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3856 state_save_event_hook
);
3858 if(event_count
) g_free(event_count
);
3862 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3864 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3866 lttv_state_save_remove_event_hooks(tss
);
3871 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3873 LttvTraceset
*traceset
= self
->parent
.ts
;
3877 int min_pos
, mid_pos
, max_pos
;
3879 guint call_rest
= 0;
3881 LttvTraceState
*tcs
;
3883 LttvAttributeValue value
;
3885 LttvAttributeType type
;
3887 LttvAttributeName name
;
3891 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3893 //g_tree_destroy(self->parent.pqueue);
3894 //self->parent.pqueue = g_tree_new(compare_tracefile);
3896 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3898 nb_trace
= lttv_traceset_number(traceset
);
3899 for(i
= 0 ; i
< nb_trace
; i
++) {
3900 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3902 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3903 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3904 LTTV_STATE_SAVED_STATES
);
3907 if(saved_states_tree
) {
3908 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3909 mid_pos
= max_pos
/ 2;
3910 while(min_pos
< max_pos
) {
3911 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3913 g_assert(type
== LTTV_GOBJECT
);
3914 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3915 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3917 g_assert(type
== LTTV_TIME
);
3918 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3920 closest_tree
= saved_state_tree
;
3922 else max_pos
= mid_pos
- 1;
3924 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3928 /* restore the closest earlier saved state */
3930 lttv_state_restore(tcs
, closest_tree
);
3934 /* There is no saved state, yet we want to have it. Restart at T0 */
3936 restore_init_state(tcs
);
3937 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3940 /* We want to seek quickly without restoring/updating the state */
3942 restore_init_state(tcs
);
3943 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3946 if(!call_rest
) g_info("NOT Calling restore");
3951 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3957 traceset_state_finalize (LttvTracesetState
*self
)
3959 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3960 finalize(G_OBJECT(self
));
3965 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3967 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3969 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3970 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3971 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3972 klass
->new_traceset_context
= new_traceset_context
;
3973 klass
->new_trace_context
= new_trace_context
;
3974 klass
->new_tracefile_context
= new_tracefile_context
;
3979 lttv_traceset_state_get_type(void)
3981 static GType type
= 0;
3983 static const GTypeInfo info
= {
3984 sizeof (LttvTracesetStateClass
),
3985 NULL
, /* base_init */
3986 NULL
, /* base_finalize */
3987 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3988 NULL
, /* class_finalize */
3989 NULL
, /* class_data */
3990 sizeof (LttvTracesetState
),
3991 0, /* n_preallocs */
3992 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3993 NULL
/* value handling */
3996 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
4004 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4010 trace_state_finalize (LttvTraceState
*self
)
4012 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
4013 finalize(G_OBJECT(self
));
4018 trace_state_class_init (LttvTraceStateClass
*klass
)
4020 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4022 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
4023 klass
->state_save
= state_save
;
4024 klass
->state_restore
= state_restore
;
4025 klass
->state_saved_free
= state_saved_free
;
4030 lttv_trace_state_get_type(void)
4032 static GType type
= 0;
4034 static const GTypeInfo info
= {
4035 sizeof (LttvTraceStateClass
),
4036 NULL
, /* base_init */
4037 NULL
, /* base_finalize */
4038 (GClassInitFunc
) trace_state_class_init
, /* class_init */
4039 NULL
, /* class_finalize */
4040 NULL
, /* class_data */
4041 sizeof (LttvTraceState
),
4042 0, /* n_preallocs */
4043 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
4044 NULL
/* value handling */
4047 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
4048 "LttvTraceStateType", &info
, 0);
4055 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
4061 tracefile_state_finalize (LttvTracefileState
*self
)
4063 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
4064 finalize(G_OBJECT(self
));
4069 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4071 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4073 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4078 lttv_tracefile_state_get_type(void)
4080 static GType type
= 0;
4082 static const GTypeInfo info
= {
4083 sizeof (LttvTracefileStateClass
),
4084 NULL
, /* base_init */
4085 NULL
, /* base_finalize */
4086 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4087 NULL
, /* class_finalize */
4088 NULL
, /* class_data */
4089 sizeof (LttvTracefileState
),
4090 0, /* n_preallocs */
4091 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4092 NULL
/* value handling */
4095 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4096 "LttvTracefileStateType", &info
, 0);
4102 static void module_init()
4104 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4105 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4106 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4107 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4108 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4109 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4110 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4111 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4112 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4113 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4114 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4115 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4116 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4117 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4118 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4119 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4120 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4121 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4122 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4123 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4124 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4125 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4126 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4127 LTTV_STATE_EVENT
= g_quark_from_string("event");
4128 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4129 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4130 LTTV_STATE_TIME
= g_quark_from_string("time");
4131 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4132 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4133 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4134 g_quark_from_string("trace_state_use_count");
4135 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4136 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4137 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4138 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4139 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4140 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4143 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4144 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4145 LTT_FACILITY_FS
= g_quark_from_string("fs");
4146 LTT_FACILITY_LIST
= g_quark_from_string("list");
4147 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4148 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4149 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4151 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4152 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4153 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4154 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4155 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4156 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4157 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4158 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4159 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4160 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4161 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4162 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4163 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4164 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4165 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4166 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4167 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4168 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4169 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4170 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4171 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4172 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4173 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4174 LTT_EVENT_SOFTIRQ_VEC
= g_quark_from_string("softirq_vec");
4176 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4177 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4178 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4179 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4180 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4181 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4182 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4183 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4184 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4185 LTT_FIELD_PID
= g_quark_from_string("pid");
4186 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4187 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4188 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4189 LTT_FIELD_NAME
= g_quark_from_string("name");
4190 LTT_FIELD_TYPE
= g_quark_from_string("type");
4191 LTT_FIELD_MODE
= g_quark_from_string("mode");
4192 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4193 LTT_FIELD_STATUS
= g_quark_from_string("status");
4194 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4195 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4196 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4197 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4198 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4199 LTT_FIELD_ACTION
= g_quark_from_string("action");
4200 LTT_FIELD_ID
= g_quark_from_string("id");
4201 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4202 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4204 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4205 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4206 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4207 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4208 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4209 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4211 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4212 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4213 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4215 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4216 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4217 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4218 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4221 static void module_destroy()
4226 LTTV_MODULE("state", "State computation", \
4227 "Update the system state, possibly saving it at intervals", \
4228 module_init
, module_destroy
)