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>
37 * usertrace is there only to be able to update the current CPU of the
38 * usertraces when there is a schedchange. it is a way to link the ProcessState
39 * to the associated usertrace. Link only created upon thread creation.
41 * The cpu id is necessary : it gives us back the current ProcessState when we
42 * are considering data from the usertrace.
45 #define PREALLOCATED_EXECUTION_STACK 10
47 /* Facilities Quarks */
51 LTT_FACILITY_KERNEL_ARCH
,
54 LTT_FACILITY_USER_GENERIC
,
60 LTT_EVENT_SYSCALL_ENTRY
,
61 LTT_EVENT_SYSCALL_EXIT
,
66 LTT_EVENT_SOFT_IRQ_ENTRY
,
67 LTT_EVENT_SOFT_IRQ_EXIT
,
68 LTT_EVENT_SCHED_SCHEDULE
,
69 LTT_EVENT_PROCESS_FORK
,
70 LTT_EVENT_KTHREAD_CREATE
,
71 LTT_EVENT_PROCESS_EXIT
,
72 LTT_EVENT_PROCESS_FREE
,
74 LTT_EVENT_PROCESS_STATE
,
75 LTT_EVENT_STATEDUMP_END
,
76 LTT_EVENT_FUNCTION_ENTRY
,
77 LTT_EVENT_FUNCTION_EXIT
,
78 LTT_EVENT_THREAD_BRAND
,
79 LTT_EVENT_REQUEST_ISSUE
,
80 LTT_EVENT_REQUEST_COMPLETE
,
81 LTT_EVENT_LIST_INTERRUPT
;
89 LTT_FIELD_SOFT_IRQ_ID
,
112 LTTV_STATE_MODE_UNKNOWN
,
113 LTTV_STATE_USER_MODE
,
120 LTTV_STATE_SUBMODE_UNKNOWN
,
121 LTTV_STATE_SUBMODE_NONE
;
125 LTTV_STATE_WAIT_FORK
,
134 LTTV_STATE_UNBRANDED
;
137 LTTV_STATE_USER_THREAD
,
138 LTTV_STATE_KERNEL_THREAD
;
156 LTTV_BDEV_BUSY_READING
,
157 LTTV_BDEV_BUSY_WRITING
;
160 LTTV_STATE_TRACEFILES
,
161 LTTV_STATE_PROCESSES
,
163 LTTV_STATE_RUNNING_PROCESS
,
165 LTTV_STATE_SAVED_STATES
,
166 LTTV_STATE_SAVED_STATES_TIME
,
169 LTTV_STATE_NAME_TABLES
,
170 LTTV_STATE_TRACE_STATE_USE_COUNT
,
171 LTTV_STATE_RESOURCE_CPUS
,
172 LTTV_STATE_RESOURCE_CPUS_COUNT
,
173 LTTV_STATE_RESOURCE_IRQS
,
174 LTTV_STATE_RESOURCE_SOFT_IRQS
,
175 LTTV_STATE_RESOURCE_TRAPS
,
176 LTTV_STATE_RESOURCE_BLKDEVS
;
178 static void create_max_time(LttvTraceState
*tcs
);
180 static void get_max_time(LttvTraceState
*tcs
);
182 static void free_max_time(LttvTraceState
*tcs
);
184 static void create_name_tables(LttvTraceState
*tcs
);
186 static void get_name_tables(LttvTraceState
*tcs
);
188 static void free_name_tables(LttvTraceState
*tcs
);
190 static void free_saved_state(LttvTraceState
*tcs
);
192 static void lttv_state_free_process_table(GHashTable
*processes
);
194 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
195 GPtrArray
*quarktable
);
197 /* Resource function prototypes */
198 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
199 static LttvBdevState
*bdevstate_new(void);
200 static void bdevstate_free(LttvBdevState
*);
201 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
202 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
205 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
207 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
211 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
213 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
217 void lttv_state_state_saved_free(LttvTraceState
*self
,
218 LttvAttribute
*container
)
220 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
224 guint
process_hash(gconstpointer key
)
226 guint pid
= ((const LttvProcessState
*)key
)->pid
;
227 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
231 /* If the hash table hash function is well distributed,
232 * the process_equal should compare different pid */
233 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
235 const LttvProcessState
*process_a
, *process_b
;
238 process_a
= (const LttvProcessState
*)a
;
239 process_b
= (const LttvProcessState
*)b
;
241 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
242 else if(likely(process_a
->pid
== 0 &&
243 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
248 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
250 g_tree_destroy((GTree
*)value
);
253 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
255 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
256 g_hash_table_destroy(usertraces
);
259 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
265 restore_init_state(LttvTraceState
*self
)
267 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
269 //LttvTracefileState *tfcs;
271 LttTime start_time
, end_time
;
273 /* Free the process tables */
274 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
275 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
276 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
277 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
280 /* Seek time to beginning */
281 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
282 // closest. It's the tracecontext job to seek the trace to the beginning
283 // anyway : the init state might be used at the middle of the trace as well...
284 //g_tree_destroy(self->parent.ts_context->pqueue);
285 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
287 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
289 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
291 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
292 nb_irqs
= self
->nb_irqs
;
293 nb_soft_irqs
= self
->nb_soft_irqs
;
294 nb_traps
= self
->nb_traps
;
296 /* Put the per cpu running_process to beginning state : process 0. */
297 for(i
=0; i
< nb_cpus
; i
++) {
298 LttvExecutionState
*es
;
299 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
300 LTTV_STATE_UNNAMED
, &start_time
);
301 /* We are not sure is it's a kernel thread or normal thread, put the
302 * bottom stack state to unknown */
303 self
->running_process
[i
]->execution_stack
=
304 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
305 es
= self
->running_process
[i
]->state
=
306 &g_array_index(self
->running_process
[i
]->execution_stack
,
307 LttvExecutionState
, 0);
308 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
309 es
->s
= LTTV_STATE_UNNAMED
;
311 //self->running_process[i]->state->s = LTTV_STATE_RUN;
312 self
->running_process
[i
]->cpu
= i
;
314 /* reset cpu states */
315 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
316 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
319 /* reset irq states */
320 for(i
=0; i
<nb_irqs
; i
++) {
321 if(self
->irq_states
[i
].mode_stack
->len
> 0)
322 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
325 /* reset softirq states */
326 for(i
=0; i
<nb_soft_irqs
; i
++) {
327 self
->soft_irq_states
[i
].running
= 0;
330 /* reset trap states */
331 for(i
=0; i
<nb_traps
; i
++) {
332 self
->trap_states
[i
].running
= 0;
335 /* reset bdev states */
336 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
337 //g_hash_table_steal_all(self->bdev_states);
338 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
341 nb_tracefile
= self
->parent
.tracefiles
->len
;
343 for(i
= 0 ; i
< nb_tracefile
; i
++) {
345 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
346 LttvTracefileContext
*, i
));
347 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
348 // tfcs->saved_position = 0;
349 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
350 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
351 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
352 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
357 //static LttTime time_zero = {0,0};
359 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
362 const LttTime
*t1
= (const LttTime
*)a
;
363 const LttTime
*t2
= (const LttTime
*)b
;
365 return ltt_time_compare(*t1
, *t2
);
368 static void free_usertrace_key(gpointer data
)
373 #define MAX_STRING_LEN 4096
376 state_load_saved_states(LttvTraceState
*tcs
)
379 GPtrArray
*quarktable
;
380 const char *trace_path
;
384 tcs
->has_precomputed_states
= FALSE
;
388 gchar buf
[MAX_STRING_LEN
];
391 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
392 strncpy(path
, trace_path
, PATH_MAX
-1);
393 count
= strnlen(trace_path
, PATH_MAX
-1);
394 // quarktable : open, test
395 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
396 fp
= fopen(path
, "r");
398 quarktable
= g_ptr_array_sized_new(4096);
400 /* Index 0 is null */
402 if(hdr
== EOF
) return;
403 g_assert(hdr
== HDR_QUARKS
);
407 if(hdr
== EOF
) break;
408 g_assert(hdr
== HDR_QUARK
);
409 g_ptr_array_set_size(quarktable
, q
+1);
412 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
413 if(buf
[i
] == '\0' || feof(fp
)) break;
416 len
= strnlen(buf
, MAX_STRING_LEN
-1);
417 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
418 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
424 // saved_states : open, test
425 strncpy(path
, trace_path
, PATH_MAX
-1);
426 count
= strnlen(trace_path
, PATH_MAX
-1);
427 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
428 fp
= fopen(path
, "r");
432 if(hdr
!= HDR_TRACE
) goto end
;
434 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
436 tcs
->has_precomputed_states
= TRUE
;
441 /* Free the quarktable */
442 for(i
=0; i
<quarktable
->len
; i
++) {
443 string
= g_ptr_array_index (quarktable
, i
);
446 g_ptr_array_free(quarktable
, TRUE
);
451 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
453 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
456 LttvTraceContext
*tc
;
460 LttvTracefileState
*tfcs
;
462 LttvAttributeValue v
;
464 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
465 init((LttvTracesetContext
*)self
, ts
);
467 nb_trace
= lttv_traceset_number(ts
);
468 for(i
= 0 ; i
< nb_trace
; i
++) {
469 tc
= self
->parent
.traces
[i
];
470 tcs
= LTTV_TRACE_STATE(tc
);
471 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
472 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
476 if(*(v
.v_uint
) == 1) {
477 create_name_tables(tcs
);
478 create_max_time(tcs
);
480 get_name_tables(tcs
);
483 nb_tracefile
= tc
->tracefiles
->len
;
484 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
485 nb_irq
= tcs
->nb_irqs
;
486 tcs
->processes
= NULL
;
487 tcs
->usertraces
= NULL
;
488 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
490 /* init cpu resource stuff */
491 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
492 for(j
= 0; j
<nb_cpu
; j
++) {
493 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
494 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
497 /* init irq resource stuff */
498 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
499 for(j
= 0; j
<nb_irq
; j
++) {
500 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
501 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
504 /* init soft irq stuff */
505 /* the kernel has a statically fixed max of 32 softirqs */
506 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
508 /* init trap stuff */
509 tcs
->trap_states
= g_new(LttvTrapState
, tcs
->nb_traps
);
511 /* init bdev resource stuff */
512 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
514 restore_init_state(tcs
);
515 for(j
= 0 ; j
< nb_tracefile
; j
++) {
517 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
518 LttvTracefileContext
*, j
));
519 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
520 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
521 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
522 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
523 /* It's a Usertrace */
524 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
525 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
527 if(!usertrace_tree
) {
528 usertrace_tree
= g_tree_new_full(compare_usertraces
,
529 NULL
, free_usertrace_key
, NULL
);
530 g_hash_table_insert(tcs
->usertraces
,
531 (gpointer
)tid
, usertrace_tree
);
533 LttTime
*timestamp
= g_new(LttTime
, 1);
534 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
535 ltt_tracefile_creation(tfcs
->parent
.tf
));
536 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
540 /* See if the trace has saved states */
541 state_load_saved_states(tcs
);
546 fini(LttvTracesetState
*self
)
552 //LttvTracefileState *tfcs;
554 LttvAttributeValue v
;
556 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
557 for(i
= 0 ; i
< nb_trace
; i
++) {
558 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
559 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
562 g_assert(*(v
.v_uint
) != 0);
565 if(*(v
.v_uint
) == 0) {
566 free_name_tables(tcs
);
568 free_saved_state(tcs
);
570 g_free(tcs
->running_process
);
571 tcs
->running_process
= NULL
;
572 lttv_state_free_process_table(tcs
->processes
);
573 lttv_state_free_usertraces(tcs
->usertraces
);
574 tcs
->processes
= NULL
;
575 tcs
->usertraces
= NULL
;
577 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
578 fini((LttvTracesetContext
*)self
);
582 static LttvTracesetContext
*
583 new_traceset_context(LttvTracesetContext
*self
)
585 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
589 static LttvTraceContext
*
590 new_trace_context(LttvTracesetContext
*self
)
592 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
596 static LttvTracefileContext
*
597 new_tracefile_context(LttvTracesetContext
*self
)
599 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
603 /* Write the process state of the trace */
605 static void write_process_state(gpointer key
, gpointer value
,
608 LttvProcessState
*process
;
610 LttvExecutionState
*es
;
612 FILE *fp
= (FILE *)user_data
;
617 process
= (LttvProcessState
*)value
;
619 " <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",
620 process
, process
->pid
, process
->tgid
, process
->ppid
,
621 g_quark_to_string(process
->type
),
622 process
->creation_time
.tv_sec
,
623 process
->creation_time
.tv_nsec
,
624 process
->insertion_time
.tv_sec
,
625 process
->insertion_time
.tv_nsec
,
626 g_quark_to_string(process
->name
),
627 g_quark_to_string(process
->brand
),
628 process
->cpu
, process
->free_events
);
630 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
631 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
632 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
633 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
634 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
635 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
636 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
639 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
640 address
= g_array_index(process
->user_stack
, guint64
, i
);
641 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
645 if(process
->usertrace
) {
646 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
647 g_quark_to_string(process
->usertrace
->tracefile_name
),
648 process
->usertrace
->cpu
);
652 fprintf(fp
, " </PROCESS>\n");
656 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
658 guint i
, nb_tracefile
, nb_block
, offset
;
661 LttvTracefileState
*tfcs
;
665 LttEventPosition
*ep
;
669 ep
= ltt_event_position_new();
671 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
673 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
675 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
676 for(i
=0;i
<nb_cpus
;i
++) {
677 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
678 i
, self
->running_process
[i
]->pid
);
681 nb_tracefile
= self
->parent
.tracefiles
->len
;
683 for(i
= 0 ; i
< nb_tracefile
; i
++) {
685 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
686 LttvTracefileContext
*, i
));
687 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
688 tfcs
->parent
.timestamp
.tv_sec
,
689 tfcs
->parent
.timestamp
.tv_nsec
);
690 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
691 if(e
== NULL
) fprintf(fp
,"/>\n");
693 ltt_event_position(e
, ep
);
694 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
695 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
700 fprintf(fp
,"</PROCESS_STATE>\n");
704 static void write_process_state_raw(gpointer key
, gpointer value
,
707 LttvProcessState
*process
;
709 LttvExecutionState
*es
;
711 FILE *fp
= (FILE *)user_data
;
716 process
= (LttvProcessState
*)value
;
717 fputc(HDR_PROCESS
, fp
);
718 //fwrite(&header, sizeof(header), 1, fp);
719 //fprintf(fp, "%s", g_quark_to_string(process->type));
721 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
722 //fprintf(fp, "%s", g_quark_to_string(process->name));
724 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
725 //fprintf(fp, "%s", g_quark_to_string(process->brand));
727 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
728 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
729 fwrite(&process
->free_events
, sizeof(process
->free_events
), 1, fp
);
730 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
731 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
732 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
733 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
734 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
738 " <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",
739 process
, process
->pid
, process
->tgid
, process
->ppid
,
740 g_quark_to_string(process
->type
),
741 process
->creation_time
.tv_sec
,
742 process
->creation_time
.tv_nsec
,
743 process
->insertion_time
.tv_sec
,
744 process
->insertion_time
.tv_nsec
,
745 g_quark_to_string(process
->name
),
746 g_quark_to_string(process
->brand
),
750 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
751 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
754 //fprintf(fp, "%s", g_quark_to_string(es->t));
756 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
757 //fprintf(fp, "%s", g_quark_to_string(es->n));
759 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
760 //fprintf(fp, "%s", g_quark_to_string(es->s));
762 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
763 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
764 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
765 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
767 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
768 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
769 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
770 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
771 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
775 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
776 address
= g_array_index(process
->user_stack
, guint64
, i
);
777 fputc(HDR_USER_STACK
, fp
);
778 fwrite(&address
, sizeof(address
), 1, fp
);
780 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
785 if(process
->usertrace
) {
786 fputc(HDR_USERTRACE
, fp
);
787 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
789 fwrite(&process
->usertrace
->tracefile_name
,
790 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
791 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
793 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
794 g_quark_to_string(process
->usertrace
->tracefile_name
),
795 process
->usertrace
->cpu
);
802 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
804 guint i
, nb_tracefile
, nb_block
, offset
;
807 LttvTracefileState
*tfcs
;
811 LttEventPosition
*ep
;
815 ep
= ltt_event_position_new();
817 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
818 fputc(HDR_PROCESS_STATE
, fp
);
819 fwrite(&t
, sizeof(t
), 1, fp
);
821 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
823 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
824 for(i
=0;i
<nb_cpus
;i
++) {
826 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
827 fwrite(&self
->running_process
[i
]->pid
,
828 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
829 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
830 // i, self->running_process[i]->pid);
833 nb_tracefile
= self
->parent
.tracefiles
->len
;
835 for(i
= 0 ; i
< nb_tracefile
; i
++) {
837 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
838 LttvTracefileContext
*, i
));
839 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
840 // tfcs->parent.timestamp.tv_sec,
841 // tfcs->parent.timestamp.tv_nsec);
842 fputc(HDR_TRACEFILE
, fp
);
843 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
844 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
845 * position following : end of trace */
846 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
848 ltt_event_position(e
, ep
);
849 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
850 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
852 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
853 fwrite(&offset
, sizeof(offset
), 1, fp
);
854 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
861 /* Read process state from a file */
863 /* Called because a HDR_PROCESS was found */
864 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
865 GPtrArray
*quarktable
)
867 LttvExecutionState
*es
;
868 LttvProcessState
*process
, *parent_process
;
869 LttvProcessState tmp
;
874 /* TODO : check return value */
875 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
876 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
877 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
878 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
879 fread(&tmp
.free_events
, sizeof(tmp
.free_events
), 1, fp
);
880 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
881 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
882 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
883 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
884 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
887 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
889 /* We must link to the parent */
890 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
892 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
893 if(process
== NULL
) {
894 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
896 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
900 process
->insertion_time
= tmp
.insertion_time
;
901 process
->creation_time
= tmp
.creation_time
;
902 process
->type
= g_quark_from_string(
903 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
904 process
->tgid
= tmp
.tgid
;
905 process
->ppid
= tmp
.ppid
;
906 process
->brand
= g_quark_from_string(
907 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
909 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
910 process
->free_events
= tmp
.free_events
;
913 if(feof(fp
) || ferror(fp
)) goto end_loop
;
915 gint hdr
= fgetc(fp
);
916 if(hdr
== EOF
) goto end_loop
;
920 process
->execution_stack
=
921 g_array_set_size(process
->execution_stack
,
922 process
->execution_stack
->len
+ 1);
923 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
924 process
->execution_stack
->len
-1);
927 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
928 es
->t
= g_quark_from_string(
929 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
930 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
931 es
->n
= g_quark_from_string(
932 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
933 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
934 es
->s
= g_quark_from_string(
935 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
936 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
937 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
938 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
941 process
->user_stack
= g_array_set_size(process
->user_stack
,
942 process
->user_stack
->len
+ 1);
943 address
= &g_array_index(process
->user_stack
, guint64
,
944 process
->user_stack
->len
-1);
945 fread(address
, sizeof(address
), 1, fp
);
946 process
->current_function
= *address
;
949 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
950 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
962 /* Called because a HDR_PROCESS_STATE was found */
963 /* Append a saved state to the trace states */
964 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
966 guint i
, nb_tracefile
, nb_block
, offset
;
968 LttvTracefileState
*tfcs
;
970 LttEventPosition
*ep
;
978 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
980 LttvAttributeValue value
;
981 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
982 ep
= ltt_event_position_new();
984 restore_init_state(self
);
986 fread(&t
, sizeof(t
), 1, fp
);
989 if(feof(fp
) || ferror(fp
)) goto end_loop
;
991 if(hdr
== EOF
) goto end_loop
;
995 /* Call read_process_state_raw */
996 read_process_state_raw(self
, fp
, quarktable
);
1004 case HDR_USER_STACK
:
1006 case HDR_PROCESS_STATE
:
1012 g_error("Error while parsing saved state file : unknown data header %d",
1018 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1019 for(i
=0;i
<nb_cpus
;i
++) {
1022 g_assert(hdr
== HDR_CPU
);
1023 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1024 g_assert(i
== cpu_num
);
1025 fread(&self
->running_process
[i
]->pid
,
1026 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1029 nb_tracefile
= self
->parent
.tracefiles
->len
;
1031 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1033 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1034 LttvTracefileContext
*, i
));
1035 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1036 // tfcs->parent.timestamp.tv_sec,
1037 // tfcs->parent.timestamp.tv_nsec);
1038 g_tree_remove(pqueue
, &tfcs
->parent
);
1040 g_assert(hdr
== HDR_TRACEFILE
);
1041 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1042 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1043 * position following : end of trace */
1044 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1045 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1046 fread(&offset
, sizeof(offset
), 1, fp
);
1047 fread(&tsc
, sizeof(tsc
), 1, fp
);
1048 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1049 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1051 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1056 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1057 LTTV_STATE_SAVED_STATES
);
1058 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1059 value
= lttv_attribute_add(saved_states_tree
,
1060 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1061 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1062 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1063 *(value
.v_time
) = t
;
1064 lttv_state_save(self
, saved_state_tree
);
1065 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1068 *(self
->max_time_state_recomputed_in_seek
) = t
;
1072 /* Called when a HDR_TRACE is found */
1073 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1074 GPtrArray
*quarktable
)
1079 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1081 if(hdr
== EOF
) goto end_loop
;
1084 case HDR_PROCESS_STATE
:
1085 /* Call read_process_state_raw */
1086 lttv_state_read_raw(tcs
, fp
, quarktable
);
1094 case HDR_USER_STACK
:
1098 g_error("Error while parsing saved state file :"
1099 " unexpected data header %d",
1103 g_error("Error while parsing saved state file : unknown data header %d",
1108 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1109 restore_init_state(tcs
);
1110 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1116 /* Copy each process from an existing hash table to a new one */
1118 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1120 LttvProcessState
*process
, *new_process
;
1122 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1126 process
= (LttvProcessState
*)value
;
1127 new_process
= g_new(LttvProcessState
, 1);
1128 *new_process
= *process
;
1129 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1130 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1131 new_process
->execution_stack
=
1132 g_array_set_size(new_process
->execution_stack
,
1133 process
->execution_stack
->len
);
1134 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1135 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1136 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1138 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1139 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1140 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1141 sizeof(guint64
), 0);
1142 new_process
->user_stack
=
1143 g_array_set_size(new_process
->user_stack
,
1144 process
->user_stack
->len
);
1145 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1146 g_array_index(new_process
->user_stack
, guint64
, i
) =
1147 g_array_index(process
->user_stack
, guint64
, i
);
1149 new_process
->current_function
= process
->current_function
;
1150 g_hash_table_insert(new_processes
, new_process
, new_process
);
1154 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1156 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1158 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1159 return new_processes
;
1162 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1165 LttvCPUState
*retval
;
1167 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1169 for(i
=0; i
<n
; i
++) {
1170 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1171 retval
[i
].last_irq
= states
[i
].last_irq
;
1172 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1173 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1174 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1181 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1185 for(i
=0; i
<n
; i
++) {
1186 g_array_free(states
[i
].mode_stack
, TRUE
);
1192 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1195 LttvIRQState
*retval
;
1197 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1199 for(i
=0; i
<n
; i
++) {
1200 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1201 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1202 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1203 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1210 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1214 for(i
=0; i
<n
; i
++) {
1215 g_array_free(states
[i
].mode_stack
, TRUE
);
1221 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1224 LttvSoftIRQState
*retval
;
1226 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1228 for(i
=0; i
<n
; i
++) {
1229 retval
[i
].running
= states
[i
].running
;
1235 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1240 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1243 LttvTrapState
*retval
;
1245 retval
= g_malloc(n
*sizeof(LttvTrapState
));
1247 for(i
=0; i
<n
; i
++) {
1248 retval
[i
].running
= states
[i
].running
;
1254 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1259 /* bdevstate stuff */
1261 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1263 gint devcode_gint
= devcode
;
1264 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1266 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1267 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1269 gint
* key
= g_malloc(sizeof(gint
));
1271 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1279 static LttvBdevState
*bdevstate_new(void)
1281 LttvBdevState
*retval
;
1282 retval
= g_malloc(sizeof(LttvBdevState
));
1283 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1288 static void bdevstate_free(LttvBdevState
*bds
)
1290 g_array_free(bds
->mode_stack
, TRUE
);
1294 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1296 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1298 bdevstate_free(bds
);
1301 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1303 LttvBdevState
*retval
;
1305 retval
= bdevstate_new();
1306 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1311 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1313 //GHashTable *ht = (GHashTable *)u;
1314 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1315 LttvBdevState
*newbds
;
1317 newbds
= bdevstate_copy(bds
);
1319 g_hash_table_insert(u
, k
, newbds
);
1322 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1326 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1328 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1333 /* Free a hashtable and the LttvBdevState structures its values
1336 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1338 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1339 g_hash_table_destroy(ht
);
1342 /* The saved state for each trace contains a member "processes", which
1343 stores a copy of the process table, and a member "tracefiles" with
1344 one entry per tracefile. Each tracefile has a "process" member pointing
1345 to the current process and a "position" member storing the tracefile
1346 position (needed to seek to the current "next" event. */
1348 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1350 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1352 LttvTracefileState
*tfcs
;
1354 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1356 guint
*running_process
;
1358 LttvAttributeValue value
;
1360 LttEventPosition
*ep
;
1362 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1363 LTTV_STATE_TRACEFILES
);
1365 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1367 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1369 /* Add the currently running processes array */
1370 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1371 running_process
= g_new(guint
, nb_cpus
);
1372 for(i
=0;i
<nb_cpus
;i
++) {
1373 running_process
[i
] = self
->running_process
[i
]->pid
;
1375 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1377 *(value
.v_pointer
) = running_process
;
1379 g_info("State save");
1381 nb_tracefile
= self
->parent
.tracefiles
->len
;
1383 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1385 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1386 LttvTracefileContext
*, i
));
1387 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1388 value
= lttv_attribute_add(tracefiles_tree
, i
,
1390 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1392 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1394 *(value
.v_uint
) = tfcs
->process
->pid
;
1396 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1398 /* Only save the position if the tfs has not infinite time. */
1399 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1400 // && current_tfcs != tfcs) {
1401 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1402 *(value
.v_pointer
) = NULL
;
1404 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1405 ep
= ltt_event_position_new();
1406 ltt_event_position(e
, ep
);
1407 *(value
.v_pointer
) = ep
;
1409 guint nb_block
, offset
;
1412 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1413 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1415 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1419 /* save the cpu state */
1421 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1423 *(value
.v_uint
) = nb_cpus
;
1425 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1427 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1430 /* save the irq state */
1431 nb_irqs
= self
->nb_irqs
;
1433 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1435 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1438 /* save the soft irq state */
1439 nb_soft_irqs
= self
->nb_soft_irqs
;
1441 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1443 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1446 /* save the trap state */
1447 nb_traps
= self
->nb_traps
;
1449 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1451 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1454 /* save the blkdev states */
1455 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1457 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1461 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1463 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1465 LttvTracefileState
*tfcs
;
1467 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1469 guint
*running_process
;
1471 LttvAttributeType type
;
1473 LttvAttributeValue value
;
1475 LttvAttributeName name
;
1479 LttEventPosition
*ep
;
1481 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1483 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1484 LTTV_STATE_TRACEFILES
);
1486 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1488 g_assert(type
== LTTV_POINTER
);
1489 lttv_state_free_process_table(self
->processes
);
1490 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1492 /* Add the currently running processes array */
1493 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1494 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1496 g_assert(type
== LTTV_POINTER
);
1497 running_process
= *(value
.v_pointer
);
1498 for(i
=0;i
<nb_cpus
;i
++) {
1499 pid
= running_process
[i
];
1500 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1501 g_assert(self
->running_process
[i
] != NULL
);
1504 nb_tracefile
= self
->parent
.tracefiles
->len
;
1506 //g_tree_destroy(tsc->pqueue);
1507 //tsc->pqueue = g_tree_new(compare_tracefile);
1509 /* restore cpu resource states */
1510 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1511 g_assert(type
== LTTV_POINTER
);
1512 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1513 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1515 /* restore irq resource states */
1516 nb_irqs
= self
->nb_irqs
;
1517 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1518 g_assert(type
== LTTV_POINTER
);
1519 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1520 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1522 /* restore soft irq resource states */
1523 nb_soft_irqs
= self
->nb_soft_irqs
;
1524 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1525 g_assert(type
== LTTV_POINTER
);
1526 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1527 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1529 /* restore trap resource states */
1530 nb_traps
= self
->nb_traps
;
1531 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1532 g_assert(type
== LTTV_POINTER
);
1533 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1534 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1536 /* restore the blkdev states */
1537 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1538 g_assert(type
== LTTV_POINTER
);
1539 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1540 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1542 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1544 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1545 LttvTracefileContext
*, i
));
1546 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1547 g_assert(type
== LTTV_GOBJECT
);
1548 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1550 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1552 g_assert(type
== LTTV_UINT
);
1553 pid
= *(value
.v_uint
);
1554 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1556 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1558 g_assert(type
== LTTV_POINTER
);
1559 //g_assert(*(value.v_pointer) != NULL);
1560 ep
= *(value
.v_pointer
);
1561 g_assert(tfcs
->parent
.t_context
!= NULL
);
1563 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1565 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1566 g_tree_remove(tsc
->pqueue
, tfc
);
1569 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1570 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1571 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1572 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1573 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1575 tfc
->timestamp
= ltt_time_infinite
;
1581 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1583 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1585 LttvTracefileState
*tfcs
;
1587 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1589 guint
*running_process
;
1591 LttvAttributeType type
;
1593 LttvAttributeValue value
;
1595 LttvAttributeName name
;
1599 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1600 LTTV_STATE_TRACEFILES
);
1601 g_object_ref(G_OBJECT(tracefiles_tree
));
1602 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1604 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1606 g_assert(type
== LTTV_POINTER
);
1607 lttv_state_free_process_table(*(value
.v_pointer
));
1608 *(value
.v_pointer
) = NULL
;
1609 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1611 /* Free running processes array */
1612 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1614 g_assert(type
== LTTV_POINTER
);
1615 running_process
= *(value
.v_pointer
);
1616 g_free(running_process
);
1618 /* free cpu resource states */
1619 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1620 g_assert(type
== LTTV_UINT
);
1621 nb_cpus
= *value
.v_uint
;
1622 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1623 g_assert(type
== LTTV_POINTER
);
1624 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1626 /* free irq resource states */
1627 nb_irqs
= self
->nb_irqs
;
1628 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1629 g_assert(type
== LTTV_POINTER
);
1630 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1632 /* free the blkdev states */
1633 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1634 g_assert(type
== LTTV_POINTER
);
1635 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1637 nb_tracefile
= self
->parent
.tracefiles
->len
;
1639 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1641 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1642 LttvTracefileContext
*, i
));
1643 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1644 g_assert(type
== LTTV_GOBJECT
);
1645 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1647 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1649 g_assert(type
== LTTV_POINTER
);
1650 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1652 g_object_unref(G_OBJECT(tracefiles_tree
));
1656 static void free_saved_state(LttvTraceState
*self
)
1660 LttvAttributeType type
;
1662 LttvAttributeValue value
;
1664 LttvAttributeName name
;
1668 LttvAttribute
*saved_states
;
1670 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1671 LTTV_STATE_SAVED_STATES
);
1673 nb
= lttv_attribute_get_number(saved_states
);
1674 for(i
= 0 ; i
< nb
; i
++) {
1675 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1676 g_assert(type
== LTTV_GOBJECT
);
1677 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1680 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1685 create_max_time(LttvTraceState
*tcs
)
1687 LttvAttributeValue v
;
1689 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1691 g_assert(*(v
.v_pointer
) == NULL
);
1692 *(v
.v_pointer
) = g_new(LttTime
,1);
1693 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1698 get_max_time(LttvTraceState
*tcs
)
1700 LttvAttributeValue v
;
1702 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1704 g_assert(*(v
.v_pointer
) != NULL
);
1705 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1710 free_max_time(LttvTraceState
*tcs
)
1712 LttvAttributeValue v
;
1714 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1716 g_free(*(v
.v_pointer
));
1717 *(v
.v_pointer
) = NULL
;
1721 typedef struct _LttvNameTables
{
1722 // FIXME GQuark *eventtype_names;
1723 GQuark
*syscall_names
;
1729 GQuark
*soft_irq_names
;
1735 create_name_tables(LttvTraceState
*tcs
)
1739 GString
*fe_name
= g_string_new("");
1741 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1743 LttvAttributeValue v
;
1747 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1749 g_assert(*(v
.v_pointer
) == NULL
);
1750 *(v
.v_pointer
) = name_tables
;
1752 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1754 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1755 LTT_FACILITY_KERNEL_ARCH
,
1756 LTT_EVENT_SYSCALL_ENTRY
,
1757 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1758 NULL
, NULL
, &hooks
)) {
1760 // th = lttv_trace_hook_get_first(&th);
1762 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1763 // nb = ltt_type_element_number(t);
1765 // name_tables->syscall_names = g_new(GQuark, nb);
1766 // name_tables->nb_syscalls = nb;
1768 // for(i = 0 ; i < nb ; i++) {
1769 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1770 // if(!name_tables->syscall_names[i]) {
1771 // GString *string = g_string_new("");
1772 // g_string_printf(string, "syscall %u", i);
1773 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1774 // g_string_free(string, TRUE);
1778 name_tables
->nb_syscalls
= 256;
1779 name_tables
->syscall_names
= g_new(GQuark
, 256);
1780 for(i
= 0 ; i
< 256 ; i
++) {
1781 g_string_printf(fe_name
, "syscall %d", i
);
1782 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1785 name_tables
->syscall_names
= NULL
;
1786 name_tables
->nb_syscalls
= 0;
1788 lttv_trace_hook_remove_all(&hooks
);
1790 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1791 LTT_FACILITY_KERNEL_ARCH
,
1792 LTT_EVENT_TRAP_ENTRY
,
1793 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1794 NULL
, NULL
, &hooks
)) {
1796 // th = lttv_trace_hook_get_first(&th);
1798 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1799 // //nb = ltt_type_element_number(t);
1801 // name_tables->trap_names = g_new(GQuark, nb);
1802 // for(i = 0 ; i < nb ; i++) {
1803 // name_tables->trap_names[i] = g_quark_from_string(
1804 // ltt_enum_string_get(t, i));
1807 name_tables
->nb_traps
= 256;
1808 name_tables
->trap_names
= g_new(GQuark
, 256);
1809 for(i
= 0 ; i
< 256 ; i
++) {
1810 g_string_printf(fe_name
, "trap %d", i
);
1811 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1814 name_tables
->trap_names
= NULL
;
1815 name_tables
->nb_traps
= 0;
1817 lttv_trace_hook_remove_all(&hooks
);
1819 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1820 LTT_FACILITY_KERNEL
,
1821 LTT_EVENT_IRQ_ENTRY
,
1822 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1823 NULL
, NULL
, &hooks
)) {
1826 name_tables->irq_names = g_new(GQuark, nb);
1827 for(i = 0 ; i < nb ; i++) {
1828 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1832 name_tables
->nb_irqs
= 256;
1833 name_tables
->irq_names
= g_new(GQuark
, 256);
1834 for(i
= 0 ; i
< 256 ; i
++) {
1835 g_string_printf(fe_name
, "irq %d", i
);
1836 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1839 name_tables
->nb_irqs
= 0;
1840 name_tables
->irq_names
= NULL
;
1842 lttv_trace_hook_remove_all(&hooks
);
1844 name_tables->soft_irq_names = g_new(GQuark, nb);
1845 for(i = 0 ; i < nb ; i++) {
1846 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1850 /* the kernel is limited to 32 statically defined softirqs */
1851 name_tables
->nb_softirqs
= 32;
1852 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1853 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1854 g_string_printf(fe_name
, "softirq %d", i
);
1855 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1857 g_array_free(hooks
, TRUE
);
1859 g_string_free(fe_name
, TRUE
);
1864 get_name_tables(LttvTraceState
*tcs
)
1866 LttvNameTables
*name_tables
;
1868 LttvAttributeValue v
;
1870 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1872 g_assert(*(v
.v_pointer
) != NULL
);
1873 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1874 //tcs->eventtype_names = name_tables->eventtype_names;
1875 tcs
->syscall_names
= name_tables
->syscall_names
;
1876 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1877 tcs
->trap_names
= name_tables
->trap_names
;
1878 tcs
->nb_traps
= name_tables
->nb_traps
;
1879 tcs
->irq_names
= name_tables
->irq_names
;
1880 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1881 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1882 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1887 free_name_tables(LttvTraceState
*tcs
)
1889 LttvNameTables
*name_tables
;
1891 LttvAttributeValue v
;
1893 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1895 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1896 *(v
.v_pointer
) = NULL
;
1898 // g_free(name_tables->eventtype_names);
1899 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1900 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1901 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1902 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1903 if(name_tables
) g_free(name_tables
);
1906 #ifdef HASH_TABLE_DEBUG
1908 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1910 LttvProcessState
*process
= (LttvProcessState
*)value
;
1912 /* Test for process corruption */
1913 guint stack_len
= process
->execution_stack
->len
;
1916 static void hash_table_check(GHashTable
*table
)
1918 g_hash_table_foreach(table
, test_process
, NULL
);
1924 /* clears the stack and sets the state passed as argument */
1925 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1927 g_array_set_size(cpust
->mode_stack
, 1);
1928 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1931 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1933 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1934 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1937 static void cpu_pop_mode(LttvCPUState
*cpust
)
1939 if(cpust
->mode_stack
->len
<= 1)
1940 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1942 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1945 /* clears the stack and sets the state passed as argument */
1946 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1948 g_array_set_size(bdevst
->mode_stack
, 1);
1949 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1952 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1954 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1955 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1958 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1960 if(bdevst
->mode_stack
->len
<= 1)
1961 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1963 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1966 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1968 g_array_set_size(irqst
->mode_stack
, 1);
1969 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1972 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1974 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1975 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1978 static void irq_pop_mode(LttvIRQState
*irqst
)
1980 if(irqst
->mode_stack
->len
<= 1)
1981 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1983 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1986 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1989 LttvExecutionState
*es
;
1991 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1992 guint cpu
= tfs
->cpu
;
1994 #ifdef HASH_TABLE_DEBUG
1995 hash_table_check(ts
->processes
);
1997 LttvProcessState
*process
= ts
->running_process
[cpu
];
1999 guint depth
= process
->execution_stack
->len
;
2001 process
->execution_stack
=
2002 g_array_set_size(process
->execution_stack
, depth
+ 1);
2005 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2007 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2010 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2011 es
->cum_cpu_time
= ltt_time_zero
;
2012 es
->s
= process
->state
->s
;
2013 process
->state
= es
;
2017 * return 1 when empty, else 0 */
2018 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2019 LttvTracefileState
*tfs
)
2021 guint depth
= process
->execution_stack
->len
;
2027 process
->execution_stack
=
2028 g_array_set_size(process
->execution_stack
, depth
- 1);
2029 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2031 process
->state
->change
= tfs
->parent
.timestamp
;
2036 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2038 guint cpu
= tfs
->cpu
;
2039 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2040 LttvProcessState
*process
= ts
->running_process
[cpu
];
2042 guint depth
= process
->execution_stack
->len
;
2044 if(process
->state
->t
!= t
){
2045 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2046 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2047 g_info("process state has %s when pop_int is %s\n",
2048 g_quark_to_string(process
->state
->t
),
2049 g_quark_to_string(t
));
2050 g_info("{ %u, %u, %s, %s, %s }\n",
2053 g_quark_to_string(process
->name
),
2054 g_quark_to_string(process
->brand
),
2055 g_quark_to_string(process
->state
->s
));
2060 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2061 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2065 process
->execution_stack
=
2066 g_array_set_size(process
->execution_stack
, depth
- 1);
2067 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2069 process
->state
->change
= tfs
->parent
.timestamp
;
2072 struct search_result
{
2073 const LttTime
*time
; /* Requested time */
2074 LttTime
*best
; /* Best result */
2077 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2079 const LttTime
*elem_time
= (const LttTime
*)a
;
2080 /* Explicit non const cast */
2081 struct search_result
*res
= (struct search_result
*)b
;
2083 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2084 /* The usertrace was created before the schedchange */
2085 /* Get larger keys */
2087 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2088 /* The usertrace was created after the schedchange time */
2089 /* Get smaller keys */
2091 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2092 res
->best
= (LttTime
*)elem_time
;
2095 res
->best
= (LttTime
*)elem_time
;
2102 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2103 guint pid
, const LttTime
*timestamp
)
2105 LttvTracefileState
*tfs
= NULL
;
2106 struct search_result res
;
2107 /* Find the usertrace associated with a pid and time interval.
2108 * Search in the usertraces by PID (within a hash) and then, for each
2109 * corresponding element of the array, find the first one with creation
2110 * timestamp the lowest, but higher or equal to "timestamp". */
2111 res
.time
= timestamp
;
2113 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2114 if(usertrace_tree
) {
2115 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2117 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2125 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2126 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2128 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2130 LttvExecutionState
*es
;
2135 process
->tgid
= tgid
;
2137 process
->name
= name
;
2138 process
->brand
= LTTV_STATE_UNBRANDED
;
2139 //process->last_cpu = tfs->cpu_name;
2140 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2141 process
->type
= LTTV_STATE_USER_THREAD
;
2142 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2143 process
->current_function
= 0; //function 0x0 by default.
2145 g_info("Process %u, core %p", process
->pid
, process
);
2146 g_hash_table_insert(tcs
->processes
, process
, process
);
2149 process
->ppid
= parent
->pid
;
2150 process
->creation_time
= *timestamp
;
2153 /* No parent. This process exists but we are missing all information about
2154 its creation. The birth time is set to zero but we remember the time of
2159 process
->creation_time
= ltt_time_zero
;
2162 process
->insertion_time
= *timestamp
;
2163 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2164 process
->creation_time
.tv_nsec
);
2165 process
->pid_time
= g_quark_from_string(buffer
);
2167 process
->free_events
= 0;
2168 //process->last_cpu = tfs->cpu_name;
2169 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2170 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2171 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2172 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2173 es
= process
->state
= &g_array_index(process
->execution_stack
,
2174 LttvExecutionState
, 0);
2175 es
->t
= LTTV_STATE_USER_MODE
;
2176 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2177 es
->entry
= *timestamp
;
2178 //g_assert(timestamp->tv_sec != 0);
2179 es
->change
= *timestamp
;
2180 es
->cum_cpu_time
= ltt_time_zero
;
2181 es
->s
= LTTV_STATE_RUN
;
2183 es
= process
->state
= &g_array_index(process
->execution_stack
,
2184 LttvExecutionState
, 1);
2185 es
->t
= LTTV_STATE_SYSCALL
;
2186 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2187 es
->entry
= *timestamp
;
2188 //g_assert(timestamp->tv_sec != 0);
2189 es
->change
= *timestamp
;
2190 es
->cum_cpu_time
= ltt_time_zero
;
2191 es
->s
= LTTV_STATE_WAIT_FORK
;
2193 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2194 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2195 sizeof(guint64
), 0);
2200 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2203 LttvProcessState key
;
2204 LttvProcessState
*process
;
2208 process
= g_hash_table_lookup(ts
->processes
, &key
);
2213 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2214 const LttTime
*timestamp
)
2216 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2217 LttvExecutionState
*es
;
2219 /* Put ltt_time_zero creation time for unexisting processes */
2220 if(unlikely(process
== NULL
)) {
2221 process
= lttv_state_create_process(ts
,
2222 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2223 /* We are not sure is it's a kernel thread or normal thread, put the
2224 * bottom stack state to unknown */
2225 process
->execution_stack
=
2226 g_array_set_size(process
->execution_stack
, 1);
2227 process
->state
= es
=
2228 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2229 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2230 es
->s
= LTTV_STATE_UNNAMED
;
2235 /* FIXME : this function should be called when we receive an event telling that
2236 * release_task has been called in the kernel. In happens generally when
2237 * the parent waits for its child terminaison, but may also happen in special
2238 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2239 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2240 * of a killed thread group, but isn't the leader.
2242 static int exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2244 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2245 LttvProcessState key
;
2247 /* Wait for both schedule with exit dead and process free to happen.
2248 * They can happen in any order. */
2249 if (++(process
->free_events
) < 2)
2252 key
.pid
= process
->pid
;
2253 key
.cpu
= process
->cpu
;
2254 g_hash_table_remove(ts
->processes
, &key
);
2255 g_array_free(process
->execution_stack
, TRUE
);
2256 g_array_free(process
->user_stack
, TRUE
);
2262 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2264 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2265 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2270 static void lttv_state_free_process_table(GHashTable
*processes
)
2272 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2273 g_hash_table_destroy(processes
);
2277 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2279 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2281 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2282 LttvProcessState
*process
= ts
->running_process
[cpu
];
2283 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2284 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2285 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2287 LttvExecutionSubmode submode
;
2289 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2290 guint syscall
= ltt_event_get_unsigned(e
, f
);
2292 if(syscall
< nb_syscalls
) {
2293 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2296 /* Fixup an incomplete syscall table */
2297 GString
*string
= g_string_new("");
2298 g_string_printf(string
, "syscall %u", syscall
);
2299 submode
= g_quark_from_string(string
->str
);
2300 g_string_free(string
, TRUE
);
2302 /* There can be no system call from PID 0 : unknown state */
2303 if(process
->pid
!= 0)
2304 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2309 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2311 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2313 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2314 LttvProcessState
*process
= ts
->running_process
[cpu
];
2316 /* There can be no system call from PID 0 : unknown state */
2317 if(process
->pid
!= 0)
2318 pop_state(s
, LTTV_STATE_SYSCALL
);
2323 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2325 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2326 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2327 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2328 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2329 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2331 LttvExecutionSubmode submode
;
2333 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2334 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2336 if(trap
< nb_traps
) {
2337 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2339 /* Fixup an incomplete trap table */
2340 GString
*string
= g_string_new("");
2341 g_string_printf(string
, "trap %llu", trap
);
2342 submode
= g_quark_from_string(string
->str
);
2343 g_string_free(string
, TRUE
);
2346 push_state(s
, LTTV_STATE_TRAP
, submode
);
2348 /* update cpu status */
2349 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2351 /* update trap status */
2352 s
->cpu_state
->last_trap
= trap
;
2353 ts
->trap_states
[trap
].running
++;
2358 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2360 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2361 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2362 guint trap
= s
->cpu_state
->last_trap
;
2364 pop_state(s
, LTTV_STATE_TRAP
);
2366 /* update cpu status */
2367 cpu_pop_mode(s
->cpu_state
);
2369 /* update trap status */
2370 if(ts
->trap_states
[trap
].running
)
2371 ts
->trap_states
[trap
].running
--;
2376 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2378 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2379 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2380 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2381 //guint8 ev_id = ltt_event_eventtype_id(e);
2382 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2383 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2385 LttvExecutionSubmode submode
;
2386 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2387 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2390 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2392 /* Fixup an incomplete irq table */
2393 GString
*string
= g_string_new("");
2394 g_string_printf(string
, "irq %llu", irq
);
2395 submode
= g_quark_from_string(string
->str
);
2396 g_string_free(string
, TRUE
);
2399 /* Do something with the info about being in user or system mode when int? */
2400 push_state(s
, LTTV_STATE_IRQ
, submode
);
2402 /* update cpu status */
2403 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2405 /* update irq status */
2406 s
->cpu_state
->last_irq
= irq
;
2407 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2412 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2414 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2415 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2416 guint softirq
= s
->cpu_state
->last_soft_irq
;
2418 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2420 /* update softirq status */
2421 if(ts
->soft_irq_states
[softirq
].running
)
2422 ts
->soft_irq_states
[softirq
].running
--;
2424 /* update cpu status */
2425 cpu_pop_mode(s
->cpu_state
);
2430 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2432 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2433 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2435 pop_state(s
, LTTV_STATE_IRQ
);
2437 /* update cpu status */
2438 cpu_pop_mode(s
->cpu_state
);
2440 /* update irq status */
2441 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2446 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2448 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2449 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2450 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2451 //guint8 ev_id = ltt_event_eventtype_id(e);
2452 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2453 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2455 LttvExecutionSubmode submode
;
2456 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2457 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2459 if(softirq
< nb_softirqs
) {
2460 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2462 /* Fixup an incomplete irq table */
2463 GString
*string
= g_string_new("");
2464 g_string_printf(string
, "softirq %llu", softirq
);
2465 submode
= g_quark_from_string(string
->str
);
2466 g_string_free(string
, TRUE
);
2469 /* Do something with the info about being in user or system mode when int? */
2470 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2472 /* update cpu status */
2473 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2475 /* update softirq status */
2476 s
->cpu_state
->last_soft_irq
= softirq
;
2477 ts
->soft_irq_states
[softirq
].running
++;
2482 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2484 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2485 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2486 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2487 //guint8 ev_id = ltt_event_eventtype_id(e);
2488 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2490 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2491 lttv_trace_get_hook_field(th
, 0)));
2492 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2494 ts
->irq_names
[irq
] = action
;
2500 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2502 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2503 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2504 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2505 //guint8 ev_id = ltt_event_eventtype_id(e);
2506 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2508 guint major
= ltt_event_get_long_unsigned(e
,
2509 lttv_trace_get_hook_field(th
, 0));
2510 guint minor
= ltt_event_get_long_unsigned(e
,
2511 lttv_trace_get_hook_field(th
, 1));
2512 guint oper
= ltt_event_get_long_unsigned(e
,
2513 lttv_trace_get_hook_field(th
, 2));
2514 guint16 devcode
= MKDEV(major
,minor
);
2516 /* have we seen this block device before? */
2517 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2520 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2522 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2527 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2529 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2530 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2531 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2532 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2534 guint major
= ltt_event_get_long_unsigned(e
,
2535 lttv_trace_get_hook_field(th
, 0));
2536 guint minor
= ltt_event_get_long_unsigned(e
,
2537 lttv_trace_get_hook_field(th
, 1));
2538 //guint oper = ltt_event_get_long_unsigned(e,
2539 // lttv_trace_get_hook_field(th, 2));
2540 guint16 devcode
= MKDEV(major
,minor
);
2542 /* have we seen this block device before? */
2543 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2545 /* update block device */
2546 bdev_pop_mode(bdev
);
2551 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2555 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2556 guint cpu
= tfs
->cpu
;
2557 LttvProcessState
*process
= ts
->running_process
[cpu
];
2559 guint depth
= process
->user_stack
->len
;
2561 process
->user_stack
=
2562 g_array_set_size(process
->user_stack
, depth
+ 1);
2564 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2565 *new_func
= funcptr
;
2566 process
->current_function
= funcptr
;
2569 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2571 guint cpu
= tfs
->cpu
;
2572 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2573 LttvProcessState
*process
= ts
->running_process
[cpu
];
2575 if(process
->current_function
!= funcptr
){
2576 g_info("Different functions (%lu.%09lu): ignore it\n",
2577 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2578 g_info("process state has %llu when pop_function is %llu\n",
2579 process
->current_function
, funcptr
);
2580 g_info("{ %u, %u, %s, %s, %s }\n",
2583 g_quark_to_string(process
->name
),
2584 g_quark_to_string(process
->brand
),
2585 g_quark_to_string(process
->state
->s
));
2588 guint depth
= process
->user_stack
->len
;
2591 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2592 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2596 process
->user_stack
=
2597 g_array_set_size(process
->user_stack
, depth
- 1);
2598 process
->current_function
=
2599 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2603 static gboolean
function_entry(void *hook_data
, void *call_data
)
2605 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2606 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2607 //guint8 ev_id = ltt_event_eventtype_id(e);
2608 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2609 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2610 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2612 push_function(s
, funcptr
);
2616 static gboolean
function_exit(void *hook_data
, void *call_data
)
2618 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2619 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2620 //guint8 ev_id = ltt_event_eventtype_id(e);
2621 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2622 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2623 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2625 pop_function(s
, funcptr
);
2629 static gboolean
schedchange(void *hook_data
, void *call_data
)
2631 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2633 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2634 LttvProcessState
*process
= ts
->running_process
[cpu
];
2635 //LttvProcessState *old_process = ts->running_process[cpu];
2637 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2638 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2639 guint pid_in
, pid_out
;
2642 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2643 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2644 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2646 if(likely(process
!= NULL
)) {
2648 /* We could not know but it was not the idle process executing.
2649 This should only happen at the beginning, before the first schedule
2650 event, and when the initial information (current process for each CPU)
2651 is missing. It is not obvious how we could, after the fact, compensate
2652 the wrongly attributed statistics. */
2654 //This test only makes sense once the state is known and if there is no
2655 //missing events. We need to silently ignore schedchange coming after a
2656 //process_free, or it causes glitches. (FIXME)
2657 //if(unlikely(process->pid != pid_out)) {
2658 // g_assert(process->pid == 0);
2660 if(process
->pid
== 0
2661 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2663 /* Scheduling out of pid 0 at beginning of the trace :
2664 * we know for sure it is in syscall mode at this point. */
2665 g_assert(process
->execution_stack
->len
== 1);
2666 process
->state
->t
= LTTV_STATE_SYSCALL
;
2667 process
->state
->s
= LTTV_STATE_WAIT
;
2668 process
->state
->change
= s
->parent
.timestamp
;
2669 process
->state
->entry
= s
->parent
.timestamp
;
2672 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2673 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2674 process
->state
->change
= s
->parent
.timestamp
;
2676 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2677 else process
->state
->s
= LTTV_STATE_WAIT
;
2678 process
->state
->change
= s
->parent
.timestamp
;
2681 if(state_out
== 32 || state_out
== 64) { /* EXIT_DEAD || TASK_DEAD */
2682 /* see sched.h for states */
2683 if (!exit_process(s
, process
)) {
2684 process
->state
->s
= LTTV_STATE_DEAD
;
2685 process
->state
->change
= s
->parent
.timestamp
;
2690 process
= ts
->running_process
[cpu
] =
2691 lttv_state_find_process_or_create(
2692 (LttvTraceState
*)s
->parent
.t_context
,
2694 &s
->parent
.timestamp
);
2695 process
->state
->s
= LTTV_STATE_RUN
;
2697 if(process
->usertrace
)
2698 process
->usertrace
->cpu
= cpu
;
2699 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2700 process
->state
->change
= s
->parent
.timestamp
;
2702 /* update cpu status */
2704 /* going to idle task */
2705 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2707 /* scheduling a real task.
2708 * we must be careful here:
2709 * if we just schedule()'ed to a process that is
2710 * in a trap, we must put the cpu in trap mode
2712 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2713 if(process
->state
->t
== LTTV_STATE_TRAP
)
2714 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2720 static gboolean
process_fork(void *hook_data
, void *call_data
)
2722 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2723 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2724 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2726 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2727 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2728 //LttvProcessState *zombie_process;
2730 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2731 LttvProcessState
*process
= ts
->running_process
[cpu
];
2732 LttvProcessState
*child_process
;
2733 struct marker_field
*f
;
2736 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2739 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2740 s
->parent
.target_pid
= child_pid
;
2743 f
= lttv_trace_get_hook_field(th
, 2);
2745 child_tgid
= ltt_event_get_unsigned(e
, f
);
2749 /* Mathieu : it seems like the process might have been scheduled in before the
2750 * fork, and, in a rare case, might be the current process. This might happen
2751 * in a SMP case where we don't have enough precision on the clocks.
2753 * Test reenabled after precision fixes on time. (Mathieu) */
2755 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2757 if(unlikely(zombie_process
!= NULL
)) {
2758 /* Reutilisation of PID. Only now we are sure that the old PID
2759 * has been released. FIXME : should know when release_task happens instead.
2761 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2763 for(i
=0; i
< num_cpus
; i
++) {
2764 g_assert(zombie_process
!= ts
->running_process
[i
]);
2767 exit_process(s
, zombie_process
);
2770 g_assert(process
->pid
!= child_pid
);
2771 // FIXME : Add this test in the "known state" section
2772 // g_assert(process->pid == parent_pid);
2773 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2774 if(child_process
== NULL
) {
2775 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2776 child_pid
, child_tgid
,
2777 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2779 /* The process has already been created : due to time imprecision between
2780 * multiple CPUs : it has been scheduled in before creation. Note that we
2781 * shouldn't have this kind of imprecision.
2783 * Simply put a correct parent.
2785 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid
, cpu
);
2786 //g_assert(0); /* This is a problematic case : the process has been created
2787 // before the fork event */
2788 child_process
->ppid
= process
->pid
;
2789 child_process
->tgid
= child_tgid
;
2791 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2792 child_process
->name
= process
->name
;
2793 child_process
->brand
= process
->brand
;
2798 /* We stamp a newly created process as kernel_thread.
2799 * The thread should not be running yet. */
2800 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2802 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2803 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2804 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2806 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2807 LttvProcessState
*process
;
2808 LttvExecutionState
*es
;
2811 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2812 s
->parent
.target_pid
= pid
;
2814 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2816 if (process
->state
->s
!= LTTV_STATE_DEAD
) {
2817 process
->execution_stack
=
2818 g_array_set_size(process
->execution_stack
, 1);
2819 es
= process
->state
=
2820 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2821 es
->t
= LTTV_STATE_SYSCALL
;
2823 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2828 static gboolean
process_exit(void *hook_data
, void *call_data
)
2830 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2831 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2832 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2834 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2835 LttvProcessState
*process
; // = ts->running_process[cpu];
2837 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2838 s
->parent
.target_pid
= pid
;
2840 // FIXME : Add this test in the "known state" section
2841 // g_assert(process->pid == pid);
2843 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2844 if(likely(process
!= NULL
)) {
2845 process
->state
->s
= LTTV_STATE_EXIT
;
2850 static gboolean
process_free(void *hook_data
, void *call_data
)
2852 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2853 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2854 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2855 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2857 LttvProcessState
*process
;
2859 /* PID of the process to release */
2860 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2861 s
->parent
.target_pid
= release_pid
;
2863 g_assert(release_pid
!= 0);
2865 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2866 if(likely(process
!= NULL
))
2867 exit_process(s
, process
);
2870 if(likely(process
!= NULL
)) {
2871 /* release_task is happening at kernel level : we can now safely release
2872 * the data structure of the process */
2873 //This test is fun, though, as it may happen that
2874 //at time t : CPU 0 : process_free
2875 //at time t+150ns : CPU 1 : schedule out
2876 //Clearly due to time imprecision, we disable it. (Mathieu)
2877 //If this weird case happen, we have no choice but to put the
2878 //Currently running process on the cpu to 0.
2879 //I re-enable it following time precision fixes. (Mathieu)
2880 //Well, in the case where an process is freed by a process on another CPU
2881 //and still scheduled, it happens that this is the schedchange that will
2882 //drop the last reference count. Do not free it here!
2883 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2885 for(i
=0; i
< num_cpus
; i
++) {
2886 //g_assert(process != ts->running_process[i]);
2887 if(process
== ts
->running_process
[i
]) {
2888 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2892 if(i
== num_cpus
) /* process is not scheduled */
2893 exit_process(s
, process
);
2900 static gboolean
process_exec(void *hook_data
, void *call_data
)
2902 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2903 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2904 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2905 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2908 LttvProcessState
*process
= ts
->running_process
[cpu
];
2910 #if 0//how to use a sequence that must be transformed in a string
2911 /* PID of the process to release */
2912 guint64 name_len
= ltt_event_field_element_number(e
,
2913 lttv_trace_get_hook_field(th
, 0));
2914 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2915 LttField
*child
= ltt_event_field_element_select(e
,
2916 lttv_trace_get_hook_field(th
, 0), 0);
2918 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2919 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2920 memcpy(null_term_name
, name_begin
, name_len
);
2921 null_term_name
[name_len
] = '\0';
2922 process
->name
= g_quark_from_string(null_term_name
);
2925 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2926 lttv_trace_get_hook_field(th
, 0)));
2927 process
->brand
= LTTV_STATE_UNBRANDED
;
2928 //g_free(null_term_name);
2932 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2934 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2935 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2936 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2937 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2940 LttvProcessState
*process
= ts
->running_process
[cpu
];
2942 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2943 process
->brand
= g_quark_from_string(name
);
2948 static void fix_process(gpointer key
, gpointer value
,
2951 LttvProcessState
*process
;
2952 LttvExecutionState
*es
;
2953 process
= (LttvProcessState
*)value
;
2954 LttTime
*timestamp
= (LttTime
*)user_data
;
2956 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2957 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2958 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2959 es
->t
= LTTV_STATE_SYSCALL
;
2960 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2961 es
->entry
= *timestamp
;
2962 es
->change
= *timestamp
;
2963 es
->cum_cpu_time
= ltt_time_zero
;
2964 if(es
->s
== LTTV_STATE_UNNAMED
)
2965 es
->s
= LTTV_STATE_WAIT
;
2968 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2969 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2970 es
->t
= LTTV_STATE_USER_MODE
;
2971 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2972 es
->entry
= *timestamp
;
2973 //g_assert(timestamp->tv_sec != 0);
2974 es
->change
= *timestamp
;
2975 es
->cum_cpu_time
= ltt_time_zero
;
2976 if(es
->s
== LTTV_STATE_UNNAMED
)
2977 es
->s
= LTTV_STATE_RUN
;
2979 if(process
->execution_stack
->len
== 1) {
2980 /* Still in bottom unknown mode, means never did a system call
2981 * May be either in user mode, syscall mode, running or waiting.*/
2982 /* FIXME : we may be tagging syscall mode when being user mode */
2983 process
->execution_stack
=
2984 g_array_set_size(process
->execution_stack
, 2);
2985 es
= process
->state
= &g_array_index(process
->execution_stack
,
2986 LttvExecutionState
, 1);
2987 es
->t
= LTTV_STATE_SYSCALL
;
2988 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2989 es
->entry
= *timestamp
;
2990 //g_assert(timestamp->tv_sec != 0);
2991 es
->change
= *timestamp
;
2992 es
->cum_cpu_time
= ltt_time_zero
;
2993 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2994 es
->s
= LTTV_STATE_WAIT
;
3000 static gboolean
statedump_end(void *hook_data
, void *call_data
)
3002 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3003 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3004 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
3005 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3006 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3008 /* For all processes */
3009 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3010 /* else, if stack[0] is unknown, set to user mode, running */
3012 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
3017 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3019 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3020 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3021 //It's slow : optimise later by doing this before reading trace.
3022 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3028 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3029 LttvProcessState
*process
= ts
->running_process
[cpu
];
3030 LttvProcessState
*parent_process
;
3031 struct marker_field
*f
;
3032 GQuark type
, mode
, submode
, status
;
3033 LttvExecutionState
*es
;
3037 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3038 s
->parent
.target_pid
= pid
;
3041 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3044 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3047 f
= lttv_trace_get_hook_field(th
, 3);
3048 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3050 //FIXME: type is rarely used, enum must match possible types.
3053 f
= lttv_trace_get_hook_field(th
, 4);
3054 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3057 f
= lttv_trace_get_hook_field(th
, 5);
3058 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3061 f
= lttv_trace_get_hook_field(th
, 6);
3062 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3065 f
= lttv_trace_get_hook_field(th
, 7);
3067 tgid
= ltt_event_get_unsigned(e
, f
);
3072 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3073 for(i
=0; i
<nb_cpus
; i
++) {
3074 process
= lttv_state_find_process(ts
, i
, pid
);
3075 g_assert(process
!= NULL
);
3077 process
->ppid
= parent_pid
;
3078 process
->tgid
= tgid
;
3079 process
->name
= g_quark_from_string(command
);
3081 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3082 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3086 /* The process might exist if a process was forked while performing the
3088 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3089 if(process
== NULL
) {
3090 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3091 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3092 pid
, tgid
, g_quark_from_string(command
),
3093 &s
->parent
.timestamp
);
3095 /* Keep the stack bottom : a running user mode */
3096 /* Disabled because of inconsistencies in the current statedump states. */
3097 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3098 /* Only keep the bottom
3099 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3100 /* Will cause expected trap when in fact being syscall (even after end of
3102 * Will cause expected interrupt when being syscall. (only before end of
3103 * statedump event) */
3104 // This will cause a "popping last state on stack, ignoring it."
3105 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3106 es
= process
->state
= &g_array_index(process
->execution_stack
,
3107 LttvExecutionState
, 0);
3108 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3109 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3110 es
->s
= LTTV_STATE_UNNAMED
;
3111 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3113 es
->t
= LTTV_STATE_SYSCALL
;
3118 /* User space process :
3119 * bottom : user mode
3120 * either currently running or scheduled out.
3121 * can be scheduled out because interrupted in (user mode or in syscall)
3122 * or because of an explicit call to the scheduler in syscall. Note that
3123 * the scheduler call comes after the irq_exit, so never in interrupt
3125 // temp workaround : set size to 1 : only have user mode bottom of stack.
3126 // will cause g_info message of expected syscall mode when in fact being
3127 // in user mode. Can also cause expected trap when in fact being user
3128 // mode in the event of a page fault reenabling interrupts in the handler.
3129 // Expected syscall and trap can also happen after the end of statedump
3130 // This will cause a "popping last state on stack, ignoring it."
3131 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3132 es
= process
->state
= &g_array_index(process
->execution_stack
,
3133 LttvExecutionState
, 0);
3134 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3135 es
->s
= LTTV_STATE_UNNAMED
;
3136 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3138 es
->t
= LTTV_STATE_USER_MODE
;
3146 es
= process
->state
= &g_array_index(process
->execution_stack
,
3147 LttvExecutionState
, 1);
3148 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3149 es
->s
= LTTV_STATE_UNNAMED
;
3150 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3154 /* The process has already been created :
3155 * Probably was forked while dumping the process state or
3156 * was simply scheduled in prior to get the state dump event.
3158 process
->ppid
= parent_pid
;
3159 process
->tgid
= tgid
;
3160 process
->name
= g_quark_from_string(command
);
3161 process
->type
= type
;
3163 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3165 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3166 if(type
== LTTV_STATE_KERNEL_THREAD
)
3167 es
->t
= LTTV_STATE_SYSCALL
;
3169 es
->t
= LTTV_STATE_USER_MODE
;
3172 /* Don't mess around with the stack, it will eventually become
3173 * ok after the end of state dump. */
3180 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3182 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3184 lttv_state_add_event_hooks(tss
);
3189 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3191 LttvTraceset
*traceset
= self
->parent
.ts
;
3193 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3197 LttvTracefileState
*tfs
;
3203 LttvAttributeValue val
;
3205 nb_trace
= lttv_traceset_number(traceset
);
3206 for(i
= 0 ; i
< nb_trace
; i
++) {
3207 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3209 /* Find the eventtype id for the following events and register the
3210 associated by id hooks. */
3212 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3213 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3216 lttv_trace_find_hook(ts
->parent
.t
,
3217 LTT_FACILITY_KERNEL_ARCH
,
3218 LTT_EVENT_SYSCALL_ENTRY
,
3219 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3220 syscall_entry
, NULL
, &hooks
);
3222 lttv_trace_find_hook(ts
->parent
.t
,
3223 LTT_FACILITY_KERNEL_ARCH
,
3224 LTT_EVENT_SYSCALL_EXIT
,
3226 syscall_exit
, NULL
, &hooks
);
3228 lttv_trace_find_hook(ts
->parent
.t
,
3229 LTT_FACILITY_KERNEL_ARCH
,
3230 LTT_EVENT_TRAP_ENTRY
,
3231 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3232 trap_entry
, NULL
, &hooks
);
3234 lttv_trace_find_hook(ts
->parent
.t
,
3235 LTT_FACILITY_KERNEL_ARCH
,
3236 LTT_EVENT_TRAP_EXIT
,
3238 trap_exit
, NULL
, &hooks
);
3240 lttv_trace_find_hook(ts
->parent
.t
,
3241 LTT_FACILITY_KERNEL
,
3242 LTT_EVENT_IRQ_ENTRY
,
3243 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3244 irq_entry
, NULL
, &hooks
);
3246 lttv_trace_find_hook(ts
->parent
.t
,
3247 LTT_FACILITY_KERNEL
,
3250 irq_exit
, NULL
, &hooks
);
3252 lttv_trace_find_hook(ts
->parent
.t
,
3253 LTT_FACILITY_KERNEL
,
3254 LTT_EVENT_SOFT_IRQ_ENTRY
,
3255 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3256 soft_irq_entry
, NULL
, &hooks
);
3258 lttv_trace_find_hook(ts
->parent
.t
,
3259 LTT_FACILITY_KERNEL
,
3260 LTT_EVENT_SOFT_IRQ_EXIT
,
3262 soft_irq_exit
, NULL
, &hooks
);
3264 lttv_trace_find_hook(ts
->parent
.t
,
3265 LTT_FACILITY_KERNEL
,
3266 LTT_EVENT_SCHED_SCHEDULE
,
3267 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3268 LTT_FIELD_PREV_STATE
),
3269 schedchange
, NULL
, &hooks
);
3271 lttv_trace_find_hook(ts
->parent
.t
,
3272 LTT_FACILITY_KERNEL
,
3273 LTT_EVENT_PROCESS_FORK
,
3274 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3275 LTT_FIELD_CHILD_TGID
),
3276 process_fork
, NULL
, &hooks
);
3278 lttv_trace_find_hook(ts
->parent
.t
,
3279 LTT_FACILITY_KERNEL_ARCH
,
3280 LTT_EVENT_KTHREAD_CREATE
,
3281 FIELD_ARRAY(LTT_FIELD_PID
),
3282 process_kernel_thread
, NULL
, &hooks
);
3284 lttv_trace_find_hook(ts
->parent
.t
,
3285 LTT_FACILITY_KERNEL
,
3286 LTT_EVENT_PROCESS_EXIT
,
3287 FIELD_ARRAY(LTT_FIELD_PID
),
3288 process_exit
, NULL
, &hooks
);
3290 lttv_trace_find_hook(ts
->parent
.t
,
3291 LTT_FACILITY_KERNEL
,
3292 LTT_EVENT_PROCESS_FREE
,
3293 FIELD_ARRAY(LTT_FIELD_PID
),
3294 process_free
, NULL
, &hooks
);
3296 lttv_trace_find_hook(ts
->parent
.t
,
3299 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3300 process_exec
, NULL
, &hooks
);
3302 lttv_trace_find_hook(ts
->parent
.t
,
3303 LTT_FACILITY_USER_GENERIC
,
3304 LTT_EVENT_THREAD_BRAND
,
3305 FIELD_ARRAY(LTT_FIELD_NAME
),
3306 thread_brand
, NULL
, &hooks
);
3308 /* statedump-related hooks */
3309 lttv_trace_find_hook(ts
->parent
.t
,
3311 LTT_EVENT_PROCESS_STATE
,
3312 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3313 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3314 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3315 enum_process_state
, NULL
, &hooks
);
3317 lttv_trace_find_hook(ts
->parent
.t
,
3319 LTT_EVENT_STATEDUMP_END
,
3321 statedump_end
, NULL
, &hooks
);
3323 lttv_trace_find_hook(ts
->parent
.t
,
3325 LTT_EVENT_LIST_INTERRUPT
,
3326 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3327 enum_interrupt
, NULL
, &hooks
);
3329 lttv_trace_find_hook(ts
->parent
.t
,
3331 LTT_EVENT_REQUEST_ISSUE
,
3332 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3333 bdev_request_issue
, NULL
, &hooks
);
3335 lttv_trace_find_hook(ts
->parent
.t
,
3337 LTT_EVENT_REQUEST_COMPLETE
,
3338 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3339 bdev_request_complete
, NULL
, &hooks
);
3341 lttv_trace_find_hook(ts
->parent
.t
,
3342 LTT_FACILITY_USER_GENERIC
,
3343 LTT_EVENT_FUNCTION_ENTRY
,
3344 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3345 function_entry
, NULL
, &hooks
);
3347 lttv_trace_find_hook(ts
->parent
.t
,
3348 LTT_FACILITY_USER_GENERIC
,
3349 LTT_EVENT_FUNCTION_EXIT
,
3350 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3351 function_exit
, NULL
, &hooks
);
3353 /* Add these hooks to each event_by_id hooks list */
3355 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3357 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3359 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3360 LttvTracefileContext
*, j
));
3362 for(k
= 0 ; k
< hooks
->len
; k
++) {
3363 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3365 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3371 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3372 *(val
.v_pointer
) = hooks
;
3376 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3378 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3380 lttv_state_remove_event_hooks(tss
);
3385 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3387 LttvTraceset
*traceset
= self
->parent
.ts
;
3389 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3393 LttvTracefileState
*tfs
;
3399 LttvAttributeValue val
;
3401 nb_trace
= lttv_traceset_number(traceset
);
3402 for(i
= 0 ; i
< nb_trace
; i
++) {
3403 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3405 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3406 hooks
= *(val
.v_pointer
);
3408 /* Remove these hooks from each event_by_id hooks list */
3410 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3412 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3414 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3415 LttvTracefileContext
*, j
));
3417 for(k
= 0 ; k
< hooks
->len
; k
++) {
3418 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3419 lttv_hooks_remove_data(
3420 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3425 lttv_trace_hook_remove_all(&hooks
);
3426 g_array_free(hooks
, TRUE
);
3430 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3432 guint
*event_count
= (guint
*)hook_data
;
3434 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3435 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3440 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3442 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3444 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3446 LttvAttributeValue value
;
3448 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3449 LTTV_STATE_SAVED_STATES
);
3450 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3451 value
= lttv_attribute_add(saved_states_tree
,
3452 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3453 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3454 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3455 *(value
.v_time
) = self
->parent
.timestamp
;
3456 lttv_state_save(tcs
, saved_state_tree
);
3457 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3458 self
->parent
.timestamp
.tv_nsec
);
3460 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3465 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3467 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3469 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3474 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3482 static gboolean
block_start(void *hook_data
, void *call_data
)
3484 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3486 LttvTracefileState
*tfcs
;
3488 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3490 LttEventPosition
*ep
;
3492 guint i
, nb_block
, nb_event
, nb_tracefile
;
3496 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3498 LttvAttributeValue value
;
3500 ep
= ltt_event_position_new();
3502 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3504 /* Count the number of events added since the last block end in any
3507 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3509 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3510 LttvTracefileContext
, i
));
3511 ltt_event_position(tfcs
->parent
.e
, ep
);
3512 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3513 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3514 tfcs
->saved_position
= nb_event
;
3518 if(tcs
->nb_event
>= tcs
->save_interval
) {
3519 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3520 LTTV_STATE_SAVED_STATES
);
3521 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3522 value
= lttv_attribute_add(saved_states_tree
,
3523 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3524 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3525 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3526 *(value
.v_time
) = self
->parent
.timestamp
;
3527 lttv_state_save(tcs
, saved_state_tree
);
3529 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3530 self
->parent
.timestamp
.tv_nsec
);
3532 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3538 static gboolean
block_end(void *hook_data
, void *call_data
)
3540 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3542 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3546 LttEventPosition
*ep
;
3548 guint nb_block
, nb_event
;
3550 ep
= ltt_event_position_new();
3551 ltt_event_position(self
->parent
.e
, ep
);
3552 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3553 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3554 self
->saved_position
= 0;
3555 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3562 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3564 LttvTraceset
*traceset
= self
->parent
.ts
;
3566 guint i
, j
, nb_trace
, nb_tracefile
;
3570 LttvTracefileState
*tfs
;
3572 LttvTraceHook hook_start
, hook_end
;
3574 nb_trace
= lttv_traceset_number(traceset
);
3575 for(i
= 0 ; i
< nb_trace
; i
++) {
3576 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3578 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3579 NULL
, NULL
, block_start
, &hook_start
);
3580 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3581 NULL
, NULL
, block_end
, &hook_end
);
3583 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3585 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3587 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3588 LttvTracefileContext
, j
));
3589 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3590 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3591 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3592 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3598 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3600 LttvTraceset
*traceset
= self
->parent
.ts
;
3602 guint i
, j
, nb_trace
, nb_tracefile
;
3606 LttvTracefileState
*tfs
;
3609 nb_trace
= lttv_traceset_number(traceset
);
3610 for(i
= 0 ; i
< nb_trace
; i
++) {
3612 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3613 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3615 if(ts
->has_precomputed_states
) continue;
3617 guint
*event_count
= g_new(guint
, 1);
3620 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3622 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3623 LttvTracefileContext
*, j
));
3624 lttv_hooks_add(tfs
->parent
.event
,
3625 state_save_event_hook
,
3632 lttv_process_traceset_begin(&self
->parent
,
3633 NULL
, NULL
, NULL
, NULL
, NULL
);
3637 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3639 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3641 lttv_state_save_add_event_hooks(tss
);
3648 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3650 LttvTraceset
*traceset
= self
->parent
.ts
;
3652 guint i
, j
, nb_trace
, nb_tracefile
;
3656 LttvTracefileState
*tfs
;
3658 LttvTraceHook hook_start
, hook_end
;
3660 nb_trace
= lttv_traceset_number(traceset
);
3661 for(i
= 0 ; i
< nb_trace
; i
++) {
3662 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3664 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3665 NULL
, NULL
, block_start
, &hook_start
);
3667 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3668 NULL
, NULL
, block_end
, &hook_end
);
3670 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3672 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3674 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3675 LttvTracefileContext
, j
));
3676 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3677 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3678 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3679 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3685 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3687 LttvTraceset
*traceset
= self
->parent
.ts
;
3689 guint i
, j
, nb_trace
, nb_tracefile
;
3693 LttvTracefileState
*tfs
;
3695 LttvHooks
*after_trace
= lttv_hooks_new();
3697 lttv_hooks_add(after_trace
,
3698 state_save_after_trace_hook
,
3703 lttv_process_traceset_end(&self
->parent
,
3704 NULL
, after_trace
, NULL
, NULL
, NULL
);
3706 lttv_hooks_destroy(after_trace
);
3708 nb_trace
= lttv_traceset_number(traceset
);
3709 for(i
= 0 ; i
< nb_trace
; i
++) {
3711 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3712 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3714 if(ts
->has_precomputed_states
) continue;
3716 guint
*event_count
= NULL
;
3718 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3720 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3721 LttvTracefileContext
*, j
));
3722 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3723 state_save_event_hook
);
3725 if(event_count
) g_free(event_count
);
3729 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3731 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3733 lttv_state_save_remove_event_hooks(tss
);
3738 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3740 LttvTraceset
*traceset
= self
->parent
.ts
;
3744 int min_pos
, mid_pos
, max_pos
;
3746 guint call_rest
= 0;
3748 LttvTraceState
*tcs
;
3750 LttvAttributeValue value
;
3752 LttvAttributeType type
;
3754 LttvAttributeName name
;
3758 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3760 //g_tree_destroy(self->parent.pqueue);
3761 //self->parent.pqueue = g_tree_new(compare_tracefile);
3763 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3765 nb_trace
= lttv_traceset_number(traceset
);
3766 for(i
= 0 ; i
< nb_trace
; i
++) {
3767 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3769 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3770 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3771 LTTV_STATE_SAVED_STATES
);
3774 if(saved_states_tree
) {
3775 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3776 mid_pos
= max_pos
/ 2;
3777 while(min_pos
< max_pos
) {
3778 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3780 g_assert(type
== LTTV_GOBJECT
);
3781 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3782 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3784 g_assert(type
== LTTV_TIME
);
3785 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3787 closest_tree
= saved_state_tree
;
3789 else max_pos
= mid_pos
- 1;
3791 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3795 /* restore the closest earlier saved state */
3797 lttv_state_restore(tcs
, closest_tree
);
3801 /* There is no saved state, yet we want to have it. Restart at T0 */
3803 restore_init_state(tcs
);
3804 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3807 /* We want to seek quickly without restoring/updating the state */
3809 restore_init_state(tcs
);
3810 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3813 if(!call_rest
) g_info("NOT Calling restore");
3818 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3824 traceset_state_finalize (LttvTracesetState
*self
)
3826 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3827 finalize(G_OBJECT(self
));
3832 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3834 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3836 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3837 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3838 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3839 klass
->new_traceset_context
= new_traceset_context
;
3840 klass
->new_trace_context
= new_trace_context
;
3841 klass
->new_tracefile_context
= new_tracefile_context
;
3846 lttv_traceset_state_get_type(void)
3848 static GType type
= 0;
3850 static const GTypeInfo info
= {
3851 sizeof (LttvTracesetStateClass
),
3852 NULL
, /* base_init */
3853 NULL
, /* base_finalize */
3854 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3855 NULL
, /* class_finalize */
3856 NULL
, /* class_data */
3857 sizeof (LttvTracesetState
),
3858 0, /* n_preallocs */
3859 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3860 NULL
/* value handling */
3863 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3871 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3877 trace_state_finalize (LttvTraceState
*self
)
3879 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3880 finalize(G_OBJECT(self
));
3885 trace_state_class_init (LttvTraceStateClass
*klass
)
3887 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3889 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3890 klass
->state_save
= state_save
;
3891 klass
->state_restore
= state_restore
;
3892 klass
->state_saved_free
= state_saved_free
;
3897 lttv_trace_state_get_type(void)
3899 static GType type
= 0;
3901 static const GTypeInfo info
= {
3902 sizeof (LttvTraceStateClass
),
3903 NULL
, /* base_init */
3904 NULL
, /* base_finalize */
3905 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3906 NULL
, /* class_finalize */
3907 NULL
, /* class_data */
3908 sizeof (LttvTraceState
),
3909 0, /* n_preallocs */
3910 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3911 NULL
/* value handling */
3914 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3915 "LttvTraceStateType", &info
, 0);
3922 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3928 tracefile_state_finalize (LttvTracefileState
*self
)
3930 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3931 finalize(G_OBJECT(self
));
3936 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3938 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3940 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3945 lttv_tracefile_state_get_type(void)
3947 static GType type
= 0;
3949 static const GTypeInfo info
= {
3950 sizeof (LttvTracefileStateClass
),
3951 NULL
, /* base_init */
3952 NULL
, /* base_finalize */
3953 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3954 NULL
, /* class_finalize */
3955 NULL
, /* class_data */
3956 sizeof (LttvTracefileState
),
3957 0, /* n_preallocs */
3958 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3959 NULL
/* value handling */
3962 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3963 "LttvTracefileStateType", &info
, 0);
3969 static void module_init()
3971 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3972 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3973 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3974 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3975 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3976 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3977 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3978 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3979 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3980 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3981 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3982 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3983 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3984 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3985 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3986 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3987 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3988 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3989 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3990 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3991 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3992 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3993 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3994 LTTV_STATE_EVENT
= g_quark_from_string("event");
3995 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3996 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3997 LTTV_STATE_TIME
= g_quark_from_string("time");
3998 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3999 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4000 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4001 g_quark_from_string("trace_state_use_count");
4002 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
4003 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
4004 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
4005 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
4006 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
4007 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
4010 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4011 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4012 LTT_FACILITY_FS
= g_quark_from_string("fs");
4013 LTT_FACILITY_LIST
= g_quark_from_string("list");
4014 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4015 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
4018 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4019 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4020 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4021 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4022 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4023 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4024 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4025 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4026 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4027 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4028 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4029 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4030 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4031 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4032 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4033 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4034 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4035 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4036 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4037 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4038 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4039 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
4042 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4043 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4044 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4045 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4046 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4047 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4048 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4049 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4050 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4051 LTT_FIELD_PID
= g_quark_from_string("pid");
4052 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4053 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4054 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4055 LTT_FIELD_NAME
= g_quark_from_string("name");
4056 LTT_FIELD_TYPE
= g_quark_from_string("type");
4057 LTT_FIELD_MODE
= g_quark_from_string("mode");
4058 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4059 LTT_FIELD_STATUS
= g_quark_from_string("status");
4060 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4061 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4062 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4063 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4064 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4065 LTT_FIELD_ACTION
= g_quark_from_string("action");
4067 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4068 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4069 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4070 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4071 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4072 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4074 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4075 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4076 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4078 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4079 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4080 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4081 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4084 static void module_destroy()
4089 LTTV_MODULE("state", "State computation", \
4090 "Update the system state, possibly saving it at intervals", \
4091 module_init
, module_destroy
)