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\">\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
),
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
->tgid
, sizeof(process
->tgid
), 1, fp
);
730 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
731 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
732 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
733 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
737 " <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",
738 process
, process
->pid
, process
->tgid
, process
->ppid
,
739 g_quark_to_string(process
->type
),
740 process
->creation_time
.tv_sec
,
741 process
->creation_time
.tv_nsec
,
742 process
->insertion_time
.tv_sec
,
743 process
->insertion_time
.tv_nsec
,
744 g_quark_to_string(process
->name
),
745 g_quark_to_string(process
->brand
),
749 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
750 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
753 //fprintf(fp, "%s", g_quark_to_string(es->t));
755 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
756 //fprintf(fp, "%s", g_quark_to_string(es->n));
758 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
759 //fprintf(fp, "%s", g_quark_to_string(es->s));
761 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
762 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
763 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
764 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
766 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
767 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
768 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
769 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
770 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
774 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
775 address
= g_array_index(process
->user_stack
, guint64
, i
);
776 fputc(HDR_USER_STACK
, fp
);
777 fwrite(&address
, sizeof(address
), 1, fp
);
779 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
784 if(process
->usertrace
) {
785 fputc(HDR_USERTRACE
, fp
);
786 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
788 fwrite(&process
->usertrace
->tracefile_name
,
789 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
790 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
792 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
793 g_quark_to_string(process
->usertrace
->tracefile_name
),
794 process
->usertrace
->cpu
);
801 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
803 guint i
, nb_tracefile
, nb_block
, offset
;
806 LttvTracefileState
*tfcs
;
810 LttEventPosition
*ep
;
814 ep
= ltt_event_position_new();
816 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
817 fputc(HDR_PROCESS_STATE
, fp
);
818 fwrite(&t
, sizeof(t
), 1, fp
);
820 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
822 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
823 for(i
=0;i
<nb_cpus
;i
++) {
825 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
826 fwrite(&self
->running_process
[i
]->pid
,
827 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
828 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
829 // i, self->running_process[i]->pid);
832 nb_tracefile
= self
->parent
.tracefiles
->len
;
834 for(i
= 0 ; i
< nb_tracefile
; i
++) {
836 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
837 LttvTracefileContext
*, i
));
838 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
839 // tfcs->parent.timestamp.tv_sec,
840 // tfcs->parent.timestamp.tv_nsec);
841 fputc(HDR_TRACEFILE
, fp
);
842 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
843 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
844 * position following : end of trace */
845 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
847 ltt_event_position(e
, ep
);
848 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
849 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
851 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
852 fwrite(&offset
, sizeof(offset
), 1, fp
);
853 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
860 /* Read process state from a file */
862 /* Called because a HDR_PROCESS was found */
863 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
864 GPtrArray
*quarktable
)
866 LttvExecutionState
*es
;
867 LttvProcessState
*process
, *parent_process
;
868 LttvProcessState tmp
;
873 /* TODO : check return value */
874 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
875 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
876 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
877 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
878 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
879 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
880 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
881 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
882 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
885 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
887 /* We must link to the parent */
888 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
890 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
891 if(process
== NULL
) {
892 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
894 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
898 process
->insertion_time
= tmp
.insertion_time
;
899 process
->creation_time
= tmp
.creation_time
;
900 process
->type
= g_quark_from_string(
901 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
902 process
->tgid
= tmp
.tgid
;
903 process
->ppid
= tmp
.ppid
;
904 process
->brand
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
907 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
911 if(feof(fp
) || ferror(fp
)) goto end_loop
;
913 gint hdr
= fgetc(fp
);
914 if(hdr
== EOF
) goto end_loop
;
918 process
->execution_stack
=
919 g_array_set_size(process
->execution_stack
,
920 process
->execution_stack
->len
+ 1);
921 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
922 process
->execution_stack
->len
-1);
925 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
926 es
->t
= g_quark_from_string(
927 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
928 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
929 es
->n
= g_quark_from_string(
930 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
931 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
932 es
->s
= g_quark_from_string(
933 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
934 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
935 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
936 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
939 process
->user_stack
= g_array_set_size(process
->user_stack
,
940 process
->user_stack
->len
+ 1);
941 address
= &g_array_index(process
->user_stack
, guint64
,
942 process
->user_stack
->len
-1);
943 fread(address
, sizeof(address
), 1, fp
);
944 process
->current_function
= *address
;
947 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
948 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
960 /* Called because a HDR_PROCESS_STATE was found */
961 /* Append a saved state to the trace states */
962 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
964 guint i
, nb_tracefile
, nb_block
, offset
;
966 LttvTracefileState
*tfcs
;
968 LttEventPosition
*ep
;
976 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
978 LttvAttributeValue value
;
979 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
980 ep
= ltt_event_position_new();
982 restore_init_state(self
);
984 fread(&t
, sizeof(t
), 1, fp
);
987 if(feof(fp
) || ferror(fp
)) goto end_loop
;
989 if(hdr
== EOF
) goto end_loop
;
993 /* Call read_process_state_raw */
994 read_process_state_raw(self
, fp
, quarktable
);
1002 case HDR_USER_STACK
:
1004 case HDR_PROCESS_STATE
:
1010 g_error("Error while parsing saved state file : unknown data header %d",
1016 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1017 for(i
=0;i
<nb_cpus
;i
++) {
1020 g_assert(hdr
== HDR_CPU
);
1021 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1022 g_assert(i
== cpu_num
);
1023 fread(&self
->running_process
[i
]->pid
,
1024 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1027 nb_tracefile
= self
->parent
.tracefiles
->len
;
1029 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1031 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1032 LttvTracefileContext
*, i
));
1033 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1034 // tfcs->parent.timestamp.tv_sec,
1035 // tfcs->parent.timestamp.tv_nsec);
1036 g_tree_remove(pqueue
, &tfcs
->parent
);
1038 g_assert(hdr
== HDR_TRACEFILE
);
1039 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1040 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1041 * position following : end of trace */
1042 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1043 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1044 fread(&offset
, sizeof(offset
), 1, fp
);
1045 fread(&tsc
, sizeof(tsc
), 1, fp
);
1046 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1047 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1049 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1054 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1055 LTTV_STATE_SAVED_STATES
);
1056 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1057 value
= lttv_attribute_add(saved_states_tree
,
1058 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1059 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1060 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1061 *(value
.v_time
) = t
;
1062 lttv_state_save(self
, saved_state_tree
);
1063 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1066 *(self
->max_time_state_recomputed_in_seek
) = t
;
1070 /* Called when a HDR_TRACE is found */
1071 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1072 GPtrArray
*quarktable
)
1077 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1079 if(hdr
== EOF
) goto end_loop
;
1082 case HDR_PROCESS_STATE
:
1083 /* Call read_process_state_raw */
1084 lttv_state_read_raw(tcs
, fp
, quarktable
);
1092 case HDR_USER_STACK
:
1096 g_error("Error while parsing saved state file :"
1097 " unexpected data header %d",
1101 g_error("Error while parsing saved state file : unknown data header %d",
1106 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1107 restore_init_state(tcs
);
1108 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1114 /* Copy each process from an existing hash table to a new one */
1116 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1118 LttvProcessState
*process
, *new_process
;
1120 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1124 process
= (LttvProcessState
*)value
;
1125 new_process
= g_new(LttvProcessState
, 1);
1126 *new_process
= *process
;
1127 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1128 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1129 new_process
->execution_stack
=
1130 g_array_set_size(new_process
->execution_stack
,
1131 process
->execution_stack
->len
);
1132 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1133 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1134 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1136 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1137 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1138 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1139 sizeof(guint64
), 0);
1140 new_process
->user_stack
=
1141 g_array_set_size(new_process
->user_stack
,
1142 process
->user_stack
->len
);
1143 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1144 g_array_index(new_process
->user_stack
, guint64
, i
) =
1145 g_array_index(process
->user_stack
, guint64
, i
);
1147 new_process
->current_function
= process
->current_function
;
1148 g_hash_table_insert(new_processes
, new_process
, new_process
);
1152 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1154 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1156 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1157 return new_processes
;
1160 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1163 LttvCPUState
*retval
;
1165 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1167 for(i
=0; i
<n
; i
++) {
1168 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1169 retval
[i
].last_irq
= states
[i
].last_irq
;
1170 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1171 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1172 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1179 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1183 for(i
=0; i
<n
; i
++) {
1184 g_array_free(states
[i
].mode_stack
, TRUE
);
1190 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1193 LttvIRQState
*retval
;
1195 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1197 for(i
=0; i
<n
; i
++) {
1198 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1199 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1200 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1201 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1208 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1212 for(i
=0; i
<n
; i
++) {
1213 g_array_free(states
[i
].mode_stack
, TRUE
);
1219 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1222 LttvSoftIRQState
*retval
;
1224 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1226 for(i
=0; i
<n
; i
++) {
1227 retval
[i
].running
= states
[i
].running
;
1233 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1238 static LttvTrapState
*lttv_state_copy_trap_states(LttvTrapState
*states
, guint n
)
1241 LttvTrapState
*retval
;
1243 retval
= g_malloc(n
*sizeof(LttvTrapState
));
1245 for(i
=0; i
<n
; i
++) {
1246 retval
[i
].running
= states
[i
].running
;
1252 static void lttv_state_free_trap_states(LttvTrapState
*states
, guint n
)
1257 /* bdevstate stuff */
1259 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1261 gint devcode_gint
= devcode
;
1262 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1264 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1265 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1267 gint
* key
= g_malloc(sizeof(gint
));
1269 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1277 static LttvBdevState
*bdevstate_new(void)
1279 LttvBdevState
*retval
;
1280 retval
= g_malloc(sizeof(LttvBdevState
));
1281 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1286 static void bdevstate_free(LttvBdevState
*bds
)
1288 g_array_free(bds
->mode_stack
, TRUE
);
1292 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1294 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1296 bdevstate_free(bds
);
1299 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1301 LttvBdevState
*retval
;
1303 retval
= bdevstate_new();
1304 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1309 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1311 //GHashTable *ht = (GHashTable *)u;
1312 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1313 LttvBdevState
*newbds
;
1315 newbds
= bdevstate_copy(bds
);
1317 g_hash_table_insert(u
, k
, newbds
);
1320 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1324 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1326 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1331 /* Free a hashtable and the LttvBdevState structures its values
1334 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1336 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1337 g_hash_table_destroy(ht
);
1340 /* The saved state for each trace contains a member "processes", which
1341 stores a copy of the process table, and a member "tracefiles" with
1342 one entry per tracefile. Each tracefile has a "process" member pointing
1343 to the current process and a "position" member storing the tracefile
1344 position (needed to seek to the current "next" event. */
1346 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1348 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1350 LttvTracefileState
*tfcs
;
1352 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1354 guint
*running_process
;
1356 LttvAttributeValue value
;
1358 LttEventPosition
*ep
;
1360 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1361 LTTV_STATE_TRACEFILES
);
1363 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1365 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1367 /* Add the currently running processes array */
1368 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1369 running_process
= g_new(guint
, nb_cpus
);
1370 for(i
=0;i
<nb_cpus
;i
++) {
1371 running_process
[i
] = self
->running_process
[i
]->pid
;
1373 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1375 *(value
.v_pointer
) = running_process
;
1377 g_info("State save");
1379 nb_tracefile
= self
->parent
.tracefiles
->len
;
1381 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1383 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1384 LttvTracefileContext
*, i
));
1385 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1386 value
= lttv_attribute_add(tracefiles_tree
, i
,
1388 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1390 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1392 *(value
.v_uint
) = tfcs
->process
->pid
;
1394 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1396 /* Only save the position if the tfs has not infinite time. */
1397 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1398 // && current_tfcs != tfcs) {
1399 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1400 *(value
.v_pointer
) = NULL
;
1402 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1403 ep
= ltt_event_position_new();
1404 ltt_event_position(e
, ep
);
1405 *(value
.v_pointer
) = ep
;
1407 guint nb_block
, offset
;
1410 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1411 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1413 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1417 /* save the cpu state */
1419 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1421 *(value
.v_uint
) = nb_cpus
;
1423 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1425 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1428 /* save the irq state */
1429 nb_irqs
= self
->nb_irqs
;
1431 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1433 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1436 /* save the soft irq state */
1437 nb_soft_irqs
= self
->nb_soft_irqs
;
1439 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1441 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1444 /* save the trap state */
1445 nb_traps
= self
->nb_traps
;
1447 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_TRAPS
,
1449 *(value
.v_pointer
) = lttv_state_copy_trap_states(self
->trap_states
, nb_traps
);
1452 /* save the blkdev states */
1453 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1455 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1459 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1461 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
, nb_traps
;
1463 LttvTracefileState
*tfcs
;
1465 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1467 guint
*running_process
;
1469 LttvAttributeType type
;
1471 LttvAttributeValue value
;
1473 LttvAttributeName name
;
1477 LttEventPosition
*ep
;
1479 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1481 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1482 LTTV_STATE_TRACEFILES
);
1484 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1486 g_assert(type
== LTTV_POINTER
);
1487 lttv_state_free_process_table(self
->processes
);
1488 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1490 /* Add the currently running processes array */
1491 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1492 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1494 g_assert(type
== LTTV_POINTER
);
1495 running_process
= *(value
.v_pointer
);
1496 for(i
=0;i
<nb_cpus
;i
++) {
1497 pid
= running_process
[i
];
1498 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1499 g_assert(self
->running_process
[i
] != NULL
);
1502 nb_tracefile
= self
->parent
.tracefiles
->len
;
1504 //g_tree_destroy(tsc->pqueue);
1505 //tsc->pqueue = g_tree_new(compare_tracefile);
1507 /* restore cpu resource states */
1508 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1509 g_assert(type
== LTTV_POINTER
);
1510 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1511 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1513 /* restore irq resource states */
1514 nb_irqs
= self
->nb_irqs
;
1515 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1516 g_assert(type
== LTTV_POINTER
);
1517 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1518 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1520 /* restore soft irq resource states */
1521 nb_soft_irqs
= self
->nb_soft_irqs
;
1522 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1523 g_assert(type
== LTTV_POINTER
);
1524 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1525 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1527 /* restore trap resource states */
1528 nb_traps
= self
->nb_traps
;
1529 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_TRAPS
, &value
);
1530 g_assert(type
== LTTV_POINTER
);
1531 lttv_state_free_trap_states(self
->trap_states
, nb_traps
);
1532 self
->trap_states
= lttv_state_copy_trap_states(*(value
.v_pointer
), nb_traps
);
1534 /* restore the blkdev states */
1535 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1536 g_assert(type
== LTTV_POINTER
);
1537 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1538 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1540 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1542 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1543 LttvTracefileContext
*, i
));
1544 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1545 g_assert(type
== LTTV_GOBJECT
);
1546 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1548 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1550 g_assert(type
== LTTV_UINT
);
1551 pid
= *(value
.v_uint
);
1552 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1554 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1556 g_assert(type
== LTTV_POINTER
);
1557 //g_assert(*(value.v_pointer) != NULL);
1558 ep
= *(value
.v_pointer
);
1559 g_assert(tfcs
->parent
.t_context
!= NULL
);
1561 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1563 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1564 g_tree_remove(tsc
->pqueue
, tfc
);
1567 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1568 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1569 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1570 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1571 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1573 tfc
->timestamp
= ltt_time_infinite
;
1579 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1581 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1583 LttvTracefileState
*tfcs
;
1585 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1587 guint
*running_process
;
1589 LttvAttributeType type
;
1591 LttvAttributeValue value
;
1593 LttvAttributeName name
;
1597 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1598 LTTV_STATE_TRACEFILES
);
1599 g_object_ref(G_OBJECT(tracefiles_tree
));
1600 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1602 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1604 g_assert(type
== LTTV_POINTER
);
1605 lttv_state_free_process_table(*(value
.v_pointer
));
1606 *(value
.v_pointer
) = NULL
;
1607 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1609 /* Free running processes array */
1610 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1612 g_assert(type
== LTTV_POINTER
);
1613 running_process
= *(value
.v_pointer
);
1614 g_free(running_process
);
1616 /* free cpu resource states */
1617 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1618 g_assert(type
== LTTV_UINT
);
1619 nb_cpus
= *value
.v_uint
;
1620 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1621 g_assert(type
== LTTV_POINTER
);
1622 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1624 /* free irq resource states */
1625 nb_irqs
= self
->nb_irqs
;
1626 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1627 g_assert(type
== LTTV_POINTER
);
1628 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1630 /* free the blkdev states */
1631 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1632 g_assert(type
== LTTV_POINTER
);
1633 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1635 nb_tracefile
= self
->parent
.tracefiles
->len
;
1637 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1639 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1640 LttvTracefileContext
*, i
));
1641 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1642 g_assert(type
== LTTV_GOBJECT
);
1643 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1645 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1647 g_assert(type
== LTTV_POINTER
);
1648 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1650 g_object_unref(G_OBJECT(tracefiles_tree
));
1654 static void free_saved_state(LttvTraceState
*self
)
1658 LttvAttributeType type
;
1660 LttvAttributeValue value
;
1662 LttvAttributeName name
;
1666 LttvAttribute
*saved_states
;
1668 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1669 LTTV_STATE_SAVED_STATES
);
1671 nb
= lttv_attribute_get_number(saved_states
);
1672 for(i
= 0 ; i
< nb
; i
++) {
1673 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1674 g_assert(type
== LTTV_GOBJECT
);
1675 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1678 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1683 create_max_time(LttvTraceState
*tcs
)
1685 LttvAttributeValue v
;
1687 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1689 g_assert(*(v
.v_pointer
) == NULL
);
1690 *(v
.v_pointer
) = g_new(LttTime
,1);
1691 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1696 get_max_time(LttvTraceState
*tcs
)
1698 LttvAttributeValue v
;
1700 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1702 g_assert(*(v
.v_pointer
) != NULL
);
1703 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1708 free_max_time(LttvTraceState
*tcs
)
1710 LttvAttributeValue v
;
1712 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1714 g_free(*(v
.v_pointer
));
1715 *(v
.v_pointer
) = NULL
;
1719 typedef struct _LttvNameTables
{
1720 // FIXME GQuark *eventtype_names;
1721 GQuark
*syscall_names
;
1727 GQuark
*soft_irq_names
;
1733 create_name_tables(LttvTraceState
*tcs
)
1737 GString
*fe_name
= g_string_new("");
1739 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1741 LttvAttributeValue v
;
1745 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1747 g_assert(*(v
.v_pointer
) == NULL
);
1748 *(v
.v_pointer
) = name_tables
;
1750 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1752 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1753 LTT_FACILITY_KERNEL_ARCH
,
1754 LTT_EVENT_SYSCALL_ENTRY
,
1755 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1756 NULL
, NULL
, &hooks
)) {
1758 // th = lttv_trace_hook_get_first(&th);
1760 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1761 // nb = ltt_type_element_number(t);
1763 // name_tables->syscall_names = g_new(GQuark, nb);
1764 // name_tables->nb_syscalls = nb;
1766 // for(i = 0 ; i < nb ; i++) {
1767 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1768 // if(!name_tables->syscall_names[i]) {
1769 // GString *string = g_string_new("");
1770 // g_string_printf(string, "syscall %u", i);
1771 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1772 // g_string_free(string, TRUE);
1776 name_tables
->nb_syscalls
= 256;
1777 name_tables
->syscall_names
= g_new(GQuark
, 256);
1778 for(i
= 0 ; i
< 256 ; i
++) {
1779 g_string_printf(fe_name
, "syscall %d", i
);
1780 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1783 name_tables
->syscall_names
= NULL
;
1784 name_tables
->nb_syscalls
= 0;
1786 lttv_trace_hook_remove_all(&hooks
);
1788 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1789 LTT_FACILITY_KERNEL_ARCH
,
1790 LTT_EVENT_TRAP_ENTRY
,
1791 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1792 NULL
, NULL
, &hooks
)) {
1794 // th = lttv_trace_hook_get_first(&th);
1796 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1797 // //nb = ltt_type_element_number(t);
1799 // name_tables->trap_names = g_new(GQuark, nb);
1800 // for(i = 0 ; i < nb ; i++) {
1801 // name_tables->trap_names[i] = g_quark_from_string(
1802 // ltt_enum_string_get(t, i));
1805 name_tables
->nb_traps
= 256;
1806 name_tables
->trap_names
= g_new(GQuark
, 256);
1807 for(i
= 0 ; i
< 256 ; i
++) {
1808 g_string_printf(fe_name
, "trap %d", i
);
1809 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1812 name_tables
->trap_names
= NULL
;
1813 name_tables
->nb_traps
= 0;
1815 lttv_trace_hook_remove_all(&hooks
);
1817 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1818 LTT_FACILITY_KERNEL
,
1819 LTT_EVENT_IRQ_ENTRY
,
1820 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1821 NULL
, NULL
, &hooks
)) {
1824 name_tables->irq_names = g_new(GQuark, nb);
1825 for(i = 0 ; i < nb ; i++) {
1826 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1830 name_tables
->nb_irqs
= 256;
1831 name_tables
->irq_names
= g_new(GQuark
, 256);
1832 for(i
= 0 ; i
< 256 ; i
++) {
1833 g_string_printf(fe_name
, "irq %d", i
);
1834 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1837 name_tables
->nb_irqs
= 0;
1838 name_tables
->irq_names
= NULL
;
1840 lttv_trace_hook_remove_all(&hooks
);
1842 name_tables->soft_irq_names = g_new(GQuark, nb);
1843 for(i = 0 ; i < nb ; i++) {
1844 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1848 /* the kernel is limited to 32 statically defined softirqs */
1849 name_tables
->nb_softirqs
= 32;
1850 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1851 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1852 g_string_printf(fe_name
, "softirq %d", i
);
1853 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1855 g_array_free(hooks
, TRUE
);
1857 g_string_free(fe_name
, TRUE
);
1862 get_name_tables(LttvTraceState
*tcs
)
1864 LttvNameTables
*name_tables
;
1866 LttvAttributeValue v
;
1868 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1870 g_assert(*(v
.v_pointer
) != NULL
);
1871 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1872 //tcs->eventtype_names = name_tables->eventtype_names;
1873 tcs
->syscall_names
= name_tables
->syscall_names
;
1874 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1875 tcs
->trap_names
= name_tables
->trap_names
;
1876 tcs
->nb_traps
= name_tables
->nb_traps
;
1877 tcs
->irq_names
= name_tables
->irq_names
;
1878 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1879 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1880 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1885 free_name_tables(LttvTraceState
*tcs
)
1887 LttvNameTables
*name_tables
;
1889 LttvAttributeValue v
;
1891 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1893 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1894 *(v
.v_pointer
) = NULL
;
1896 // g_free(name_tables->eventtype_names);
1897 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1898 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1899 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1900 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1901 if(name_tables
) g_free(name_tables
);
1904 #ifdef HASH_TABLE_DEBUG
1906 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1908 LttvProcessState
*process
= (LttvProcessState
*)value
;
1910 /* Test for process corruption */
1911 guint stack_len
= process
->execution_stack
->len
;
1914 static void hash_table_check(GHashTable
*table
)
1916 g_hash_table_foreach(table
, test_process
, NULL
);
1922 /* clears the stack and sets the state passed as argument */
1923 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1925 g_array_set_size(cpust
->mode_stack
, 1);
1926 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1929 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1931 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1932 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1935 static void cpu_pop_mode(LttvCPUState
*cpust
)
1937 if(cpust
->mode_stack
->len
<= 1)
1938 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1940 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1943 /* clears the stack and sets the state passed as argument */
1944 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1946 g_array_set_size(bdevst
->mode_stack
, 1);
1947 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1950 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1952 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1953 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1956 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1958 if(bdevst
->mode_stack
->len
<= 1)
1959 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1961 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1964 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1966 g_array_set_size(irqst
->mode_stack
, 1);
1967 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1970 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1972 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1973 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1976 static void irq_pop_mode(LttvIRQState
*irqst
)
1978 if(irqst
->mode_stack
->len
<= 1)
1979 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1981 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1984 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1987 LttvExecutionState
*es
;
1989 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1990 guint cpu
= tfs
->cpu
;
1992 #ifdef HASH_TABLE_DEBUG
1993 hash_table_check(ts
->processes
);
1995 LttvProcessState
*process
= ts
->running_process
[cpu
];
1997 guint depth
= process
->execution_stack
->len
;
1999 process
->execution_stack
=
2000 g_array_set_size(process
->execution_stack
, depth
+ 1);
2003 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
2005 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
2008 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2009 es
->cum_cpu_time
= ltt_time_zero
;
2010 es
->s
= process
->state
->s
;
2011 process
->state
= es
;
2015 * return 1 when empty, else 0 */
2016 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
2017 LttvTracefileState
*tfs
)
2019 guint depth
= process
->execution_stack
->len
;
2025 process
->execution_stack
=
2026 g_array_set_size(process
->execution_stack
, depth
- 1);
2027 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2029 process
->state
->change
= tfs
->parent
.timestamp
;
2034 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
2036 guint cpu
= tfs
->cpu
;
2037 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2038 LttvProcessState
*process
= ts
->running_process
[cpu
];
2040 guint depth
= process
->execution_stack
->len
;
2042 if(process
->state
->t
!= t
){
2043 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2044 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2045 g_info("process state has %s when pop_int is %s\n",
2046 g_quark_to_string(process
->state
->t
),
2047 g_quark_to_string(t
));
2048 g_info("{ %u, %u, %s, %s, %s }\n",
2051 g_quark_to_string(process
->name
),
2052 g_quark_to_string(process
->brand
),
2053 g_quark_to_string(process
->state
->s
));
2058 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2059 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2063 process
->execution_stack
=
2064 g_array_set_size(process
->execution_stack
, depth
- 1);
2065 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2067 process
->state
->change
= tfs
->parent
.timestamp
;
2070 struct search_result
{
2071 const LttTime
*time
; /* Requested time */
2072 LttTime
*best
; /* Best result */
2075 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2077 const LttTime
*elem_time
= (const LttTime
*)a
;
2078 /* Explicit non const cast */
2079 struct search_result
*res
= (struct search_result
*)b
;
2081 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2082 /* The usertrace was created before the schedchange */
2083 /* Get larger keys */
2085 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2086 /* The usertrace was created after the schedchange time */
2087 /* Get smaller keys */
2089 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2090 res
->best
= (LttTime
*)elem_time
;
2093 res
->best
= (LttTime
*)elem_time
;
2100 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2101 guint pid
, const LttTime
*timestamp
)
2103 LttvTracefileState
*tfs
= NULL
;
2104 struct search_result res
;
2105 /* Find the usertrace associated with a pid and time interval.
2106 * Search in the usertraces by PID (within a hash) and then, for each
2107 * corresponding element of the array, find the first one with creation
2108 * timestamp the lowest, but higher or equal to "timestamp". */
2109 res
.time
= timestamp
;
2111 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2112 if(usertrace_tree
) {
2113 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2115 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2123 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2124 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2126 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2128 LttvExecutionState
*es
;
2133 process
->tgid
= tgid
;
2135 process
->name
= name
;
2136 process
->brand
= LTTV_STATE_UNBRANDED
;
2137 //process->last_cpu = tfs->cpu_name;
2138 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2139 process
->type
= LTTV_STATE_USER_THREAD
;
2140 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2141 process
->current_function
= 0; //function 0x0 by default.
2143 g_info("Process %u, core %p", process
->pid
, process
);
2144 g_hash_table_insert(tcs
->processes
, process
, process
);
2147 process
->ppid
= parent
->pid
;
2148 process
->creation_time
= *timestamp
;
2151 /* No parent. This process exists but we are missing all information about
2152 its creation. The birth time is set to zero but we remember the time of
2157 process
->creation_time
= ltt_time_zero
;
2160 process
->insertion_time
= *timestamp
;
2161 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2162 process
->creation_time
.tv_nsec
);
2163 process
->pid_time
= g_quark_from_string(buffer
);
2165 //process->last_cpu = tfs->cpu_name;
2166 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2167 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2168 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2169 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2170 es
= process
->state
= &g_array_index(process
->execution_stack
,
2171 LttvExecutionState
, 0);
2172 es
->t
= LTTV_STATE_USER_MODE
;
2173 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2174 es
->entry
= *timestamp
;
2175 //g_assert(timestamp->tv_sec != 0);
2176 es
->change
= *timestamp
;
2177 es
->cum_cpu_time
= ltt_time_zero
;
2178 es
->s
= LTTV_STATE_RUN
;
2180 es
= process
->state
= &g_array_index(process
->execution_stack
,
2181 LttvExecutionState
, 1);
2182 es
->t
= LTTV_STATE_SYSCALL
;
2183 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2184 es
->entry
= *timestamp
;
2185 //g_assert(timestamp->tv_sec != 0);
2186 es
->change
= *timestamp
;
2187 es
->cum_cpu_time
= ltt_time_zero
;
2188 es
->s
= LTTV_STATE_WAIT_FORK
;
2190 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2191 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2192 sizeof(guint64
), 0);
2197 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2200 LttvProcessState key
;
2201 LttvProcessState
*process
;
2205 process
= g_hash_table_lookup(ts
->processes
, &key
);
2210 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2211 const LttTime
*timestamp
)
2213 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2214 LttvExecutionState
*es
;
2216 /* Put ltt_time_zero creation time for unexisting processes */
2217 if(unlikely(process
== NULL
)) {
2218 process
= lttv_state_create_process(ts
,
2219 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2220 /* We are not sure is it's a kernel thread or normal thread, put the
2221 * bottom stack state to unknown */
2222 process
->execution_stack
=
2223 g_array_set_size(process
->execution_stack
, 1);
2224 process
->state
= es
=
2225 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2226 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2227 es
->s
= LTTV_STATE_UNNAMED
;
2232 /* FIXME : this function should be called when we receive an event telling that
2233 * release_task has been called in the kernel. In happens generally when
2234 * the parent waits for its child terminaison, but may also happen in special
2235 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2236 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2237 * of a killed thread group, but isn't the leader.
2239 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2241 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2242 LttvProcessState key
;
2244 key
.pid
= process
->pid
;
2245 key
.cpu
= process
->cpu
;
2246 g_hash_table_remove(ts
->processes
, &key
);
2247 g_array_free(process
->execution_stack
, TRUE
);
2248 g_array_free(process
->user_stack
, TRUE
);
2253 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2255 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2256 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2261 static void lttv_state_free_process_table(GHashTable
*processes
)
2263 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2264 g_hash_table_destroy(processes
);
2268 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2270 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2272 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2273 LttvProcessState
*process
= ts
->running_process
[cpu
];
2274 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2275 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2276 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2278 LttvExecutionSubmode submode
;
2280 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2281 guint syscall
= ltt_event_get_unsigned(e
, f
);
2283 if(syscall
< nb_syscalls
) {
2284 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2287 /* Fixup an incomplete syscall table */
2288 GString
*string
= g_string_new("");
2289 g_string_printf(string
, "syscall %u", syscall
);
2290 submode
= g_quark_from_string(string
->str
);
2291 g_string_free(string
, TRUE
);
2293 /* There can be no system call from PID 0 : unknown state */
2294 if(process
->pid
!= 0)
2295 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2300 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2302 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2304 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2305 LttvProcessState
*process
= ts
->running_process
[cpu
];
2307 /* There can be no system call from PID 0 : unknown state */
2308 if(process
->pid
!= 0)
2309 pop_state(s
, LTTV_STATE_SYSCALL
);
2314 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2316 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2317 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2318 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2319 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2320 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2322 LttvExecutionSubmode submode
;
2324 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2325 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2327 if(trap
< nb_traps
) {
2328 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2330 /* Fixup an incomplete trap table */
2331 GString
*string
= g_string_new("");
2332 g_string_printf(string
, "trap %llu", trap
);
2333 submode
= g_quark_from_string(string
->str
);
2334 g_string_free(string
, TRUE
);
2337 push_state(s
, LTTV_STATE_TRAP
, submode
);
2339 /* update cpu status */
2340 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2342 /* update trap status */
2343 s
->cpu_state
->last_trap
= trap
;
2344 ts
->trap_states
[trap
].running
++;
2349 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2351 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2352 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2353 guint trap
= s
->cpu_state
->last_trap
;
2355 pop_state(s
, LTTV_STATE_TRAP
);
2357 /* update cpu status */
2358 cpu_pop_mode(s
->cpu_state
);
2360 /* update trap status */
2361 if(ts
->trap_states
[trap
].running
)
2362 ts
->trap_states
[trap
].running
--;
2367 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2369 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2370 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2371 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2372 //guint8 ev_id = ltt_event_eventtype_id(e);
2373 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2374 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2376 LttvExecutionSubmode submode
;
2377 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2378 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2381 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2383 /* Fixup an incomplete irq table */
2384 GString
*string
= g_string_new("");
2385 g_string_printf(string
, "irq %llu", irq
);
2386 submode
= g_quark_from_string(string
->str
);
2387 g_string_free(string
, TRUE
);
2390 /* Do something with the info about being in user or system mode when int? */
2391 push_state(s
, LTTV_STATE_IRQ
, submode
);
2393 /* update cpu status */
2394 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2396 /* update irq status */
2397 s
->cpu_state
->last_irq
= irq
;
2398 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2403 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2405 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2406 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2407 guint softirq
= s
->cpu_state
->last_soft_irq
;
2409 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2411 /* update softirq status */
2412 if(ts
->soft_irq_states
[softirq
].running
)
2413 ts
->soft_irq_states
[softirq
].running
--;
2415 /* update cpu status */
2416 cpu_pop_mode(s
->cpu_state
);
2421 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2423 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2424 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2426 pop_state(s
, LTTV_STATE_IRQ
);
2428 /* update cpu status */
2429 cpu_pop_mode(s
->cpu_state
);
2431 /* update irq status */
2432 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2437 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2439 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2440 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2441 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2442 //guint8 ev_id = ltt_event_eventtype_id(e);
2443 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2444 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2446 LttvExecutionSubmode submode
;
2447 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2448 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2450 if(softirq
< nb_softirqs
) {
2451 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2453 /* Fixup an incomplete irq table */
2454 GString
*string
= g_string_new("");
2455 g_string_printf(string
, "softirq %llu", softirq
);
2456 submode
= g_quark_from_string(string
->str
);
2457 g_string_free(string
, TRUE
);
2460 /* Do something with the info about being in user or system mode when int? */
2461 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2463 /* update cpu status */
2464 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2466 /* update softirq status */
2467 s
->cpu_state
->last_soft_irq
= softirq
;
2468 ts
->soft_irq_states
[softirq
].running
++;
2473 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2475 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2476 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2477 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2478 //guint8 ev_id = ltt_event_eventtype_id(e);
2479 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2481 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2482 lttv_trace_get_hook_field(th
, 0)));
2483 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2485 ts
->irq_names
[irq
] = action
;
2491 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2493 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2494 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2495 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2496 //guint8 ev_id = ltt_event_eventtype_id(e);
2497 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2499 guint major
= ltt_event_get_long_unsigned(e
,
2500 lttv_trace_get_hook_field(th
, 0));
2501 guint minor
= ltt_event_get_long_unsigned(e
,
2502 lttv_trace_get_hook_field(th
, 1));
2503 guint oper
= ltt_event_get_long_unsigned(e
,
2504 lttv_trace_get_hook_field(th
, 2));
2505 guint16 devcode
= MKDEV(major
,minor
);
2507 /* have we seen this block device before? */
2508 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2511 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2513 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2518 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2520 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2521 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2522 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2523 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2525 guint major
= ltt_event_get_long_unsigned(e
,
2526 lttv_trace_get_hook_field(th
, 0));
2527 guint minor
= ltt_event_get_long_unsigned(e
,
2528 lttv_trace_get_hook_field(th
, 1));
2529 //guint oper = ltt_event_get_long_unsigned(e,
2530 // lttv_trace_get_hook_field(th, 2));
2531 guint16 devcode
= MKDEV(major
,minor
);
2533 /* have we seen this block device before? */
2534 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2536 /* update block device */
2537 bdev_pop_mode(bdev
);
2542 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2546 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2547 guint cpu
= tfs
->cpu
;
2548 LttvProcessState
*process
= ts
->running_process
[cpu
];
2550 guint depth
= process
->user_stack
->len
;
2552 process
->user_stack
=
2553 g_array_set_size(process
->user_stack
, depth
+ 1);
2555 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2556 *new_func
= funcptr
;
2557 process
->current_function
= funcptr
;
2560 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2562 guint cpu
= tfs
->cpu
;
2563 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2564 LttvProcessState
*process
= ts
->running_process
[cpu
];
2566 if(process
->current_function
!= funcptr
){
2567 g_info("Different functions (%lu.%09lu): ignore it\n",
2568 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2569 g_info("process state has %llu when pop_function is %llu\n",
2570 process
->current_function
, funcptr
);
2571 g_info("{ %u, %u, %s, %s, %s }\n",
2574 g_quark_to_string(process
->name
),
2575 g_quark_to_string(process
->brand
),
2576 g_quark_to_string(process
->state
->s
));
2579 guint depth
= process
->user_stack
->len
;
2582 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2583 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2587 process
->user_stack
=
2588 g_array_set_size(process
->user_stack
, depth
- 1);
2589 process
->current_function
=
2590 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2594 static gboolean
function_entry(void *hook_data
, void *call_data
)
2596 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2597 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2598 //guint8 ev_id = ltt_event_eventtype_id(e);
2599 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2600 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2601 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2603 push_function(s
, funcptr
);
2607 static gboolean
function_exit(void *hook_data
, void *call_data
)
2609 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2610 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2611 //guint8 ev_id = ltt_event_eventtype_id(e);
2612 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2613 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2614 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2616 pop_function(s
, funcptr
);
2620 static gboolean
schedchange(void *hook_data
, void *call_data
)
2622 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2624 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2625 LttvProcessState
*process
= ts
->running_process
[cpu
];
2626 //LttvProcessState *old_process = ts->running_process[cpu];
2628 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2629 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2630 guint pid_in
, pid_out
;
2633 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2634 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2635 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2637 if(likely(process
!= NULL
)) {
2639 /* We could not know but it was not the idle process executing.
2640 This should only happen at the beginning, before the first schedule
2641 event, and when the initial information (current process for each CPU)
2642 is missing. It is not obvious how we could, after the fact, compensate
2643 the wrongly attributed statistics. */
2645 //This test only makes sense once the state is known and if there is no
2646 //missing events. We need to silently ignore schedchange coming after a
2647 //process_free, or it causes glitches. (FIXME)
2648 //if(unlikely(process->pid != pid_out)) {
2649 // g_assert(process->pid == 0);
2651 if(process
->pid
== 0
2652 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2654 /* Scheduling out of pid 0 at beginning of the trace :
2655 * we know for sure it is in syscall mode at this point. */
2656 g_assert(process
->execution_stack
->len
== 1);
2657 process
->state
->t
= LTTV_STATE_SYSCALL
;
2658 process
->state
->s
= LTTV_STATE_WAIT
;
2659 process
->state
->change
= s
->parent
.timestamp
;
2660 process
->state
->entry
= s
->parent
.timestamp
;
2663 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2664 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2665 process
->state
->change
= s
->parent
.timestamp
;
2667 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2668 else process
->state
->s
= LTTV_STATE_WAIT
;
2669 process
->state
->change
= s
->parent
.timestamp
;
2672 if(state_out
== 32 || state_out
== 64)
2673 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2674 /* see sched.h for states */
2677 process
= ts
->running_process
[cpu
] =
2678 lttv_state_find_process_or_create(
2679 (LttvTraceState
*)s
->parent
.t_context
,
2681 &s
->parent
.timestamp
);
2682 process
->state
->s
= LTTV_STATE_RUN
;
2684 if(process
->usertrace
)
2685 process
->usertrace
->cpu
= cpu
;
2686 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2687 process
->state
->change
= s
->parent
.timestamp
;
2689 /* update cpu status */
2691 /* going to idle task */
2692 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2694 /* scheduling a real task.
2695 * we must be careful here:
2696 * if we just schedule()'ed to a process that is
2697 * in a trap, we must put the cpu in trap mode
2699 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2700 if(process
->state
->t
== LTTV_STATE_TRAP
)
2701 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2707 static gboolean
process_fork(void *hook_data
, void *call_data
)
2709 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2710 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2711 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2713 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2714 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2715 //LttvProcessState *zombie_process;
2717 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2718 LttvProcessState
*process
= ts
->running_process
[cpu
];
2719 LttvProcessState
*child_process
;
2720 struct marker_field
*f
;
2723 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2726 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2727 s
->parent
.target_pid
= child_pid
;
2730 f
= lttv_trace_get_hook_field(th
, 2);
2732 child_tgid
= ltt_event_get_unsigned(e
, f
);
2736 /* Mathieu : it seems like the process might have been scheduled in before the
2737 * fork, and, in a rare case, might be the current process. This might happen
2738 * in a SMP case where we don't have enough precision on the clocks.
2740 * Test reenabled after precision fixes on time. (Mathieu) */
2742 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2744 if(unlikely(zombie_process
!= NULL
)) {
2745 /* Reutilisation of PID. Only now we are sure that the old PID
2746 * has been released. FIXME : should know when release_task happens instead.
2748 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2750 for(i
=0; i
< num_cpus
; i
++) {
2751 g_assert(zombie_process
!= ts
->running_process
[i
]);
2754 exit_process(s
, zombie_process
);
2757 g_assert(process
->pid
!= child_pid
);
2758 // FIXME : Add this test in the "known state" section
2759 // g_assert(process->pid == parent_pid);
2760 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2761 if(child_process
== NULL
) {
2762 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2763 child_pid
, child_tgid
,
2764 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2766 /* The process has already been created : due to time imprecision between
2767 * multiple CPUs : it has been scheduled in before creation. Note that we
2768 * shouldn't have this kind of imprecision.
2770 * Simply put a correct parent.
2772 g_assert(0); /* This is a problematic case : the process has been created
2773 before the fork event */
2774 child_process
->ppid
= process
->pid
;
2775 child_process
->tgid
= child_tgid
;
2777 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2778 child_process
->name
= process
->name
;
2779 child_process
->brand
= process
->brand
;
2784 /* We stamp a newly created process as kernel_thread.
2785 * The thread should not be running yet. */
2786 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2788 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2789 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2790 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2792 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2793 LttvProcessState
*process
;
2794 LttvExecutionState
*es
;
2797 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2798 s
->parent
.target_pid
= pid
;
2800 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2802 process
->execution_stack
=
2803 g_array_set_size(process
->execution_stack
, 1);
2804 es
= process
->state
=
2805 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2806 es
->t
= LTTV_STATE_SYSCALL
;
2807 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2812 static gboolean
process_exit(void *hook_data
, void *call_data
)
2814 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2815 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2816 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2818 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2819 LttvProcessState
*process
; // = ts->running_process[cpu];
2821 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2822 s
->parent
.target_pid
= pid
;
2824 // FIXME : Add this test in the "known state" section
2825 // g_assert(process->pid == pid);
2827 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2828 if(likely(process
!= NULL
)) {
2829 process
->state
->s
= LTTV_STATE_EXIT
;
2834 static gboolean
process_free(void *hook_data
, void *call_data
)
2836 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2837 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2838 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2839 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2841 LttvProcessState
*process
;
2843 /* PID of the process to release */
2844 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2845 s
->parent
.target_pid
= release_pid
;
2847 g_assert(release_pid
!= 0);
2849 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2851 if(likely(process
!= NULL
)) {
2852 /* release_task is happening at kernel level : we can now safely release
2853 * the data structure of the process */
2854 //This test is fun, though, as it may happen that
2855 //at time t : CPU 0 : process_free
2856 //at time t+150ns : CPU 1 : schedule out
2857 //Clearly due to time imprecision, we disable it. (Mathieu)
2858 //If this weird case happen, we have no choice but to put the
2859 //Currently running process on the cpu to 0.
2860 //I re-enable it following time precision fixes. (Mathieu)
2861 //Well, in the case where an process is freed by a process on another CPU
2862 //and still scheduled, it happens that this is the schedchange that will
2863 //drop the last reference count. Do not free it here!
2864 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2866 for(i
=0; i
< num_cpus
; i
++) {
2867 //g_assert(process != ts->running_process[i]);
2868 if(process
== ts
->running_process
[i
]) {
2869 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2873 if(i
== num_cpus
) /* process is not scheduled */
2874 exit_process(s
, process
);
2881 static gboolean
process_exec(void *hook_data
, void *call_data
)
2883 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2884 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2885 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2886 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2889 LttvProcessState
*process
= ts
->running_process
[cpu
];
2891 #if 0//how to use a sequence that must be transformed in a string
2892 /* PID of the process to release */
2893 guint64 name_len
= ltt_event_field_element_number(e
,
2894 lttv_trace_get_hook_field(th
, 0));
2895 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2896 LttField
*child
= ltt_event_field_element_select(e
,
2897 lttv_trace_get_hook_field(th
, 0), 0);
2899 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2900 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2901 memcpy(null_term_name
, name_begin
, name_len
);
2902 null_term_name
[name_len
] = '\0';
2903 process
->name
= g_quark_from_string(null_term_name
);
2906 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2907 lttv_trace_get_hook_field(th
, 0)));
2908 process
->brand
= LTTV_STATE_UNBRANDED
;
2909 //g_free(null_term_name);
2913 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2915 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2916 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2917 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2918 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2921 LttvProcessState
*process
= ts
->running_process
[cpu
];
2923 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2924 process
->brand
= g_quark_from_string(name
);
2929 static void fix_process(gpointer key
, gpointer value
,
2932 LttvProcessState
*process
;
2933 LttvExecutionState
*es
;
2934 process
= (LttvProcessState
*)value
;
2935 LttTime
*timestamp
= (LttTime
*)user_data
;
2937 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2938 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2939 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2940 es
->t
= LTTV_STATE_SYSCALL
;
2941 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2942 es
->entry
= *timestamp
;
2943 es
->change
= *timestamp
;
2944 es
->cum_cpu_time
= ltt_time_zero
;
2945 if(es
->s
== LTTV_STATE_UNNAMED
)
2946 es
->s
= LTTV_STATE_WAIT
;
2949 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2950 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2951 es
->t
= LTTV_STATE_USER_MODE
;
2952 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2953 es
->entry
= *timestamp
;
2954 //g_assert(timestamp->tv_sec != 0);
2955 es
->change
= *timestamp
;
2956 es
->cum_cpu_time
= ltt_time_zero
;
2957 if(es
->s
== LTTV_STATE_UNNAMED
)
2958 es
->s
= LTTV_STATE_RUN
;
2960 if(process
->execution_stack
->len
== 1) {
2961 /* Still in bottom unknown mode, means never did a system call
2962 * May be either in user mode, syscall mode, running or waiting.*/
2963 /* FIXME : we may be tagging syscall mode when being user mode */
2964 process
->execution_stack
=
2965 g_array_set_size(process
->execution_stack
, 2);
2966 es
= process
->state
= &g_array_index(process
->execution_stack
,
2967 LttvExecutionState
, 1);
2968 es
->t
= LTTV_STATE_SYSCALL
;
2969 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2970 es
->entry
= *timestamp
;
2971 //g_assert(timestamp->tv_sec != 0);
2972 es
->change
= *timestamp
;
2973 es
->cum_cpu_time
= ltt_time_zero
;
2974 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2975 es
->s
= LTTV_STATE_WAIT
;
2981 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2983 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2984 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2985 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2986 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2987 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2989 /* For all processes */
2990 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2991 /* else, if stack[0] is unknown, set to user mode, running */
2993 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2998 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
3000 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3001 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3002 //It's slow : optimise later by doing this before reading trace.
3003 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
3009 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3010 LttvProcessState
*process
= ts
->running_process
[cpu
];
3011 LttvProcessState
*parent_process
;
3012 struct marker_field
*f
;
3013 GQuark type
, mode
, submode
, status
;
3014 LttvExecutionState
*es
;
3018 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
3019 s
->parent
.target_pid
= pid
;
3022 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
3025 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
3028 f
= lttv_trace_get_hook_field(th
, 3);
3029 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3031 //FIXME: type is rarely used, enum must match possible types.
3034 f
= lttv_trace_get_hook_field(th
, 4);
3035 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
3038 f
= lttv_trace_get_hook_field(th
, 5);
3039 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3042 f
= lttv_trace_get_hook_field(th
, 6);
3043 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
3046 f
= lttv_trace_get_hook_field(th
, 7);
3048 tgid
= ltt_event_get_unsigned(e
, f
);
3053 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
3054 for(i
=0; i
<nb_cpus
; i
++) {
3055 process
= lttv_state_find_process(ts
, i
, pid
);
3056 g_assert(process
!= NULL
);
3058 process
->ppid
= parent_pid
;
3059 process
->tgid
= tgid
;
3060 process
->name
= g_quark_from_string(command
);
3062 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3063 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3067 /* The process might exist if a process was forked while performing the
3069 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3070 if(process
== NULL
) {
3071 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3072 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3073 pid
, tgid
, g_quark_from_string(command
),
3074 &s
->parent
.timestamp
);
3076 /* Keep the stack bottom : a running user mode */
3077 /* Disabled because of inconsistencies in the current statedump states. */
3078 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3079 /* Only keep the bottom
3080 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3081 /* Will cause expected trap when in fact being syscall (even after end of
3083 * Will cause expected interrupt when being syscall. (only before end of
3084 * statedump event) */
3085 // This will cause a "popping last state on stack, ignoring it."
3086 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3087 es
= process
->state
= &g_array_index(process
->execution_stack
,
3088 LttvExecutionState
, 0);
3089 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3090 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3091 es
->s
= LTTV_STATE_UNNAMED
;
3092 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3094 es
->t
= LTTV_STATE_SYSCALL
;
3099 /* User space process :
3100 * bottom : user mode
3101 * either currently running or scheduled out.
3102 * can be scheduled out because interrupted in (user mode or in syscall)
3103 * or because of an explicit call to the scheduler in syscall. Note that
3104 * the scheduler call comes after the irq_exit, so never in interrupt
3106 // temp workaround : set size to 1 : only have user mode bottom of stack.
3107 // will cause g_info message of expected syscall mode when in fact being
3108 // in user mode. Can also cause expected trap when in fact being user
3109 // mode in the event of a page fault reenabling interrupts in the handler.
3110 // Expected syscall and trap can also happen after the end of statedump
3111 // This will cause a "popping last state on stack, ignoring it."
3112 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3113 es
= process
->state
= &g_array_index(process
->execution_stack
,
3114 LttvExecutionState
, 0);
3115 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3116 es
->s
= LTTV_STATE_UNNAMED
;
3117 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3119 es
->t
= LTTV_STATE_USER_MODE
;
3127 es
= process
->state
= &g_array_index(process
->execution_stack
,
3128 LttvExecutionState
, 1);
3129 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3130 es
->s
= LTTV_STATE_UNNAMED
;
3131 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3135 /* The process has already been created :
3136 * Probably was forked while dumping the process state or
3137 * was simply scheduled in prior to get the state dump event.
3139 process
->ppid
= parent_pid
;
3140 process
->tgid
= tgid
;
3141 process
->name
= g_quark_from_string(command
);
3142 process
->type
= type
;
3144 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3146 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3147 if(type
== LTTV_STATE_KERNEL_THREAD
)
3148 es
->t
= LTTV_STATE_SYSCALL
;
3150 es
->t
= LTTV_STATE_USER_MODE
;
3153 /* Don't mess around with the stack, it will eventually become
3154 * ok after the end of state dump. */
3161 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3163 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3165 lttv_state_add_event_hooks(tss
);
3170 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3172 LttvTraceset
*traceset
= self
->parent
.ts
;
3174 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3178 LttvTracefileState
*tfs
;
3184 LttvAttributeValue val
;
3186 nb_trace
= lttv_traceset_number(traceset
);
3187 for(i
= 0 ; i
< nb_trace
; i
++) {
3188 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3190 /* Find the eventtype id for the following events and register the
3191 associated by id hooks. */
3193 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3194 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3197 lttv_trace_find_hook(ts
->parent
.t
,
3198 LTT_FACILITY_KERNEL_ARCH
,
3199 LTT_EVENT_SYSCALL_ENTRY
,
3200 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3201 syscall_entry
, NULL
, &hooks
);
3203 lttv_trace_find_hook(ts
->parent
.t
,
3204 LTT_FACILITY_KERNEL_ARCH
,
3205 LTT_EVENT_SYSCALL_EXIT
,
3207 syscall_exit
, NULL
, &hooks
);
3209 lttv_trace_find_hook(ts
->parent
.t
,
3210 LTT_FACILITY_KERNEL_ARCH
,
3211 LTT_EVENT_TRAP_ENTRY
,
3212 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3213 trap_entry
, NULL
, &hooks
);
3215 lttv_trace_find_hook(ts
->parent
.t
,
3216 LTT_FACILITY_KERNEL_ARCH
,
3217 LTT_EVENT_TRAP_EXIT
,
3219 trap_exit
, NULL
, &hooks
);
3221 lttv_trace_find_hook(ts
->parent
.t
,
3222 LTT_FACILITY_KERNEL
,
3223 LTT_EVENT_IRQ_ENTRY
,
3224 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3225 irq_entry
, NULL
, &hooks
);
3227 lttv_trace_find_hook(ts
->parent
.t
,
3228 LTT_FACILITY_KERNEL
,
3231 irq_exit
, NULL
, &hooks
);
3233 lttv_trace_find_hook(ts
->parent
.t
,
3234 LTT_FACILITY_KERNEL
,
3235 LTT_EVENT_SOFT_IRQ_ENTRY
,
3236 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3237 soft_irq_entry
, NULL
, &hooks
);
3239 lttv_trace_find_hook(ts
->parent
.t
,
3240 LTT_FACILITY_KERNEL
,
3241 LTT_EVENT_SOFT_IRQ_EXIT
,
3243 soft_irq_exit
, NULL
, &hooks
);
3245 lttv_trace_find_hook(ts
->parent
.t
,
3246 LTT_FACILITY_KERNEL
,
3247 LTT_EVENT_SCHED_SCHEDULE
,
3248 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3249 LTT_FIELD_PREV_STATE
),
3250 schedchange
, NULL
, &hooks
);
3252 lttv_trace_find_hook(ts
->parent
.t
,
3253 LTT_FACILITY_KERNEL
,
3254 LTT_EVENT_PROCESS_FORK
,
3255 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3256 LTT_FIELD_CHILD_TGID
),
3257 process_fork
, NULL
, &hooks
);
3259 lttv_trace_find_hook(ts
->parent
.t
,
3260 LTT_FACILITY_KERNEL_ARCH
,
3261 LTT_EVENT_KTHREAD_CREATE
,
3262 FIELD_ARRAY(LTT_FIELD_PID
),
3263 process_kernel_thread
, NULL
, &hooks
);
3265 lttv_trace_find_hook(ts
->parent
.t
,
3266 LTT_FACILITY_KERNEL
,
3267 LTT_EVENT_PROCESS_EXIT
,
3268 FIELD_ARRAY(LTT_FIELD_PID
),
3269 process_exit
, NULL
, &hooks
);
3271 lttv_trace_find_hook(ts
->parent
.t
,
3272 LTT_FACILITY_KERNEL
,
3273 LTT_EVENT_PROCESS_FREE
,
3274 FIELD_ARRAY(LTT_FIELD_PID
),
3275 process_free
, NULL
, &hooks
);
3277 lttv_trace_find_hook(ts
->parent
.t
,
3280 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3281 process_exec
, NULL
, &hooks
);
3283 lttv_trace_find_hook(ts
->parent
.t
,
3284 LTT_FACILITY_USER_GENERIC
,
3285 LTT_EVENT_THREAD_BRAND
,
3286 FIELD_ARRAY(LTT_FIELD_NAME
),
3287 thread_brand
, NULL
, &hooks
);
3289 /* statedump-related hooks */
3290 lttv_trace_find_hook(ts
->parent
.t
,
3292 LTT_EVENT_PROCESS_STATE
,
3293 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3294 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3295 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3296 enum_process_state
, NULL
, &hooks
);
3298 lttv_trace_find_hook(ts
->parent
.t
,
3300 LTT_EVENT_STATEDUMP_END
,
3302 statedump_end
, NULL
, &hooks
);
3304 lttv_trace_find_hook(ts
->parent
.t
,
3306 LTT_EVENT_LIST_INTERRUPT
,
3307 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3308 enum_interrupt
, NULL
, &hooks
);
3310 lttv_trace_find_hook(ts
->parent
.t
,
3312 LTT_EVENT_REQUEST_ISSUE
,
3313 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3314 bdev_request_issue
, NULL
, &hooks
);
3316 lttv_trace_find_hook(ts
->parent
.t
,
3318 LTT_EVENT_REQUEST_COMPLETE
,
3319 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3320 bdev_request_complete
, NULL
, &hooks
);
3322 lttv_trace_find_hook(ts
->parent
.t
,
3323 LTT_FACILITY_USER_GENERIC
,
3324 LTT_EVENT_FUNCTION_ENTRY
,
3325 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3326 function_entry
, NULL
, &hooks
);
3328 lttv_trace_find_hook(ts
->parent
.t
,
3329 LTT_FACILITY_USER_GENERIC
,
3330 LTT_EVENT_FUNCTION_EXIT
,
3331 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3332 function_exit
, NULL
, &hooks
);
3334 /* Add these hooks to each event_by_id hooks list */
3336 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3338 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3340 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3341 LttvTracefileContext
*, j
));
3343 for(k
= 0 ; k
< hooks
->len
; k
++) {
3344 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3346 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3352 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3353 *(val
.v_pointer
) = hooks
;
3357 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3359 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3361 lttv_state_remove_event_hooks(tss
);
3366 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3368 LttvTraceset
*traceset
= self
->parent
.ts
;
3370 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3374 LttvTracefileState
*tfs
;
3380 LttvAttributeValue val
;
3382 nb_trace
= lttv_traceset_number(traceset
);
3383 for(i
= 0 ; i
< nb_trace
; i
++) {
3384 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3386 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3387 hooks
= *(val
.v_pointer
);
3389 /* Remove these hooks from each event_by_id hooks list */
3391 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3393 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3395 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3396 LttvTracefileContext
*, j
));
3398 for(k
= 0 ; k
< hooks
->len
; k
++) {
3399 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3400 lttv_hooks_remove_data(
3401 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3406 lttv_trace_hook_remove_all(&hooks
);
3407 g_array_free(hooks
, TRUE
);
3411 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3413 guint
*event_count
= (guint
*)hook_data
;
3415 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3416 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3421 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3423 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3425 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3427 LttvAttributeValue value
;
3429 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3430 LTTV_STATE_SAVED_STATES
);
3431 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3432 value
= lttv_attribute_add(saved_states_tree
,
3433 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3434 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3435 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3436 *(value
.v_time
) = self
->parent
.timestamp
;
3437 lttv_state_save(tcs
, saved_state_tree
);
3438 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3439 self
->parent
.timestamp
.tv_nsec
);
3441 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3446 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3448 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3450 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3455 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3463 static gboolean
block_start(void *hook_data
, void *call_data
)
3465 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3467 LttvTracefileState
*tfcs
;
3469 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3471 LttEventPosition
*ep
;
3473 guint i
, nb_block
, nb_event
, nb_tracefile
;
3477 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3479 LttvAttributeValue value
;
3481 ep
= ltt_event_position_new();
3483 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3485 /* Count the number of events added since the last block end in any
3488 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3490 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3491 LttvTracefileContext
, i
));
3492 ltt_event_position(tfcs
->parent
.e
, ep
);
3493 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3494 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3495 tfcs
->saved_position
= nb_event
;
3499 if(tcs
->nb_event
>= tcs
->save_interval
) {
3500 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3501 LTTV_STATE_SAVED_STATES
);
3502 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3503 value
= lttv_attribute_add(saved_states_tree
,
3504 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3505 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3506 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3507 *(value
.v_time
) = self
->parent
.timestamp
;
3508 lttv_state_save(tcs
, saved_state_tree
);
3510 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3511 self
->parent
.timestamp
.tv_nsec
);
3513 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3519 static gboolean
block_end(void *hook_data
, void *call_data
)
3521 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3523 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3527 LttEventPosition
*ep
;
3529 guint nb_block
, nb_event
;
3531 ep
= ltt_event_position_new();
3532 ltt_event_position(self
->parent
.e
, ep
);
3533 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3534 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3535 self
->saved_position
= 0;
3536 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3543 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3545 LttvTraceset
*traceset
= self
->parent
.ts
;
3547 guint i
, j
, nb_trace
, nb_tracefile
;
3551 LttvTracefileState
*tfs
;
3553 LttvTraceHook hook_start
, hook_end
;
3555 nb_trace
= lttv_traceset_number(traceset
);
3556 for(i
= 0 ; i
< nb_trace
; i
++) {
3557 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3559 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3560 NULL
, NULL
, block_start
, &hook_start
);
3561 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3562 NULL
, NULL
, block_end
, &hook_end
);
3564 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3566 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3568 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3569 LttvTracefileContext
, j
));
3570 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3571 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3572 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3573 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3579 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3581 LttvTraceset
*traceset
= self
->parent
.ts
;
3583 guint i
, j
, nb_trace
, nb_tracefile
;
3587 LttvTracefileState
*tfs
;
3590 nb_trace
= lttv_traceset_number(traceset
);
3591 for(i
= 0 ; i
< nb_trace
; i
++) {
3593 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3594 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3596 if(ts
->has_precomputed_states
) continue;
3598 guint
*event_count
= g_new(guint
, 1);
3601 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3603 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3604 LttvTracefileContext
*, j
));
3605 lttv_hooks_add(tfs
->parent
.event
,
3606 state_save_event_hook
,
3613 lttv_process_traceset_begin(&self
->parent
,
3614 NULL
, NULL
, NULL
, NULL
, NULL
);
3618 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3620 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3622 lttv_state_save_add_event_hooks(tss
);
3629 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3631 LttvTraceset
*traceset
= self
->parent
.ts
;
3633 guint i
, j
, nb_trace
, nb_tracefile
;
3637 LttvTracefileState
*tfs
;
3639 LttvTraceHook hook_start
, hook_end
;
3641 nb_trace
= lttv_traceset_number(traceset
);
3642 for(i
= 0 ; i
< nb_trace
; i
++) {
3643 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3645 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3646 NULL
, NULL
, block_start
, &hook_start
);
3648 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3649 NULL
, NULL
, block_end
, &hook_end
);
3651 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3653 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3655 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3656 LttvTracefileContext
, j
));
3657 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3658 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3659 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3660 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3666 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3668 LttvTraceset
*traceset
= self
->parent
.ts
;
3670 guint i
, j
, nb_trace
, nb_tracefile
;
3674 LttvTracefileState
*tfs
;
3676 LttvHooks
*after_trace
= lttv_hooks_new();
3678 lttv_hooks_add(after_trace
,
3679 state_save_after_trace_hook
,
3684 lttv_process_traceset_end(&self
->parent
,
3685 NULL
, after_trace
, NULL
, NULL
, NULL
);
3687 lttv_hooks_destroy(after_trace
);
3689 nb_trace
= lttv_traceset_number(traceset
);
3690 for(i
= 0 ; i
< nb_trace
; i
++) {
3692 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3693 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3695 if(ts
->has_precomputed_states
) continue;
3697 guint
*event_count
= NULL
;
3699 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3701 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3702 LttvTracefileContext
*, j
));
3703 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3704 state_save_event_hook
);
3706 if(event_count
) g_free(event_count
);
3710 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3712 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3714 lttv_state_save_remove_event_hooks(tss
);
3719 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3721 LttvTraceset
*traceset
= self
->parent
.ts
;
3725 int min_pos
, mid_pos
, max_pos
;
3727 guint call_rest
= 0;
3729 LttvTraceState
*tcs
;
3731 LttvAttributeValue value
;
3733 LttvAttributeType type
;
3735 LttvAttributeName name
;
3739 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3741 //g_tree_destroy(self->parent.pqueue);
3742 //self->parent.pqueue = g_tree_new(compare_tracefile);
3744 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3746 nb_trace
= lttv_traceset_number(traceset
);
3747 for(i
= 0 ; i
< nb_trace
; i
++) {
3748 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3750 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3751 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3752 LTTV_STATE_SAVED_STATES
);
3755 if(saved_states_tree
) {
3756 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3757 mid_pos
= max_pos
/ 2;
3758 while(min_pos
< max_pos
) {
3759 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3761 g_assert(type
== LTTV_GOBJECT
);
3762 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3763 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3765 g_assert(type
== LTTV_TIME
);
3766 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3768 closest_tree
= saved_state_tree
;
3770 else max_pos
= mid_pos
- 1;
3772 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3776 /* restore the closest earlier saved state */
3778 lttv_state_restore(tcs
, closest_tree
);
3782 /* There is no saved state, yet we want to have it. Restart at T0 */
3784 restore_init_state(tcs
);
3785 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3788 /* We want to seek quickly without restoring/updating the state */
3790 restore_init_state(tcs
);
3791 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3794 if(!call_rest
) g_info("NOT Calling restore");
3799 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3805 traceset_state_finalize (LttvTracesetState
*self
)
3807 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3808 finalize(G_OBJECT(self
));
3813 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3815 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3817 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3818 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3819 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3820 klass
->new_traceset_context
= new_traceset_context
;
3821 klass
->new_trace_context
= new_trace_context
;
3822 klass
->new_tracefile_context
= new_tracefile_context
;
3827 lttv_traceset_state_get_type(void)
3829 static GType type
= 0;
3831 static const GTypeInfo info
= {
3832 sizeof (LttvTracesetStateClass
),
3833 NULL
, /* base_init */
3834 NULL
, /* base_finalize */
3835 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3836 NULL
, /* class_finalize */
3837 NULL
, /* class_data */
3838 sizeof (LttvTracesetState
),
3839 0, /* n_preallocs */
3840 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3841 NULL
/* value handling */
3844 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3852 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3858 trace_state_finalize (LttvTraceState
*self
)
3860 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3861 finalize(G_OBJECT(self
));
3866 trace_state_class_init (LttvTraceStateClass
*klass
)
3868 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3870 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3871 klass
->state_save
= state_save
;
3872 klass
->state_restore
= state_restore
;
3873 klass
->state_saved_free
= state_saved_free
;
3878 lttv_trace_state_get_type(void)
3880 static GType type
= 0;
3882 static const GTypeInfo info
= {
3883 sizeof (LttvTraceStateClass
),
3884 NULL
, /* base_init */
3885 NULL
, /* base_finalize */
3886 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3887 NULL
, /* class_finalize */
3888 NULL
, /* class_data */
3889 sizeof (LttvTraceState
),
3890 0, /* n_preallocs */
3891 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3892 NULL
/* value handling */
3895 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3896 "LttvTraceStateType", &info
, 0);
3903 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3909 tracefile_state_finalize (LttvTracefileState
*self
)
3911 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3912 finalize(G_OBJECT(self
));
3917 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3919 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3921 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3926 lttv_tracefile_state_get_type(void)
3928 static GType type
= 0;
3930 static const GTypeInfo info
= {
3931 sizeof (LttvTracefileStateClass
),
3932 NULL
, /* base_init */
3933 NULL
, /* base_finalize */
3934 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3935 NULL
, /* class_finalize */
3936 NULL
, /* class_data */
3937 sizeof (LttvTracefileState
),
3938 0, /* n_preallocs */
3939 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3940 NULL
/* value handling */
3943 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3944 "LttvTracefileStateType", &info
, 0);
3950 static void module_init()
3952 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3953 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3954 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3955 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3956 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3957 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3958 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3959 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3960 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3961 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3962 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3963 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3964 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3965 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3966 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3967 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3968 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3969 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3970 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3971 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3972 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3973 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3974 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3975 LTTV_STATE_EVENT
= g_quark_from_string("event");
3976 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3977 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3978 LTTV_STATE_TIME
= g_quark_from_string("time");
3979 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3980 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3981 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3982 g_quark_from_string("trace_state_use_count");
3983 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3984 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
3985 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3986 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
3987 LTTV_STATE_RESOURCE_TRAPS
= g_quark_from_string("trap resource states");
3988 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3991 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3992 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3993 LTT_FACILITY_FS
= g_quark_from_string("fs");
3994 LTT_FACILITY_LIST
= g_quark_from_string("list");
3995 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3996 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3999 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4000 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4001 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4002 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4003 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4004 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4005 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
4006 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
4007 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
4008 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
4009 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
4010 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
4011 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
4012 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4013 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
4014 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
4015 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4016 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4017 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4018 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
4019 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
4020 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
4023 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4024 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4025 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4026 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4027 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
4028 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
4029 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
4030 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4031 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4032 LTT_FIELD_PID
= g_quark_from_string("pid");
4033 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4034 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
4035 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4036 LTT_FIELD_NAME
= g_quark_from_string("name");
4037 LTT_FIELD_TYPE
= g_quark_from_string("type");
4038 LTT_FIELD_MODE
= g_quark_from_string("mode");
4039 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4040 LTT_FIELD_STATUS
= g_quark_from_string("status");
4041 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4042 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4043 LTT_FIELD_MAJOR
= g_quark_from_string("major");
4044 LTT_FIELD_MINOR
= g_quark_from_string("minor");
4045 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
4046 LTT_FIELD_ACTION
= g_quark_from_string("action");
4048 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
4049 LTTV_CPU_IDLE
= g_quark_from_string("idle");
4050 LTTV_CPU_BUSY
= g_quark_from_string("busy");
4051 LTTV_CPU_IRQ
= g_quark_from_string("irq");
4052 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
4053 LTTV_CPU_TRAP
= g_quark_from_string("trap");
4055 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4056 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4057 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4059 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4060 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4061 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4062 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4065 static void module_destroy()
4070 LTTV_MODULE("state", "State computation", \
4071 "Update the system state, possibly saving it at intervals", \
4072 module_init
, module_destroy
)