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_BLKDEVS
;
177 static void create_max_time(LttvTraceState
*tcs
);
179 static void get_max_time(LttvTraceState
*tcs
);
181 static void free_max_time(LttvTraceState
*tcs
);
183 static void create_name_tables(LttvTraceState
*tcs
);
185 static void get_name_tables(LttvTraceState
*tcs
);
187 static void free_name_tables(LttvTraceState
*tcs
);
189 static void free_saved_state(LttvTraceState
*tcs
);
191 static void lttv_state_free_process_table(GHashTable
*processes
);
193 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
194 GPtrArray
*quarktable
);
196 /* Resource function prototypes */
197 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
198 static LttvBdevState
*bdevstate_new(void);
199 static void bdevstate_free(LttvBdevState
*);
200 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
201 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
204 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
206 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
210 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
212 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
216 void lttv_state_state_saved_free(LttvTraceState
*self
,
217 LttvAttribute
*container
)
219 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
223 guint
process_hash(gconstpointer key
)
225 guint pid
= ((const LttvProcessState
*)key
)->pid
;
226 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
230 /* If the hash table hash function is well distributed,
231 * the process_equal should compare different pid */
232 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
234 const LttvProcessState
*process_a
, *process_b
;
237 process_a
= (const LttvProcessState
*)a
;
238 process_b
= (const LttvProcessState
*)b
;
240 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
241 else if(likely(process_a
->pid
== 0 &&
242 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
247 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
249 g_tree_destroy((GTree
*)value
);
252 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
254 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
255 g_hash_table_destroy(usertraces
);
258 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
264 restore_init_state(LttvTraceState
*self
)
266 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
268 //LttvTracefileState *tfcs;
270 LttTime start_time
, end_time
;
272 /* Free the process tables */
273 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
274 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
275 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
276 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
279 /* Seek time to beginning */
280 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
281 // closest. It's the tracecontext job to seek the trace to the beginning
282 // anyway : the init state might be used at the middle of the trace as well...
283 //g_tree_destroy(self->parent.ts_context->pqueue);
284 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
286 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
288 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
290 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
291 nb_irqs
= self
->nb_irqs
;
292 nb_soft_irqs
= self
->nb_soft_irqs
;
294 /* Put the per cpu running_process to beginning state : process 0. */
295 for(i
=0; i
< nb_cpus
; i
++) {
296 LttvExecutionState
*es
;
297 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
298 LTTV_STATE_UNNAMED
, &start_time
);
299 /* We are not sure is it's a kernel thread or normal thread, put the
300 * bottom stack state to unknown */
301 self
->running_process
[i
]->execution_stack
=
302 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
303 es
= self
->running_process
[i
]->state
=
304 &g_array_index(self
->running_process
[i
]->execution_stack
,
305 LttvExecutionState
, 0);
306 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
307 es
->s
= LTTV_STATE_UNNAMED
;
309 //self->running_process[i]->state->s = LTTV_STATE_RUN;
310 self
->running_process
[i
]->cpu
= i
;
312 /* reset cpu states */
313 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
314 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
317 /* reset irq states */
318 for(i
=0; i
<nb_irqs
; i
++) {
319 if(self
->irq_states
[i
].mode_stack
->len
> 0)
320 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
323 /* reset softirq states */
324 for(i
=0; i
<nb_soft_irqs
; i
++) {
325 self
->soft_irq_states
[i
].running
= 0;
328 /* reset bdev states */
329 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
330 //g_hash_table_steal_all(self->bdev_states);
331 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
334 nb_tracefile
= self
->parent
.tracefiles
->len
;
336 for(i
= 0 ; i
< nb_tracefile
; i
++) {
338 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
339 LttvTracefileContext
*, i
));
340 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
341 // tfcs->saved_position = 0;
342 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
343 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
344 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
345 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
350 //static LttTime time_zero = {0,0};
352 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
355 const LttTime
*t1
= (const LttTime
*)a
;
356 const LttTime
*t2
= (const LttTime
*)b
;
358 return ltt_time_compare(*t1
, *t2
);
361 static void free_usertrace_key(gpointer data
)
366 #define MAX_STRING_LEN 4096
369 state_load_saved_states(LttvTraceState
*tcs
)
372 GPtrArray
*quarktable
;
373 const char *trace_path
;
377 tcs
->has_precomputed_states
= FALSE
;
381 gchar buf
[MAX_STRING_LEN
];
384 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
385 strncpy(path
, trace_path
, PATH_MAX
-1);
386 count
= strnlen(trace_path
, PATH_MAX
-1);
387 // quarktable : open, test
388 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
389 fp
= fopen(path
, "r");
391 quarktable
= g_ptr_array_sized_new(4096);
393 /* Index 0 is null */
395 if(hdr
== EOF
) return;
396 g_assert(hdr
== HDR_QUARKS
);
400 if(hdr
== EOF
) break;
401 g_assert(hdr
== HDR_QUARK
);
402 g_ptr_array_set_size(quarktable
, q
+1);
405 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
406 if(buf
[i
] == '\0' || feof(fp
)) break;
409 len
= strnlen(buf
, MAX_STRING_LEN
-1);
410 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
411 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
417 // saved_states : open, test
418 strncpy(path
, trace_path
, PATH_MAX
-1);
419 count
= strnlen(trace_path
, PATH_MAX
-1);
420 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
421 fp
= fopen(path
, "r");
425 if(hdr
!= HDR_TRACE
) goto end
;
427 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
429 tcs
->has_precomputed_states
= TRUE
;
434 /* Free the quarktable */
435 for(i
=0; i
<quarktable
->len
; i
++) {
436 string
= g_ptr_array_index (quarktable
, i
);
439 g_ptr_array_free(quarktable
, TRUE
);
444 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
446 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
449 LttvTraceContext
*tc
;
453 LttvTracefileState
*tfcs
;
455 LttvAttributeValue v
;
457 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
458 init((LttvTracesetContext
*)self
, ts
);
460 nb_trace
= lttv_traceset_number(ts
);
461 for(i
= 0 ; i
< nb_trace
; i
++) {
462 tc
= self
->parent
.traces
[i
];
463 tcs
= LTTV_TRACE_STATE(tc
);
464 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
465 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
469 if(*(v
.v_uint
) == 1) {
470 create_name_tables(tcs
);
471 create_max_time(tcs
);
473 get_name_tables(tcs
);
476 nb_tracefile
= tc
->tracefiles
->len
;
477 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
478 nb_irq
= tcs
->nb_irqs
;
479 tcs
->processes
= NULL
;
480 tcs
->usertraces
= NULL
;
481 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
483 /* init cpu resource stuff */
484 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
485 for(j
= 0; j
<nb_cpu
; j
++) {
486 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
487 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
490 /* init irq resource stuff */
491 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
492 for(j
= 0; j
<nb_irq
; j
++) {
493 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
494 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
497 /* init soft irq stuff */
498 /* the kernel has a statically fixed max of 32 softirqs */
499 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
501 /* init bdev resource stuff */
502 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
504 restore_init_state(tcs
);
505 for(j
= 0 ; j
< nb_tracefile
; j
++) {
507 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
508 LttvTracefileContext
*, j
));
509 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
510 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
511 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
512 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
513 /* It's a Usertrace */
514 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
515 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
517 if(!usertrace_tree
) {
518 usertrace_tree
= g_tree_new_full(compare_usertraces
,
519 NULL
, free_usertrace_key
, NULL
);
520 g_hash_table_insert(tcs
->usertraces
,
521 (gpointer
)tid
, usertrace_tree
);
523 LttTime
*timestamp
= g_new(LttTime
, 1);
524 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
525 ltt_tracefile_creation(tfcs
->parent
.tf
));
526 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
530 /* See if the trace has saved states */
531 state_load_saved_states(tcs
);
536 fini(LttvTracesetState
*self
)
542 //LttvTracefileState *tfcs;
544 LttvAttributeValue v
;
546 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
547 for(i
= 0 ; i
< nb_trace
; i
++) {
548 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
549 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
552 g_assert(*(v
.v_uint
) != 0);
555 if(*(v
.v_uint
) == 0) {
556 free_name_tables(tcs
);
558 free_saved_state(tcs
);
560 g_free(tcs
->running_process
);
561 tcs
->running_process
= NULL
;
562 lttv_state_free_process_table(tcs
->processes
);
563 lttv_state_free_usertraces(tcs
->usertraces
);
564 tcs
->processes
= NULL
;
565 tcs
->usertraces
= NULL
;
567 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
568 fini((LttvTracesetContext
*)self
);
572 static LttvTracesetContext
*
573 new_traceset_context(LttvTracesetContext
*self
)
575 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
579 static LttvTraceContext
*
580 new_trace_context(LttvTracesetContext
*self
)
582 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
586 static LttvTracefileContext
*
587 new_tracefile_context(LttvTracesetContext
*self
)
589 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
593 /* Write the process state of the trace */
595 static void write_process_state(gpointer key
, gpointer value
,
598 LttvProcessState
*process
;
600 LttvExecutionState
*es
;
602 FILE *fp
= (FILE *)user_data
;
607 process
= (LttvProcessState
*)value
;
609 " <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",
610 process
, process
->pid
, process
->tgid
, process
->ppid
,
611 g_quark_to_string(process
->type
),
612 process
->creation_time
.tv_sec
,
613 process
->creation_time
.tv_nsec
,
614 process
->insertion_time
.tv_sec
,
615 process
->insertion_time
.tv_nsec
,
616 g_quark_to_string(process
->name
),
617 g_quark_to_string(process
->brand
),
620 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
621 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
622 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
623 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
624 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
625 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
626 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
629 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
630 address
= g_array_index(process
->user_stack
, guint64
, i
);
631 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
635 if(process
->usertrace
) {
636 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
637 g_quark_to_string(process
->usertrace
->tracefile_name
),
638 process
->usertrace
->cpu
);
642 fprintf(fp
, " </PROCESS>\n");
646 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
648 guint i
, nb_tracefile
, nb_block
, offset
;
651 LttvTracefileState
*tfcs
;
655 LttEventPosition
*ep
;
659 ep
= ltt_event_position_new();
661 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
663 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
665 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
666 for(i
=0;i
<nb_cpus
;i
++) {
667 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
668 i
, self
->running_process
[i
]->pid
);
671 nb_tracefile
= self
->parent
.tracefiles
->len
;
673 for(i
= 0 ; i
< nb_tracefile
; i
++) {
675 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
676 LttvTracefileContext
*, i
));
677 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
678 tfcs
->parent
.timestamp
.tv_sec
,
679 tfcs
->parent
.timestamp
.tv_nsec
);
680 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
681 if(e
== NULL
) fprintf(fp
,"/>\n");
683 ltt_event_position(e
, ep
);
684 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
685 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
690 fprintf(fp
,"</PROCESS_STATE>\n");
694 static void write_process_state_raw(gpointer key
, gpointer value
,
697 LttvProcessState
*process
;
699 LttvExecutionState
*es
;
701 FILE *fp
= (FILE *)user_data
;
706 process
= (LttvProcessState
*)value
;
707 fputc(HDR_PROCESS
, fp
);
708 //fwrite(&header, sizeof(header), 1, fp);
709 //fprintf(fp, "%s", g_quark_to_string(process->type));
711 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
712 //fprintf(fp, "%s", g_quark_to_string(process->name));
714 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
715 //fprintf(fp, "%s", g_quark_to_string(process->brand));
717 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
718 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
719 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
720 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
721 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
722 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
723 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
727 " <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",
728 process
, process
->pid
, process
->tgid
, process
->ppid
,
729 g_quark_to_string(process
->type
),
730 process
->creation_time
.tv_sec
,
731 process
->creation_time
.tv_nsec
,
732 process
->insertion_time
.tv_sec
,
733 process
->insertion_time
.tv_nsec
,
734 g_quark_to_string(process
->name
),
735 g_quark_to_string(process
->brand
),
739 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
740 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
743 //fprintf(fp, "%s", g_quark_to_string(es->t));
745 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
746 //fprintf(fp, "%s", g_quark_to_string(es->n));
748 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
749 //fprintf(fp, "%s", g_quark_to_string(es->s));
751 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
752 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
753 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
754 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
756 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
757 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
758 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
759 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
760 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
764 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
765 address
= g_array_index(process
->user_stack
, guint64
, i
);
766 fputc(HDR_USER_STACK
, fp
);
767 fwrite(&address
, sizeof(address
), 1, fp
);
769 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
774 if(process
->usertrace
) {
775 fputc(HDR_USERTRACE
, fp
);
776 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
778 fwrite(&process
->usertrace
->tracefile_name
,
779 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
780 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
782 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
783 g_quark_to_string(process
->usertrace
->tracefile_name
),
784 process
->usertrace
->cpu
);
791 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
793 guint i
, nb_tracefile
, nb_block
, offset
;
796 LttvTracefileState
*tfcs
;
800 LttEventPosition
*ep
;
804 ep
= ltt_event_position_new();
806 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
807 fputc(HDR_PROCESS_STATE
, fp
);
808 fwrite(&t
, sizeof(t
), 1, fp
);
810 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
812 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
813 for(i
=0;i
<nb_cpus
;i
++) {
815 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
816 fwrite(&self
->running_process
[i
]->pid
,
817 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
818 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
819 // i, self->running_process[i]->pid);
822 nb_tracefile
= self
->parent
.tracefiles
->len
;
824 for(i
= 0 ; i
< nb_tracefile
; i
++) {
826 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
827 LttvTracefileContext
*, i
));
828 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
829 // tfcs->parent.timestamp.tv_sec,
830 // tfcs->parent.timestamp.tv_nsec);
831 fputc(HDR_TRACEFILE
, fp
);
832 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
833 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
834 * position following : end of trace */
835 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
837 ltt_event_position(e
, ep
);
838 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
839 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
841 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
842 fwrite(&offset
, sizeof(offset
), 1, fp
);
843 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
850 /* Read process state from a file */
852 /* Called because a HDR_PROCESS was found */
853 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
854 GPtrArray
*quarktable
)
856 LttvExecutionState
*es
;
857 LttvProcessState
*process
, *parent_process
;
858 LttvProcessState tmp
;
863 /* TODO : check return value */
864 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
865 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
866 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
867 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
868 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
869 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
870 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
871 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
872 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
875 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
877 /* We must link to the parent */
878 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
880 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
881 if(process
== NULL
) {
882 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
884 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
888 process
->insertion_time
= tmp
.insertion_time
;
889 process
->creation_time
= tmp
.creation_time
;
890 process
->type
= g_quark_from_string(
891 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
892 process
->tgid
= tmp
.tgid
;
893 process
->ppid
= tmp
.ppid
;
894 process
->brand
= g_quark_from_string(
895 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
897 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
901 if(feof(fp
) || ferror(fp
)) goto end_loop
;
903 gint hdr
= fgetc(fp
);
904 if(hdr
== EOF
) goto end_loop
;
908 process
->execution_stack
=
909 g_array_set_size(process
->execution_stack
,
910 process
->execution_stack
->len
+ 1);
911 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
912 process
->execution_stack
->len
-1);
915 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
916 es
->t
= g_quark_from_string(
917 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
918 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
919 es
->n
= g_quark_from_string(
920 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
921 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
922 es
->s
= g_quark_from_string(
923 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
924 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
925 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
926 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
929 process
->user_stack
= g_array_set_size(process
->user_stack
,
930 process
->user_stack
->len
+ 1);
931 address
= &g_array_index(process
->user_stack
, guint64
,
932 process
->user_stack
->len
-1);
933 fread(address
, sizeof(address
), 1, fp
);
934 process
->current_function
= *address
;
937 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
938 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
950 /* Called because a HDR_PROCESS_STATE was found */
951 /* Append a saved state to the trace states */
952 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
954 guint i
, nb_tracefile
, nb_block
, offset
;
956 LttvTracefileState
*tfcs
;
958 LttEventPosition
*ep
;
966 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
968 LttvAttributeValue value
;
969 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
970 ep
= ltt_event_position_new();
972 restore_init_state(self
);
974 fread(&t
, sizeof(t
), 1, fp
);
977 if(feof(fp
) || ferror(fp
)) goto end_loop
;
979 if(hdr
== EOF
) goto end_loop
;
983 /* Call read_process_state_raw */
984 read_process_state_raw(self
, fp
, quarktable
);
994 case HDR_PROCESS_STATE
:
1000 g_error("Error while parsing saved state file : unknown data header %d",
1006 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1007 for(i
=0;i
<nb_cpus
;i
++) {
1010 g_assert(hdr
== HDR_CPU
);
1011 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1012 g_assert(i
== cpu_num
);
1013 fread(&self
->running_process
[i
]->pid
,
1014 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1017 nb_tracefile
= self
->parent
.tracefiles
->len
;
1019 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1021 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1022 LttvTracefileContext
*, i
));
1023 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1024 // tfcs->parent.timestamp.tv_sec,
1025 // tfcs->parent.timestamp.tv_nsec);
1026 g_tree_remove(pqueue
, &tfcs
->parent
);
1028 g_assert(hdr
== HDR_TRACEFILE
);
1029 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1030 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1031 * position following : end of trace */
1032 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1033 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1034 fread(&offset
, sizeof(offset
), 1, fp
);
1035 fread(&tsc
, sizeof(tsc
), 1, fp
);
1036 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1037 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1039 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1044 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1045 LTTV_STATE_SAVED_STATES
);
1046 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1047 value
= lttv_attribute_add(saved_states_tree
,
1048 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1049 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1050 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1051 *(value
.v_time
) = t
;
1052 lttv_state_save(self
, saved_state_tree
);
1053 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1056 *(self
->max_time_state_recomputed_in_seek
) = t
;
1060 /* Called when a HDR_TRACE is found */
1061 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1062 GPtrArray
*quarktable
)
1067 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1069 if(hdr
== EOF
) goto end_loop
;
1072 case HDR_PROCESS_STATE
:
1073 /* Call read_process_state_raw */
1074 lttv_state_read_raw(tcs
, fp
, quarktable
);
1082 case HDR_USER_STACK
:
1086 g_error("Error while parsing saved state file :"
1087 " unexpected data header %d",
1091 g_error("Error while parsing saved state file : unknown data header %d",
1096 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1097 restore_init_state(tcs
);
1098 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1104 /* Copy each process from an existing hash table to a new one */
1106 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1108 LttvProcessState
*process
, *new_process
;
1110 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1114 process
= (LttvProcessState
*)value
;
1115 new_process
= g_new(LttvProcessState
, 1);
1116 *new_process
= *process
;
1117 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1118 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1119 new_process
->execution_stack
=
1120 g_array_set_size(new_process
->execution_stack
,
1121 process
->execution_stack
->len
);
1122 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1123 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1124 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1126 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1127 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1128 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1129 sizeof(guint64
), 0);
1130 new_process
->user_stack
=
1131 g_array_set_size(new_process
->user_stack
,
1132 process
->user_stack
->len
);
1133 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1134 g_array_index(new_process
->user_stack
, guint64
, i
) =
1135 g_array_index(process
->user_stack
, guint64
, i
);
1137 new_process
->current_function
= process
->current_function
;
1138 g_hash_table_insert(new_processes
, new_process
, new_process
);
1142 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1144 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1146 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1147 return new_processes
;
1150 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1153 LttvCPUState
*retval
;
1155 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1157 for(i
=0; i
<n
; i
++) {
1158 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1159 retval
[i
].last_irq
= states
[i
].last_irq
;
1160 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1161 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1162 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1169 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1173 for(i
=0; i
<n
; i
++) {
1174 g_array_free(states
[i
].mode_stack
, TRUE
);
1180 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1183 LttvIRQState
*retval
;
1185 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1187 for(i
=0; i
<n
; i
++) {
1188 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1189 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1190 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1191 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1198 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1202 for(i
=0; i
<n
; i
++) {
1203 g_array_free(states
[i
].mode_stack
, TRUE
);
1209 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1212 LttvSoftIRQState
*retval
;
1214 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1216 for(i
=0; i
<n
; i
++) {
1217 retval
[i
].running
= states
[i
].running
;
1223 static void lttv_state_free_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1228 /* bdevstate stuff */
1230 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1232 gint devcode_gint
= devcode
;
1233 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1235 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1236 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1238 gint
* key
= g_malloc(sizeof(gint
));
1240 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1248 static LttvBdevState
*bdevstate_new(void)
1250 LttvBdevState
*retval
;
1251 retval
= g_malloc(sizeof(LttvBdevState
));
1252 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1257 static void bdevstate_free(LttvBdevState
*bds
)
1259 g_array_free(bds
->mode_stack
, TRUE
);
1263 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1265 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1267 bdevstate_free(bds
);
1270 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1272 LttvBdevState
*retval
;
1274 retval
= bdevstate_new();
1275 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1280 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1282 //GHashTable *ht = (GHashTable *)u;
1283 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1284 LttvBdevState
*newbds
;
1286 newbds
= bdevstate_copy(bds
);
1288 g_hash_table_insert(u
, k
, newbds
);
1291 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1295 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1297 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1302 /* Free a hashtable and the LttvBdevState structures its values
1305 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1307 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1308 g_hash_table_destroy(ht
);
1311 /* The saved state for each trace contains a member "processes", which
1312 stores a copy of the process table, and a member "tracefiles" with
1313 one entry per tracefile. Each tracefile has a "process" member pointing
1314 to the current process and a "position" member storing the tracefile
1315 position (needed to seek to the current "next" event. */
1317 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1319 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1321 LttvTracefileState
*tfcs
;
1323 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1325 guint
*running_process
;
1327 LttvAttributeValue value
;
1329 LttEventPosition
*ep
;
1331 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1332 LTTV_STATE_TRACEFILES
);
1334 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1336 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1338 /* Add the currently running processes array */
1339 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1340 running_process
= g_new(guint
, nb_cpus
);
1341 for(i
=0;i
<nb_cpus
;i
++) {
1342 running_process
[i
] = self
->running_process
[i
]->pid
;
1344 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1346 *(value
.v_pointer
) = running_process
;
1348 g_info("State save");
1350 nb_tracefile
= self
->parent
.tracefiles
->len
;
1352 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1354 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1355 LttvTracefileContext
*, i
));
1356 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1357 value
= lttv_attribute_add(tracefiles_tree
, i
,
1359 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1361 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1363 *(value
.v_uint
) = tfcs
->process
->pid
;
1365 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1367 /* Only save the position if the tfs has not infinite time. */
1368 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1369 // && current_tfcs != tfcs) {
1370 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1371 *(value
.v_pointer
) = NULL
;
1373 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1374 ep
= ltt_event_position_new();
1375 ltt_event_position(e
, ep
);
1376 *(value
.v_pointer
) = ep
;
1378 guint nb_block
, offset
;
1381 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1382 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1384 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1388 /* save the cpu state */
1390 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1392 *(value
.v_uint
) = nb_cpus
;
1394 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1396 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1399 /* save the irq state */
1400 nb_irqs
= self
->nb_irqs
;
1402 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1404 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1407 /* save the soft irq state */
1408 nb_irqs
= self
->nb_irqs
;
1410 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1412 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_irqs
);
1415 /* save the blkdev states */
1416 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1418 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1422 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1424 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1426 LttvTracefileState
*tfcs
;
1428 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1430 guint
*running_process
;
1432 LttvAttributeType type
;
1434 LttvAttributeValue value
;
1436 LttvAttributeName name
;
1440 LttEventPosition
*ep
;
1442 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1444 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1445 LTTV_STATE_TRACEFILES
);
1447 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1449 g_assert(type
== LTTV_POINTER
);
1450 lttv_state_free_process_table(self
->processes
);
1451 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1453 /* Add the currently running processes array */
1454 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1455 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1457 g_assert(type
== LTTV_POINTER
);
1458 running_process
= *(value
.v_pointer
);
1459 for(i
=0;i
<nb_cpus
;i
++) {
1460 pid
= running_process
[i
];
1461 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1462 g_assert(self
->running_process
[i
] != NULL
);
1465 nb_tracefile
= self
->parent
.tracefiles
->len
;
1467 //g_tree_destroy(tsc->pqueue);
1468 //tsc->pqueue = g_tree_new(compare_tracefile);
1470 /* restore cpu resource states */
1471 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1472 g_assert(type
== LTTV_POINTER
);
1473 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1474 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1476 /* restore irq resource states */
1477 nb_irqs
= self
->nb_irqs
;
1478 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1479 g_assert(type
== LTTV_POINTER
);
1480 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1481 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1483 /* restore soft irq resource states */
1484 nb_soft_irqs
= self
->nb_soft_irqs
;
1485 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1486 g_assert(type
== LTTV_POINTER
);
1487 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1488 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1490 /* restore the blkdev states */
1491 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1492 g_assert(type
== LTTV_POINTER
);
1493 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1494 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1496 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1498 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1499 LttvTracefileContext
*, i
));
1500 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1501 g_assert(type
== LTTV_GOBJECT
);
1502 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1504 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1506 g_assert(type
== LTTV_UINT
);
1507 pid
= *(value
.v_uint
);
1508 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1510 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1512 g_assert(type
== LTTV_POINTER
);
1513 //g_assert(*(value.v_pointer) != NULL);
1514 ep
= *(value
.v_pointer
);
1515 g_assert(tfcs
->parent
.t_context
!= NULL
);
1517 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1519 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1520 g_tree_remove(tsc
->pqueue
, tfc
);
1523 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1524 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1525 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1526 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1527 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1529 tfc
->timestamp
= ltt_time_infinite
;
1535 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1537 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1539 LttvTracefileState
*tfcs
;
1541 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1543 guint
*running_process
;
1545 LttvAttributeType type
;
1547 LttvAttributeValue value
;
1549 LttvAttributeName name
;
1553 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1554 LTTV_STATE_TRACEFILES
);
1555 g_object_ref(G_OBJECT(tracefiles_tree
));
1556 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1558 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1560 g_assert(type
== LTTV_POINTER
);
1561 lttv_state_free_process_table(*(value
.v_pointer
));
1562 *(value
.v_pointer
) = NULL
;
1563 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1565 /* Free running processes array */
1566 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1568 g_assert(type
== LTTV_POINTER
);
1569 running_process
= *(value
.v_pointer
);
1570 g_free(running_process
);
1572 /* free cpu resource states */
1573 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1574 g_assert(type
== LTTV_UINT
);
1575 nb_cpus
= *value
.v_uint
;
1576 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1577 g_assert(type
== LTTV_POINTER
);
1578 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1580 /* free irq resource states */
1581 nb_irqs
= self
->nb_irqs
;
1582 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1583 g_assert(type
== LTTV_POINTER
);
1584 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1586 /* free the blkdev states */
1587 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1588 g_assert(type
== LTTV_POINTER
);
1589 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1591 nb_tracefile
= self
->parent
.tracefiles
->len
;
1593 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1595 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1596 LttvTracefileContext
*, i
));
1597 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1598 g_assert(type
== LTTV_GOBJECT
);
1599 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1601 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1603 g_assert(type
== LTTV_POINTER
);
1604 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1606 g_object_unref(G_OBJECT(tracefiles_tree
));
1610 static void free_saved_state(LttvTraceState
*self
)
1614 LttvAttributeType type
;
1616 LttvAttributeValue value
;
1618 LttvAttributeName name
;
1622 LttvAttribute
*saved_states
;
1624 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1625 LTTV_STATE_SAVED_STATES
);
1627 nb
= lttv_attribute_get_number(saved_states
);
1628 for(i
= 0 ; i
< nb
; i
++) {
1629 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1630 g_assert(type
== LTTV_GOBJECT
);
1631 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1634 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1639 create_max_time(LttvTraceState
*tcs
)
1641 LttvAttributeValue v
;
1643 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1645 g_assert(*(v
.v_pointer
) == NULL
);
1646 *(v
.v_pointer
) = g_new(LttTime
,1);
1647 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1652 get_max_time(LttvTraceState
*tcs
)
1654 LttvAttributeValue v
;
1656 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1658 g_assert(*(v
.v_pointer
) != NULL
);
1659 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1664 free_max_time(LttvTraceState
*tcs
)
1666 LttvAttributeValue v
;
1668 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1670 g_free(*(v
.v_pointer
));
1671 *(v
.v_pointer
) = NULL
;
1675 typedef struct _LttvNameTables
{
1676 // FIXME GQuark *eventtype_names;
1677 GQuark
*syscall_names
;
1683 GQuark
*soft_irq_names
;
1689 create_name_tables(LttvTraceState
*tcs
)
1693 GString
*fe_name
= g_string_new("");
1695 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1697 LttvAttributeValue v
;
1701 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1703 g_assert(*(v
.v_pointer
) == NULL
);
1704 *(v
.v_pointer
) = name_tables
;
1706 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1708 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1709 LTT_FACILITY_KERNEL_ARCH
,
1710 LTT_EVENT_SYSCALL_ENTRY
,
1711 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1712 NULL
, NULL
, &hooks
)) {
1714 // th = lttv_trace_hook_get_first(&th);
1716 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1717 // nb = ltt_type_element_number(t);
1719 // name_tables->syscall_names = g_new(GQuark, nb);
1720 // name_tables->nb_syscalls = nb;
1722 // for(i = 0 ; i < nb ; i++) {
1723 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1724 // if(!name_tables->syscall_names[i]) {
1725 // GString *string = g_string_new("");
1726 // g_string_printf(string, "syscall %u", i);
1727 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1728 // g_string_free(string, TRUE);
1732 name_tables
->nb_syscalls
= 256;
1733 name_tables
->syscall_names
= g_new(GQuark
, 256);
1734 for(i
= 0 ; i
< 256 ; i
++) {
1735 g_string_printf(fe_name
, "syscall %d", i
);
1736 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1739 name_tables
->syscall_names
= NULL
;
1740 name_tables
->nb_syscalls
= 0;
1742 lttv_trace_hook_remove_all(&hooks
);
1744 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1745 LTT_FACILITY_KERNEL_ARCH
,
1746 LTT_EVENT_TRAP_ENTRY
,
1747 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1748 NULL
, NULL
, &hooks
)) {
1750 // th = lttv_trace_hook_get_first(&th);
1752 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1753 // //nb = ltt_type_element_number(t);
1755 // name_tables->trap_names = g_new(GQuark, nb);
1756 // for(i = 0 ; i < nb ; i++) {
1757 // name_tables->trap_names[i] = g_quark_from_string(
1758 // ltt_enum_string_get(t, i));
1761 name_tables
->nb_traps
= 256;
1762 name_tables
->trap_names
= g_new(GQuark
, 256);
1763 for(i
= 0 ; i
< 256 ; i
++) {
1764 g_string_printf(fe_name
, "trap %d", i
);
1765 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1768 name_tables
->trap_names
= NULL
;
1769 name_tables
->nb_traps
= 0;
1771 lttv_trace_hook_remove_all(&hooks
);
1773 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1774 LTT_FACILITY_KERNEL
,
1775 LTT_EVENT_IRQ_ENTRY
,
1776 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1777 NULL
, NULL
, &hooks
)) {
1780 name_tables->irq_names = g_new(GQuark, nb);
1781 for(i = 0 ; i < nb ; i++) {
1782 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1786 name_tables
->nb_irqs
= 256;
1787 name_tables
->irq_names
= g_new(GQuark
, 256);
1788 for(i
= 0 ; i
< 256 ; i
++) {
1789 g_string_printf(fe_name
, "irq %d", i
);
1790 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1793 name_tables
->nb_irqs
= 0;
1794 name_tables
->irq_names
= NULL
;
1796 lttv_trace_hook_remove_all(&hooks
);
1798 name_tables->soft_irq_names = g_new(GQuark, nb);
1799 for(i = 0 ; i < nb ; i++) {
1800 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1804 /* the kernel is limited to 32 statically defined softirqs */
1805 name_tables
->nb_softirqs
= 32;
1806 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1807 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1808 g_string_printf(fe_name
, "softirq %d", i
);
1809 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1811 g_array_free(hooks
, TRUE
);
1813 g_string_free(fe_name
, TRUE
);
1818 get_name_tables(LttvTraceState
*tcs
)
1820 LttvNameTables
*name_tables
;
1822 LttvAttributeValue v
;
1824 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1826 g_assert(*(v
.v_pointer
) != NULL
);
1827 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1828 //tcs->eventtype_names = name_tables->eventtype_names;
1829 tcs
->syscall_names
= name_tables
->syscall_names
;
1830 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1831 tcs
->trap_names
= name_tables
->trap_names
;
1832 tcs
->nb_traps
= name_tables
->nb_traps
;
1833 tcs
->irq_names
= name_tables
->irq_names
;
1834 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1835 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1836 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1841 free_name_tables(LttvTraceState
*tcs
)
1843 LttvNameTables
*name_tables
;
1845 LttvAttributeValue v
;
1847 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1849 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1850 *(v
.v_pointer
) = NULL
;
1852 // g_free(name_tables->eventtype_names);
1853 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1854 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1855 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1856 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1857 if(name_tables
) g_free(name_tables
);
1860 #ifdef HASH_TABLE_DEBUG
1862 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1864 LttvProcessState
*process
= (LttvProcessState
*)value
;
1866 /* Test for process corruption */
1867 guint stack_len
= process
->execution_stack
->len
;
1870 static void hash_table_check(GHashTable
*table
)
1872 g_hash_table_foreach(table
, test_process
, NULL
);
1878 /* clears the stack and sets the state passed as argument */
1879 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1881 g_array_set_size(cpust
->mode_stack
, 1);
1882 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1885 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1887 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1888 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1891 static void cpu_pop_mode(LttvCPUState
*cpust
)
1893 if(cpust
->mode_stack
->len
<= 1)
1894 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1896 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1899 /* clears the stack and sets the state passed as argument */
1900 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1902 g_array_set_size(bdevst
->mode_stack
, 1);
1903 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1906 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1908 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1909 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1912 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1914 if(bdevst
->mode_stack
->len
<= 1)
1915 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1917 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1920 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1922 g_array_set_size(irqst
->mode_stack
, 1);
1923 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1926 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1928 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1929 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1932 static void irq_pop_mode(LttvIRQState
*irqst
)
1934 if(irqst
->mode_stack
->len
<= 1)
1935 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1937 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1940 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1943 LttvExecutionState
*es
;
1945 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1946 guint cpu
= tfs
->cpu
;
1948 #ifdef HASH_TABLE_DEBUG
1949 hash_table_check(ts
->processes
);
1951 LttvProcessState
*process
= ts
->running_process
[cpu
];
1953 guint depth
= process
->execution_stack
->len
;
1955 process
->execution_stack
=
1956 g_array_set_size(process
->execution_stack
, depth
+ 1);
1959 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1961 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1964 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1965 es
->cum_cpu_time
= ltt_time_zero
;
1966 es
->s
= process
->state
->s
;
1967 process
->state
= es
;
1971 * return 1 when empty, else 0 */
1972 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1973 LttvTracefileState
*tfs
)
1975 guint depth
= process
->execution_stack
->len
;
1981 process
->execution_stack
=
1982 g_array_set_size(process
->execution_stack
, depth
- 1);
1983 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1985 process
->state
->change
= tfs
->parent
.timestamp
;
1990 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1992 guint cpu
= tfs
->cpu
;
1993 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1994 LttvProcessState
*process
= ts
->running_process
[cpu
];
1996 guint depth
= process
->execution_stack
->len
;
1998 if(process
->state
->t
!= t
){
1999 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2000 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2001 g_info("process state has %s when pop_int is %s\n",
2002 g_quark_to_string(process
->state
->t
),
2003 g_quark_to_string(t
));
2004 g_info("{ %u, %u, %s, %s, %s }\n",
2007 g_quark_to_string(process
->name
),
2008 g_quark_to_string(process
->brand
),
2009 g_quark_to_string(process
->state
->s
));
2014 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2015 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2019 process
->execution_stack
=
2020 g_array_set_size(process
->execution_stack
, depth
- 1);
2021 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2023 process
->state
->change
= tfs
->parent
.timestamp
;
2026 struct search_result
{
2027 const LttTime
*time
; /* Requested time */
2028 LttTime
*best
; /* Best result */
2031 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2033 const LttTime
*elem_time
= (const LttTime
*)a
;
2034 /* Explicit non const cast */
2035 struct search_result
*res
= (struct search_result
*)b
;
2037 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2038 /* The usertrace was created before the schedchange */
2039 /* Get larger keys */
2041 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2042 /* The usertrace was created after the schedchange time */
2043 /* Get smaller keys */
2045 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2046 res
->best
= (LttTime
*)elem_time
;
2049 res
->best
= (LttTime
*)elem_time
;
2056 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2057 guint pid
, const LttTime
*timestamp
)
2059 LttvTracefileState
*tfs
= NULL
;
2060 struct search_result res
;
2061 /* Find the usertrace associated with a pid and time interval.
2062 * Search in the usertraces by PID (within a hash) and then, for each
2063 * corresponding element of the array, find the first one with creation
2064 * timestamp the lowest, but higher or equal to "timestamp". */
2065 res
.time
= timestamp
;
2067 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2068 if(usertrace_tree
) {
2069 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2071 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2079 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2080 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2082 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2084 LttvExecutionState
*es
;
2089 process
->tgid
= tgid
;
2091 process
->name
= name
;
2092 process
->brand
= LTTV_STATE_UNBRANDED
;
2093 //process->last_cpu = tfs->cpu_name;
2094 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2095 process
->type
= LTTV_STATE_USER_THREAD
;
2096 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2097 process
->current_function
= 0; //function 0x0 by default.
2099 g_info("Process %u, core %p", process
->pid
, process
);
2100 g_hash_table_insert(tcs
->processes
, process
, process
);
2103 process
->ppid
= parent
->pid
;
2104 process
->creation_time
= *timestamp
;
2107 /* No parent. This process exists but we are missing all information about
2108 its creation. The birth time is set to zero but we remember the time of
2113 process
->creation_time
= ltt_time_zero
;
2116 process
->insertion_time
= *timestamp
;
2117 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2118 process
->creation_time
.tv_nsec
);
2119 process
->pid_time
= g_quark_from_string(buffer
);
2121 //process->last_cpu = tfs->cpu_name;
2122 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2123 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2124 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2125 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2126 es
= process
->state
= &g_array_index(process
->execution_stack
,
2127 LttvExecutionState
, 0);
2128 es
->t
= LTTV_STATE_USER_MODE
;
2129 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2130 es
->entry
= *timestamp
;
2131 //g_assert(timestamp->tv_sec != 0);
2132 es
->change
= *timestamp
;
2133 es
->cum_cpu_time
= ltt_time_zero
;
2134 es
->s
= LTTV_STATE_RUN
;
2136 es
= process
->state
= &g_array_index(process
->execution_stack
,
2137 LttvExecutionState
, 1);
2138 es
->t
= LTTV_STATE_SYSCALL
;
2139 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2140 es
->entry
= *timestamp
;
2141 //g_assert(timestamp->tv_sec != 0);
2142 es
->change
= *timestamp
;
2143 es
->cum_cpu_time
= ltt_time_zero
;
2144 es
->s
= LTTV_STATE_WAIT_FORK
;
2146 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2147 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2148 sizeof(guint64
), 0);
2153 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2156 LttvProcessState key
;
2157 LttvProcessState
*process
;
2161 process
= g_hash_table_lookup(ts
->processes
, &key
);
2166 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2167 const LttTime
*timestamp
)
2169 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2170 LttvExecutionState
*es
;
2172 /* Put ltt_time_zero creation time for unexisting processes */
2173 if(unlikely(process
== NULL
)) {
2174 process
= lttv_state_create_process(ts
,
2175 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2176 /* We are not sure is it's a kernel thread or normal thread, put the
2177 * bottom stack state to unknown */
2178 process
->execution_stack
=
2179 g_array_set_size(process
->execution_stack
, 1);
2180 process
->state
= es
=
2181 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2182 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2183 es
->s
= LTTV_STATE_UNNAMED
;
2188 /* FIXME : this function should be called when we receive an event telling that
2189 * release_task has been called in the kernel. In happens generally when
2190 * the parent waits for its child terminaison, but may also happen in special
2191 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2192 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2193 * of a killed thread group, but isn't the leader.
2195 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2197 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2198 LttvProcessState key
;
2200 key
.pid
= process
->pid
;
2201 key
.cpu
= process
->cpu
;
2202 g_hash_table_remove(ts
->processes
, &key
);
2203 g_array_free(process
->execution_stack
, TRUE
);
2204 g_array_free(process
->user_stack
, TRUE
);
2209 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2211 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2212 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2217 static void lttv_state_free_process_table(GHashTable
*processes
)
2219 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2220 g_hash_table_destroy(processes
);
2224 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2226 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2228 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2229 LttvProcessState
*process
= ts
->running_process
[cpu
];
2230 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2231 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2232 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2234 LttvExecutionSubmode submode
;
2236 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2237 guint syscall
= ltt_event_get_unsigned(e
, f
);
2239 if(syscall
< nb_syscalls
) {
2240 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2243 /* Fixup an incomplete syscall table */
2244 GString
*string
= g_string_new("");
2245 g_string_printf(string
, "syscall %u", syscall
);
2246 submode
= g_quark_from_string(string
->str
);
2247 g_string_free(string
, TRUE
);
2249 /* There can be no system call from PID 0 : unknown state */
2250 if(process
->pid
!= 0)
2251 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2256 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2258 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2260 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2261 LttvProcessState
*process
= ts
->running_process
[cpu
];
2263 /* There can be no system call from PID 0 : unknown state */
2264 if(process
->pid
!= 0)
2265 pop_state(s
, LTTV_STATE_SYSCALL
);
2270 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2272 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2273 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2274 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2275 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2277 LttvExecutionSubmode submode
;
2279 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2280 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2282 if(trap
< nb_traps
) {
2283 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2285 /* Fixup an incomplete trap table */
2286 GString
*string
= g_string_new("");
2287 g_string_printf(string
, "trap %llu", trap
);
2288 submode
= g_quark_from_string(string
->str
);
2289 g_string_free(string
, TRUE
);
2292 push_state(s
, LTTV_STATE_TRAP
, submode
);
2294 /* update cpu status */
2295 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2300 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2302 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2304 pop_state(s
, LTTV_STATE_TRAP
);
2306 /* update cpu status */
2307 cpu_pop_mode(s
->cpu_state
);
2312 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2314 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2315 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2316 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2317 //guint8 ev_id = ltt_event_eventtype_id(e);
2318 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2319 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2321 LttvExecutionSubmode submode
;
2322 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2323 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2326 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2328 /* Fixup an incomplete irq table */
2329 GString
*string
= g_string_new("");
2330 g_string_printf(string
, "irq %llu", irq
);
2331 submode
= g_quark_from_string(string
->str
);
2332 g_string_free(string
, TRUE
);
2335 /* Do something with the info about being in user or system mode when int? */
2336 push_state(s
, LTTV_STATE_IRQ
, submode
);
2338 /* update cpu status */
2339 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2341 /* update irq status */
2342 s
->cpu_state
->last_irq
= irq
;
2343 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2348 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2350 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2351 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2352 guint softirq
= s
->cpu_state
->last_soft_irq
;
2354 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2356 /* update softirq status */
2357 if(ts
->soft_irq_states
[softirq
].running
)
2358 ts
->soft_irq_states
[softirq
].running
--;
2360 /* update cpu status */
2361 cpu_pop_mode(s
->cpu_state
);
2366 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2368 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2369 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2371 pop_state(s
, LTTV_STATE_IRQ
);
2373 /* update cpu status */
2374 cpu_pop_mode(s
->cpu_state
);
2376 /* update irq status */
2377 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2382 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2384 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2385 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2386 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2387 //guint8 ev_id = ltt_event_eventtype_id(e);
2388 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2389 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2391 LttvExecutionSubmode submode
;
2392 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2393 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2395 if(softirq
< nb_softirqs
) {
2396 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2398 /* Fixup an incomplete irq table */
2399 GString
*string
= g_string_new("");
2400 g_string_printf(string
, "softirq %llu", softirq
);
2401 submode
= g_quark_from_string(string
->str
);
2402 g_string_free(string
, TRUE
);
2405 /* Do something with the info about being in user or system mode when int? */
2406 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2408 /* update cpu status */
2409 cpu_push_mode(s
->cpu_state
, LTTV_CPU_SOFT_IRQ
);
2411 /* update softirq status */
2412 s
->cpu_state
->last_soft_irq
= softirq
;
2413 ts
->soft_irq_states
[softirq
].running
++;
2418 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2420 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2421 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2422 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2423 //guint8 ev_id = ltt_event_eventtype_id(e);
2424 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2426 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2427 lttv_trace_get_hook_field(th
, 0)));
2428 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2430 ts
->irq_names
[irq
] = action
;
2436 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2438 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2439 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2440 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2441 //guint8 ev_id = ltt_event_eventtype_id(e);
2442 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2444 guint major
= ltt_event_get_long_unsigned(e
,
2445 lttv_trace_get_hook_field(th
, 0));
2446 guint minor
= ltt_event_get_long_unsigned(e
,
2447 lttv_trace_get_hook_field(th
, 1));
2448 guint oper
= ltt_event_get_long_unsigned(e
,
2449 lttv_trace_get_hook_field(th
, 2));
2450 guint16 devcode
= MKDEV(major
,minor
);
2452 /* have we seen this block device before? */
2453 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2456 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2458 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2463 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2465 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2466 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2467 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2468 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2470 guint major
= ltt_event_get_long_unsigned(e
,
2471 lttv_trace_get_hook_field(th
, 0));
2472 guint minor
= ltt_event_get_long_unsigned(e
,
2473 lttv_trace_get_hook_field(th
, 1));
2474 //guint oper = ltt_event_get_long_unsigned(e,
2475 // lttv_trace_get_hook_field(th, 2));
2476 guint16 devcode
= MKDEV(major
,minor
);
2478 /* have we seen this block device before? */
2479 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2481 /* update block device */
2482 bdev_pop_mode(bdev
);
2487 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2491 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2492 guint cpu
= tfs
->cpu
;
2493 LttvProcessState
*process
= ts
->running_process
[cpu
];
2495 guint depth
= process
->user_stack
->len
;
2497 process
->user_stack
=
2498 g_array_set_size(process
->user_stack
, depth
+ 1);
2500 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2501 *new_func
= funcptr
;
2502 process
->current_function
= funcptr
;
2505 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2507 guint cpu
= tfs
->cpu
;
2508 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2509 LttvProcessState
*process
= ts
->running_process
[cpu
];
2511 if(process
->current_function
!= funcptr
){
2512 g_info("Different functions (%lu.%09lu): ignore it\n",
2513 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2514 g_info("process state has %llu when pop_function is %llu\n",
2515 process
->current_function
, funcptr
);
2516 g_info("{ %u, %u, %s, %s, %s }\n",
2519 g_quark_to_string(process
->name
),
2520 g_quark_to_string(process
->brand
),
2521 g_quark_to_string(process
->state
->s
));
2524 guint depth
= process
->user_stack
->len
;
2527 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2528 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2532 process
->user_stack
=
2533 g_array_set_size(process
->user_stack
, depth
- 1);
2534 process
->current_function
=
2535 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2539 static gboolean
function_entry(void *hook_data
, void *call_data
)
2541 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2542 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2543 //guint8 ev_id = ltt_event_eventtype_id(e);
2544 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2545 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2546 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2548 push_function(s
, funcptr
);
2552 static gboolean
function_exit(void *hook_data
, void *call_data
)
2554 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2555 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2556 //guint8 ev_id = ltt_event_eventtype_id(e);
2557 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2558 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2559 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2561 pop_function(s
, funcptr
);
2565 static gboolean
schedchange(void *hook_data
, void *call_data
)
2567 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2569 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2570 LttvProcessState
*process
= ts
->running_process
[cpu
];
2571 //LttvProcessState *old_process = ts->running_process[cpu];
2573 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2574 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2575 guint pid_in
, pid_out
;
2578 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2579 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2580 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2582 if(likely(process
!= NULL
)) {
2584 /* We could not know but it was not the idle process executing.
2585 This should only happen at the beginning, before the first schedule
2586 event, and when the initial information (current process for each CPU)
2587 is missing. It is not obvious how we could, after the fact, compensate
2588 the wrongly attributed statistics. */
2590 //This test only makes sense once the state is known and if there is no
2591 //missing events. We need to silently ignore schedchange coming after a
2592 //process_free, or it causes glitches. (FIXME)
2593 //if(unlikely(process->pid != pid_out)) {
2594 // g_assert(process->pid == 0);
2596 if(process
->pid
== 0
2597 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2599 /* Scheduling out of pid 0 at beginning of the trace :
2600 * we know for sure it is in syscall mode at this point. */
2601 g_assert(process
->execution_stack
->len
== 1);
2602 process
->state
->t
= LTTV_STATE_SYSCALL
;
2603 process
->state
->s
= LTTV_STATE_WAIT
;
2604 process
->state
->change
= s
->parent
.timestamp
;
2605 process
->state
->entry
= s
->parent
.timestamp
;
2608 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2609 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2610 process
->state
->change
= s
->parent
.timestamp
;
2612 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2613 else process
->state
->s
= LTTV_STATE_WAIT
;
2614 process
->state
->change
= s
->parent
.timestamp
;
2617 if(state_out
== 32 || state_out
== 64)
2618 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2619 /* see sched.h for states */
2622 process
= ts
->running_process
[cpu
] =
2623 lttv_state_find_process_or_create(
2624 (LttvTraceState
*)s
->parent
.t_context
,
2626 &s
->parent
.timestamp
);
2627 process
->state
->s
= LTTV_STATE_RUN
;
2629 if(process
->usertrace
)
2630 process
->usertrace
->cpu
= cpu
;
2631 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2632 process
->state
->change
= s
->parent
.timestamp
;
2634 /* update cpu status */
2636 /* going to idle task */
2637 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2639 /* scheduling a real task.
2640 * we must be careful here:
2641 * if we just schedule()'ed to a process that is
2642 * in a trap, we must put the cpu in trap mode
2644 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2645 if(process
->state
->t
== LTTV_STATE_TRAP
)
2646 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2652 static gboolean
process_fork(void *hook_data
, void *call_data
)
2654 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2655 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2656 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2658 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2659 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2660 //LttvProcessState *zombie_process;
2662 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2663 LttvProcessState
*process
= ts
->running_process
[cpu
];
2664 LttvProcessState
*child_process
;
2665 struct marker_field
*f
;
2668 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2671 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2672 s
->parent
.target_pid
= child_pid
;
2675 f
= lttv_trace_get_hook_field(th
, 2);
2677 child_tgid
= ltt_event_get_unsigned(e
, f
);
2681 /* Mathieu : it seems like the process might have been scheduled in before the
2682 * fork, and, in a rare case, might be the current process. This might happen
2683 * in a SMP case where we don't have enough precision on the clocks.
2685 * Test reenabled after precision fixes on time. (Mathieu) */
2687 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2689 if(unlikely(zombie_process
!= NULL
)) {
2690 /* Reutilisation of PID. Only now we are sure that the old PID
2691 * has been released. FIXME : should know when release_task happens instead.
2693 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2695 for(i
=0; i
< num_cpus
; i
++) {
2696 g_assert(zombie_process
!= ts
->running_process
[i
]);
2699 exit_process(s
, zombie_process
);
2702 g_assert(process
->pid
!= child_pid
);
2703 // FIXME : Add this test in the "known state" section
2704 // g_assert(process->pid == parent_pid);
2705 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2706 if(child_process
== NULL
) {
2707 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2708 child_pid
, child_tgid
,
2709 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2711 /* The process has already been created : due to time imprecision between
2712 * multiple CPUs : it has been scheduled in before creation. Note that we
2713 * shouldn't have this kind of imprecision.
2715 * Simply put a correct parent.
2717 g_assert(0); /* This is a problematic case : the process has been created
2718 before the fork event */
2719 child_process
->ppid
= process
->pid
;
2720 child_process
->tgid
= child_tgid
;
2722 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2723 child_process
->name
= process
->name
;
2724 child_process
->brand
= process
->brand
;
2729 /* We stamp a newly created process as kernel_thread.
2730 * The thread should not be running yet. */
2731 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2733 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2734 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2735 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2737 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2738 LttvProcessState
*process
;
2739 LttvExecutionState
*es
;
2742 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2743 s
->parent
.target_pid
= pid
;
2745 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2747 process
->execution_stack
=
2748 g_array_set_size(process
->execution_stack
, 1);
2749 es
= process
->state
=
2750 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2751 es
->t
= LTTV_STATE_SYSCALL
;
2752 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2757 static gboolean
process_exit(void *hook_data
, void *call_data
)
2759 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2760 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2761 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2763 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2764 LttvProcessState
*process
; // = ts->running_process[cpu];
2766 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2767 s
->parent
.target_pid
= pid
;
2769 // FIXME : Add this test in the "known state" section
2770 // g_assert(process->pid == pid);
2772 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2773 if(likely(process
!= NULL
)) {
2774 process
->state
->s
= LTTV_STATE_EXIT
;
2779 static gboolean
process_free(void *hook_data
, void *call_data
)
2781 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2782 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2783 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2784 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2786 LttvProcessState
*process
;
2788 /* PID of the process to release */
2789 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2790 s
->parent
.target_pid
= release_pid
;
2792 g_assert(release_pid
!= 0);
2794 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2796 if(likely(process
!= NULL
)) {
2797 /* release_task is happening at kernel level : we can now safely release
2798 * the data structure of the process */
2799 //This test is fun, though, as it may happen that
2800 //at time t : CPU 0 : process_free
2801 //at time t+150ns : CPU 1 : schedule out
2802 //Clearly due to time imprecision, we disable it. (Mathieu)
2803 //If this weird case happen, we have no choice but to put the
2804 //Currently running process on the cpu to 0.
2805 //I re-enable it following time precision fixes. (Mathieu)
2806 //Well, in the case where an process is freed by a process on another CPU
2807 //and still scheduled, it happens that this is the schedchange that will
2808 //drop the last reference count. Do not free it here!
2809 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2811 for(i
=0; i
< num_cpus
; i
++) {
2812 //g_assert(process != ts->running_process[i]);
2813 if(process
== ts
->running_process
[i
]) {
2814 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2818 if(i
== num_cpus
) /* process is not scheduled */
2819 exit_process(s
, process
);
2826 static gboolean
process_exec(void *hook_data
, void *call_data
)
2828 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2829 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2830 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2831 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2834 LttvProcessState
*process
= ts
->running_process
[cpu
];
2836 #if 0//how to use a sequence that must be transformed in a string
2837 /* PID of the process to release */
2838 guint64 name_len
= ltt_event_field_element_number(e
,
2839 lttv_trace_get_hook_field(th
, 0));
2840 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2841 LttField
*child
= ltt_event_field_element_select(e
,
2842 lttv_trace_get_hook_field(th
, 0), 0);
2844 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2845 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2846 memcpy(null_term_name
, name_begin
, name_len
);
2847 null_term_name
[name_len
] = '\0';
2848 process
->name
= g_quark_from_string(null_term_name
);
2851 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2852 lttv_trace_get_hook_field(th
, 0)));
2853 process
->brand
= LTTV_STATE_UNBRANDED
;
2854 //g_free(null_term_name);
2858 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2860 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2861 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2862 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2863 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2866 LttvProcessState
*process
= ts
->running_process
[cpu
];
2868 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2869 process
->brand
= g_quark_from_string(name
);
2874 static void fix_process(gpointer key
, gpointer value
,
2877 LttvProcessState
*process
;
2878 LttvExecutionState
*es
;
2879 process
= (LttvProcessState
*)value
;
2880 LttTime
*timestamp
= (LttTime
*)user_data
;
2882 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2883 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2884 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2885 es
->t
= LTTV_STATE_SYSCALL
;
2886 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2887 es
->entry
= *timestamp
;
2888 es
->change
= *timestamp
;
2889 es
->cum_cpu_time
= ltt_time_zero
;
2890 if(es
->s
== LTTV_STATE_UNNAMED
)
2891 es
->s
= LTTV_STATE_WAIT
;
2894 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2895 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2896 es
->t
= LTTV_STATE_USER_MODE
;
2897 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2898 es
->entry
= *timestamp
;
2899 //g_assert(timestamp->tv_sec != 0);
2900 es
->change
= *timestamp
;
2901 es
->cum_cpu_time
= ltt_time_zero
;
2902 if(es
->s
== LTTV_STATE_UNNAMED
)
2903 es
->s
= LTTV_STATE_RUN
;
2905 if(process
->execution_stack
->len
== 1) {
2906 /* Still in bottom unknown mode, means never did a system call
2907 * May be either in user mode, syscall mode, running or waiting.*/
2908 /* FIXME : we may be tagging syscall mode when being user mode */
2909 process
->execution_stack
=
2910 g_array_set_size(process
->execution_stack
, 2);
2911 es
= process
->state
= &g_array_index(process
->execution_stack
,
2912 LttvExecutionState
, 1);
2913 es
->t
= LTTV_STATE_SYSCALL
;
2914 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2915 es
->entry
= *timestamp
;
2916 //g_assert(timestamp->tv_sec != 0);
2917 es
->change
= *timestamp
;
2918 es
->cum_cpu_time
= ltt_time_zero
;
2919 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2920 es
->s
= LTTV_STATE_WAIT
;
2926 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2928 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2929 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2930 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2931 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2932 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2934 /* For all processes */
2935 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2936 /* else, if stack[0] is unknown, set to user mode, running */
2938 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2943 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2945 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2946 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2947 //It's slow : optimise later by doing this before reading trace.
2948 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2954 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2955 LttvProcessState
*process
= ts
->running_process
[cpu
];
2956 LttvProcessState
*parent_process
;
2957 struct marker_field
*f
;
2958 GQuark type
, mode
, submode
, status
;
2959 LttvExecutionState
*es
;
2963 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2964 s
->parent
.target_pid
= pid
;
2967 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2970 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2973 f
= lttv_trace_get_hook_field(th
, 3);
2974 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2976 //FIXME: type is rarely used, enum must match possible types.
2979 f
= lttv_trace_get_hook_field(th
, 4);
2980 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2983 f
= lttv_trace_get_hook_field(th
, 5);
2984 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2987 f
= lttv_trace_get_hook_field(th
, 6);
2988 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2991 f
= lttv_trace_get_hook_field(th
, 7);
2993 tgid
= ltt_event_get_unsigned(e
, f
);
2998 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2999 for(i
=0; i
<nb_cpus
; i
++) {
3000 process
= lttv_state_find_process(ts
, i
, pid
);
3001 g_assert(process
!= NULL
);
3003 process
->ppid
= parent_pid
;
3004 process
->tgid
= tgid
;
3005 process
->name
= g_quark_from_string(command
);
3007 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3008 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3012 /* The process might exist if a process was forked while performing the
3014 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3015 if(process
== NULL
) {
3016 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3017 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3018 pid
, tgid
, g_quark_from_string(command
),
3019 &s
->parent
.timestamp
);
3021 /* Keep the stack bottom : a running user mode */
3022 /* Disabled because of inconsistencies in the current statedump states. */
3023 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3024 /* Only keep the bottom
3025 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3026 /* Will cause expected trap when in fact being syscall (even after end of
3028 * Will cause expected interrupt when being syscall. (only before end of
3029 * statedump event) */
3030 // This will cause a "popping last state on stack, ignoring it."
3031 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3032 es
= process
->state
= &g_array_index(process
->execution_stack
,
3033 LttvExecutionState
, 0);
3034 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3035 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3036 es
->s
= LTTV_STATE_UNNAMED
;
3037 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3039 es
->t
= LTTV_STATE_SYSCALL
;
3044 /* User space process :
3045 * bottom : user mode
3046 * either currently running or scheduled out.
3047 * can be scheduled out because interrupted in (user mode or in syscall)
3048 * or because of an explicit call to the scheduler in syscall. Note that
3049 * the scheduler call comes after the irq_exit, so never in interrupt
3051 // temp workaround : set size to 1 : only have user mode bottom of stack.
3052 // will cause g_info message of expected syscall mode when in fact being
3053 // in user mode. Can also cause expected trap when in fact being user
3054 // mode in the event of a page fault reenabling interrupts in the handler.
3055 // Expected syscall and trap can also happen after the end of statedump
3056 // This will cause a "popping last state on stack, ignoring it."
3057 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3058 es
= process
->state
= &g_array_index(process
->execution_stack
,
3059 LttvExecutionState
, 0);
3060 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3061 es
->s
= LTTV_STATE_UNNAMED
;
3062 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3064 es
->t
= LTTV_STATE_USER_MODE
;
3072 es
= process
->state
= &g_array_index(process
->execution_stack
,
3073 LttvExecutionState
, 1);
3074 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3075 es
->s
= LTTV_STATE_UNNAMED
;
3076 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3080 /* The process has already been created :
3081 * Probably was forked while dumping the process state or
3082 * was simply scheduled in prior to get the state dump event.
3084 process
->ppid
= parent_pid
;
3085 process
->tgid
= tgid
;
3086 process
->name
= g_quark_from_string(command
);
3087 process
->type
= type
;
3089 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3091 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3092 if(type
== LTTV_STATE_KERNEL_THREAD
)
3093 es
->t
= LTTV_STATE_SYSCALL
;
3095 es
->t
= LTTV_STATE_USER_MODE
;
3098 /* Don't mess around with the stack, it will eventually become
3099 * ok after the end of state dump. */
3106 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3108 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3110 lttv_state_add_event_hooks(tss
);
3115 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3117 LttvTraceset
*traceset
= self
->parent
.ts
;
3119 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3123 LttvTracefileState
*tfs
;
3129 LttvAttributeValue val
;
3131 nb_trace
= lttv_traceset_number(traceset
);
3132 for(i
= 0 ; i
< nb_trace
; i
++) {
3133 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3135 /* Find the eventtype id for the following events and register the
3136 associated by id hooks. */
3138 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3139 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3142 lttv_trace_find_hook(ts
->parent
.t
,
3143 LTT_FACILITY_KERNEL_ARCH
,
3144 LTT_EVENT_SYSCALL_ENTRY
,
3145 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3146 syscall_entry
, NULL
, &hooks
);
3148 lttv_trace_find_hook(ts
->parent
.t
,
3149 LTT_FACILITY_KERNEL_ARCH
,
3150 LTT_EVENT_SYSCALL_EXIT
,
3152 syscall_exit
, NULL
, &hooks
);
3154 lttv_trace_find_hook(ts
->parent
.t
,
3155 LTT_FACILITY_KERNEL_ARCH
,
3156 LTT_EVENT_TRAP_ENTRY
,
3157 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3158 trap_entry
, NULL
, &hooks
);
3160 lttv_trace_find_hook(ts
->parent
.t
,
3161 LTT_FACILITY_KERNEL_ARCH
,
3162 LTT_EVENT_TRAP_EXIT
,
3164 trap_exit
, NULL
, &hooks
);
3166 lttv_trace_find_hook(ts
->parent
.t
,
3167 LTT_FACILITY_KERNEL
,
3168 LTT_EVENT_IRQ_ENTRY
,
3169 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3170 irq_entry
, NULL
, &hooks
);
3172 lttv_trace_find_hook(ts
->parent
.t
,
3173 LTT_FACILITY_KERNEL
,
3176 irq_exit
, NULL
, &hooks
);
3178 lttv_trace_find_hook(ts
->parent
.t
,
3179 LTT_FACILITY_KERNEL
,
3180 LTT_EVENT_SOFT_IRQ_ENTRY
,
3181 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3182 soft_irq_entry
, NULL
, &hooks
);
3184 lttv_trace_find_hook(ts
->parent
.t
,
3185 LTT_FACILITY_KERNEL
,
3186 LTT_EVENT_SOFT_IRQ_EXIT
,
3188 soft_irq_exit
, NULL
, &hooks
);
3190 lttv_trace_find_hook(ts
->parent
.t
,
3191 LTT_FACILITY_KERNEL
,
3192 LTT_EVENT_SCHED_SCHEDULE
,
3193 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3194 LTT_FIELD_PREV_STATE
),
3195 schedchange
, NULL
, &hooks
);
3197 lttv_trace_find_hook(ts
->parent
.t
,
3198 LTT_FACILITY_KERNEL
,
3199 LTT_EVENT_PROCESS_FORK
,
3200 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3201 LTT_FIELD_CHILD_TGID
),
3202 process_fork
, NULL
, &hooks
);
3204 lttv_trace_find_hook(ts
->parent
.t
,
3205 LTT_FACILITY_KERNEL_ARCH
,
3206 LTT_EVENT_KTHREAD_CREATE
,
3207 FIELD_ARRAY(LTT_FIELD_PID
),
3208 process_kernel_thread
, NULL
, &hooks
);
3210 lttv_trace_find_hook(ts
->parent
.t
,
3211 LTT_FACILITY_KERNEL
,
3212 LTT_EVENT_PROCESS_EXIT
,
3213 FIELD_ARRAY(LTT_FIELD_PID
),
3214 process_exit
, NULL
, &hooks
);
3216 lttv_trace_find_hook(ts
->parent
.t
,
3217 LTT_FACILITY_KERNEL
,
3218 LTT_EVENT_PROCESS_FREE
,
3219 FIELD_ARRAY(LTT_FIELD_PID
),
3220 process_free
, NULL
, &hooks
);
3222 lttv_trace_find_hook(ts
->parent
.t
,
3225 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3226 process_exec
, NULL
, &hooks
);
3228 lttv_trace_find_hook(ts
->parent
.t
,
3229 LTT_FACILITY_USER_GENERIC
,
3230 LTT_EVENT_THREAD_BRAND
,
3231 FIELD_ARRAY(LTT_FIELD_NAME
),
3232 thread_brand
, NULL
, &hooks
);
3234 /* statedump-related hooks */
3235 lttv_trace_find_hook(ts
->parent
.t
,
3237 LTT_EVENT_PROCESS_STATE
,
3238 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3239 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3240 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3241 enum_process_state
, NULL
, &hooks
);
3243 lttv_trace_find_hook(ts
->parent
.t
,
3245 LTT_EVENT_STATEDUMP_END
,
3247 statedump_end
, NULL
, &hooks
);
3249 lttv_trace_find_hook(ts
->parent
.t
,
3251 LTT_EVENT_LIST_INTERRUPT
,
3252 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3253 enum_interrupt
, NULL
, &hooks
);
3255 lttv_trace_find_hook(ts
->parent
.t
,
3257 LTT_EVENT_REQUEST_ISSUE
,
3258 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3259 bdev_request_issue
, NULL
, &hooks
);
3261 lttv_trace_find_hook(ts
->parent
.t
,
3263 LTT_EVENT_REQUEST_COMPLETE
,
3264 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3265 bdev_request_complete
, NULL
, &hooks
);
3267 lttv_trace_find_hook(ts
->parent
.t
,
3268 LTT_FACILITY_USER_GENERIC
,
3269 LTT_EVENT_FUNCTION_ENTRY
,
3270 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3271 function_entry
, NULL
, &hooks
);
3273 lttv_trace_find_hook(ts
->parent
.t
,
3274 LTT_FACILITY_USER_GENERIC
,
3275 LTT_EVENT_FUNCTION_EXIT
,
3276 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3277 function_exit
, NULL
, &hooks
);
3279 /* Add these hooks to each event_by_id hooks list */
3281 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3283 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3285 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3286 LttvTracefileContext
*, j
));
3288 for(k
= 0 ; k
< hooks
->len
; k
++) {
3289 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3291 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3297 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3298 *(val
.v_pointer
) = hooks
;
3302 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3304 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3306 lttv_state_remove_event_hooks(tss
);
3311 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3313 LttvTraceset
*traceset
= self
->parent
.ts
;
3315 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3319 LttvTracefileState
*tfs
;
3325 LttvAttributeValue val
;
3327 nb_trace
= lttv_traceset_number(traceset
);
3328 for(i
= 0 ; i
< nb_trace
; i
++) {
3329 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3331 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3332 hooks
= *(val
.v_pointer
);
3334 /* Remove these hooks from 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
);
3345 lttv_hooks_remove_data(
3346 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3351 lttv_trace_hook_remove_all(&hooks
);
3352 g_array_free(hooks
, TRUE
);
3356 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3358 guint
*event_count
= (guint
*)hook_data
;
3360 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3361 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3366 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3368 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3370 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3372 LttvAttributeValue value
;
3374 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3375 LTTV_STATE_SAVED_STATES
);
3376 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3377 value
= lttv_attribute_add(saved_states_tree
,
3378 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3379 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3380 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3381 *(value
.v_time
) = self
->parent
.timestamp
;
3382 lttv_state_save(tcs
, saved_state_tree
);
3383 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3384 self
->parent
.timestamp
.tv_nsec
);
3386 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3391 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3393 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3395 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3400 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3408 static gboolean
block_start(void *hook_data
, void *call_data
)
3410 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3412 LttvTracefileState
*tfcs
;
3414 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3416 LttEventPosition
*ep
;
3418 guint i
, nb_block
, nb_event
, nb_tracefile
;
3422 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3424 LttvAttributeValue value
;
3426 ep
= ltt_event_position_new();
3428 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3430 /* Count the number of events added since the last block end in any
3433 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3435 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3436 LttvTracefileContext
, i
));
3437 ltt_event_position(tfcs
->parent
.e
, ep
);
3438 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3439 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3440 tfcs
->saved_position
= nb_event
;
3444 if(tcs
->nb_event
>= tcs
->save_interval
) {
3445 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3446 LTTV_STATE_SAVED_STATES
);
3447 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3448 value
= lttv_attribute_add(saved_states_tree
,
3449 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3450 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3451 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3452 *(value
.v_time
) = self
->parent
.timestamp
;
3453 lttv_state_save(tcs
, saved_state_tree
);
3455 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3456 self
->parent
.timestamp
.tv_nsec
);
3458 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3464 static gboolean
block_end(void *hook_data
, void *call_data
)
3466 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3468 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3472 LttEventPosition
*ep
;
3474 guint nb_block
, nb_event
;
3476 ep
= ltt_event_position_new();
3477 ltt_event_position(self
->parent
.e
, ep
);
3478 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3479 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3480 self
->saved_position
= 0;
3481 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3488 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3490 LttvTraceset
*traceset
= self
->parent
.ts
;
3492 guint i
, j
, nb_trace
, nb_tracefile
;
3496 LttvTracefileState
*tfs
;
3498 LttvTraceHook hook_start
, hook_end
;
3500 nb_trace
= lttv_traceset_number(traceset
);
3501 for(i
= 0 ; i
< nb_trace
; i
++) {
3502 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3504 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3505 NULL
, NULL
, block_start
, &hook_start
);
3506 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3507 NULL
, NULL
, block_end
, &hook_end
);
3509 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3511 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3513 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3514 LttvTracefileContext
, j
));
3515 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3516 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3517 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3518 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3524 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3526 LttvTraceset
*traceset
= self
->parent
.ts
;
3528 guint i
, j
, nb_trace
, nb_tracefile
;
3532 LttvTracefileState
*tfs
;
3535 nb_trace
= lttv_traceset_number(traceset
);
3536 for(i
= 0 ; i
< nb_trace
; i
++) {
3538 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3539 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3541 if(ts
->has_precomputed_states
) continue;
3543 guint
*event_count
= g_new(guint
, 1);
3546 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3548 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3549 LttvTracefileContext
*, j
));
3550 lttv_hooks_add(tfs
->parent
.event
,
3551 state_save_event_hook
,
3558 lttv_process_traceset_begin(&self
->parent
,
3559 NULL
, NULL
, NULL
, NULL
, NULL
);
3563 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3565 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3567 lttv_state_save_add_event_hooks(tss
);
3574 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3576 LttvTraceset
*traceset
= self
->parent
.ts
;
3578 guint i
, j
, nb_trace
, nb_tracefile
;
3582 LttvTracefileState
*tfs
;
3584 LttvTraceHook hook_start
, hook_end
;
3586 nb_trace
= lttv_traceset_number(traceset
);
3587 for(i
= 0 ; i
< nb_trace
; i
++) {
3588 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3590 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3591 NULL
, NULL
, block_start
, &hook_start
);
3593 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3594 NULL
, NULL
, block_end
, &hook_end
);
3596 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3598 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3600 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3601 LttvTracefileContext
, j
));
3602 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3603 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3604 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3605 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3611 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3613 LttvTraceset
*traceset
= self
->parent
.ts
;
3615 guint i
, j
, nb_trace
, nb_tracefile
;
3619 LttvTracefileState
*tfs
;
3621 LttvHooks
*after_trace
= lttv_hooks_new();
3623 lttv_hooks_add(after_trace
,
3624 state_save_after_trace_hook
,
3629 lttv_process_traceset_end(&self
->parent
,
3630 NULL
, after_trace
, NULL
, NULL
, NULL
);
3632 lttv_hooks_destroy(after_trace
);
3634 nb_trace
= lttv_traceset_number(traceset
);
3635 for(i
= 0 ; i
< nb_trace
; i
++) {
3637 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3638 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3640 if(ts
->has_precomputed_states
) continue;
3642 guint
*event_count
= NULL
;
3644 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3646 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3647 LttvTracefileContext
*, j
));
3648 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3649 state_save_event_hook
);
3651 if(event_count
) g_free(event_count
);
3655 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3657 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3659 lttv_state_save_remove_event_hooks(tss
);
3664 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3666 LttvTraceset
*traceset
= self
->parent
.ts
;
3670 int min_pos
, mid_pos
, max_pos
;
3672 guint call_rest
= 0;
3674 LttvTraceState
*tcs
;
3676 LttvAttributeValue value
;
3678 LttvAttributeType type
;
3680 LttvAttributeName name
;
3684 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3686 //g_tree_destroy(self->parent.pqueue);
3687 //self->parent.pqueue = g_tree_new(compare_tracefile);
3689 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3691 nb_trace
= lttv_traceset_number(traceset
);
3692 for(i
= 0 ; i
< nb_trace
; i
++) {
3693 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3695 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3696 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3697 LTTV_STATE_SAVED_STATES
);
3700 if(saved_states_tree
) {
3701 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3702 mid_pos
= max_pos
/ 2;
3703 while(min_pos
< max_pos
) {
3704 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3706 g_assert(type
== LTTV_GOBJECT
);
3707 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3708 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3710 g_assert(type
== LTTV_TIME
);
3711 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3713 closest_tree
= saved_state_tree
;
3715 else max_pos
= mid_pos
- 1;
3717 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3721 /* restore the closest earlier saved state */
3723 lttv_state_restore(tcs
, closest_tree
);
3727 /* There is no saved state, yet we want to have it. Restart at T0 */
3729 restore_init_state(tcs
);
3730 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3733 /* We want to seek quickly without restoring/updating the state */
3735 restore_init_state(tcs
);
3736 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3739 if(!call_rest
) g_info("NOT Calling restore");
3744 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3750 traceset_state_finalize (LttvTracesetState
*self
)
3752 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3753 finalize(G_OBJECT(self
));
3758 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3760 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3762 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3763 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3764 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3765 klass
->new_traceset_context
= new_traceset_context
;
3766 klass
->new_trace_context
= new_trace_context
;
3767 klass
->new_tracefile_context
= new_tracefile_context
;
3772 lttv_traceset_state_get_type(void)
3774 static GType type
= 0;
3776 static const GTypeInfo info
= {
3777 sizeof (LttvTracesetStateClass
),
3778 NULL
, /* base_init */
3779 NULL
, /* base_finalize */
3780 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3781 NULL
, /* class_finalize */
3782 NULL
, /* class_data */
3783 sizeof (LttvTracesetState
),
3784 0, /* n_preallocs */
3785 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3786 NULL
/* value handling */
3789 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3797 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3803 trace_state_finalize (LttvTraceState
*self
)
3805 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3806 finalize(G_OBJECT(self
));
3811 trace_state_class_init (LttvTraceStateClass
*klass
)
3813 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3815 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3816 klass
->state_save
= state_save
;
3817 klass
->state_restore
= state_restore
;
3818 klass
->state_saved_free
= state_saved_free
;
3823 lttv_trace_state_get_type(void)
3825 static GType type
= 0;
3827 static const GTypeInfo info
= {
3828 sizeof (LttvTraceStateClass
),
3829 NULL
, /* base_init */
3830 NULL
, /* base_finalize */
3831 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3832 NULL
, /* class_finalize */
3833 NULL
, /* class_data */
3834 sizeof (LttvTraceState
),
3835 0, /* n_preallocs */
3836 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3837 NULL
/* value handling */
3840 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3841 "LttvTraceStateType", &info
, 0);
3848 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3854 tracefile_state_finalize (LttvTracefileState
*self
)
3856 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3857 finalize(G_OBJECT(self
));
3862 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3864 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3866 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3871 lttv_tracefile_state_get_type(void)
3873 static GType type
= 0;
3875 static const GTypeInfo info
= {
3876 sizeof (LttvTracefileStateClass
),
3877 NULL
, /* base_init */
3878 NULL
, /* base_finalize */
3879 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3880 NULL
, /* class_finalize */
3881 NULL
, /* class_data */
3882 sizeof (LttvTracefileState
),
3883 0, /* n_preallocs */
3884 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3885 NULL
/* value handling */
3888 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3889 "LttvTracefileStateType", &info
, 0);
3895 static void module_init()
3897 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3898 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3899 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3900 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3901 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3902 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3903 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3904 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3905 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3906 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3907 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3908 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3909 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3910 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3911 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3912 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3913 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3914 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3915 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3916 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3917 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3918 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3919 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3920 LTTV_STATE_EVENT
= g_quark_from_string("event");
3921 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3922 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3923 LTTV_STATE_TIME
= g_quark_from_string("time");
3924 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3925 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3926 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3927 g_quark_from_string("trace_state_use_count");
3928 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3929 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
3930 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3931 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
3932 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3935 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3936 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3937 LTT_FACILITY_FS
= g_quark_from_string("fs");
3938 LTT_FACILITY_LIST
= g_quark_from_string("list");
3939 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3940 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3943 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3944 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3945 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3946 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3947 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3948 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3949 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3950 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3951 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3952 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3953 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3954 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3955 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3956 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3957 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3958 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3959 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3960 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3961 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3962 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3963 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3964 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3967 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3968 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3969 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3970 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3971 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3972 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3973 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3974 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3975 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3976 LTT_FIELD_PID
= g_quark_from_string("pid");
3977 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3978 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3979 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3980 LTT_FIELD_NAME
= g_quark_from_string("name");
3981 LTT_FIELD_TYPE
= g_quark_from_string("type");
3982 LTT_FIELD_MODE
= g_quark_from_string("mode");
3983 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3984 LTT_FIELD_STATUS
= g_quark_from_string("status");
3985 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3986 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3987 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3988 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3989 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3990 LTT_FIELD_ACTION
= g_quark_from_string("action");
3992 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3993 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3994 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3995 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3996 LTTV_CPU_SOFT_IRQ
= g_quark_from_string("softirq");
3997 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3999 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
4000 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
4001 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
4003 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
4004 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
4005 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
4006 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4009 static void module_destroy()
4014 LTTV_MODULE("state", "State computation", \
4015 "Update the system state, possibly saving it at intervals", \
4016 module_init
, module_destroy
)