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
;
92 LTT_FIELD_SOFT_IRQ_ID
,
100 LTT_FIELD_CHILD_TGID
,
118 LTTV_STATE_MODE_UNKNOWN
,
119 LTTV_STATE_USER_MODE
,
126 LTTV_STATE_SUBMODE_UNKNOWN
,
127 LTTV_STATE_SUBMODE_NONE
;
131 LTTV_STATE_WAIT_FORK
,
140 LTTV_STATE_UNBRANDED
;
143 LTTV_STATE_USER_THREAD
,
144 LTTV_STATE_KERNEL_THREAD
;
162 LTTV_BDEV_BUSY_READING
,
163 LTTV_BDEV_BUSY_WRITING
;
166 LTTV_STATE_TRACEFILES
,
167 LTTV_STATE_PROCESSES
,
169 LTTV_STATE_RUNNING_PROCESS
,
171 LTTV_STATE_SAVED_STATES
,
172 LTTV_STATE_SAVED_STATES_TIME
,
175 LTTV_STATE_NAME_TABLES
,
176 LTTV_STATE_TRACE_STATE_USE_COUNT
,
177 LTTV_STATE_RESOURCE_CPUS
,
178 LTTV_STATE_RESOURCE_CPUS_COUNT
,
179 LTTV_STATE_RESOURCE_IRQS
,
180 LTTV_STATE_RESOURCE_SOFT_IRQS
,
181 LTTV_STATE_RESOURCE_TRAPS
,
182 LTTV_STATE_RESOURCE_BLKDEVS
;
184 static void create_max_time(LttvTraceState
*tcs
);
186 static void get_max_time(LttvTraceState
*tcs
);
188 static void free_max_time(LttvTraceState
*tcs
);
190 static void create_name_tables(LttvTraceState
*tcs
);
192 static void get_name_tables(LttvTraceState
*tcs
);
194 static void free_name_tables(LttvTraceState
*tcs
);
196 static void free_saved_state(LttvTraceState
*tcs
);
198 static void lttv_state_free_process_table(GHashTable
*processes
);
200 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
201 GPtrArray
*quarktable
);
203 /* Resource function prototypes */
204 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
205 static LttvBdevState
*bdevstate_new(void);
206 static void bdevstate_free(LttvBdevState
*);
207 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
208 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
211 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
213 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
217 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
219 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
223 void lttv_state_state_saved_free(LttvTraceState
*self
,
224 LttvAttribute
*container
)
226 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
230 guint
process_hash(gconstpointer key
)
232 guint pid
= ((const LttvProcessState
*)key
)->pid
;
233 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
237 /* If the hash table hash function is well distributed,
238 * the process_equal should compare different pid */
239 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
241 const LttvProcessState
*process_a
, *process_b
;
244 process_a
= (const LttvProcessState
*)a
;
245 process_b
= (const LttvProcessState
*)b
;
247 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
248 else if(likely(process_a
->pid
== 0 &&
249 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
254 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
256 g_tree_destroy((GTree
*)value
);
259 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
261 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
262 g_hash_table_destroy(usertraces
);
265 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
271 restore_init_state(LttvTraceState
*self
)
273 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
275 //LttvTracefileState *tfcs;
277 LttTime start_time
, end_time
;
279 /* Free the process tables */
280 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
281 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
282 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
283 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
286 /* Seek time to beginning */
287 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
288 // closest. It's the tracecontext job to seek the trace to the beginning
289 // anyway : the init state might be used at the middle of the trace as well...
290 //g_tree_destroy(self->parent.ts_context->pqueue);
291 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
293 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
295 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
297 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
298 nb_irqs
= self
->nb_irqs
;
299 nb_soft_irqs
= self
->nb_soft_irqs
;
300 nb_traps
= self
->nb_traps
;
302 /* Put the per cpu running_process to beginning state : process 0. */
303 for(i
=0; i
< nb_cpus
; i
++) {
304 LttvExecutionState
*es
;
305 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
306 LTTV_STATE_UNNAMED
, &start_time
);
307 /* We are not sure is it's a kernel thread or normal thread, put the
308 * bottom stack state to unknown */
309 self
->running_process
[i
]->execution_stack
=
310 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
311 es
= self
->running_process
[i
]->state
=
312 &g_array_index(self
->running_process
[i
]->execution_stack
,
313 LttvExecutionState
, 0);
314 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
315 es
->s
= LTTV_STATE_UNNAMED
;
317 //self->running_process[i]->state->s = LTTV_STATE_RUN;
318 self
->running_process
[i
]->cpu
= i
;
320 /* reset cpu states */
321 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
322 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
325 /* reset irq states */
326 for(i
=0; i
<nb_irqs
; i
++) {
327 if(self
->irq_states
[i
].mode_stack
->len
> 0)
328 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
331 /* reset softirq states */
332 for(i
=0; i
<nb_soft_irqs
; i
++) {
333 self
->soft_irq_states
[i
].running
= 0;
336 /* reset trap states */
337 for(i
=0; i
<nb_traps
; i
++) {
338 self
->trap_states
[i
].running
= 0;
341 /* reset bdev states */
342 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
343 //g_hash_table_steal_all(self->bdev_states);
344 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
347 nb_tracefile
= self
->parent
.tracefiles
->len
;
349 for(i
= 0 ; i
< nb_tracefile
; i
++) {
351 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
352 LttvTracefileContext
*, i
));
353 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
354 // tfcs->saved_position = 0;
355 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
356 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
357 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
358 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
363 //static LttTime time_zero = {0,0};
365 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
368 const LttTime
*t1
= (const LttTime
*)a
;
369 const LttTime
*t2
= (const LttTime
*)b
;
371 return ltt_time_compare(*t1
, *t2
);
374 static void free_usertrace_key(gpointer data
)
379 #define MAX_STRING_LEN 4096
382 state_load_saved_states(LttvTraceState
*tcs
)
385 GPtrArray
*quarktable
;
386 const char *trace_path
;
390 tcs
->has_precomputed_states
= FALSE
;
394 gchar buf
[MAX_STRING_LEN
];
397 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
398 strncpy(path
, trace_path
, PATH_MAX
-1);
399 count
= strnlen(trace_path
, PATH_MAX
-1);
400 // quarktable : open, test
401 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
402 fp
= fopen(path
, "r");
404 quarktable
= g_ptr_array_sized_new(4096);
406 /* Index 0 is null */
408 if(hdr
== EOF
) return;
409 g_assert(hdr
== HDR_QUARKS
);
413 if(hdr
== EOF
) break;
414 g_assert(hdr
== HDR_QUARK
);
415 g_ptr_array_set_size(quarktable
, q
+1);
418 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
419 if(buf
[i
] == '\0' || feof(fp
)) break;
422 len
= strnlen(buf
, MAX_STRING_LEN
-1);
423 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
424 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
430 // saved_states : open, test
431 strncpy(path
, trace_path
, PATH_MAX
-1);
432 count
= strnlen(trace_path
, PATH_MAX
-1);
433 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
434 fp
= fopen(path
, "r");
438 if(hdr
!= HDR_TRACE
) goto end
;
440 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
442 tcs
->has_precomputed_states
= TRUE
;
447 /* Free the quarktable */
448 for(i
=0; i
<quarktable
->len
; i
++) {
449 string
= g_ptr_array_index (quarktable
, i
);
452 g_ptr_array_free(quarktable
, TRUE
);
457 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
459 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
462 LttvTraceContext
*tc
;
466 LttvTracefileState
*tfcs
;
468 LttvAttributeValue v
;
470 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
471 init((LttvTracesetContext
*)self
, ts
);
473 nb_trace
= lttv_traceset_number(ts
);
474 for(i
= 0 ; i
< nb_trace
; i
++) {
475 tc
= self
->parent
.traces
[i
];
476 tcs
= LTTV_TRACE_STATE(tc
);
477 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
478 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
482 if(*(v
.v_uint
) == 1) {
483 create_name_tables(tcs
);
484 create_max_time(tcs
);
486 get_name_tables(tcs
);
489 nb_tracefile
= tc
->tracefiles
->len
;
490 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
491 nb_irq
= tcs
->nb_irqs
;
492 tcs
->processes
= NULL
;
493 tcs
->usertraces
= NULL
;
494 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
496 /* init cpu resource stuff */
497 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
498 for(j
= 0; j
<nb_cpu
; j
++) {
499 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
500 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
503 /* init irq resource stuff */
504 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
505 for(j
= 0; j
<nb_irq
; j
++) {
506 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
507 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
510 /* init soft irq stuff */
511 /* the kernel has a statically fixed max of 32 softirqs */
512 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
514 /* init trap stuff */
515 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
517 /* init bdev resource stuff */
518 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
520 restore_init_state(tcs
);
521 for(j
= 0 ; j
< nb_tracefile
; j
++) {
523 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
524 LttvTracefileContext
*, j
));
525 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
526 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
527 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
528 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
529 /* It's a Usertrace */
530 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
531 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
533 if(!usertrace_tree
) {
534 usertrace_tree
= g_tree_new_full(compare_usertraces
,
535 NULL
, free_usertrace_key
, NULL
);
536 g_hash_table_insert(tcs
->usertraces
,
537 (gpointer
)tid
, usertrace_tree
);
539 LttTime
*timestamp
= g_new(LttTime
, 1);
540 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
541 ltt_tracefile_creation(tfcs
->parent
.tf
));
542 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
546 /* See if the trace has saved states */
547 state_load_saved_states(tcs
);
552 fini(LttvTracesetState
*self
)
558 //LttvTracefileState *tfcs;
560 LttvAttributeValue v
;
562 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
563 for(i
= 0 ; i
< nb_trace
; i
++) {
564 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
565 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
568 g_assert(*(v
.v_uint
) != 0);
571 if(*(v
.v_uint
) == 0) {
572 free_name_tables(tcs
);
574 free_saved_state(tcs
);
576 g_free(tcs
->running_process
);
577 tcs
->running_process
= NULL
;
578 lttv_state_free_process_table(tcs
->processes
);
579 lttv_state_free_usertraces(tcs
->usertraces
);
580 tcs
->processes
= NULL
;
581 tcs
->usertraces
= NULL
;
583 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
584 fini((LttvTracesetContext
*)self
);
588 static LttvTracesetContext
*
589 new_traceset_context(LttvTracesetContext
*self
)
591 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
595 static LttvTraceContext
*
596 new_trace_context(LttvTracesetContext
*self
)
598 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
602 static LttvTracefileContext
*
603 new_tracefile_context(LttvTracesetContext
*self
)
605 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
609 /* Write the process state of the trace */
611 static void write_process_state(gpointer key
, gpointer value
,
614 LttvProcessState
*process
;
616 LttvExecutionState
*es
;
618 FILE *fp
= (FILE *)user_data
;
623 process
= (LttvProcessState
*)value
;
625 " <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",
626 process
, process
->pid
, process
->tgid
, process
->ppid
,
627 g_quark_to_string(process
->type
),
628 process
->creation_time
.tv_sec
,
629 process
->creation_time
.tv_nsec
,
630 process
->insertion_time
.tv_sec
,
631 process
->insertion_time
.tv_nsec
,
632 g_quark_to_string(process
->name
),
633 g_quark_to_string(process
->brand
),
634 process
->cpu
, process
->free_events
);
636 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
637 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
638 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
639 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
640 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
641 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
642 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
645 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
646 address
= g_array_index(process
->user_stack
, guint64
, i
);
647 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
651 if(process
->usertrace
) {
652 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
653 g_quark_to_string(process
->usertrace
->tracefile_name
),
654 process
->usertrace
->cpu
);
658 fprintf(fp
, " </PROCESS>\n");
662 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
664 guint i
, nb_tracefile
, nb_block
, offset
;
667 LttvTracefileState
*tfcs
;
671 LttEventPosition
*ep
;
675 ep
= ltt_event_position_new();
677 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
679 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
681 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
682 for(i
=0;i
<nb_cpus
;i
++) {
683 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
684 i
, self
->running_process
[i
]->pid
);
687 nb_tracefile
= self
->parent
.tracefiles
->len
;
689 for(i
= 0 ; i
< nb_tracefile
; i
++) {
691 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
692 LttvTracefileContext
*, i
));
693 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
694 tfcs
->parent
.timestamp
.tv_sec
,
695 tfcs
->parent
.timestamp
.tv_nsec
);
696 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
697 if(e
== NULL
) fprintf(fp
,"/>\n");
699 ltt_event_position(e
, ep
);
700 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
701 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
706 fprintf(fp
,"</PROCESS_STATE>\n");
710 static void write_process_state_raw(gpointer key
, gpointer value
,
713 LttvProcessState
*process
;
715 LttvExecutionState
*es
;
717 FILE *fp
= (FILE *)user_data
;
722 process
= (LttvProcessState
*)value
;
723 fputc(HDR_PROCESS
, fp
);
724 //fwrite(&header, sizeof(header), 1, fp);
725 //fprintf(fp, "%s", g_quark_to_string(process->type));
727 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
728 //fprintf(fp, "%s", g_quark_to_string(process->name));
730 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
731 //fprintf(fp, "%s", g_quark_to_string(process->brand));
733 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
734 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
735 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
736 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
737 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
738 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
739 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
740 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
744 " <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",
745 process
, process
->pid
, process
->tgid
, process
->ppid
,
746 g_quark_to_string(process
->type
),
747 process
->creation_time
.tv_sec
,
748 process
->creation_time
.tv_nsec
,
749 process
->insertion_time
.tv_sec
,
750 process
->insertion_time
.tv_nsec
,
751 g_quark_to_string(process
->name
),
752 g_quark_to_string(process
->brand
),
756 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
757 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
760 //fprintf(fp, "%s", g_quark_to_string(es->t));
762 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
763 //fprintf(fp, "%s", g_quark_to_string(es->n));
765 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
766 //fprintf(fp, "%s", g_quark_to_string(es->s));
768 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
769 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
770 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
771 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
773 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
774 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
775 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
776 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
777 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
781 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
782 address
= g_array_index(process
->user_stack
, guint64
, i
);
783 fputc(HDR_USER_STACK
, fp
);
784 fwrite(&address
, sizeof(address
), 1, fp
);
786 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
791 if(process
->usertrace
) {
792 fputc(HDR_USERTRACE
, fp
);
793 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
795 fwrite(&process
->usertrace
->tracefile_name
,
796 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
797 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
799 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
800 g_quark_to_string(process
->usertrace
->tracefile_name
),
801 process
->usertrace
->cpu
);
808 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
810 guint i
, nb_tracefile
, nb_block
, offset
;
813 LttvTracefileState
*tfcs
;
817 LttEventPosition
*ep
;
821 ep
= ltt_event_position_new();
823 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
824 fputc(HDR_PROCESS_STATE
, fp
);
825 fwrite(&t
, sizeof(t
), 1, fp
);
827 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
829 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
830 for(i
=0;i
<nb_cpus
;i
++) {
832 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
833 fwrite(&self
->running_process
[i
]->pid
,
834 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
835 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
836 // i, self->running_process[i]->pid);
839 nb_tracefile
= self
->parent
.tracefiles
->len
;
841 for(i
= 0 ; i
< nb_tracefile
; i
++) {
843 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
844 LttvTracefileContext
*, i
));
845 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
846 // tfcs->parent.timestamp.tv_sec,
847 // tfcs->parent.timestamp.tv_nsec);
848 fputc(HDR_TRACEFILE
, fp
);
849 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
850 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
851 * position following : end of trace */
852 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
854 ltt_event_position(e
, ep
);
855 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
856 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
858 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
859 fwrite(&offset
, sizeof(offset
), 1, fp
);
860 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
867 /* Read process state from a file */
869 /* Called because a HDR_PROCESS was found */
870 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
871 GPtrArray
*quarktable
)
873 LttvExecutionState
*es
;
874 LttvProcessState
*process
, *parent_process
;
875 LttvProcessState tmp
;
880 /* TODO : check return value */
881 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
882 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
883 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
884 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
885 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
886 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
887 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
888 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
889 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
890 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
893 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
895 /* We must link to the parent */
896 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
898 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
899 if(process
== NULL
) {
900 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
902 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
906 process
->insertion_time
= tmp
.insertion_time
;
907 process
->creation_time
= tmp
.creation_time
;
908 process
->type
= g_quark_from_string(
909 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
910 process
->tgid
= tmp
.tgid
;
911 process
->ppid
= tmp
.ppid
;
912 process
->brand
= g_quark_from_string(
913 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
915 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
916 process
->free_events
= tmp
.free_events
;
919 if(feof(fp
) || ferror(fp
)) goto end_loop
;
921 gint hdr
= fgetc(fp
);
922 if(hdr
== EOF
) goto end_loop
;
926 process
->execution_stack
=
927 g_array_set_size(process
->execution_stack
,
928 process
->execution_stack
->len
+ 1);
929 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
930 process
->execution_stack
->len
-1);
933 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
934 es
->t
= g_quark_from_string(
935 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
936 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
937 es
->n
= g_quark_from_string(
938 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
939 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
940 es
->s
= g_quark_from_string(
941 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
942 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
943 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
944 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
947 process
->user_stack
= g_array_set_size(process
->user_stack
,
948 process
->user_stack
->len
+ 1);
949 address
= &g_array_index(process
->user_stack
, guint64
,
950 process
->user_stack
->len
-1);
951 fread(address
, sizeof(address
), 1, fp
);
952 process
->current_function
= *address
;
955 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
956 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
968 /* Called because a HDR_PROCESS_STATE was found */
969 /* Append a saved state to the trace states */
970 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
972 guint i
, nb_tracefile
, nb_block
, offset
;
974 LttvTracefileState
*tfcs
;
976 LttEventPosition
*ep
;
984 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
986 LttvAttributeValue value
;
987 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
988 ep
= ltt_event_position_new();
990 restore_init_state(self
);
992 fread(&t
, sizeof(t
), 1, fp
);
995 if(feof(fp
) || ferror(fp
)) goto end_loop
;
997 if(hdr
== EOF
) goto end_loop
;
1001 /* Call read_process_state_raw */
1002 read_process_state_raw(self
, fp
, quarktable
);
1010 case HDR_USER_STACK
:
1012 case HDR_PROCESS_STATE
:
1018 g_error("Error while parsing saved state file : unknown data header %d",
1024 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1025 for(i
=0;i
<nb_cpus
;i
++) {
1028 g_assert(hdr
== HDR_CPU
);
1029 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1030 g_assert(i
== cpu_num
);
1031 fread(&self
->running_process
[i
]->pid
,
1032 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1035 nb_tracefile
= self
->parent
.tracefiles
->len
;
1037 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1039 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1040 LttvTracefileContext
*, i
));
1041 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1042 // tfcs->parent.timestamp.tv_sec,
1043 // tfcs->parent.timestamp.tv_nsec);
1044 g_tree_remove(pqueue
, &tfcs
->parent
);
1046 g_assert(hdr
== HDR_TRACEFILE
);
1047 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1048 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1049 * position following : end of trace */
1050 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1051 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1052 fread(&offset
, sizeof(offset
), 1, fp
);
1053 fread(&tsc
, sizeof(tsc
), 1, fp
);
1054 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1055 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1057 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1062 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1063 LTTV_STATE_SAVED_STATES
);
1064 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1065 value
= lttv_attribute_add(saved_states_tree
,
1066 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1067 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1068 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1069 *(value
.v_time
) = t
;
1070 lttv_state_save(self
, saved_state_tree
);
1071 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1074 *(self
->max_time_state_recomputed_in_seek
) = t
;
1078 /* Called when a HDR_TRACE is found */
1079 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1080 GPtrArray
*quarktable
)
1085 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1087 if(hdr
== EOF
) goto end_loop
;
1090 case HDR_PROCESS_STATE
:
1091 /* Call read_process_state_raw */
1092 lttv_state_read_raw(tcs
, fp
, quarktable
);
1100 case HDR_USER_STACK
:
1104 g_error("Error while parsing saved state file :"
1105 " unexpected data header %d",
1109 g_error("Error while parsing saved state file : unknown data header %d",
1114 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1115 restore_init_state(tcs
);
1116 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1122 /* Copy each process from an existing hash table to a new one */
1124 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1126 LttvProcessState
*process
, *new_process
;
1128 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1132 process
= (LttvProcessState
*)value
;
1133 new_process
= g_new(LttvProcessState
, 1);
1134 *new_process
= *process
;
1135 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1136 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1137 new_process
->execution_stack
=
1138 g_array_set_size(new_process
->execution_stack
,
1139 process
->execution_stack
->len
);
1140 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1141 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1142 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1144 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1145 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1146 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1147 sizeof(guint64
), 0);
1148 new_process
->user_stack
=
1149 g_array_set_size(new_process
->user_stack
,
1150 process
->user_stack
->len
);
1151 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1152 g_array_index(new_process
->user_stack
, guint64
, i
) =
1153 g_array_index(process
->user_stack
, guint64
, i
);
1155 new_process
->current_function
= process
->current_function
;
1156 g_hash_table_insert(new_processes
, new_process
, new_process
);
1160 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1162 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1164 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1165 return new_processes
;
1168 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1171 LttvCPUState
*retval
;
1173 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1175 for(i
=0; i
<n
; i
++) {
1176 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1177 retval
[i
].last_irq
= states
[i
].last_irq
;
1178 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1179 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1180 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1187 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1191 for(i
=0; i
<n
; i
++) {
1192 g_array_free(states
[i
].mode_stack
, TRUE
);
1198 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1201 LttvIRQState
*retval
;
1203 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1205 for(i
=0; i
<n
; i
++) {
1206 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1207 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1208 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1209 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1216 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1220 for(i
=0; i
<n
; i
++) {
1221 g_array_free(states
[i
].mode_stack
, TRUE
);
1227 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1230 LttvSoftIRQState
*retval
;
1232 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1234 for(i
=0; i
<n
; i
++) {
1235 retval
[i
].running
= states
[i
].running
;
1241 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1246 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1249 LttvTrapState
*retval
;
1251 retval
= g_malloc(n
*sizeof(LttvTrapState
));
1253 for(i
=0; i
<n
; i
++) {
1254 retval
[i
].running
= states
[i
].running
;
1260 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1265 /* bdevstate stuff */
1267 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1269 gint devcode_gint
= devcode
;
1270 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1272 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1273 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1275 gint
* key
= g_malloc(sizeof(gint
));
1277 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1285 static LttvBdevState
*bdevstate_new(void)
1287 LttvBdevState
*retval
;
1288 retval
= g_malloc(sizeof(LttvBdevState
));
1289 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1294 static void bdevstate_free(LttvBdevState
*bds
)
1296 g_array_free(bds
->mode_stack
, TRUE
);
1300 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1302 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1304 bdevstate_free(bds
);
1307 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1309 LttvBdevState
*retval
;
1311 retval
= bdevstate_new();
1312 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1317 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1319 //GHashTable *ht = (GHashTable *)u;
1320 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1321 LttvBdevState
*newbds
;
1323 newbds
= bdevstate_copy(bds
);
1325 g_hash_table_insert(u
, k
, newbds
);
1328 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1332 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1334 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1339 /* Free a hashtable and the LttvBdevState structures its values
1342 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1344 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1345 g_hash_table_destroy(ht
);
1348 /* The saved state for each trace contains a member "processes", which
1349 stores a copy of the process table, and a member "tracefiles" with
1350 one entry per tracefile. Each tracefile has a "process" member pointing
1351 to the current process and a "position" member storing the tracefile
1352 position (needed to seek to the current "next" event. */
1354 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1356 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1358 LttvTracefileState
*tfcs
;
1360 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1362 guint
*running_process
;
1364 LttvAttributeValue value
;
1366 LttEventPosition
*ep
;
1368 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1369 LTTV_STATE_TRACEFILES
);
1371 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1373 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1375 /* Add the currently running processes array */
1376 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1377 running_process
= g_new(guint
, nb_cpus
);
1378 for(i
=0;i
<nb_cpus
;i
++) {
1379 running_process
[i
] = self
->running_process
[i
]->pid
;
1381 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1383 *(value
.v_pointer
) = running_process
;
1385 g_info("State save");
1387 nb_tracefile
= self
->parent
.tracefiles
->len
;
1389 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1391 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1392 LttvTracefileContext
*, i
));
1393 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1394 value
= lttv_attribute_add(tracefiles_tree
, i
,
1396 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1398 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1400 *(value
.v_uint
) = tfcs
->process
->pid
;
1402 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1404 /* Only save the position if the tfs has not infinite time. */
1405 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1406 // && current_tfcs != tfcs) {
1407 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1408 *(value
.v_pointer
) = NULL
;
1410 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1411 ep
= ltt_event_position_new();
1412 ltt_event_position(e
, ep
);
1413 *(value
.v_pointer
) = ep
;
1415 guint nb_block
, offset
;
1418 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1419 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1421 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1425 /* save the cpu state */
1427 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1429 *(value
.v_uint
) = nb_cpus
;
1431 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1433 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1436 /* save the irq state */
1437 nb_irqs
= self
->nb_irqs
;
1439 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1441 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1444 /* save the soft irq state */
1445 nb_soft_irqs
= self
->nb_soft_irqs
;
1447 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1449 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1452 /* save the trap state */
1453 nb_traps
= self
->nb_traps
;
1455 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1457 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1460 /* save the blkdev states */
1461 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1463 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1467 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1469 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1471 LttvTracefileState
*tfcs
;
1473 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1475 guint
*running_process
;
1477 LttvAttributeType type
;
1479 LttvAttributeValue value
;
1481 LttvAttributeName name
;
1485 LttEventPosition
*ep
;
1487 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1489 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1490 LTTV_STATE_TRACEFILES
);
1492 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1494 g_assert(type
== LTTV_POINTER
);
1495 lttv_state_free_process_table(self
->processes
);
1496 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1498 /* Add the currently running processes array */
1499 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1500 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1502 g_assert(type
== LTTV_POINTER
);
1503 running_process
= *(value
.v_pointer
);
1504 for(i
=0;i
<nb_cpus
;i
++) {
1505 pid
= running_process
[i
];
1506 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1507 g_assert(self
->running_process
[i
] != NULL
);
1510 nb_tracefile
= self
->parent
.tracefiles
->len
;
1512 //g_tree_destroy(tsc->pqueue);
1513 //tsc->pqueue = g_tree_new(compare_tracefile);
1515 /* restore cpu resource states */
1516 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1517 g_assert(type
== LTTV_POINTER
);
1518 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1519 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1521 /* restore irq resource states */
1522 nb_irqs
= self
->nb_irqs
;
1523 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1524 g_assert(type
== LTTV_POINTER
);
1525 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1526 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1528 /* restore soft irq resource states */
1529 nb_soft_irqs
= self
->nb_soft_irqs
;
1530 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1531 g_assert(type
== LTTV_POINTER
);
1532 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1533 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1535 /* restore trap resource states */
1536 nb_traps
= self
->nb_traps
;
1537 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1538 g_assert(type
== LTTV_POINTER
);
1539 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1540 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1542 /* restore the blkdev states */
1543 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1544 g_assert(type
== LTTV_POINTER
);
1545 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1546 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1548 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1550 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1551 LttvTracefileContext
*, i
));
1552 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1553 g_assert(type
== LTTV_GOBJECT
);
1554 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1556 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1558 g_assert(type
== LTTV_UINT
);
1559 pid
= *(value
.v_uint
);
1560 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1562 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1564 g_assert(type
== LTTV_POINTER
);
1565 //g_assert(*(value.v_pointer) != NULL);
1566 ep
= *(value
.v_pointer
);
1567 g_assert(tfcs
->parent
.t_context
!= NULL
);
1569 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1571 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1572 g_tree_remove(tsc
->pqueue
, tfc
);
1575 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1576 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1577 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1578 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1579 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1581 tfc
->timestamp
= ltt_time_infinite
;
1587 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1589 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1591 LttvTracefileState
*tfcs
;
1593 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1595 guint
*running_process
;
1597 LttvAttributeType type
;
1599 LttvAttributeValue value
;
1601 LttvAttributeName name
;
1605 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1606 LTTV_STATE_TRACEFILES
);
1607 g_object_ref(G_OBJECT(tracefiles_tree
));
1608 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1610 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1612 g_assert(type
== LTTV_POINTER
);
1613 lttv_state_free_process_table(*(value
.v_pointer
));
1614 *(value
.v_pointer
) = NULL
;
1615 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1617 /* Free running processes array */
1618 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1620 g_assert(type
== LTTV_POINTER
);
1621 running_process
= *(value
.v_pointer
);
1622 g_free(running_process
);
1624 /* free cpu resource states */
1625 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1626 g_assert(type
== LTTV_UINT
);
1627 nb_cpus
= *value
.v_uint
;
1628 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1629 g_assert(type
== LTTV_POINTER
);
1630 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1632 /* free irq resource states */
1633 nb_irqs
= self
->nb_irqs
;
1634 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1635 g_assert(type
== LTTV_POINTER
);
1636 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1638 /* free the blkdev states */
1639 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1640 g_assert(type
== LTTV_POINTER
);
1641 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1643 nb_tracefile
= self
->parent
.tracefiles
->len
;
1645 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1647 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1648 LttvTracefileContext
*, i
));
1649 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1650 g_assert(type
== LTTV_GOBJECT
);
1651 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1653 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1655 g_assert(type
== LTTV_POINTER
);
1656 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1658 g_object_unref(G_OBJECT(tracefiles_tree
));
1662 static void free_saved_state(LttvTraceState
*self
)
1666 LttvAttributeType type
;
1668 LttvAttributeValue value
;
1670 LttvAttributeName name
;
1674 LttvAttribute
*saved_states
;
1676 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1677 LTTV_STATE_SAVED_STATES
);
1679 nb
= lttv_attribute_get_number(saved_states
);
1680 for(i
= 0 ; i
< nb
; i
++) {
1681 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1682 g_assert(type
== LTTV_GOBJECT
);
1683 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1686 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1691 create_max_time(LttvTraceState
*tcs
)
1693 LttvAttributeValue v
;
1695 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1697 g_assert(*(v
.v_pointer
) == NULL
);
1698 *(v
.v_pointer
) = g_new(LttTime
,1);
1699 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1704 get_max_time(LttvTraceState
*tcs
)
1706 LttvAttributeValue v
;
1708 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1710 g_assert(*(v
.v_pointer
) != NULL
);
1711 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1716 free_max_time(LttvTraceState
*tcs
)
1718 LttvAttributeValue v
;
1720 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1722 g_free(*(v
.v_pointer
));
1723 *(v
.v_pointer
) = NULL
;
1727 typedef struct _LttvNameTables
{
1728 // FIXME GQuark *eventtype_names;
1729 GQuark
*syscall_names
;
1735 GQuark
*soft_irq_names
;
1741 create_name_tables(LttvTraceState
*tcs
)
1745 GString
*fe_name
= g_string_new("");
1747 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1749 LttvAttributeValue v
;
1753 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1755 g_assert(*(v
.v_pointer
) == NULL
);
1756 *(v
.v_pointer
) = name_tables
;
1758 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1760 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1761 LTT_FACILITY_KERNEL_ARCH
,
1762 LTT_EVENT_SYSCALL_ENTRY
,
1763 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1764 NULL
, NULL
, &hooks
)) {
1766 // th = lttv_trace_hook_get_first(&th);
1768 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1769 // nb = ltt_type_element_number(t);
1771 // name_tables->syscall_names = g_new(GQuark, nb);
1772 // name_tables->nb_syscalls = nb;
1774 // for(i = 0 ; i < nb ; i++) {
1775 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1776 // if(!name_tables->syscall_names[i]) {
1777 // GString *string = g_string_new("");
1778 // g_string_printf(string, "syscall %u", i);
1779 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1780 // g_string_free(string, TRUE);
1784 name_tables
->nb_syscalls
= 256;
1785 name_tables
->syscall_names
= g_new(GQuark
, 256);
1786 for(i
= 0 ; i
< 256 ; i
++) {
1787 g_string_printf(fe_name
, "syscall %d", i
);
1788 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1791 name_tables
->syscall_names
= NULL
;
1792 name_tables
->nb_syscalls
= 0;
1794 lttv_trace_hook_remove_all(&hooks
);
1796 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1797 LTT_FACILITY_KERNEL_ARCH
,
1798 LTT_EVENT_TRAP_ENTRY
,
1799 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1800 NULL
, NULL
, &hooks
)) {
1802 // th = lttv_trace_hook_get_first(&th);
1804 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1805 // //nb = ltt_type_element_number(t);
1807 // name_tables->trap_names = g_new(GQuark, nb);
1808 // for(i = 0 ; i < nb ; i++) {
1809 // name_tables->trap_names[i] = g_quark_from_string(
1810 // ltt_enum_string_get(t, i));
1813 name_tables
->nb_traps
= 256;
1814 name_tables
->trap_names
= g_new(GQuark
, 256);
1815 for(i
= 0 ; i
< 256 ; i
++) {
1816 g_string_printf(fe_name
, "trap %d", i
);
1817 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1820 name_tables
->trap_names
= NULL
;
1821 name_tables
->nb_traps
= 0;
1823 lttv_trace_hook_remove_all(&hooks
);
1825 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1826 LTT_FACILITY_KERNEL
,
1827 LTT_EVENT_IRQ_ENTRY
,
1828 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1829 NULL
, NULL
, &hooks
)) {
1832 name_tables->irq_names = g_new(GQuark, nb);
1833 for(i = 0 ; i < nb ; i++) {
1834 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1838 name_tables
->nb_irqs
= 256;
1839 name_tables
->irq_names
= g_new(GQuark
, 256);
1840 for(i
= 0 ; i
< 256 ; i
++) {
1841 g_string_printf(fe_name
, "irq %d", i
);
1842 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1845 name_tables
->nb_irqs
= 0;
1846 name_tables
->irq_names
= NULL
;
1848 lttv_trace_hook_remove_all(&hooks
);
1850 name_tables->soft_irq_names = g_new(GQuark, nb);
1851 for(i = 0 ; i < nb ; i++) {
1852 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1856 /* the kernel is limited to 32 statically defined softirqs */
1857 name_tables
->nb_softirqs
= 32;
1858 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1859 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1860 g_string_printf(fe_name
, "softirq %d", i
);
1861 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1863 g_array_free(hooks
, TRUE
);
1865 g_string_free(fe_name
, TRUE
);
1870 get_name_tables(LttvTraceState
*tcs
)
1872 LttvNameTables
*name_tables
;
1874 LttvAttributeValue v
;
1876 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1878 g_assert(*(v
.v_pointer
) != NULL
);
1879 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1880 //tcs->eventtype_names = name_tables->eventtype_names;
1881 tcs
->syscall_names
= name_tables
->syscall_names
;
1882 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1883 tcs
->trap_names
= name_tables
->trap_names
;
1884 tcs
->nb_traps
= name_tables
->nb_traps
;
1885 tcs
->irq_names
= name_tables
->irq_names
;
1886 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1887 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1888 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1893 free_name_tables(LttvTraceState
*tcs
)
1895 LttvNameTables
*name_tables
;
1897 LttvAttributeValue v
;
1899 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1901 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1902 *(v
.v_pointer
) = NULL
;
1904 // g_free(name_tables->eventtype_names);
1905 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1906 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1907 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1908 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1909 if(name_tables
) g_free(name_tables
);
1912 #ifdef HASH_TABLE_DEBUG
1914 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1916 LttvProcessState
*process
= (LttvProcessState
*)value
;
1918 /* Test for process corruption */
1919 guint stack_len
= process
->execution_stack
->len
;
1922 static void hash_table_check(GHashTable
*table
)
1924 g_hash_table_foreach(table
, test_process
, NULL
);
1930 /* clears the stack and sets the state passed as argument */
1931 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1933 g_array_set_size(cpust
->mode_stack
, 1);
1934 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1937 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1939 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1940 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1943 static void cpu_pop_mode(LttvCPUState
*cpust
)
1945 if(cpust
->mode_stack
->len
<= 1)
1946 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1948 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1951 /* clears the stack and sets the state passed as argument */
1952 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1954 g_array_set_size(bdevst
->mode_stack
, 1);
1955 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1958 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1960 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1961 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1964 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1966 if(bdevst
->mode_stack
->len
<= 1)
1967 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1969 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1972 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1974 g_array_set_size(irqst
->mode_stack
, 1);
1975 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1978 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1980 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1981 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1984 static void irq_pop_mode(LttvIRQState
*irqst
)
1986 if(irqst
->mode_stack
->len
<= 1)
1987 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1989 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1992 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1995 LttvExecutionState
*es
;
1997 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1998 guint cpu
= tfs
->cpu
;
2000 #ifdef HASH_TABLE_DEBUG
2001 hash_table_check(ts
->processes
);
2003 LttvProcessState
*process
= ts
->running_process
[cpu
];
2005 guint depth
= process
->execution_stack
->len
;
2007 process
->execution_stack
=
2008 g_array_set_size(process
->execution_stack
, depth
+ 1);
2011 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2013 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2016 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2017 es
->cum_cpu_time
= ltt_time_zero
;
2018 es
->s
= process
->state
->s
;
2019 process
->state
= es
;
2023 * return 1 when empty, else 0 */
2024 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2025 LttvTracefileState
*tfs
)
2027 guint depth
= process
->execution_stack
->len
;
2033 process
->execution_stack
=
2034 g_array_set_size(process
->execution_stack
, depth
- 1);
2035 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2037 process
->state
->change
= tfs
->parent
.timestamp
;
2042 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2044 guint cpu
= tfs
->cpu
;
2045 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2046 LttvProcessState
*process
= ts
->running_process
[cpu
];
2048 guint depth
= process
->execution_stack
->len
;
2050 if(process
->state
->t
!= t
){
2051 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2052 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2053 g_info("process state has %s when pop_int is %s\n",
2054 g_quark_to_string(process
->state
->t
),
2055 g_quark_to_string(t
));
2056 g_info("{ %u, %u, %s, %s, %s }\n",
2059 g_quark_to_string(process
->name
),
2060 g_quark_to_string(process
->brand
),
2061 g_quark_to_string(process
->state
->s
));
2066 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2067 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2071 process
->execution_stack
=
2072 g_array_set_size(process
->execution_stack
, depth
- 1);
2073 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2075 process
->state
->change
= tfs
->parent
.timestamp
;
2078 struct search_result
{
2079 const LttTime
*time
; /* Requested time */
2080 LttTime
*best
; /* Best result */
2083 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2085 const LttTime
*elem_time
= (const LttTime
*)a
;
2086 /* Explicit non const cast */
2087 struct search_result
*res
= (struct search_result
*)b
;
2089 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2090 /* The usertrace was created before the schedchange */
2091 /* Get larger keys */
2093 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2094 /* The usertrace was created after the schedchange time */
2095 /* Get smaller keys */
2097 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2098 res
->best
= (LttTime
*)elem_time
;
2101 res
->best
= (LttTime
*)elem_time
;
2108 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2109 guint pid
, const LttTime
*timestamp
)
2111 LttvTracefileState
*tfs
= NULL
;
2112 struct search_result res
;
2113 /* Find the usertrace associated with a pid and time interval.
2114 * Search in the usertraces by PID (within a hash) and then, for each
2115 * corresponding element of the array, find the first one with creation
2116 * timestamp the lowest, but higher or equal to "timestamp". */
2117 res
.time
= timestamp
;
2119 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2120 if(usertrace_tree
) {
2121 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2123 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2131 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2132 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2134 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2136 LttvExecutionState
*es
;
2141 process
->tgid
= tgid
;
2143 process
->name
= name
;
2144 process
->brand
= LTTV_STATE_UNBRANDED
;
2145 //process->last_cpu = tfs->cpu_name;
2146 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2147 process
->type
= LTTV_STATE_USER_THREAD
;
2148 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2149 process
->current_function
= 0; //function 0x0 by default.
2151 g_info("Process %u, core %p", process
->pid
, process
);
2152 g_hash_table_insert(tcs
->processes
, process
, process
);
2155 process
->ppid
= parent
->pid
;
2156 process
->creation_time
= *timestamp
;
2159 /* No parent. This process exists but we are missing all information about
2160 its creation. The birth time is set to zero but we remember the time of
2165 process
->creation_time
= ltt_time_zero
;
2168 process
->insertion_time
= *timestamp
;
2169 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2170 process
->creation_time
.tv_nsec
);
2171 process
->pid_time
= g_quark_from_string(buffer
);
2173 process
->free_events
= 0;
2174 //process->last_cpu = tfs->cpu_name;
2175 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2176 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2177 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2178 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2179 es
= process
->state
= &g_array_index(process
->execution_stack
,
2180 LttvExecutionState
, 0);
2181 es
->t
= LTTV_STATE_USER_MODE
;
2182 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2183 es
->entry
= *timestamp
;
2184 //g_assert(timestamp->tv_sec != 0);
2185 es
->change
= *timestamp
;
2186 es
->cum_cpu_time
= ltt_time_zero
;
2187 es
->s
= LTTV_STATE_RUN
;
2189 es
= process
->state
= &g_array_index(process
->execution_stack
,
2190 LttvExecutionState
, 1);
2191 es
->t
= LTTV_STATE_SYSCALL
;
2192 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2193 es
->entry
= *timestamp
;
2194 //g_assert(timestamp->tv_sec != 0);
2195 es
->change
= *timestamp
;
2196 es
->cum_cpu_time
= ltt_time_zero
;
2197 es
->s
= LTTV_STATE_WAIT_FORK
;
2199 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2200 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2201 sizeof(guint64
), 0);
2206 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2209 LttvProcessState key
;
2210 LttvProcessState
*process
;
2214 process
= g_hash_table_lookup(ts
->processes
, &key
);
2219 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2220 const LttTime
*timestamp
)
2222 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2223 LttvExecutionState
*es
;
2225 /* Put ltt_time_zero creation time for unexisting processes */
2226 if(unlikely(process
== NULL
)) {
2227 process
= lttv_state_create_process(ts
,
2228 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2229 /* We are not sure is it's a kernel thread or normal thread, put the
2230 * bottom stack state to unknown */
2231 process
->execution_stack
=
2232 g_array_set_size(process
->execution_stack
, 1);
2233 process
->state
= es
=
2234 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2235 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2236 es
->s
= LTTV_STATE_UNNAMED
;
2241 /* FIXME : this function should be called when we receive an event telling that
2242 * release_task has been called in the kernel. In happens generally when
2243 * the parent waits for its child terminaison, but may also happen in special
2244 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2245 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2246 * of a killed thread group, but isn't the leader.
2248 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2250 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2251 LttvProcessState key
;
2253 /* Wait for both schedule with exit dead and process free to happen.
2254 * They can happen in any order. */
2255 if (++(process
->free_events
) < 2)
2258 key
.pid
= process
->pid
;
2259 key
.cpu
= process
->cpu
;
2260 g_hash_table_remove(ts
->processes
, &key
);
2261 g_array_free(process
->execution_stack
, TRUE
);
2262 g_array_free(process
->user_stack
, TRUE
);
2268 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2270 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2271 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2276 static void lttv_state_free_process_table(GHashTable
*processes
)
2278 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2279 g_hash_table_destroy(processes
);
2283 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2285 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2287 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2288 LttvProcessState
*process
= ts
->running_process
[cpu
];
2289 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2290 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2291 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2293 LttvExecutionSubmode submode
;
2295 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2296 guint syscall
= ltt_event_get_unsigned(e
, f
);
2298 if(syscall
< nb_syscalls
) {
2299 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2302 /* Fixup an incomplete syscall table */
2303 GString
*string
= g_string_new("");
2304 g_string_printf(string
, "syscall %u", syscall
);
2305 submode
= g_quark_from_string(string
->str
);
2306 g_string_free(string
, TRUE
);
2308 /* There can be no system call from PID 0 : unknown state */
2309 if(process
->pid
!= 0)
2310 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2315 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2317 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2319 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2320 LttvProcessState
*process
= ts
->running_process
[cpu
];
2322 /* There can be no system call from PID 0 : unknown state */
2323 if(process
->pid
!= 0)
2324 pop_state(s
, LTTV_STATE_SYSCALL
);
2329 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2331 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2332 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2333 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2334 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2335 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2337 LttvExecutionSubmode submode
;
2339 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2340 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2342 if(trap
< nb_traps
) {
2343 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2345 /* Fixup an incomplete trap table */
2346 GString
*string
= g_string_new("");
2347 g_string_printf(string
, "trap %llu", trap
);
2348 submode
= g_quark_from_string(string
->str
);
2349 g_string_free(string
, TRUE
);
2352 push_state(s
, LTTV_STATE_TRAP
, submode
);
2354 /* update cpu status */
2355 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2357 /* update trap status */
2358 s
->cpu_state
->last_trap
= trap
;
2359 ts
->trap_states
[trap
].running
++;
2364 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2366 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2367 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2368 guint trap
= s
->cpu_state
->last_trap
;
2370 pop_state(s
, LTTV_STATE_TRAP
);
2372 /* update cpu status */
2373 cpu_pop_mode(s
->cpu_state
);
2375 /* update trap status */
2376 if(ts
->trap_states
[trap
].running
)
2377 ts
->trap_states
[trap
].running
--;
2382 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2384 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2385 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2386 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2387 //guint8 ev_id = ltt_event_eventtype_id(e);
2388 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2389 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2391 LttvExecutionSubmode submode
;
2392 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2393 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2396 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2398 /* Fixup an incomplete irq table */
2399 GString
*string
= g_string_new("");
2400 g_string_printf(string
, "irq %llu", irq
);
2401 submode
= g_quark_from_string(string
->str
);
2402 g_string_free(string
, TRUE
);
2405 /* Do something with the info about being in user or system mode when int? */
2406 push_state(s
, LTTV_STATE_IRQ
, submode
);
2408 /* update cpu status */
2409 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2411 /* update irq status */
2412 s
->cpu_state
->last_irq
= irq
;
2413 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2418 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2420 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2421 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2422 guint softirq
= s
->cpu_state
->last_soft_irq
;
2424 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2426 /* update softirq status */
2427 if(ts
->soft_irq_states
[softirq
].running
)
2428 ts
->soft_irq_states
[softirq
].running
--;
2430 /* update cpu status */
2431 cpu_pop_mode(s
->cpu_state
);
2436 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2438 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2439 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2441 pop_state(s
, LTTV_STATE_IRQ
);
2443 /* update cpu status */
2444 cpu_pop_mode(s
->cpu_state
);
2446 /* update irq status */
2447 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2452 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2454 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2455 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2456 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2457 //guint8 ev_id = ltt_event_eventtype_id(e);
2458 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2459 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2461 LttvExecutionSubmode submode
;
2462 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2463 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2465 if(softirq
< nb_softirqs
) {
2466 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2468 /* Fixup an incomplete irq table */
2469 GString
*string
= g_string_new("");
2470 g_string_printf(string
, "softirq %llu", softirq
);
2471 submode
= g_quark_from_string(string
->str
);
2472 g_string_free(string
, TRUE
);
2475 /* Do something with the info about being in user or system mode when int? */
2476 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2478 /* update cpu status */
2479 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2481 /* update softirq status */
2482 s
->cpu_state
->last_soft_irq
= softirq
;
2483 ts
->soft_irq_states
[softirq
].running
++;
2488 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2490 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2491 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2492 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2493 //guint8 ev_id = ltt_event_eventtype_id(e);
2494 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2496 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2497 lttv_trace_get_hook_field(th
, 0)));
2498 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2500 ts
->irq_names
[irq
] = action
;
2506 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2508 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2509 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2510 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2511 //guint8 ev_id = ltt_event_eventtype_id(e);
2512 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2514 guint major
= ltt_event_get_long_unsigned(e
,
2515 lttv_trace_get_hook_field(th
, 0));
2516 guint minor
= ltt_event_get_long_unsigned(e
,
2517 lttv_trace_get_hook_field(th
, 1));
2518 guint oper
= ltt_event_get_long_unsigned(e
,
2519 lttv_trace_get_hook_field(th
, 2));
2520 guint16 devcode
= MKDEV(major
,minor
);
2522 /* have we seen this block device before? */
2523 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2526 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2528 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2533 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2535 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2536 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2537 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2538 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2540 guint major
= ltt_event_get_long_unsigned(e
,
2541 lttv_trace_get_hook_field(th
, 0));
2542 guint minor
= ltt_event_get_long_unsigned(e
,
2543 lttv_trace_get_hook_field(th
, 1));
2544 //guint oper = ltt_event_get_long_unsigned(e,
2545 // lttv_trace_get_hook_field(th, 2));
2546 guint16 devcode
= MKDEV(major
,minor
);
2548 /* have we seen this block device before? */
2549 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2551 /* update block device */
2552 bdev_pop_mode(bdev
);
2557 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2561 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2562 guint cpu
= tfs
->cpu
;
2563 LttvProcessState
*process
= ts
->running_process
[cpu
];
2565 guint depth
= process
->user_stack
->len
;
2567 process
->user_stack
=
2568 g_array_set_size(process
->user_stack
, depth
+ 1);
2570 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2571 *new_func
= funcptr
;
2572 process
->current_function
= funcptr
;
2575 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2577 guint cpu
= tfs
->cpu
;
2578 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2579 LttvProcessState
*process
= ts
->running_process
[cpu
];
2581 if(process
->current_function
!= funcptr
){
2582 g_info("Different functions (%lu.%09lu): ignore it\n",
2583 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2584 g_info("process state has %llu when pop_function is %llu\n",
2585 process
->current_function
, funcptr
);
2586 g_info("{ %u, %u, %s, %s, %s }\n",
2589 g_quark_to_string(process
->name
),
2590 g_quark_to_string(process
->brand
),
2591 g_quark_to_string(process
->state
->s
));
2594 guint depth
= process
->user_stack
->len
;
2597 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2598 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2602 process
->user_stack
=
2603 g_array_set_size(process
->user_stack
, depth
- 1);
2604 process
->current_function
=
2605 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2609 static gboolean
function_entry(void *hook_data
, void *call_data
)
2611 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2612 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2613 //guint8 ev_id = ltt_event_eventtype_id(e);
2614 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2615 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2616 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2618 push_function(s
, funcptr
);
2622 static gboolean
function_exit(void *hook_data
, void *call_data
)
2624 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2625 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2626 //guint8 ev_id = ltt_event_eventtype_id(e);
2627 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2628 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2629 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2631 pop_function(s
, funcptr
);
2635 static gboolean
dump_syscall(void *hook_data
, void *call_data
)
2637 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2638 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2639 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2640 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2645 id
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2646 address
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2647 symbol
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2649 if (ts
->nb_syscalls
< id
) {
2650 GQuark
*old_names
= ts
->syscall_names
;
2651 guint new_nb_syscalls
= max(id
+ 1, ts
->nb_syscalls
* 2);
2653 GString
*fe_name
= g_string_new("");
2654 ts
->syscall_names
= g_new(GQuark
, new_nb_syscalls
);
2655 memcpy(ts
->syscall_names
, old_names
,
2656 ts
->nb_syscalls
* sizeof(GQuark
));
2657 for(i
= ts
->nb_syscalls
; i
< new_nb_syscalls
; i
++) {
2658 g_string_printf(fe_name
, "syscall %d", i
);
2659 ts
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
2661 g_string_free(fe_name
, TRUE
);
2662 ts
->nb_syscalls
= new_nb_syscalls
;
2664 ts
->syscall_names
[id
] = g_quark_from_string(symbol
);
2669 static gboolean
schedchange(void *hook_data
, void *call_data
)
2671 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2673 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2674 LttvProcessState
*process
= ts
->running_process
[cpu
];
2675 //LttvProcessState *old_process = ts->running_process[cpu];
2677 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2678 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2679 guint pid_in
, pid_out
;
2682 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2683 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2684 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2686 if(likely(process
!= NULL
)) {
2688 /* We could not know but it was not the idle process executing.
2689 This should only happen at the beginning, before the first schedule
2690 event, and when the initial information (current process for each CPU)
2691 is missing. It is not obvious how we could, after the fact, compensate
2692 the wrongly attributed statistics. */
2694 //This test only makes sense once the state is known and if there is no
2695 //missing events. We need to silently ignore schedchange coming after a
2696 //process_free, or it causes glitches. (FIXME)
2697 //if(unlikely(process->pid != pid_out)) {
2698 // g_assert(process->pid == 0);
2700 if(process
->pid
== 0
2701 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2703 /* Scheduling out of pid 0 at beginning of the trace :
2704 * we know for sure it is in syscall mode at this point. */
2705 g_assert(process
->execution_stack
->len
== 1);
2706 process
->state
->t
= LTTV_STATE_SYSCALL
;
2707 process
->state
->s
= LTTV_STATE_WAIT
;
2708 process
->state
->change
= s
->parent
.timestamp
;
2709 process
->state
->entry
= s
->parent
.timestamp
;
2712 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2713 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2714 process
->state
->change
= s
->parent
.timestamp
;
2716 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2717 else process
->state
->s
= LTTV_STATE_WAIT
;
2718 process
->state
->change
= s
->parent
.timestamp
;
2721 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2722 /* see sched.h for states */
2723 if (!exit_process(s
, process
)) {
2724 process
->state
->s
= LTTV_STATE_DEAD
;
2725 process
->state
->change
= s
->parent
.timestamp
;
2730 process
= ts
->running_process
[cpu
] =
2731 lttv_state_find_process_or_create(
2732 (LttvTraceState
*)s
->parent
.t_context
,
2734 &s
->parent
.timestamp
);
2735 process
->state
->s
= LTTV_STATE_RUN
;
2737 if(process
->usertrace
)
2738 process
->usertrace
->cpu
= cpu
;
2739 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2740 process
->state
->change
= s
->parent
.timestamp
;
2742 /* update cpu status */
2744 /* going to idle task */
2745 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2747 /* scheduling a real task.
2748 * we must be careful here:
2749 * if we just schedule()'ed to a process that is
2750 * in a trap, we must put the cpu in trap mode
2752 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2753 if(process
->state
->t
== LTTV_STATE_TRAP
)
2754 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2760 static gboolean
process_fork(void *hook_data
, void *call_data
)
2762 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2763 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2764 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2766 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2767 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2768 //LttvProcessState *zombie_process;
2770 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2771 LttvProcessState
*process
= ts
->running_process
[cpu
];
2772 LttvProcessState
*child_process
;
2773 struct marker_field
*f
;
2776 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2779 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2780 s
->parent
.target_pid
= child_pid
;
2783 f
= lttv_trace_get_hook_field(th
, 2);
2785 child_tgid
= ltt_event_get_unsigned(e
, f
);
2789 /* Mathieu : it seems like the process might have been scheduled in before the
2790 * fork, and, in a rare case, might be the current process. This might happen
2791 * in a SMP case where we don't have enough precision on the clocks.
2793 * Test reenabled after precision fixes on time. (Mathieu) */
2795 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2797 if(unlikely(zombie_process
!= NULL
)) {
2798 /* Reutilisation of PID. Only now we are sure that the old PID
2799 * has been released. FIXME : should know when release_task happens instead.
2801 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2803 for(i
=0; i
< num_cpus
; i
++) {
2804 g_assert(zombie_process
!= ts
->running_process
[i
]);
2807 exit_process(s
, zombie_process
);
2810 g_assert(process
->pid
!= child_pid
);
2811 // FIXME : Add this test in the "known state" section
2812 // g_assert(process->pid == parent_pid);
2813 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2814 if(child_process
== NULL
) {
2815 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2816 child_pid
, child_tgid
,
2817 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2819 /* The process has already been created : due to time imprecision between
2820 * multiple CPUs : it has been scheduled in before creation. Note that we
2821 * shouldn't have this kind of imprecision.
2823 * Simply put a correct parent.
2825 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2826 //g_assert(0); /* This is a problematic case : the process has been created
2827 // before the fork event */
2828 child_process
->ppid
= process
->pid
;
2829 child_process
->tgid
= child_tgid
;
2831 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2832 child_process
->name
= process
->name
;
2833 child_process
->brand
= process
->brand
;
2838 /* We stamp a newly created process as kernel_thread.
2839 * The thread should not be running yet. */
2840 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2842 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2843 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2844 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2846 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2847 LttvProcessState
*process
;
2848 LttvExecutionState
*es
;
2851 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2852 s
->parent
.target_pid
= pid
;
2854 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2856 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2857 process
->execution_stack
=
2858 g_array_set_size(process
->execution_stack
, 1);
2859 es
= process
->state
=
2860 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2861 es
->t
= LTTV_STATE_SYSCALL
;
2863 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2868 static gboolean
process_exit(void *hook_data
, void *call_data
)
2870 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2871 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2872 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2874 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2875 LttvProcessState
*process
; // = ts->running_process[cpu];
2877 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2878 s
->parent
.target_pid
= pid
;
2880 // FIXME : Add this test in the "known state" section
2881 // g_assert(process->pid == pid);
2883 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2884 if(likely(process
!= NULL
)) {
2885 process
->state
->s
= LTTV_STATE_EXIT
;
2890 static gboolean
process_free(void *hook_data
, void *call_data
)
2892 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2893 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2894 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2895 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2897 LttvProcessState
*process
;
2899 /* PID of the process to release */
2900 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2901 s
->parent
.target_pid
= release_pid
;
2903 g_assert(release_pid
!= 0);
2905 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2906 if(likely(process
!= NULL
))
2907 exit_process(s
, process
);
2910 if(likely(process
!= NULL
)) {
2911 /* release_task is happening at kernel level : we can now safely release
2912 * the data structure of the process */
2913 //This test is fun, though, as it may happen that
2914 //at time t : CPU 0 : process_free
2915 //at time t+150ns : CPU 1 : schedule out
2916 //Clearly due to time imprecision, we disable it. (Mathieu)
2917 //If this weird case happen, we have no choice but to put the
2918 //Currently running process on the cpu to 0.
2919 //I re-enable it following time precision fixes. (Mathieu)
2920 //Well, in the case where an process is freed by a process on another CPU
2921 //and still scheduled, it happens that this is the schedchange that will
2922 //drop the last reference count. Do not free it here!
2923 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2925 for(i
=0; i
< num_cpus
; i
++) {
2926 //g_assert(process != ts->running_process[i]);
2927 if(process
== ts
->running_process
[i
]) {
2928 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2932 if(i
== num_cpus
) /* process is not scheduled */
2933 exit_process(s
, process
);
2940 static gboolean
process_exec(void *hook_data
, void *call_data
)
2942 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2943 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2944 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2945 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2948 LttvProcessState
*process
= ts
->running_process
[cpu
];
2950 #if 0//how to use a sequence that must be transformed in a string
2951 /* PID of the process to release */
2952 guint64 name_len
= ltt_event_field_element_number(e
,
2953 lttv_trace_get_hook_field(th
, 0));
2954 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2955 LttField
*child
= ltt_event_field_element_select(e
,
2956 lttv_trace_get_hook_field(th
, 0), 0);
2958 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2959 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2960 memcpy(null_term_name
, name_begin
, name_len
);
2961 null_term_name
[name_len
] = '\0';
2962 process
->name
= g_quark_from_string(null_term_name
);
2965 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2966 lttv_trace_get_hook_field(th
, 0)));
2967 process
->brand
= LTTV_STATE_UNBRANDED
;
2968 //g_free(null_term_name);
2972 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2974 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2975 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2976 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2977 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2980 LttvProcessState
*process
= ts
->running_process
[cpu
];
2982 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2983 process
->brand
= g_quark_from_string(name
);
2988 static void fix_process(gpointer key
, gpointer value
,
2991 LttvProcessState
*process
;
2992 LttvExecutionState
*es
;
2993 process
= (LttvProcessState
*)value
;
2994 LttTime
*timestamp
= (LttTime
*)user_data
;
2996 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2997 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2998 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2999 es
->t
= LTTV_STATE_SYSCALL
;
3000 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3001 es
->entry
= *timestamp
;
3002 es
->change
= *timestamp
;
3003 es
->cum_cpu_time
= ltt_time_zero
;
3004 if(es
->s
== LTTV_STATE_UNNAMED
)
3005 es
->s
= LTTV_STATE_WAIT
;
3008 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3009 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3010 es
->t
= LTTV_STATE_USER_MODE
;
3011 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3012 es
->entry
= *timestamp
;
3013 //g_assert(timestamp->tv_sec != 0);
3014 es
->change
= *timestamp
;
3015 es
->cum_cpu_time
= ltt_time_zero
;
3016 if(es
->s
== LTTV_STATE_UNNAMED
)
3017 es
->s
= LTTV_STATE_RUN
;
3019 if(process
->execution_stack
->len
== 1) {
3020 /* Still in bottom unknown mode, means never did a system call
3021 * May be either in user mode, syscall mode, running or waiting.*/
3022 /* FIXME : we may be tagging syscall mode when being user mode */
3023 process
->execution_stack
=
3024 g_array_set_size(process
->execution_stack
, 2);
3025 es
= process
->state
= &g_array_index(process
->execution_stack
,
3026 LttvExecutionState
, 1);
3027 es
->t
= LTTV_STATE_SYSCALL
;
3028 es
->n
= LTTV_STATE_SUBMODE_NONE
;
3029 es
->entry
= *timestamp
;
3030 //g_assert(timestamp->tv_sec != 0);
3031 es
->change
= *timestamp
;
3032 es
->cum_cpu_time
= ltt_time_zero
;
3033 if(es
->s
== LTTV_STATE_WAIT_FORK
)
3034 es
->s
= LTTV_STATE_WAIT
;
3040 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3042 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3043 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3044 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3045 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3046 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3048 /* For all processes */
3049 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3050 /* else, if stack[0] is unknown, set to user mode, running */
3052 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3057 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3059 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3060 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3061 //It's slow : optimise later by doing this before reading trace.
3062 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3068 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3069 LttvProcessState
*process
= ts
->running_process
[cpu
];
3070 LttvProcessState
*parent_process
;
3071 struct marker_field
*f
;
3072 GQuark type
, mode
, submode
, status
;
3073 LttvExecutionState
*es
;
3077 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3078 s
->parent
.target_pid
= pid
;
3081 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3084 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3087 f
= lttv_trace_get_hook_field(th
, 3);
3088 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3090 //FIXME: type is rarely used, enum must match possible types.
3093 f
= lttv_trace_get_hook_field(th
, 4);
3094 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3097 f
= lttv_trace_get_hook_field(th
, 5);
3098 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3101 f
= lttv_trace_get_hook_field(th
, 6);
3102 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3105 f
= lttv_trace_get_hook_field(th
, 7);
3107 tgid
= ltt_event_get_unsigned(e
, f
);
3112 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3113 for(i
=0; i
<nb_cpus
; i
++) {
3114 process
= lttv_state_find_process(ts
, i
, pid
);
3115 g_assert(process
!= NULL
);
3117 process
->ppid
= parent_pid
;
3118 process
->tgid
= tgid
;
3119 process
->name
= g_quark_from_string(command
);
3121 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3122 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3126 /* The process might exist if a process was forked while performing the
3128 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3129 if(process
== NULL
) {
3130 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3131 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3132 pid
, tgid
, g_quark_from_string(command
),
3133 &s
->parent
.timestamp
);
3135 /* Keep the stack bottom : a running user mode */
3136 /* Disabled because of inconsistencies in the current statedump states. */
3137 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3138 /* Only keep the bottom
3139 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3140 /* Will cause expected trap when in fact being syscall (even after end of
3142 * Will cause expected interrupt when being syscall. (only before end of
3143 * statedump event) */
3144 // This will cause a "popping last state on stack, ignoring it."
3145 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3146 es
= process
->state
= &g_array_index(process
->execution_stack
,
3147 LttvExecutionState
, 0);
3148 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3149 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3150 es
->s
= LTTV_STATE_UNNAMED
;
3151 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3153 es
->t
= LTTV_STATE_SYSCALL
;
3158 /* User space process :
3159 * bottom : user mode
3160 * either currently running or scheduled out.
3161 * can be scheduled out because interrupted in (user mode or in syscall)
3162 * or because of an explicit call to the scheduler in syscall. Note that
3163 * the scheduler call comes after the irq_exit, so never in interrupt
3165 // temp workaround : set size to 1 : only have user mode bottom of stack.
3166 // will cause g_info message of expected syscall mode when in fact being
3167 // in user mode. Can also cause expected trap when in fact being user
3168 // mode in the event of a page fault reenabling interrupts in the handler.
3169 // Expected syscall and trap can also happen after the end of statedump
3170 // This will cause a "popping last state on stack, ignoring it."
3171 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3172 es
= process
->state
= &g_array_index(process
->execution_stack
,
3173 LttvExecutionState
, 0);
3174 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3175 es
->s
= LTTV_STATE_UNNAMED
;
3176 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3178 es
->t
= LTTV_STATE_USER_MODE
;
3186 es
= process
->state
= &g_array_index(process
->execution_stack
,
3187 LttvExecutionState
, 1);
3188 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3189 es
->s
= LTTV_STATE_UNNAMED
;
3190 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3194 /* The process has already been created :
3195 * Probably was forked while dumping the process state or
3196 * was simply scheduled in prior to get the state dump event.
3198 process
->ppid
= parent_pid
;
3199 process
->tgid
= tgid
;
3200 process
->name
= g_quark_from_string(command
);
3201 process
->type
= type
;
3203 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3205 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3206 if(type
== LTTV_STATE_KERNEL_THREAD
)
3207 es
->t
= LTTV_STATE_SYSCALL
;
3209 es
->t
= LTTV_STATE_USER_MODE
;
3212 /* Don't mess around with the stack, it will eventually become
3213 * ok after the end of state dump. */
3220 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3222 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3224 lttv_state_add_event_hooks(tss
);
3229 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3231 LttvTraceset
*traceset
= self
->parent
.ts
;
3233 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3237 LttvTracefileState
*tfs
;
3243 LttvAttributeValue val
;
3245 nb_trace
= lttv_traceset_number(traceset
);
3246 for(i
= 0 ; i
< nb_trace
; i
++) {
3247 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3249 /* Find the eventtype id for the following events and register the
3250 associated by id hooks. */
3252 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3253 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3256 lttv_trace_find_hook(ts
->parent
.t
,
3257 LTT_FACILITY_KERNEL_ARCH
,
3258 LTT_EVENT_SYSCALL_ENTRY
,
3259 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3260 syscall_entry
, NULL
, &hooks
);
3262 lttv_trace_find_hook(ts
->parent
.t
,
3263 LTT_FACILITY_KERNEL_ARCH
,
3264 LTT_EVENT_SYSCALL_EXIT
,
3266 syscall_exit
, NULL
, &hooks
);
3268 lttv_trace_find_hook(ts
->parent
.t
,
3269 LTT_FACILITY_KERNEL_ARCH
,
3270 LTT_EVENT_TRAP_ENTRY
,
3271 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3272 trap_entry
, NULL
, &hooks
);
3274 lttv_trace_find_hook(ts
->parent
.t
,
3275 LTT_FACILITY_KERNEL_ARCH
,
3276 LTT_EVENT_TRAP_EXIT
,
3278 trap_exit
, NULL
, &hooks
);
3280 lttv_trace_find_hook(ts
->parent
.t
,
3281 LTT_FACILITY_KERNEL
,
3282 LTT_EVENT_IRQ_ENTRY
,
3283 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3284 irq_entry
, NULL
, &hooks
);
3286 lttv_trace_find_hook(ts
->parent
.t
,
3287 LTT_FACILITY_KERNEL
,
3290 irq_exit
, NULL
, &hooks
);
3292 lttv_trace_find_hook(ts
->parent
.t
,
3293 LTT_FACILITY_KERNEL
,
3294 LTT_EVENT_SOFT_IRQ_ENTRY
,
3295 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3296 soft_irq_entry
, NULL
, &hooks
);
3298 lttv_trace_find_hook(ts
->parent
.t
,
3299 LTT_FACILITY_KERNEL
,
3300 LTT_EVENT_SOFT_IRQ_EXIT
,
3302 soft_irq_exit
, NULL
, &hooks
);
3304 lttv_trace_find_hook(ts
->parent
.t
,
3305 LTT_FACILITY_KERNEL
,
3306 LTT_EVENT_SCHED_SCHEDULE
,
3307 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3308 LTT_FIELD_PREV_STATE
),
3309 schedchange
, NULL
, &hooks
);
3311 lttv_trace_find_hook(ts
->parent
.t
,
3312 LTT_FACILITY_KERNEL
,
3313 LTT_EVENT_PROCESS_FORK
,
3314 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3315 LTT_FIELD_CHILD_TGID
),
3316 process_fork
, NULL
, &hooks
);
3318 lttv_trace_find_hook(ts
->parent
.t
,
3319 LTT_FACILITY_KERNEL_ARCH
,
3320 LTT_EVENT_KTHREAD_CREATE
,
3321 FIELD_ARRAY(LTT_FIELD_PID
),
3322 process_kernel_thread
, NULL
, &hooks
);
3324 lttv_trace_find_hook(ts
->parent
.t
,
3325 LTT_FACILITY_KERNEL
,
3326 LTT_EVENT_PROCESS_EXIT
,
3327 FIELD_ARRAY(LTT_FIELD_PID
),
3328 process_exit
, NULL
, &hooks
);
3330 lttv_trace_find_hook(ts
->parent
.t
,
3331 LTT_FACILITY_KERNEL
,
3332 LTT_EVENT_PROCESS_FREE
,
3333 FIELD_ARRAY(LTT_FIELD_PID
),
3334 process_free
, NULL
, &hooks
);
3336 lttv_trace_find_hook(ts
->parent
.t
,
3339 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3340 process_exec
, NULL
, &hooks
);
3342 lttv_trace_find_hook(ts
->parent
.t
,
3343 LTT_FACILITY_USER_GENERIC
,
3344 LTT_EVENT_THREAD_BRAND
,
3345 FIELD_ARRAY(LTT_FIELD_NAME
),
3346 thread_brand
, NULL
, &hooks
);
3348 /* statedump-related hooks */
3349 lttv_trace_find_hook(ts
->parent
.t
,
3351 LTT_EVENT_PROCESS_STATE
,
3352 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3353 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3354 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3355 enum_process_state
, NULL
, &hooks
);
3357 lttv_trace_find_hook(ts
->parent
.t
,
3359 LTT_EVENT_STATEDUMP_END
,
3361 statedump_end
, NULL
, &hooks
);
3363 lttv_trace_find_hook(ts
->parent
.t
,
3365 LTT_EVENT_LIST_INTERRUPT
,
3366 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3367 enum_interrupt
, NULL
, &hooks
);
3369 lttv_trace_find_hook(ts
->parent
.t
,
3371 LTT_EVENT_REQUEST_ISSUE
,
3372 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3373 bdev_request_issue
, NULL
, &hooks
);
3375 lttv_trace_find_hook(ts
->parent
.t
,
3377 LTT_EVENT_REQUEST_COMPLETE
,
3378 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3379 bdev_request_complete
, NULL
, &hooks
);
3381 lttv_trace_find_hook(ts
->parent
.t
,
3382 LTT_FACILITY_USER_GENERIC
,
3383 LTT_EVENT_FUNCTION_ENTRY
,
3384 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3385 function_entry
, NULL
, &hooks
);
3387 lttv_trace_find_hook(ts
->parent
.t
,
3388 LTT_FACILITY_USER_GENERIC
,
3389 LTT_EVENT_FUNCTION_EXIT
,
3390 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3391 function_exit
, NULL
, &hooks
);
3393 lttv_trace_find_hook(ts
->parent
.t
,
3394 LTT_FACILITY_STATEDUMP
,
3395 LTT_EVENT_SYS_CALL_TABLE
,
3396 FIELD_ARRAY(LTT_FIELD_ID
, LTT_FIELD_ADDRESS
, LTT_FIELD_SYMBOL
),
3397 dump_syscall
, NULL
, &hooks
);
3399 /* Add these hooks to each event_by_id hooks list */
3401 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3403 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3405 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3406 LttvTracefileContext
*, j
));
3408 for(k
= 0 ; k
< hooks
->len
; k
++) {
3409 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3411 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3417 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3418 *(val
.v_pointer
) = hooks
;
3422 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3424 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3426 lttv_state_remove_event_hooks(tss
);
3431 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3433 LttvTraceset
*traceset
= self
->parent
.ts
;
3435 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3439 LttvTracefileState
*tfs
;
3445 LttvAttributeValue val
;
3447 nb_trace
= lttv_traceset_number(traceset
);
3448 for(i
= 0 ; i
< nb_trace
; i
++) {
3449 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3451 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3452 hooks
= *(val
.v_pointer
);
3454 /* Remove these hooks from each event_by_id hooks list */
3456 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3458 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3460 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3461 LttvTracefileContext
*, j
));
3463 for(k
= 0 ; k
< hooks
->len
; k
++) {
3464 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3465 lttv_hooks_remove_data(
3466 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3471 lttv_trace_hook_remove_all(&hooks
);
3472 g_array_free(hooks
, TRUE
);
3476 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3478 guint
*event_count
= (guint
*)hook_data
;
3480 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3481 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3486 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3488 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3490 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3492 LttvAttributeValue value
;
3494 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3495 LTTV_STATE_SAVED_STATES
);
3496 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3497 value
= lttv_attribute_add(saved_states_tree
,
3498 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3499 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3500 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3501 *(value
.v_time
) = self
->parent
.timestamp
;
3502 lttv_state_save(tcs
, saved_state_tree
);
3503 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3504 self
->parent
.timestamp
.tv_nsec
);
3506 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3511 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3513 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3515 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3520 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3528 static gboolean
block_start(void *hook_data
, void *call_data
)
3530 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3532 LttvTracefileState
*tfcs
;
3534 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3536 LttEventPosition
*ep
;
3538 guint i
, nb_block
, nb_event
, nb_tracefile
;
3542 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3544 LttvAttributeValue value
;
3546 ep
= ltt_event_position_new();
3548 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3550 /* Count the number of events added since the last block end in any
3553 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3555 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3556 LttvTracefileContext
, i
));
3557 ltt_event_position(tfcs
->parent
.e
, ep
);
3558 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3559 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3560 tfcs
->saved_position
= nb_event
;
3564 if(tcs
->nb_event
>= tcs
->save_interval
) {
3565 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3566 LTTV_STATE_SAVED_STATES
);
3567 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3568 value
= lttv_attribute_add(saved_states_tree
,
3569 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3570 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3571 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3572 *(value
.v_time
) = self
->parent
.timestamp
;
3573 lttv_state_save(tcs
, saved_state_tree
);
3575 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3576 self
->parent
.timestamp
.tv_nsec
);
3578 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3584 static gboolean
block_end(void *hook_data
, void *call_data
)
3586 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3588 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3592 LttEventPosition
*ep
;
3594 guint nb_block
, nb_event
;
3596 ep
= ltt_event_position_new();
3597 ltt_event_position(self
->parent
.e
, ep
);
3598 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3599 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3600 self
->saved_position
= 0;
3601 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3608 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3610 LttvTraceset
*traceset
= self
->parent
.ts
;
3612 guint i
, j
, nb_trace
, nb_tracefile
;
3616 LttvTracefileState
*tfs
;
3618 LttvTraceHook hook_start
, hook_end
;
3620 nb_trace
= lttv_traceset_number(traceset
);
3621 for(i
= 0 ; i
< nb_trace
; i
++) {
3622 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3624 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3625 NULL
, NULL
, block_start
, &hook_start
);
3626 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3627 NULL
, NULL
, block_end
, &hook_end
);
3629 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3631 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3633 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3634 LttvTracefileContext
, j
));
3635 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3636 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3637 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3638 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3644 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3646 LttvTraceset
*traceset
= self
->parent
.ts
;
3648 guint i
, j
, nb_trace
, nb_tracefile
;
3652 LttvTracefileState
*tfs
;
3655 nb_trace
= lttv_traceset_number(traceset
);
3656 for(i
= 0 ; i
< nb_trace
; i
++) {
3658 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3659 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3661 if(ts
->has_precomputed_states
) continue;
3663 guint
*event_count
= g_new(guint
, 1);
3666 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3668 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3669 LttvTracefileContext
*, j
));
3670 lttv_hooks_add(tfs
->parent
.event
,
3671 state_save_event_hook
,
3678 lttv_process_traceset_begin(&self
->parent
,
3679 NULL
, NULL
, NULL
, NULL
, NULL
);
3683 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3685 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3687 lttv_state_save_add_event_hooks(tss
);
3694 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3696 LttvTraceset
*traceset
= self
->parent
.ts
;
3698 guint i
, j
, nb_trace
, nb_tracefile
;
3702 LttvTracefileState
*tfs
;
3704 LttvTraceHook hook_start
, hook_end
;
3706 nb_trace
= lttv_traceset_number(traceset
);
3707 for(i
= 0 ; i
< nb_trace
; i
++) {
3708 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3710 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3711 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_remove_data(lttv_hooks_by_id_find(
3723 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3724 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3725 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3731 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3733 LttvTraceset
*traceset
= self
->parent
.ts
;
3735 guint i
, j
, nb_trace
, nb_tracefile
;
3739 LttvTracefileState
*tfs
;
3741 LttvHooks
*after_trace
= lttv_hooks_new();
3743 lttv_hooks_add(after_trace
,
3744 state_save_after_trace_hook
,
3749 lttv_process_traceset_end(&self
->parent
,
3750 NULL
, after_trace
, NULL
, NULL
, NULL
);
3752 lttv_hooks_destroy(after_trace
);
3754 nb_trace
= lttv_traceset_number(traceset
);
3755 for(i
= 0 ; i
< nb_trace
; i
++) {
3757 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3758 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3760 if(ts
->has_precomputed_states
) continue;
3762 guint
*event_count
= NULL
;
3764 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3766 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3767 LttvTracefileContext
*, j
));
3768 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3769 state_save_event_hook
);
3771 if(event_count
) g_free(event_count
);
3775 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3777 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3779 lttv_state_save_remove_event_hooks(tss
);
3784 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3786 LttvTraceset
*traceset
= self
->parent
.ts
;
3790 int min_pos
, mid_pos
, max_pos
;
3792 guint call_rest
= 0;
3794 LttvTraceState
*tcs
;
3796 LttvAttributeValue value
;
3798 LttvAttributeType type
;
3800 LttvAttributeName name
;
3804 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3806 //g_tree_destroy(self->parent.pqueue);
3807 //self->parent.pqueue = g_tree_new(compare_tracefile);
3809 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3811 nb_trace
= lttv_traceset_number(traceset
);
3812 for(i
= 0 ; i
< nb_trace
; i
++) {
3813 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3815 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3816 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3817 LTTV_STATE_SAVED_STATES
);
3820 if(saved_states_tree
) {
3821 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3822 mid_pos
= max_pos
/ 2;
3823 while(min_pos
< max_pos
) {
3824 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3826 g_assert(type
== LTTV_GOBJECT
);
3827 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3828 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3830 g_assert(type
== LTTV_TIME
);
3831 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3833 closest_tree
= saved_state_tree
;
3835 else max_pos
= mid_pos
- 1;
3837 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3841 /* restore the closest earlier saved state */
3843 lttv_state_restore(tcs
, closest_tree
);
3847 /* There is no saved state, yet we want to have it. Restart at T0 */
3849 restore_init_state(tcs
);
3850 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3853 /* We want to seek quickly without restoring/updating the state */
3855 restore_init_state(tcs
);
3856 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3859 if(!call_rest
) g_info("NOT Calling restore");
3864 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3870 traceset_state_finalize (LttvTracesetState
*self
)
3872 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3873 finalize(G_OBJECT(self
));
3878 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3880 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3882 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3883 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3884 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3885 klass
->new_traceset_context
= new_traceset_context
;
3886 klass
->new_trace_context
= new_trace_context
;
3887 klass
->new_tracefile_context
= new_tracefile_context
;
3892 lttv_traceset_state_get_type(void)
3894 static GType type
= 0;
3896 static const GTypeInfo info
= {
3897 sizeof (LttvTracesetStateClass
),
3898 NULL
, /* base_init */
3899 NULL
, /* base_finalize */
3900 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3901 NULL
, /* class_finalize */
3902 NULL
, /* class_data */
3903 sizeof (LttvTracesetState
),
3904 0, /* n_preallocs */
3905 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3906 NULL
/* value handling */
3909 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3917 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3923 trace_state_finalize (LttvTraceState
*self
)
3925 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3926 finalize(G_OBJECT(self
));
3931 trace_state_class_init (LttvTraceStateClass
*klass
)
3933 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3935 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3936 klass
->state_save
= state_save
;
3937 klass
->state_restore
= state_restore
;
3938 klass
->state_saved_free
= state_saved_free
;
3943 lttv_trace_state_get_type(void)
3945 static GType type
= 0;
3947 static const GTypeInfo info
= {
3948 sizeof (LttvTraceStateClass
),
3949 NULL
, /* base_init */
3950 NULL
, /* base_finalize */
3951 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3952 NULL
, /* class_finalize */
3953 NULL
, /* class_data */
3954 sizeof (LttvTraceState
),
3955 0, /* n_preallocs */
3956 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3957 NULL
/* value handling */
3960 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3961 "LttvTraceStateType", &info
, 0);
3968 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3974 tracefile_state_finalize (LttvTracefileState
*self
)
3976 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3977 finalize(G_OBJECT(self
));
3982 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3984 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3986 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3991 lttv_tracefile_state_get_type(void)
3993 static GType type
= 0;
3995 static const GTypeInfo info
= {
3996 sizeof (LttvTracefileStateClass
),
3997 NULL
, /* base_init */
3998 NULL
, /* base_finalize */
3999 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4000 NULL
, /* class_finalize */
4001 NULL
, /* class_data */
4002 sizeof (LttvTracefileState
),
4003 0, /* n_preallocs */
4004 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4005 NULL
/* value handling */
4008 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4009 "LttvTracefileStateType", &info
, 0);
4015 static void module_init()
4017 LTTV_STATE_UNNAMED
= g_quark_from_string("");
4018 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
4019 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4020 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4021 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4022 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4023 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4024 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4025 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4026 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4027 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4028 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4029 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4030 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4031 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4032 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4033 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4034 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4035 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4036 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4037 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4038 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4039 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4040 LTTV_STATE_EVENT
= g_quark_from_string("event");
4041 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4042 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4043 LTTV_STATE_TIME
= g_quark_from_string("time");
4044 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4045 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4046 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4047 g_quark_from_string("trace_state_use_count");
4048 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4049 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4050 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4051 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4052 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4053 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4056 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4057 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4058 LTT_FACILITY_FS
= g_quark_from_string("fs");
4059 LTT_FACILITY_LIST
= g_quark_from_string("list");
4060 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4061 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4062 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4064 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4065 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4066 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4067 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4068 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4069 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4070 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4071 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4072 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4073 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4074 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4075 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4076 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4077 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4078 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4079 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4080 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4081 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4082 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4083 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4084 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4085 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");
4086 LTT_EVENT_SYS_CALL_TABLE
= g_quark_from_string("sys_call_table");
4088 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4089 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4090 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4091 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4092 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4093 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4094 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4095 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4096 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4097 LTT_FIELD_PID
= g_quark_from_string("pid");
4098 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4099 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4100 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4101 LTT_FIELD_NAME
= g_quark_from_string("name");
4102 LTT_FIELD_TYPE
= g_quark_from_string("type");
4103 LTT_FIELD_MODE
= g_quark_from_string("mode");
4104 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4105 LTT_FIELD_STATUS
= g_quark_from_string("status");
4106 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4107 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4108 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4109 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4110 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4111 LTT_FIELD_ACTION
= g_quark_from_string("action");
4112 LTT_FIELD_ID
= g_quark_from_string("id");
4113 LTT_FIELD_ADDRESS
= g_quark_from_string("address");
4114 LTT_FIELD_SYMBOL
= g_quark_from_string("symbol");
4116 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4117 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4118 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4119 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4120 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4121 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4123 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4124 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4125 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4127 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4128 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4129 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4130 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4133 static void module_destroy()
4138 LTTV_MODULE("state", "State computation", \
4139 "Update the system state, possibly saving it at intervals", \
4140 module_init
, module_destroy
)