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,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_USER_GENERIC
,
58 LTT_EVENT_SYSCALL_ENTRY
,
59 LTT_EVENT_SYSCALL_EXIT
,
64 LTT_EVENT_SOFT_IRQ_ENTRY
,
65 LTT_EVENT_SOFT_IRQ_EXIT
,
66 LTT_EVENT_SCHED_SCHEDULE
,
67 LTT_EVENT_PROCESS_FORK
,
68 LTT_EVENT_KTHREAD_CREATE
,
69 LTT_EVENT_PROCESS_EXIT
,
70 LTT_EVENT_PROCESS_FREE
,
72 LTT_EVENT_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
,
77 LTT_EVENT_REQUEST_ISSUE
,
78 LTT_EVENT_REQUEST_COMPLETE
;
86 LTT_FIELD_SOFT_IRQ_ID
,
108 LTTV_STATE_MODE_UNKNOWN
,
109 LTTV_STATE_USER_MODE
,
116 LTTV_STATE_SUBMODE_UNKNOWN
,
117 LTTV_STATE_SUBMODE_NONE
;
121 LTTV_STATE_WAIT_FORK
,
130 LTTV_STATE_UNBRANDED
;
133 LTTV_STATE_USER_THREAD
,
134 LTTV_STATE_KERNEL_THREAD
;
151 LTTV_BDEV_BUSY_READING
,
152 LTTV_BDEV_BUSY_WRITING
;
155 LTTV_STATE_TRACEFILES
,
156 LTTV_STATE_PROCESSES
,
158 LTTV_STATE_RUNNING_PROCESS
,
160 LTTV_STATE_SAVED_STATES
,
161 LTTV_STATE_SAVED_STATES_TIME
,
164 LTTV_STATE_NAME_TABLES
,
165 LTTV_STATE_TRACE_STATE_USE_COUNT
,
166 LTTV_STATE_RESOURCE_CPUS
;
168 static void create_max_time(LttvTraceState
*tcs
);
170 static void get_max_time(LttvTraceState
*tcs
);
172 static void free_max_time(LttvTraceState
*tcs
);
174 static void create_name_tables(LttvTraceState
*tcs
);
176 static void get_name_tables(LttvTraceState
*tcs
);
178 static void free_name_tables(LttvTraceState
*tcs
);
180 static void free_saved_state(LttvTraceState
*tcs
);
182 static void lttv_state_free_process_table(GHashTable
*processes
);
184 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
185 GPtrArray
*quarktable
);
187 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
189 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
193 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
195 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
199 void lttv_state_state_saved_free(LttvTraceState
*self
,
200 LttvAttribute
*container
)
202 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
206 guint
process_hash(gconstpointer key
)
208 guint pid
= ((const LttvProcessState
*)key
)->pid
;
209 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
213 /* If the hash table hash function is well distributed,
214 * the process_equal should compare different pid */
215 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
217 const LttvProcessState
*process_a
, *process_b
;
220 process_a
= (const LttvProcessState
*)a
;
221 process_b
= (const LttvProcessState
*)b
;
223 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
224 else if(likely(process_a
->pid
== 0 &&
225 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
230 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
232 g_tree_destroy((GTree
*)value
);
235 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
237 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
238 g_hash_table_destroy(usertraces
);
244 restore_init_state(LttvTraceState
*self
)
248 LttvTracefileState
*tfcs
;
250 LttTime start_time
, end_time
;
252 /* Free the process tables */
253 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
254 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
255 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
256 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
259 /* Seek time to beginning */
260 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
261 // closest. It's the tracecontext job to seek the trace to the beginning
262 // anyway : the init state might be used at the middle of the trace as well...
263 //g_tree_destroy(self->parent.ts_context->pqueue);
264 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
266 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
268 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
270 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
272 /* Put the per cpu running_process to beginning state : process 0. */
273 for(i
=0; i
< nb_cpus
; i
++) {
274 LttvExecutionState
*es
;
275 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
276 LTTV_STATE_UNNAMED
, &start_time
);
277 /* We are not sure is it's a kernel thread or normal thread, put the
278 * bottom stack state to unknown */
279 self
->running_process
[i
]->execution_stack
=
280 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
281 es
= self
->running_process
[i
]->state
=
282 &g_array_index(self
->running_process
[i
]->execution_stack
,
283 LttvExecutionState
, 0);
284 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
285 es
->s
= LTTV_STATE_UNNAMED
;
287 //self->running_process[i]->state->s = LTTV_STATE_RUN;
288 self
->running_process
[i
]->cpu
= i
;
292 nb_tracefile
= self
->parent
.tracefiles
->len
;
294 for(i
= 0 ; i
< nb_tracefile
; i
++) {
296 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
297 LttvTracefileContext
*, i
));
298 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
299 // tfcs->saved_position = 0;
300 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
301 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
302 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
303 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
308 //static LttTime time_zero = {0,0};
310 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
313 const LttTime
*t1
= (const LttTime
*)a
;
314 const LttTime
*t2
= (const LttTime
*)b
;
316 return ltt_time_compare(*t1
, *t2
);
319 static void free_usertrace_key(gpointer data
)
324 #define MAX_STRING_LEN 4096
327 state_load_saved_states(LttvTraceState
*tcs
)
330 GPtrArray
*quarktable
;
335 tcs
->has_precomputed_states
= FALSE
;
339 gchar buf
[MAX_STRING_LEN
];
342 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
343 strncpy(path
, trace_path
, PATH_MAX
-1);
344 count
= strnlen(trace_path
, PATH_MAX
-1);
345 // quarktable : open, test
346 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
347 fp
= fopen(path
, "r");
349 quarktable
= g_ptr_array_sized_new(4096);
351 /* Index 0 is null */
353 if(hdr
== EOF
) return;
354 g_assert(hdr
== HDR_QUARKS
);
358 if(hdr
== EOF
) break;
359 g_assert(hdr
== HDR_QUARK
);
360 g_ptr_array_set_size(quarktable
, q
+1);
363 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
364 if(buf
[i
] == '\0' || feof(fp
)) break;
367 len
= strnlen(buf
, MAX_STRING_LEN
-1);
368 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
369 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
375 // saved_states : open, test
376 strncpy(path
, trace_path
, PATH_MAX
-1);
377 count
= strnlen(trace_path
, PATH_MAX
-1);
378 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
379 fp
= fopen(path
, "r");
383 if(hdr
!= HDR_TRACE
) goto end
;
385 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
387 tcs
->has_precomputed_states
= TRUE
;
392 /* Free the quarktable */
393 for(i
=0; i
<quarktable
->len
; i
++) {
394 string
= g_ptr_array_index (quarktable
, i
);
397 g_ptr_array_free(quarktable
, TRUE
);
402 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
404 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
407 LttvTraceContext
*tc
;
411 LttvTracefileState
*tfcs
;
413 LttvAttributeValue v
;
415 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
416 init((LttvTracesetContext
*)self
, ts
);
418 nb_trace
= lttv_traceset_number(ts
);
419 for(i
= 0 ; i
< nb_trace
; i
++) {
420 tc
= self
->parent
.traces
[i
];
421 tcs
= LTTV_TRACE_STATE(tc
);
422 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
423 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
427 if(*(v
.v_uint
) == 1) {
428 create_name_tables(tcs
);
429 create_max_time(tcs
);
431 get_name_tables(tcs
);
434 nb_tracefile
= tc
->tracefiles
->len
;
435 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
436 nb_irq
= tcs
->nb_irqs
;
437 tcs
->processes
= NULL
;
438 tcs
->usertraces
= NULL
;
439 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
441 /* init cpu resource stuff */
442 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
443 for(j
= 0; j
<nb_cpu
; j
++) {
444 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
445 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
448 /* init irq resource stuff */
449 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
450 for(j
= 0; j
<nb_irq
; j
++) {
451 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
452 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
455 /* init bdev resource stuff */
456 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
458 restore_init_state(tcs
);
459 for(j
= 0 ; j
< nb_tracefile
; j
++) {
461 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
462 LttvTracefileContext
*, j
));
463 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
464 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
465 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
466 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
467 /* It's a Usertrace */
468 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
469 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
471 if(!usertrace_tree
) {
472 usertrace_tree
= g_tree_new_full(compare_usertraces
,
473 NULL
, free_usertrace_key
, NULL
);
474 g_hash_table_insert(tcs
->usertraces
,
475 (gpointer
)tid
, usertrace_tree
);
477 LttTime
*timestamp
= g_new(LttTime
, 1);
478 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
479 ltt_tracefile_creation(tfcs
->parent
.tf
));
480 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
484 /* See if the trace has saved states */
485 state_load_saved_states(tcs
);
490 fini(LttvTracesetState
*self
)
496 LttvTracefileState
*tfcs
;
498 LttvAttributeValue v
;
500 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
501 for(i
= 0 ; i
< nb_trace
; i
++) {
502 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
503 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
506 g_assert(*(v
.v_uint
) != 0);
509 if(*(v
.v_uint
) == 0) {
510 free_name_tables(tcs
);
512 free_saved_state(tcs
);
514 g_free(tcs
->running_process
);
515 tcs
->running_process
= NULL
;
516 lttv_state_free_process_table(tcs
->processes
);
517 lttv_state_free_usertraces(tcs
->usertraces
);
518 tcs
->processes
= NULL
;
519 tcs
->usertraces
= NULL
;
521 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
522 fini((LttvTracesetContext
*)self
);
526 static LttvTracesetContext
*
527 new_traceset_context(LttvTracesetContext
*self
)
529 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
533 static LttvTraceContext
*
534 new_trace_context(LttvTracesetContext
*self
)
536 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
540 static LttvTracefileContext
*
541 new_tracefile_context(LttvTracesetContext
*self
)
543 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
547 /* Write the process state of the trace */
549 static void write_process_state(gpointer key
, gpointer value
,
552 LttvProcessState
*process
;
554 LttvExecutionState
*es
;
556 FILE *fp
= (FILE *)user_data
;
561 process
= (LttvProcessState
*)value
;
563 " <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",
564 process
, process
->pid
, process
->tgid
, process
->ppid
,
565 g_quark_to_string(process
->type
),
566 process
->creation_time
.tv_sec
,
567 process
->creation_time
.tv_nsec
,
568 process
->insertion_time
.tv_sec
,
569 process
->insertion_time
.tv_nsec
,
570 g_quark_to_string(process
->name
),
571 g_quark_to_string(process
->brand
),
574 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
575 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
576 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
577 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
578 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
579 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
580 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
583 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
584 address
= &g_array_index(process
->user_stack
, guint64
, i
);
585 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
589 if(process
->usertrace
) {
590 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
591 g_quark_to_string(process
->usertrace
->tracefile_name
),
592 process
->usertrace
->cpu
);
596 fprintf(fp
, " </PROCESS>\n");
600 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
602 guint i
, nb_tracefile
, nb_block
, offset
;
605 LttvTracefileState
*tfcs
;
609 LttEventPosition
*ep
;
613 ep
= ltt_event_position_new();
615 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
617 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
619 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
620 for(i
=0;i
<nb_cpus
;i
++) {
621 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
622 i
, self
->running_process
[i
]->pid
);
625 nb_tracefile
= self
->parent
.tracefiles
->len
;
627 for(i
= 0 ; i
< nb_tracefile
; i
++) {
629 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
630 LttvTracefileContext
*, i
));
631 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
632 tfcs
->parent
.timestamp
.tv_sec
,
633 tfcs
->parent
.timestamp
.tv_nsec
);
634 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
635 if(e
== NULL
) fprintf(fp
,"/>\n");
637 ltt_event_position(e
, ep
);
638 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
639 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
644 fprintf(fp
,"</PROCESS_STATE>\n");
648 static void write_process_state_raw(gpointer key
, gpointer value
,
651 LttvProcessState
*process
;
653 LttvExecutionState
*es
;
655 FILE *fp
= (FILE *)user_data
;
660 process
= (LttvProcessState
*)value
;
661 fputc(HDR_PROCESS
, fp
);
662 //fwrite(&header, sizeof(header), 1, fp);
663 //fprintf(fp, "%s", g_quark_to_string(process->type));
665 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
666 //fprintf(fp, "%s", g_quark_to_string(process->name));
668 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
669 //fprintf(fp, "%s", g_quark_to_string(process->brand));
671 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
672 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
673 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
674 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
675 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
676 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
677 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
681 " <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",
682 process
, process
->pid
, process
->tgid
, process
->ppid
,
683 g_quark_to_string(process
->type
),
684 process
->creation_time
.tv_sec
,
685 process
->creation_time
.tv_nsec
,
686 process
->insertion_time
.tv_sec
,
687 process
->insertion_time
.tv_nsec
,
688 g_quark_to_string(process
->name
),
689 g_quark_to_string(process
->brand
),
693 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
694 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
697 //fprintf(fp, "%s", g_quark_to_string(es->t));
699 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
700 //fprintf(fp, "%s", g_quark_to_string(es->n));
702 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
703 //fprintf(fp, "%s", g_quark_to_string(es->s));
705 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
706 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
707 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
708 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
710 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
711 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
712 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
713 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
714 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
718 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
719 address
= &g_array_index(process
->user_stack
, guint64
, i
);
720 fputc(HDR_USER_STACK
, fp
);
721 fwrite(&address
, sizeof(address
), 1, fp
);
723 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
728 if(process
->usertrace
) {
729 fputc(HDR_USERTRACE
, fp
);
730 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
732 fwrite(&process
->usertrace
->tracefile_name
,
733 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
734 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
736 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
737 g_quark_to_string(process
->usertrace
->tracefile_name
),
738 process
->usertrace
->cpu
);
745 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
747 guint i
, nb_tracefile
, nb_block
, offset
;
750 LttvTracefileState
*tfcs
;
754 LttEventPosition
*ep
;
758 ep
= ltt_event_position_new();
760 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
761 fputc(HDR_PROCESS_STATE
, fp
);
762 fwrite(&t
, sizeof(t
), 1, fp
);
764 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
766 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
767 for(i
=0;i
<nb_cpus
;i
++) {
769 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
770 fwrite(&self
->running_process
[i
]->pid
,
771 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
772 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
773 // i, self->running_process[i]->pid);
776 nb_tracefile
= self
->parent
.tracefiles
->len
;
778 for(i
= 0 ; i
< nb_tracefile
; i
++) {
780 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
781 LttvTracefileContext
*, i
));
782 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
783 // tfcs->parent.timestamp.tv_sec,
784 // tfcs->parent.timestamp.tv_nsec);
785 fputc(HDR_TRACEFILE
, fp
);
786 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
787 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
788 * position following : end of trace */
789 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
791 ltt_event_position(e
, ep
);
792 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
793 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
795 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
796 fwrite(&offset
, sizeof(offset
), 1, fp
);
797 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
804 /* Read process state from a file */
806 /* Called because a HDR_PROCESS was found */
807 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
808 GPtrArray
*quarktable
)
810 LttvExecutionState
*es
;
811 LttvProcessState
*process
, *parent_process
;
812 LttvProcessState tmp
;
819 /* TODO : check return value */
820 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
821 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
822 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
823 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
824 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
825 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
826 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
827 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
828 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
831 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
833 /* We must link to the parent */
834 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
836 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
837 if(process
== NULL
) {
838 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
840 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
844 process
->insertion_time
= tmp
.insertion_time
;
845 process
->creation_time
= tmp
.creation_time
;
846 process
->type
= g_quark_from_string(
847 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
848 process
->tgid
= tmp
.tgid
;
849 process
->ppid
= tmp
.ppid
;
850 process
->brand
= g_quark_from_string(
851 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
853 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
857 if(feof(fp
) || ferror(fp
)) goto end_loop
;
859 gint hdr
= fgetc(fp
);
860 if(hdr
== EOF
) goto end_loop
;
864 process
->execution_stack
=
865 g_array_set_size(process
->execution_stack
,
866 process
->execution_stack
->len
+ 1);
867 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
868 process
->execution_stack
->len
-1);
871 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
872 es
->t
= g_quark_from_string(
873 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
874 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
875 es
->n
= g_quark_from_string(
876 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
877 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
878 es
->s
= g_quark_from_string(
879 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
880 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
881 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
882 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
885 process
->user_stack
= g_array_set_size(process
->user_stack
,
886 process
->user_stack
->len
+ 1);
887 address
= &g_array_index(process
->user_stack
, guint64
,
888 process
->user_stack
->len
-1);
889 fread(address
, sizeof(address
), 1, fp
);
890 process
->current_function
= *address
;
893 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
894 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
906 /* Called because a HDR_PROCESS_STATE was found */
907 /* Append a saved state to the trace states */
908 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
910 guint i
, nb_tracefile
, nb_block
, offset
;
912 LttvTracefileState
*tfcs
;
914 LttEventPosition
*ep
;
922 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
924 LttvAttributeValue value
;
925 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
926 ep
= ltt_event_position_new();
928 restore_init_state(self
);
930 fread(&t
, sizeof(t
), 1, fp
);
933 if(feof(fp
) || ferror(fp
)) goto end_loop
;
935 if(hdr
== EOF
) goto end_loop
;
939 /* Call read_process_state_raw */
940 read_process_state_raw(self
, fp
, quarktable
);
950 case HDR_PROCESS_STATE
:
956 g_error("Error while parsing saved state file : unknown data header %d",
962 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
963 for(i
=0;i
<nb_cpus
;i
++) {
966 g_assert(hdr
== HDR_CPU
);
967 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
968 g_assert(i
== cpu_num
);
969 fread(&self
->running_process
[i
]->pid
,
970 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
973 nb_tracefile
= self
->parent
.tracefiles
->len
;
975 for(i
= 0 ; i
< nb_tracefile
; i
++) {
977 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
978 LttvTracefileContext
*, i
));
979 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
980 // tfcs->parent.timestamp.tv_sec,
981 // tfcs->parent.timestamp.tv_nsec);
982 g_tree_remove(pqueue
, &tfcs
->parent
);
984 g_assert(hdr
== HDR_TRACEFILE
);
985 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
986 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
987 * position following : end of trace */
988 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
989 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
990 fread(&offset
, sizeof(offset
), 1, fp
);
991 fread(&tsc
, sizeof(tsc
), 1, fp
);
992 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
993 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
995 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1000 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1001 LTTV_STATE_SAVED_STATES
);
1002 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1003 value
= lttv_attribute_add(saved_states_tree
,
1004 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1005 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1006 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1007 *(value
.v_time
) = t
;
1008 lttv_state_save(self
, saved_state_tree
);
1009 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1012 *(self
->max_time_state_recomputed_in_seek
) = t
;
1016 /* Called when a HDR_TRACE is found */
1017 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1018 GPtrArray
*quarktable
)
1023 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1025 if(hdr
== EOF
) goto end_loop
;
1028 case HDR_PROCESS_STATE
:
1029 /* Call read_process_state_raw */
1030 lttv_state_read_raw(tcs
, fp
, quarktable
);
1038 case HDR_USER_STACK
:
1042 g_error("Error while parsing saved state file :"
1043 " unexpected data header %d",
1047 g_error("Error while parsing saved state file : unknown data header %d",
1052 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1053 restore_init_state(tcs
);
1054 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1060 /* Copy each process from an existing hash table to a new one */
1062 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1064 LttvProcessState
*process
, *new_process
;
1066 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1070 process
= (LttvProcessState
*)value
;
1071 new_process
= g_new(LttvProcessState
, 1);
1072 *new_process
= *process
;
1073 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1074 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1075 new_process
->execution_stack
=
1076 g_array_set_size(new_process
->execution_stack
,
1077 process
->execution_stack
->len
);
1078 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1079 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1080 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1082 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1083 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1084 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1085 sizeof(guint64
), 0);
1086 new_process
->user_stack
=
1087 g_array_set_size(new_process
->user_stack
,
1088 process
->user_stack
->len
);
1089 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1090 g_array_index(new_process
->user_stack
, guint64
, i
) =
1091 g_array_index(process
->user_stack
, guint64
, i
);
1093 new_process
->current_function
= process
->current_function
;
1094 g_hash_table_insert(new_processes
, new_process
, new_process
);
1098 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1100 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1102 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1103 return new_processes
;
1106 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1109 LttvCPUState
*retval
;
1111 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1113 for(i
=0; i
<n
; i
++) {
1114 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1115 retval
[i
].last_irq
= states
[i
].last_irq
;
1116 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1117 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1118 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1125 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1129 for(i
=0; i
<n
; i
++) {
1130 g_array_free(states
[i
].mode_stack
, FALSE
);
1136 /* The saved state for each trace contains a member "processes", which
1137 stores a copy of the process table, and a member "tracefiles" with
1138 one entry per tracefile. Each tracefile has a "process" member pointing
1139 to the current process and a "position" member storing the tracefile
1140 position (needed to seek to the current "next" event. */
1142 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1144 guint i
, nb_tracefile
, nb_cpus
;
1146 LttvTracefileState
*tfcs
;
1148 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1150 guint
*running_process
;
1152 LttvAttributeType type
;
1154 LttvAttributeValue value
;
1156 LttvAttributeName name
;
1158 LttEventPosition
*ep
;
1160 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1161 LTTV_STATE_TRACEFILES
);
1163 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1165 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1167 /* Add the currently running processes array */
1168 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1169 running_process
= g_new(guint
, nb_cpus
);
1170 for(i
=0;i
<nb_cpus
;i
++) {
1171 running_process
[i
] = self
->running_process
[i
]->pid
;
1173 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1175 *(value
.v_pointer
) = running_process
;
1177 g_info("State save");
1179 nb_tracefile
= self
->parent
.tracefiles
->len
;
1181 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1183 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1184 LttvTracefileContext
*, i
));
1185 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1186 value
= lttv_attribute_add(tracefiles_tree
, i
,
1188 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1190 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1192 *(value
.v_uint
) = tfcs
->process
->pid
;
1194 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1196 /* Only save the position if the tfs has not infinite time. */
1197 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1198 // && current_tfcs != tfcs) {
1199 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1200 *(value
.v_pointer
) = NULL
;
1202 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1203 ep
= ltt_event_position_new();
1204 ltt_event_position(e
, ep
);
1205 *(value
.v_pointer
) = ep
;
1207 guint nb_block
, offset
;
1210 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1211 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1213 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1217 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1219 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1220 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1224 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1226 guint i
, nb_tracefile
, pid
, nb_cpus
;
1228 LttvTracefileState
*tfcs
;
1230 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1232 guint
*running_process
;
1234 LttvAttributeType type
;
1236 LttvAttributeValue value
;
1238 LttvAttributeName name
;
1242 LttEventPosition
*ep
;
1244 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1246 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1247 LTTV_STATE_TRACEFILES
);
1249 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1251 g_assert(type
== LTTV_POINTER
);
1252 lttv_state_free_process_table(self
->processes
);
1253 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1255 /* Add the currently running processes array */
1256 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1257 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1259 g_assert(type
== LTTV_POINTER
);
1260 running_process
= *(value
.v_pointer
);
1261 for(i
=0;i
<nb_cpus
;i
++) {
1262 pid
= running_process
[i
];
1263 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1264 g_assert(self
->running_process
[i
] != NULL
);
1267 printf("state restore\n");
1269 nb_tracefile
= self
->parent
.tracefiles
->len
;
1271 //g_tree_destroy(tsc->pqueue);
1272 //tsc->pqueue = g_tree_new(compare_tracefile);
1274 /* restore cpu resource states */
1275 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1276 g_assert(type
== LTTV_POINTER
);
1277 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1278 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1280 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1282 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1283 LttvTracefileContext
*, i
));
1284 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1285 g_assert(type
== LTTV_GOBJECT
);
1286 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1288 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1290 g_assert(type
== LTTV_UINT
);
1291 pid
= *(value
.v_uint
);
1292 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1294 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1296 g_assert(type
== LTTV_POINTER
);
1297 //g_assert(*(value.v_pointer) != NULL);
1298 ep
= *(value
.v_pointer
);
1299 g_assert(tfcs
->parent
.t_context
!= NULL
);
1301 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1303 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1304 g_tree_remove(tsc
->pqueue
, tfc
);
1307 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1308 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1309 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1310 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1311 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1313 tfc
->timestamp
= ltt_time_infinite
;
1319 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1321 guint i
, nb_tracefile
, nb_cpus
;
1323 LttvTracefileState
*tfcs
;
1325 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1327 guint
*running_process
;
1329 LttvAttributeType type
;
1331 LttvAttributeValue value
;
1333 LttvAttributeName name
;
1337 LttEventPosition
*ep
;
1339 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1340 LTTV_STATE_TRACEFILES
);
1341 g_object_ref(G_OBJECT(tracefiles_tree
));
1342 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1344 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1346 g_assert(type
== LTTV_POINTER
);
1347 lttv_state_free_process_table(*(value
.v_pointer
));
1348 *(value
.v_pointer
) = NULL
;
1349 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1351 /* Free running processes array */
1352 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1353 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1355 g_assert(type
== LTTV_POINTER
);
1356 running_process
= *(value
.v_pointer
);
1357 g_free(running_process
);
1359 nb_tracefile
= self
->parent
.tracefiles
->len
;
1361 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1363 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1364 LttvTracefileContext
*, i
));
1365 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1366 g_assert(type
== LTTV_GOBJECT
);
1367 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1369 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1371 g_assert(type
== LTTV_POINTER
);
1372 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1374 g_object_unref(G_OBJECT(tracefiles_tree
));
1378 static void free_saved_state(LttvTraceState
*self
)
1382 LttvAttributeType type
;
1384 LttvAttributeValue value
;
1386 LttvAttributeName name
;
1390 LttvAttribute
*saved_states
;
1392 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1393 LTTV_STATE_SAVED_STATES
);
1395 nb
= lttv_attribute_get_number(saved_states
);
1396 for(i
= 0 ; i
< nb
; i
++) {
1397 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1398 g_assert(type
== LTTV_GOBJECT
);
1399 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1402 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1407 create_max_time(LttvTraceState
*tcs
)
1409 LttvAttributeValue v
;
1411 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1413 g_assert(*(v
.v_pointer
) == NULL
);
1414 *(v
.v_pointer
) = g_new(LttTime
,1);
1415 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1420 get_max_time(LttvTraceState
*tcs
)
1422 LttvAttributeValue v
;
1424 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1426 g_assert(*(v
.v_pointer
) != NULL
);
1427 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1432 free_max_time(LttvTraceState
*tcs
)
1434 LttvAttributeValue v
;
1436 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1438 g_free(*(v
.v_pointer
));
1439 *(v
.v_pointer
) = NULL
;
1443 typedef struct _LttvNameTables
{
1444 // FIXME GQuark *eventtype_names;
1445 GQuark
*syscall_names
;
1451 GQuark
*soft_irq_names
;
1457 create_name_tables(LttvTraceState
*tcs
)
1461 GQuark f_name
, e_name
;
1465 LttvTraceHookByFacility
*thf
;
1471 GString
*fe_name
= g_string_new("");
1473 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1475 LttvAttributeValue v
;
1477 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1479 g_assert(*(v
.v_pointer
) == NULL
);
1480 *(v
.v_pointer
) = name_tables
;
1481 #if 0 // Use iteration over the facilities_by_name and then list all event
1482 // types of each facility
1483 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1484 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1485 for(i
= 0 ; i
< nb
; i
++) {
1486 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1487 e_name
= ltt_eventtype_name(et
);
1488 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1489 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1490 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1493 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1494 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1495 LTT_FIELD_SYSCALL_ID
, 0, 0,
1498 thf
= lttv_trace_hook_get_first(&h
);
1500 t
= ltt_field_type(thf
->f1
);
1501 nb
= ltt_type_element_number(t
);
1503 lttv_trace_hook_destroy(&h
);
1505 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1506 name_tables
->nb_syscalls
= nb
;
1508 for(i
= 0 ; i
< nb
; i
++) {
1509 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1510 if(!name_tables
->syscall_names
[i
]) {
1511 GString
*string
= g_string_new("");
1512 g_string_printf(string
, "syscall %u", i
);
1513 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1514 g_string_free(string
, TRUE
);
1518 //name_tables->syscall_names = g_new(GQuark, 256);
1519 //for(i = 0 ; i < 256 ; i++) {
1520 // g_string_printf(fe_name, "syscall %d", i);
1521 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1524 name_tables
->syscall_names
= NULL
;
1525 name_tables
->nb_syscalls
= 0;
1528 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1529 LTT_EVENT_TRAP_ENTRY
,
1530 LTT_FIELD_TRAP_ID
, 0, 0,
1533 thf
= lttv_trace_hook_get_first(&h
);
1535 t
= ltt_field_type(thf
->f1
);
1536 //nb = ltt_type_element_number(t);
1538 lttv_trace_hook_destroy(&h
);
1541 name_tables->trap_names = g_new(GQuark, nb);
1542 for(i = 0 ; i < nb ; i++) {
1543 name_tables->trap_names[i] = g_quark_from_string(
1544 ltt_enum_string_get(t, i));
1547 name_tables
->nb_traps
= 256;
1548 name_tables
->trap_names
= g_new(GQuark
, 256);
1549 for(i
= 0 ; i
< 256 ; i
++) {
1550 g_string_printf(fe_name
, "trap %d", i
);
1551 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1554 name_tables
->trap_names
= NULL
;
1555 name_tables
->nb_traps
= 0;
1558 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1559 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1560 LTT_FIELD_IRQ_ID
, 0, 0,
1563 thf
= lttv_trace_hook_get_first(&h
);
1565 t
= ltt_field_type(thf
->f1
);
1566 //nb = ltt_type_element_number(t);
1568 lttv_trace_hook_destroy(&h
);
1571 name_tables->irq_names = g_new(GQuark, nb);
1572 for(i = 0 ; i < nb ; i++) {
1573 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1577 name_tables
->nb_irqs
= 256;
1578 name_tables
->irq_names
= g_new(GQuark
, 256);
1579 for(i
= 0 ; i
< 256 ; i
++) {
1580 g_string_printf(fe_name
, "irq %d", i
);
1581 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1584 name_tables
->nb_irqs
= 0;
1585 name_tables
->irq_names
= NULL
;
1588 name_tables->soft_irq_names = g_new(GQuark, nb);
1589 for(i = 0 ; i < nb ; i++) {
1590 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1594 name_tables
->nb_softirqs
= 256;
1595 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1596 for(i
= 0 ; i
< 256 ; i
++) {
1597 g_string_printf(fe_name
, "softirq %d", i
);
1598 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1602 g_string_free(fe_name
, TRUE
);
1607 get_name_tables(LttvTraceState
*tcs
)
1609 LttvNameTables
*name_tables
;
1611 LttvAttributeValue v
;
1613 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1615 g_assert(*(v
.v_pointer
) != NULL
);
1616 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1617 //tcs->eventtype_names = name_tables->eventtype_names;
1618 tcs
->syscall_names
= name_tables
->syscall_names
;
1619 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1620 tcs
->trap_names
= name_tables
->trap_names
;
1621 tcs
->nb_traps
= name_tables
->nb_traps
;
1622 tcs
->irq_names
= name_tables
->irq_names
;
1623 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1624 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1625 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1630 free_name_tables(LttvTraceState
*tcs
)
1632 LttvNameTables
*name_tables
;
1634 LttvAttributeValue v
;
1636 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1638 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1639 *(v
.v_pointer
) = NULL
;
1641 // g_free(name_tables->eventtype_names);
1642 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1643 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1644 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1645 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1646 if(name_tables
) g_free(name_tables
);
1649 #ifdef HASH_TABLE_DEBUG
1651 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1653 LttvProcessState
*process
= (LttvProcessState
*)value
;
1655 /* Test for process corruption */
1656 guint stack_len
= process
->execution_stack
->len
;
1659 static void hash_table_check(GHashTable
*table
)
1661 g_hash_table_foreach(table
, test_process
, NULL
);
1667 /* clears the stack and sets the state passed as argument */
1668 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1670 g_array_set_size(cpust
->mode_stack
, 1);
1671 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1674 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1676 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1677 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1680 static void cpu_pop_mode(LttvCPUState
*cpust
)
1682 if(cpust
->mode_stack
->len
== 1)
1683 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1685 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1688 /* clears the stack and sets the state passed as argument */
1689 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1691 g_array_set_size(bdevst
->mode_stack
, 1);
1692 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1695 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1697 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1698 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1701 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1703 if(bdevst
->mode_stack
->len
== 1)
1704 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1706 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1709 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1711 g_array_set_size(irqst
->mode_stack
, 1);
1712 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1715 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1717 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1718 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1721 static void irq_pop_mode(LttvIRQState
*irqst
)
1723 if(irqst
->mode_stack
->len
== 1)
1724 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1726 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1729 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1732 LttvExecutionState
*es
;
1734 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1735 guint cpu
= tfs
->cpu
;
1737 #ifdef HASH_TABLE_DEBUG
1738 hash_table_check(ts
->processes
);
1740 LttvProcessState
*process
= ts
->running_process
[cpu
];
1742 guint depth
= process
->execution_stack
->len
;
1744 process
->execution_stack
=
1745 g_array_set_size(process
->execution_stack
, depth
+ 1);
1748 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1750 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1753 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1754 es
->cum_cpu_time
= ltt_time_zero
;
1755 es
->s
= process
->state
->s
;
1756 process
->state
= es
;
1760 * return 1 when empty, else 0 */
1761 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1762 LttvTracefileState
*tfs
)
1764 guint cpu
= tfs
->cpu
;
1765 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1767 guint depth
= process
->execution_stack
->len
;
1773 process
->execution_stack
=
1774 g_array_set_size(process
->execution_stack
, depth
- 1);
1775 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1777 process
->state
->change
= tfs
->parent
.timestamp
;
1782 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1784 guint cpu
= tfs
->cpu
;
1785 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1786 LttvProcessState
*process
= ts
->running_process
[cpu
];
1788 guint depth
= process
->execution_stack
->len
;
1790 if(process
->state
->t
!= t
){
1791 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1792 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1793 g_info("process state has %s when pop_int is %s\n",
1794 g_quark_to_string(process
->state
->t
),
1795 g_quark_to_string(t
));
1796 g_info("{ %u, %u, %s, %s, %s }\n",
1799 g_quark_to_string(process
->name
),
1800 g_quark_to_string(process
->brand
),
1801 g_quark_to_string(process
->state
->s
));
1806 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1807 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1811 process
->execution_stack
=
1812 g_array_set_size(process
->execution_stack
, depth
- 1);
1813 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1815 process
->state
->change
= tfs
->parent
.timestamp
;
1818 struct search_result
{
1819 const LttTime
*time
; /* Requested time */
1820 LttTime
*best
; /* Best result */
1823 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1825 const LttTime
*elem_time
= (const LttTime
*)a
;
1826 /* Explicit non const cast */
1827 struct search_result
*res
= (struct search_result
*)b
;
1829 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1830 /* The usertrace was created before the schedchange */
1831 /* Get larger keys */
1833 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1834 /* The usertrace was created after the schedchange time */
1835 /* Get smaller keys */
1837 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1838 res
->best
= elem_time
;
1841 res
->best
= elem_time
;
1848 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1849 guint pid
, const LttTime
*timestamp
)
1851 LttvTracefileState
*tfs
= NULL
;
1852 struct search_result res
;
1853 /* Find the usertrace associated with a pid and time interval.
1854 * Search in the usertraces by PID (within a hash) and then, for each
1855 * corresponding element of the array, find the first one with creation
1856 * timestamp the lowest, but higher or equal to "timestamp". */
1857 res
.time
= timestamp
;
1859 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1860 if(usertrace_tree
) {
1861 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1863 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1871 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1872 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1874 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1876 LttvExecutionState
*es
;
1878 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1883 process
->tgid
= tgid
;
1885 process
->name
= name
;
1886 process
->brand
= LTTV_STATE_UNBRANDED
;
1887 //process->last_cpu = tfs->cpu_name;
1888 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1889 process
->type
= LTTV_STATE_USER_THREAD
;
1890 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1891 process
->current_function
= 0; //function 0x0 by default.
1893 g_info("Process %u, core %p", process
->pid
, process
);
1894 g_hash_table_insert(tcs
->processes
, process
, process
);
1897 process
->ppid
= parent
->pid
;
1898 process
->creation_time
= *timestamp
;
1901 /* No parent. This process exists but we are missing all information about
1902 its creation. The birth time is set to zero but we remember the time of
1907 process
->creation_time
= ltt_time_zero
;
1910 process
->insertion_time
= *timestamp
;
1911 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1912 process
->creation_time
.tv_nsec
);
1913 process
->pid_time
= g_quark_from_string(buffer
);
1915 //process->last_cpu = tfs->cpu_name;
1916 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1917 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1918 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1919 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1920 es
= process
->state
= &g_array_index(process
->execution_stack
,
1921 LttvExecutionState
, 0);
1922 es
->t
= LTTV_STATE_USER_MODE
;
1923 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1924 es
->entry
= *timestamp
;
1925 //g_assert(timestamp->tv_sec != 0);
1926 es
->change
= *timestamp
;
1927 es
->cum_cpu_time
= ltt_time_zero
;
1928 es
->s
= LTTV_STATE_RUN
;
1930 es
= process
->state
= &g_array_index(process
->execution_stack
,
1931 LttvExecutionState
, 1);
1932 es
->t
= LTTV_STATE_SYSCALL
;
1933 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1934 es
->entry
= *timestamp
;
1935 //g_assert(timestamp->tv_sec != 0);
1936 es
->change
= *timestamp
;
1937 es
->cum_cpu_time
= ltt_time_zero
;
1938 es
->s
= LTTV_STATE_WAIT_FORK
;
1940 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1941 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1942 sizeof(guint64
), 0);
1947 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1950 LttvProcessState key
;
1951 LttvProcessState
*process
;
1955 process
= g_hash_table_lookup(ts
->processes
, &key
);
1960 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1961 const LttTime
*timestamp
)
1963 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1964 LttvExecutionState
*es
;
1966 /* Put ltt_time_zero creation time for unexisting processes */
1967 if(unlikely(process
== NULL
)) {
1968 process
= lttv_state_create_process(ts
,
1969 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1970 /* We are not sure is it's a kernel thread or normal thread, put the
1971 * bottom stack state to unknown */
1972 process
->execution_stack
=
1973 g_array_set_size(process
->execution_stack
, 1);
1974 process
->state
= es
=
1975 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1976 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1977 es
->s
= LTTV_STATE_UNNAMED
;
1982 /* FIXME : this function should be called when we receive an event telling that
1983 * release_task has been called in the kernel. In happens generally when
1984 * the parent waits for its child terminaison, but may also happen in special
1985 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1986 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1987 * of a killed thread ground, but isn't the leader.
1989 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1991 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1992 LttvProcessState key
;
1994 key
.pid
= process
->pid
;
1995 key
.cpu
= process
->cpu
;
1996 g_hash_table_remove(ts
->processes
, &key
);
1997 g_array_free(process
->execution_stack
, TRUE
);
1998 g_array_free(process
->user_stack
, TRUE
);
2003 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2005 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2006 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2011 static void lttv_state_free_process_table(GHashTable
*processes
)
2013 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2014 g_hash_table_destroy(processes
);
2018 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2020 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2022 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2023 LttvProcessState
*process
= ts
->running_process
[cpu
];
2024 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2025 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2026 LttField
*f
= thf
->f1
;
2028 LttvExecutionSubmode submode
;
2030 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2031 guint syscall
= ltt_event_get_unsigned(e
, f
);
2033 if(syscall
< nb_syscalls
) {
2034 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2037 /* Fixup an incomplete syscall table */
2038 GString
*string
= g_string_new("");
2039 g_string_printf(string
, "syscall %u", syscall
);
2040 submode
= g_quark_from_string(string
->str
);
2041 g_string_free(string
, TRUE
);
2043 /* There can be no system call from PID 0 : unknown state */
2044 if(process
->pid
!= 0)
2045 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2050 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2052 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2054 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2055 LttvProcessState
*process
= ts
->running_process
[cpu
];
2057 /* There can be no system call from PID 0 : unknown state */
2058 if(process
->pid
!= 0)
2059 pop_state(s
, LTTV_STATE_SYSCALL
);
2064 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2066 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2067 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2068 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2069 LttField
*f
= thf
->f1
;
2071 LttvExecutionSubmode submode
;
2073 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2074 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2076 if(trap
< nb_traps
) {
2077 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2079 /* Fixup an incomplete trap table */
2080 GString
*string
= g_string_new("");
2081 g_string_printf(string
, "trap %llu", trap
);
2082 submode
= g_quark_from_string(string
->str
);
2083 g_string_free(string
, TRUE
);
2086 push_state(s
, LTTV_STATE_TRAP
, submode
);
2088 /* update cpu status */
2089 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2094 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2096 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2098 pop_state(s
, LTTV_STATE_TRAP
);
2100 /* update cpu status */
2101 cpu_pop_mode(s
->cpu_state
);
2106 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2108 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2109 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2110 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2111 guint8 fac_id
= ltt_event_facility_id(e
);
2112 guint8 ev_id
= ltt_event_eventtype_id(e
);
2113 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2114 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2115 g_assert(thf
->f1
!= NULL
);
2116 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2117 LttField
*f
= thf
->f1
;
2119 LttvExecutionSubmode submode
;
2120 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2121 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2125 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2127 /* Fixup an incomplete irq table */
2128 GString
*string
= g_string_new("");
2129 g_string_printf(string
, "irq %llu", irq
);
2130 submode
= g_quark_from_string(string
->str
);
2131 g_string_free(string
, TRUE
);
2134 /* Do something with the info about being in user or system mode when int? */
2135 push_state(s
, LTTV_STATE_IRQ
, submode
);
2137 /* update cpu status */
2138 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2140 /* update irq status */
2141 s
->cpu_state
->last_irq
= irq
;
2142 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2147 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2149 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2151 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2157 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2159 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2160 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2162 pop_state(s
, LTTV_STATE_IRQ
);
2164 /* update cpu status */
2165 cpu_pop_mode(s
->cpu_state
);
2167 /* update irq status */
2168 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2173 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2175 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2176 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2177 guint8 fac_id
= ltt_event_facility_id(e
);
2178 guint8 ev_id
= ltt_event_eventtype_id(e
);
2179 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2180 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2181 g_assert(thf
->f1
!= NULL
);
2182 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2183 LttField
*f
= thf
->f1
;
2185 LttvExecutionSubmode submode
;
2186 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2187 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2190 if(softirq
< nb_softirqs
) {
2191 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2193 /* Fixup an incomplete irq table */
2194 GString
*string
= g_string_new("");
2195 g_string_printf(string
, "softirq %llu", softirq
);
2196 submode
= g_quark_from_string(string
->str
);
2197 g_string_free(string
, TRUE
);
2200 /* Do something with the info about being in user or system mode when int? */
2201 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2205 LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
)
2207 gint devcode_gint
= devcode
;
2208 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2210 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
2211 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
2213 gint
* key
= g_malloc(sizeof(gint
));
2215 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
2216 printf("adding key %u to hash table\n", *key
);
2224 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2226 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2227 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2228 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2229 guint8 fac_id
= ltt_event_facility_id(e
);
2230 guint8 ev_id
= ltt_event_eventtype_id(e
);
2231 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2233 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2234 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2235 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2236 guint16 devcode
= MKDEV(major
,minor
);
2238 /* have we seen this block device before? */
2239 gpointer bdev
= bdev_state_get(ts
, devcode
);
2242 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2244 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2249 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2251 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2252 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2253 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2254 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2256 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2257 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2258 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2259 guint16 devcode
= MKDEV(major
,minor
);
2261 /* have we seen this block device before? */
2262 gpointer bdev
= bdev_state_get(ts
, devcode
);
2264 /* update block device */
2265 bdev_pop_mode(bdev
);
2270 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2274 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2275 guint cpu
= tfs
->cpu
;
2276 LttvProcessState
*process
= ts
->running_process
[cpu
];
2278 guint depth
= process
->user_stack
->len
;
2280 process
->user_stack
=
2281 g_array_set_size(process
->user_stack
, depth
+ 1);
2283 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2284 *new_func
= funcptr
;
2285 process
->current_function
= funcptr
;
2288 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2290 guint cpu
= tfs
->cpu
;
2291 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2292 LttvProcessState
*process
= ts
->running_process
[cpu
];
2294 if(process
->current_function
!= funcptr
){
2295 g_info("Different functions (%lu.%09lu): ignore it\n",
2296 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2297 g_info("process state has %llu when pop_function is %llu\n",
2298 process
->current_function
, funcptr
);
2299 g_info("{ %u, %u, %s, %s, %s }\n",
2302 g_quark_to_string(process
->name
),
2303 g_quark_to_string(process
->brand
),
2304 g_quark_to_string(process
->state
->s
));
2307 guint depth
= process
->user_stack
->len
;
2310 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2311 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2315 process
->user_stack
=
2316 g_array_set_size(process
->user_stack
, depth
- 1);
2317 process
->current_function
=
2318 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2322 static gboolean
function_entry(void *hook_data
, void *call_data
)
2324 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2325 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2326 guint8 fac_id
= ltt_event_facility_id(e
);
2327 guint8 ev_id
= ltt_event_eventtype_id(e
);
2328 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2329 g_assert(thf
->f1
!= NULL
);
2330 LttField
*f
= thf
->f1
;
2331 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2333 push_function(s
, funcptr
);
2337 static gboolean
function_exit(void *hook_data
, void *call_data
)
2339 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2340 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2341 guint8 fac_id
= ltt_event_facility_id(e
);
2342 guint8 ev_id
= ltt_event_eventtype_id(e
);
2343 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2344 g_assert(thf
->f1
!= NULL
);
2345 LttField
*f
= thf
->f1
;
2346 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2348 LttvExecutionSubmode submode
;
2350 pop_function(s
, funcptr
);
2354 static gboolean
schedchange(void *hook_data
, void *call_data
)
2356 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2358 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2359 LttvProcessState
*process
= ts
->running_process
[cpu
];
2360 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2362 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2363 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2364 guint pid_in
, pid_out
;
2367 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2368 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2369 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2371 if(likely(process
!= NULL
)) {
2373 /* We could not know but it was not the idle process executing.
2374 This should only happen at the beginning, before the first schedule
2375 event, and when the initial information (current process for each CPU)
2376 is missing. It is not obvious how we could, after the fact, compensate
2377 the wrongly attributed statistics. */
2379 //This test only makes sense once the state is known and if there is no
2380 //missing events. We need to silently ignore schedchange coming after a
2381 //process_free, or it causes glitches. (FIXME)
2382 //if(unlikely(process->pid != pid_out)) {
2383 // g_assert(process->pid == 0);
2385 if(process
->pid
== 0
2386 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2388 /* Scheduling out of pid 0 at beginning of the trace :
2389 * we know for sure it is in syscall mode at this point. */
2390 g_assert(process
->execution_stack
->len
== 1);
2391 process
->state
->t
= LTTV_STATE_SYSCALL
;
2392 process
->state
->s
= LTTV_STATE_WAIT
;
2393 process
->state
->change
= s
->parent
.timestamp
;
2394 process
->state
->entry
= s
->parent
.timestamp
;
2397 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2398 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2399 process
->state
->change
= s
->parent
.timestamp
;
2401 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2402 else process
->state
->s
= LTTV_STATE_WAIT
;
2403 process
->state
->change
= s
->parent
.timestamp
;
2406 if(state_out
== 32 || state_out
== 128)
2407 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2408 /* see sched.h for states */
2411 process
= ts
->running_process
[cpu
] =
2412 lttv_state_find_process_or_create(
2413 (LttvTraceState
*)s
->parent
.t_context
,
2415 &s
->parent
.timestamp
);
2416 process
->state
->s
= LTTV_STATE_RUN
;
2418 if(process
->usertrace
)
2419 process
->usertrace
->cpu
= cpu
;
2420 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2421 process
->state
->change
= s
->parent
.timestamp
;
2423 /* update cpu status */
2425 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2427 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2432 static gboolean
process_fork(void *hook_data
, void *call_data
)
2434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2435 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2436 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2438 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2439 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2440 LttvProcessState
*zombie_process
;
2442 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2443 LttvProcessState
*process
= ts
->running_process
[cpu
];
2444 LttvProcessState
*child_process
;
2447 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2450 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2451 s
->parent
.target_pid
= child_pid
;
2454 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2455 else child_tgid
= 0;
2457 /* Mathieu : it seems like the process might have been scheduled in before the
2458 * fork, and, in a rare case, might be the current process. This might happen
2459 * in a SMP case where we don't have enough precision on the clocks.
2461 * Test reenabled after precision fixes on time. (Mathieu) */
2463 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2465 if(unlikely(zombie_process
!= NULL
)) {
2466 /* Reutilisation of PID. Only now we are sure that the old PID
2467 * has been released. FIXME : should know when release_task happens instead.
2469 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2471 for(i
=0; i
< num_cpus
; i
++) {
2472 g_assert(zombie_process
!= ts
->running_process
[i
]);
2475 exit_process(s
, zombie_process
);
2478 g_assert(process
->pid
!= child_pid
);
2479 // FIXME : Add this test in the "known state" section
2480 // g_assert(process->pid == parent_pid);
2481 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2482 if(child_process
== NULL
) {
2483 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2484 child_pid
, child_tgid
,
2485 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2487 /* The process has already been created : due to time imprecision between
2488 * multiple CPUs : it has been scheduled in before creation. Note that we
2489 * shouldn't have this kind of imprecision.
2491 * Simply put a correct parent.
2493 g_assert(0); /* This is a problematic case : the process has been created
2494 before the fork event */
2495 child_process
->ppid
= process
->pid
;
2496 child_process
->tgid
= child_tgid
;
2498 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2499 child_process
->name
= process
->name
;
2500 child_process
->brand
= process
->brand
;
2505 /* We stamp a newly created process as kernel_thread.
2506 * The thread should not be running yet. */
2507 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2509 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2510 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2511 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2514 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2515 LttvProcessState
*process
;
2516 LttvExecutionState
*es
;
2519 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2520 s
->parent
.target_pid
= pid
;
2522 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2524 process
->execution_stack
=
2525 g_array_set_size(process
->execution_stack
, 1);
2526 es
= process
->state
=
2527 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2528 es
->t
= LTTV_STATE_SYSCALL
;
2529 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2534 static gboolean
process_exit(void *hook_data
, void *call_data
)
2536 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2537 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2538 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2542 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2543 LttvProcessState
*process
; // = ts->running_process[cpu];
2545 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2546 s
->parent
.target_pid
= pid
;
2548 // FIXME : Add this test in the "known state" section
2549 // g_assert(process->pid == pid);
2551 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2552 if(likely(process
!= NULL
)) {
2553 process
->state
->s
= LTTV_STATE_EXIT
;
2558 static gboolean
process_free(void *hook_data
, void *call_data
)
2560 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2561 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2562 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2563 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2565 LttvProcessState
*process
;
2567 /* PID of the process to release */
2568 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2569 s
->parent
.target_pid
= release_pid
;
2571 g_assert(release_pid
!= 0);
2573 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2575 if(likely(process
!= NULL
)) {
2576 /* release_task is happening at kernel level : we can now safely release
2577 * the data structure of the process */
2578 //This test is fun, though, as it may happen that
2579 //at time t : CPU 0 : process_free
2580 //at time t+150ns : CPU 1 : schedule out
2581 //Clearly due to time imprecision, we disable it. (Mathieu)
2582 //If this weird case happen, we have no choice but to put the
2583 //Currently running process on the cpu to 0.
2584 //I re-enable it following time precision fixes. (Mathieu)
2585 //Well, in the case where an process is freed by a process on another CPU
2586 //and still scheduled, it happens that this is the schedchange that will
2587 //drop the last reference count. Do not free it here!
2588 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2590 for(i
=0; i
< num_cpus
; i
++) {
2591 //g_assert(process != ts->running_process[i]);
2592 if(process
== ts
->running_process
[i
]) {
2593 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2597 if(i
== num_cpus
) /* process is not scheduled */
2598 exit_process(s
, process
);
2605 static gboolean
process_exec(void *hook_data
, void *call_data
)
2607 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2608 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2609 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2610 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2613 LttvProcessState
*process
= ts
->running_process
[cpu
];
2615 #if 0//how to use a sequence that must be transformed in a string
2616 /* PID of the process to release */
2617 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2618 //name = ltt_event_get_string(e, thf->f1);
2619 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2621 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2622 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2623 memcpy(null_term_name
, name_begin
, name_len
);
2624 null_term_name
[name_len
] = '\0';
2625 process
->name
= g_quark_from_string(null_term_name
);
2628 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2629 process
->brand
= LTTV_STATE_UNBRANDED
;
2630 //g_free(null_term_name);
2634 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2636 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2637 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2638 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2639 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2642 LttvProcessState
*process
= ts
->running_process
[cpu
];
2644 name
= ltt_event_get_string(e
, thf
->f1
);
2645 process
->brand
= g_quark_from_string(name
);
2650 static void fix_process(gpointer key
, gpointer value
,
2653 LttvProcessState
*process
;
2654 LttvExecutionState
*es
;
2655 process
= (LttvProcessState
*)value
;
2656 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2657 LttTime
*timestamp
= (LttTime
*)user_data
;
2659 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2660 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2661 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2662 es
->t
= LTTV_STATE_SYSCALL
;
2663 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2664 es
->entry
= *timestamp
;
2665 es
->change
= *timestamp
;
2666 es
->cum_cpu_time
= ltt_time_zero
;
2667 if(es
->s
== LTTV_STATE_UNNAMED
)
2668 es
->s
= LTTV_STATE_WAIT
;
2671 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2672 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2673 es
->t
= LTTV_STATE_USER_MODE
;
2674 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2675 es
->entry
= *timestamp
;
2676 //g_assert(timestamp->tv_sec != 0);
2677 es
->change
= *timestamp
;
2678 es
->cum_cpu_time
= ltt_time_zero
;
2679 if(es
->s
== LTTV_STATE_UNNAMED
)
2680 es
->s
= LTTV_STATE_RUN
;
2682 if(process
->execution_stack
->len
== 1) {
2683 /* Still in bottom unknown mode, means never did a system call
2684 * May be either in user mode, syscall mode, running or waiting.*/
2685 /* FIXME : we may be tagging syscall mode when being user mode */
2686 process
->execution_stack
=
2687 g_array_set_size(process
->execution_stack
, 2);
2688 es
= process
->state
= &g_array_index(process
->execution_stack
,
2689 LttvExecutionState
, 1);
2690 es
->t
= LTTV_STATE_SYSCALL
;
2691 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2692 es
->entry
= *timestamp
;
2693 //g_assert(timestamp->tv_sec != 0);
2694 es
->change
= *timestamp
;
2695 es
->cum_cpu_time
= ltt_time_zero
;
2696 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2697 es
->s
= LTTV_STATE_WAIT
;
2703 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2705 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2706 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2707 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2708 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2709 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2711 /* For all processes */
2712 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2713 /* else, if stack[0] is unknown, set to user mode, running */
2715 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2718 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2720 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2721 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2722 //It's slow : optimise later by doing this before reading trace.
2723 LttEventType
*et
= ltt_event_eventtype(e
);
2725 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2731 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2732 LttvProcessState
*process
= ts
->running_process
[cpu
];
2733 LttvProcessState
*parent_process
;
2734 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2735 GQuark type
, mode
, submode
, status
;
2736 LttvExecutionState
*es
;
2740 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2741 s
->parent
.target_pid
= pid
;
2744 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2747 command
= ltt_event_get_string(e
, thf
->f3
);
2750 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2751 type
= ltt_enum_string_get(ltt_field_type(f4
),
2752 ltt_event_get_unsigned(e
, f4
));
2755 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2756 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2757 ltt_event_get_unsigned(e
, f5
));
2760 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2761 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2762 ltt_event_get_unsigned(e
, f6
));
2765 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2766 status
= ltt_enum_string_get(ltt_field_type(f7
),
2767 ltt_event_get_unsigned(e
, f7
));
2770 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2771 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2776 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2777 for(i
=0; i
<nb_cpus
; i
++) {
2778 process
= lttv_state_find_process(ts
, i
, pid
);
2779 g_assert(process
!= NULL
);
2781 process
->ppid
= parent_pid
;
2782 process
->tgid
= tgid
;
2783 process
->name
= g_quark_from_string(command
);
2785 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2786 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2790 /* The process might exist if a process was forked while performing the
2792 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2793 if(process
== NULL
) {
2794 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2795 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2796 pid
, tgid
, g_quark_from_string(command
),
2797 &s
->parent
.timestamp
);
2799 /* Keep the stack bottom : a running user mode */
2800 /* Disabled because of inconsistencies in the current statedump states. */
2801 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2802 /* Only keep the bottom
2803 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2804 /* Will cause expected trap when in fact being syscall (even after end of
2806 * Will cause expected interrupt when being syscall. (only before end of
2807 * statedump event) */
2808 // This will cause a "popping last state on stack, ignoring it."
2809 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2810 es
= process
->state
= &g_array_index(process
->execution_stack
,
2811 LttvExecutionState
, 0);
2812 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2813 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2814 es
->s
= LTTV_STATE_UNNAMED
;
2815 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2817 es
->t
= LTTV_STATE_SYSCALL
;
2822 /* User space process :
2823 * bottom : user mode
2824 * either currently running or scheduled out.
2825 * can be scheduled out because interrupted in (user mode or in syscall)
2826 * or because of an explicit call to the scheduler in syscall. Note that
2827 * the scheduler call comes after the irq_exit, so never in interrupt
2829 // temp workaround : set size to 1 : only have user mode bottom of stack.
2830 // will cause g_info message of expected syscall mode when in fact being
2831 // in user mode. Can also cause expected trap when in fact being user
2832 // mode in the event of a page fault reenabling interrupts in the handler.
2833 // Expected syscall and trap can also happen after the end of statedump
2834 // This will cause a "popping last state on stack, ignoring it."
2835 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2836 es
= process
->state
= &g_array_index(process
->execution_stack
,
2837 LttvExecutionState
, 0);
2838 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2839 es
->s
= LTTV_STATE_UNNAMED
;
2840 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2842 es
->t
= LTTV_STATE_USER_MODE
;
2850 es
= process
->state
= &g_array_index(process
->execution_stack
,
2851 LttvExecutionState
, 1);
2852 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2853 es
->s
= LTTV_STATE_UNNAMED
;
2854 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2858 /* The process has already been created :
2859 * Probably was forked while dumping the process state or
2860 * was simply scheduled in prior to get the state dump event.
2862 process
->ppid
= parent_pid
;
2863 process
->tgid
= tgid
;
2864 process
->name
= g_quark_from_string(command
);
2865 process
->type
= type
;
2867 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2869 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2870 if(type
== LTTV_STATE_KERNEL_THREAD
)
2871 es
->t
= LTTV_STATE_SYSCALL
;
2873 es
->t
= LTTV_STATE_USER_MODE
;
2876 /* Don't mess around with the stack, it will eventually become
2877 * ok after the end of state dump. */
2884 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2886 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2888 lttv_state_add_event_hooks(tss
);
2893 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2895 LttvTraceset
*traceset
= self
->parent
.ts
;
2897 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2901 LttvTracefileState
*tfs
;
2905 LttvTraceHookByFacility
*thf
;
2907 LttvTraceHook
*hook
;
2909 LttvAttributeValue val
;
2914 nb_trace
= lttv_traceset_number(traceset
);
2915 for(i
= 0 ; i
< nb_trace
; i
++) {
2916 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2918 /* Find the eventtype id for the following events and register the
2919 associated by id hooks. */
2921 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2922 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2925 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2926 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2927 LTT_FIELD_SYSCALL_ID
, 0, 0,
2928 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2931 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2932 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2934 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2937 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2938 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2939 LTT_FIELD_TRAP_ID
, 0, 0,
2940 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2943 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2944 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2946 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2949 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2950 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2951 LTT_FIELD_IRQ_ID
, 0, 0,
2952 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2955 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2956 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2958 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2961 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2962 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2963 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2964 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2967 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2968 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2970 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2973 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2974 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2975 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2976 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2979 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2980 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2981 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2982 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2985 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2986 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2987 LTT_FIELD_PID
, 0, 0,
2988 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2992 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2993 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2994 LTT_FIELD_PID
, 0, 0,
2995 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2998 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2999 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3000 LTT_FIELD_PID
, 0, 0,
3001 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3004 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3005 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3006 LTT_FIELD_FILENAME
, 0, 0,
3007 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3010 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3011 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3012 LTT_FIELD_NAME
, 0, 0,
3013 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3016 /* statedump-related hooks */
3017 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3018 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3019 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3020 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3023 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3024 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3026 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3029 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3030 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3031 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3032 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3035 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3036 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3037 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3038 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3041 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3042 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3043 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3044 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3047 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3048 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3049 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3050 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3053 hooks
= g_array_set_size(hooks
, hn
);
3055 /* Add these hooks to each event_by_id hooks list */
3057 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3059 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3061 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3062 LttvTracefileContext
*, j
));
3064 for(k
= 0 ; k
< hooks
->len
; k
++) {
3065 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3066 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3067 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3069 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3076 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3077 *(val
.v_pointer
) = hooks
;
3081 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3083 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3085 lttv_state_remove_event_hooks(tss
);
3090 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3092 LttvTraceset
*traceset
= self
->parent
.ts
;
3094 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3098 LttvTracefileState
*tfs
;
3102 LttvTraceHook
*hook
;
3104 LttvTraceHookByFacility
*thf
;
3106 LttvAttributeValue val
;
3108 nb_trace
= lttv_traceset_number(traceset
);
3109 for(i
= 0 ; i
< nb_trace
; i
++) {
3110 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3112 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3113 hooks
= *(val
.v_pointer
);
3115 /* Remove these hooks from each event_by_id hooks list */
3117 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3119 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3121 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3122 LttvTracefileContext
*, j
));
3124 for(k
= 0 ; k
< hooks
->len
; k
++) {
3125 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3126 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3127 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3129 lttv_hooks_remove_data(
3130 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3136 for(k
= 0 ; k
< hooks
->len
; k
++)
3137 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3138 g_array_free(hooks
, TRUE
);
3142 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3144 guint
*event_count
= (guint
*)hook_data
;
3146 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3147 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3152 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3154 LttvTracefileState
*tfcs
;
3156 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3158 LttEventPosition
*ep
;
3164 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3166 LttvAttributeValue value
;
3168 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3169 LTTV_STATE_SAVED_STATES
);
3170 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3171 value
= lttv_attribute_add(saved_states_tree
,
3172 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3173 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3174 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3175 *(value
.v_time
) = self
->parent
.timestamp
;
3176 lttv_state_save(tcs
, saved_state_tree
);
3177 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3178 self
->parent
.timestamp
.tv_nsec
);
3180 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3185 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3187 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3189 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3194 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3202 static gboolean
block_start(void *hook_data
, void *call_data
)
3204 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3206 LttvTracefileState
*tfcs
;
3208 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3210 LttEventPosition
*ep
;
3212 guint i
, nb_block
, nb_event
, nb_tracefile
;
3216 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3218 LttvAttributeValue value
;
3220 ep
= ltt_event_position_new();
3222 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3224 /* Count the number of events added since the last block end in any
3227 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3229 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3230 LttvTracefileContext
, i
));
3231 ltt_event_position(tfcs
->parent
.e
, ep
);
3232 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3233 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3234 tfcs
->saved_position
= nb_event
;
3238 if(tcs
->nb_event
>= tcs
->save_interval
) {
3239 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3240 LTTV_STATE_SAVED_STATES
);
3241 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3242 value
= lttv_attribute_add(saved_states_tree
,
3243 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3244 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3245 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3246 *(value
.v_time
) = self
->parent
.timestamp
;
3247 lttv_state_save(tcs
, saved_state_tree
);
3249 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3250 self
->parent
.timestamp
.tv_nsec
);
3252 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3258 static gboolean
block_end(void *hook_data
, void *call_data
)
3260 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3262 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3266 LttEventPosition
*ep
;
3268 guint nb_block
, nb_event
;
3270 ep
= ltt_event_position_new();
3271 ltt_event_position(self
->parent
.e
, ep
);
3272 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3273 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3274 self
->saved_position
= 0;
3275 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3282 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3284 LttvTraceset
*traceset
= self
->parent
.ts
;
3286 guint i
, j
, nb_trace
, nb_tracefile
;
3290 LttvTracefileState
*tfs
;
3292 LttvTraceHook hook_start
, hook_end
;
3294 nb_trace
= lttv_traceset_number(traceset
);
3295 for(i
= 0 ; i
< nb_trace
; i
++) {
3296 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3298 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3299 NULL
, NULL
, block_start
, &hook_start
);
3300 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3301 NULL
, NULL
, block_end
, &hook_end
);
3303 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3305 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3307 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3308 LttvTracefileContext
, j
));
3309 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3310 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3311 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3312 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3318 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3320 LttvTraceset
*traceset
= self
->parent
.ts
;
3322 guint i
, j
, nb_trace
, nb_tracefile
;
3326 LttvTracefileState
*tfs
;
3329 nb_trace
= lttv_traceset_number(traceset
);
3330 for(i
= 0 ; i
< nb_trace
; i
++) {
3332 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3333 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3335 if(ts
->has_precomputed_states
) continue;
3337 guint
*event_count
= g_new(guint
, 1);
3340 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3342 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3343 LttvTracefileContext
*, j
));
3344 lttv_hooks_add(tfs
->parent
.event
,
3345 state_save_event_hook
,
3352 lttv_process_traceset_begin(&self
->parent
,
3353 NULL
, NULL
, NULL
, NULL
, NULL
);
3357 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3359 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3361 lttv_state_save_add_event_hooks(tss
);
3368 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3370 LttvTraceset
*traceset
= self
->parent
.ts
;
3372 guint i
, j
, nb_trace
, nb_tracefile
;
3376 LttvTracefileState
*tfs
;
3378 LttvTraceHook hook_start
, hook_end
;
3380 nb_trace
= lttv_traceset_number(traceset
);
3381 for(i
= 0 ; i
< nb_trace
; i
++) {
3382 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3384 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3385 NULL
, NULL
, block_start
, &hook_start
);
3387 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3388 NULL
, NULL
, block_end
, &hook_end
);
3390 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3392 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3394 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3395 LttvTracefileContext
, j
));
3396 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3397 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3398 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3399 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3405 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3407 LttvTraceset
*traceset
= self
->parent
.ts
;
3409 guint i
, j
, nb_trace
, nb_tracefile
;
3413 LttvTracefileState
*tfs
;
3415 LttvHooks
*after_trace
= lttv_hooks_new();
3417 lttv_hooks_add(after_trace
,
3418 state_save_after_trace_hook
,
3423 lttv_process_traceset_end(&self
->parent
,
3424 NULL
, after_trace
, NULL
, NULL
, NULL
);
3426 lttv_hooks_destroy(after_trace
);
3428 nb_trace
= lttv_traceset_number(traceset
);
3429 for(i
= 0 ; i
< nb_trace
; i
++) {
3431 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3432 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3434 if(ts
->has_precomputed_states
) continue;
3436 guint
*event_count
= NULL
;
3438 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3440 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3441 LttvTracefileContext
*, j
));
3442 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3443 state_save_event_hook
);
3445 if(event_count
) g_free(event_count
);
3449 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3451 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3453 lttv_state_save_remove_event_hooks(tss
);
3458 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3460 LttvTraceset
*traceset
= self
->parent
.ts
;
3464 int min_pos
, mid_pos
, max_pos
;
3466 guint call_rest
= 0;
3468 LttvTraceState
*tcs
;
3470 LttvAttributeValue value
;
3472 LttvAttributeType type
;
3474 LttvAttributeName name
;
3478 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3480 //g_tree_destroy(self->parent.pqueue);
3481 //self->parent.pqueue = g_tree_new(compare_tracefile);
3483 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3485 nb_trace
= lttv_traceset_number(traceset
);
3486 for(i
= 0 ; i
< nb_trace
; i
++) {
3487 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3489 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3490 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3491 LTTV_STATE_SAVED_STATES
);
3494 if(saved_states_tree
) {
3495 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3496 mid_pos
= max_pos
/ 2;
3497 while(min_pos
< max_pos
) {
3498 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3500 g_assert(type
== LTTV_GOBJECT
);
3501 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3502 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3504 g_assert(type
== LTTV_TIME
);
3505 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3507 closest_tree
= saved_state_tree
;
3509 else max_pos
= mid_pos
- 1;
3511 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3515 /* restore the closest earlier saved state */
3517 lttv_state_restore(tcs
, closest_tree
);
3521 /* There is no saved state, yet we want to have it. Restart at T0 */
3523 restore_init_state(tcs
);
3524 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3527 /* We want to seek quickly without restoring/updating the state */
3529 restore_init_state(tcs
);
3530 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3533 if(!call_rest
) g_info("NOT Calling restore");
3538 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3544 traceset_state_finalize (LttvTracesetState
*self
)
3546 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3547 finalize(G_OBJECT(self
));
3552 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3554 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3556 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3557 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3558 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3559 klass
->new_traceset_context
= new_traceset_context
;
3560 klass
->new_trace_context
= new_trace_context
;
3561 klass
->new_tracefile_context
= new_tracefile_context
;
3566 lttv_traceset_state_get_type(void)
3568 static GType type
= 0;
3570 static const GTypeInfo info
= {
3571 sizeof (LttvTracesetStateClass
),
3572 NULL
, /* base_init */
3573 NULL
, /* base_finalize */
3574 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3575 NULL
, /* class_finalize */
3576 NULL
, /* class_data */
3577 sizeof (LttvTracesetState
),
3578 0, /* n_preallocs */
3579 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3580 NULL
/* value handling */
3583 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3591 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3597 trace_state_finalize (LttvTraceState
*self
)
3599 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3600 finalize(G_OBJECT(self
));
3605 trace_state_class_init (LttvTraceStateClass
*klass
)
3607 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3609 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3610 klass
->state_save
= state_save
;
3611 klass
->state_restore
= state_restore
;
3612 klass
->state_saved_free
= state_saved_free
;
3617 lttv_trace_state_get_type(void)
3619 static GType type
= 0;
3621 static const GTypeInfo info
= {
3622 sizeof (LttvTraceStateClass
),
3623 NULL
, /* base_init */
3624 NULL
, /* base_finalize */
3625 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3626 NULL
, /* class_finalize */
3627 NULL
, /* class_data */
3628 sizeof (LttvTraceState
),
3629 0, /* n_preallocs */
3630 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3631 NULL
/* value handling */
3634 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3635 "LttvTraceStateType", &info
, 0);
3642 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3648 tracefile_state_finalize (LttvTracefileState
*self
)
3650 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3651 finalize(G_OBJECT(self
));
3656 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3658 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3660 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3665 lttv_tracefile_state_get_type(void)
3667 static GType type
= 0;
3669 static const GTypeInfo info
= {
3670 sizeof (LttvTracefileStateClass
),
3671 NULL
, /* base_init */
3672 NULL
, /* base_finalize */
3673 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3674 NULL
, /* class_finalize */
3675 NULL
, /* class_data */
3676 sizeof (LttvTracefileState
),
3677 0, /* n_preallocs */
3678 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3679 NULL
/* value handling */
3682 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3683 "LttvTracefileStateType", &info
, 0);
3689 static void module_init()
3691 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3692 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3693 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3694 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3695 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3696 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3697 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3698 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3699 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3700 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3701 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3702 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3703 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3704 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3705 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3706 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3707 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3708 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3709 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3710 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3711 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3712 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3713 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3714 LTTV_STATE_EVENT
= g_quark_from_string("event");
3715 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3716 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3717 LTTV_STATE_TIME
= g_quark_from_string("time");
3718 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3719 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3720 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3721 g_quark_from_string("trace_state_use_count");
3722 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3725 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3726 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3727 LTT_FACILITY_FS
= g_quark_from_string("fs");
3728 LTT_FACILITY_LIST
= g_quark_from_string("list");
3729 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3730 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3733 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3734 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3735 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3736 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3737 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3738 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3739 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3740 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3741 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3742 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3743 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3744 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3745 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3746 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3747 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3748 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3749 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3750 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3751 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3752 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3753 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3756 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3757 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3758 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3759 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3760 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3761 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3762 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3763 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3764 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3765 LTT_FIELD_PID
= g_quark_from_string("pid");
3766 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3767 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3768 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3769 LTT_FIELD_NAME
= g_quark_from_string("name");
3770 LTT_FIELD_TYPE
= g_quark_from_string("type");
3771 LTT_FIELD_MODE
= g_quark_from_string("mode");
3772 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3773 LTT_FIELD_STATUS
= g_quark_from_string("status");
3774 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3775 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3776 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3777 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3778 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3780 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3781 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3782 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3783 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3784 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3786 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3787 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3788 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3790 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3791 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3792 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3793 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3796 static void module_destroy()
3801 LTTV_MODULE("state", "State computation", \
3802 "Update the system state, possibly saving it at intervals", \
3803 module_init
, module_destroy
)