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
,
167 LTTV_STATE_RESOURCE_IRQS
;
169 static void create_max_time(LttvTraceState
*tcs
);
171 static void get_max_time(LttvTraceState
*tcs
);
173 static void free_max_time(LttvTraceState
*tcs
);
175 static void create_name_tables(LttvTraceState
*tcs
);
177 static void get_name_tables(LttvTraceState
*tcs
);
179 static void free_name_tables(LttvTraceState
*tcs
);
181 static void free_saved_state(LttvTraceState
*tcs
);
183 static void lttv_state_free_process_table(GHashTable
*processes
);
185 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
186 GPtrArray
*quarktable
);
188 /* Resource function prototypes */
189 static void bdev_state_free(gpointer key
, gpointer value
, gpointer user_data
);
190 static LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
);
193 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
195 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
199 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
201 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
205 void lttv_state_state_saved_free(LttvTraceState
*self
,
206 LttvAttribute
*container
)
208 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
212 guint
process_hash(gconstpointer key
)
214 guint pid
= ((const LttvProcessState
*)key
)->pid
;
215 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
219 /* If the hash table hash function is well distributed,
220 * the process_equal should compare different pid */
221 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
223 const LttvProcessState
*process_a
, *process_b
;
226 process_a
= (const LttvProcessState
*)a
;
227 process_b
= (const LttvProcessState
*)b
;
229 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
230 else if(likely(process_a
->pid
== 0 &&
231 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
236 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
238 g_tree_destroy((GTree
*)value
);
241 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
243 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
244 g_hash_table_destroy(usertraces
);
250 restore_init_state(LttvTraceState
*self
)
252 guint i
, nb_cpus
, nb_irqs
;
254 LttvTracefileState
*tfcs
;
256 LttTime start_time
, end_time
;
258 /* Free the process tables */
259 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
260 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
261 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
262 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
265 /* Seek time to beginning */
266 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
267 // closest. It's the tracecontext job to seek the trace to the beginning
268 // anyway : the init state might be used at the middle of the trace as well...
269 //g_tree_destroy(self->parent.ts_context->pqueue);
270 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
272 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
274 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
276 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
277 nb_irqs
= self
->nb_irqs
;
279 /* Put the per cpu running_process to beginning state : process 0. */
280 for(i
=0; i
< nb_cpus
; i
++) {
281 LttvExecutionState
*es
;
282 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
283 LTTV_STATE_UNNAMED
, &start_time
);
284 /* We are not sure is it's a kernel thread or normal thread, put the
285 * bottom stack state to unknown */
286 self
->running_process
[i
]->execution_stack
=
287 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
288 es
= self
->running_process
[i
]->state
=
289 &g_array_index(self
->running_process
[i
]->execution_stack
,
290 LttvExecutionState
, 0);
291 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
292 es
->s
= LTTV_STATE_UNNAMED
;
294 //self->running_process[i]->state->s = LTTV_STATE_RUN;
295 self
->running_process
[i
]->cpu
= i
;
297 /* reset cpu states */
298 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
299 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
302 for(i
=0; i
<nb_irqs
; i
++) {
303 if(self
->irq_states
[i
].mode_stack
->len
> 0)
304 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
307 g_hash_table_foreach(self
->bdev_states
, bdev_state_free
, NULL
);
308 g_hash_table_steal_all(self
->bdev_states
);
311 nb_tracefile
= self
->parent
.tracefiles
->len
;
313 for(i
= 0 ; i
< nb_tracefile
; i
++) {
315 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
316 LttvTracefileContext
*, i
));
317 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
318 // tfcs->saved_position = 0;
319 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
320 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
321 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
322 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
327 //static LttTime time_zero = {0,0};
329 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
332 const LttTime
*t1
= (const LttTime
*)a
;
333 const LttTime
*t2
= (const LttTime
*)b
;
335 return ltt_time_compare(*t1
, *t2
);
338 static void free_usertrace_key(gpointer data
)
343 #define MAX_STRING_LEN 4096
346 state_load_saved_states(LttvTraceState
*tcs
)
349 GPtrArray
*quarktable
;
354 tcs
->has_precomputed_states
= FALSE
;
358 gchar buf
[MAX_STRING_LEN
];
361 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
362 strncpy(path
, trace_path
, PATH_MAX
-1);
363 count
= strnlen(trace_path
, PATH_MAX
-1);
364 // quarktable : open, test
365 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
366 fp
= fopen(path
, "r");
368 quarktable
= g_ptr_array_sized_new(4096);
370 /* Index 0 is null */
372 if(hdr
== EOF
) return;
373 g_assert(hdr
== HDR_QUARKS
);
377 if(hdr
== EOF
) break;
378 g_assert(hdr
== HDR_QUARK
);
379 g_ptr_array_set_size(quarktable
, q
+1);
382 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
383 if(buf
[i
] == '\0' || feof(fp
)) break;
386 len
= strnlen(buf
, MAX_STRING_LEN
-1);
387 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
388 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
394 // saved_states : open, test
395 strncpy(path
, trace_path
, PATH_MAX
-1);
396 count
= strnlen(trace_path
, PATH_MAX
-1);
397 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
398 fp
= fopen(path
, "r");
402 if(hdr
!= HDR_TRACE
) goto end
;
404 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
406 tcs
->has_precomputed_states
= TRUE
;
411 /* Free the quarktable */
412 for(i
=0; i
<quarktable
->len
; i
++) {
413 string
= g_ptr_array_index (quarktable
, i
);
416 g_ptr_array_free(quarktable
, TRUE
);
421 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
423 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
426 LttvTraceContext
*tc
;
430 LttvTracefileState
*tfcs
;
432 LttvAttributeValue v
;
434 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
435 init((LttvTracesetContext
*)self
, ts
);
437 nb_trace
= lttv_traceset_number(ts
);
438 for(i
= 0 ; i
< nb_trace
; i
++) {
439 tc
= self
->parent
.traces
[i
];
440 tcs
= LTTV_TRACE_STATE(tc
);
441 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
442 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
446 if(*(v
.v_uint
) == 1) {
447 create_name_tables(tcs
);
448 create_max_time(tcs
);
450 get_name_tables(tcs
);
453 nb_tracefile
= tc
->tracefiles
->len
;
454 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
455 nb_irq
= tcs
->nb_irqs
;
456 tcs
->processes
= NULL
;
457 tcs
->usertraces
= NULL
;
458 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
460 /* init cpu resource stuff */
461 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
462 for(j
= 0; j
<nb_cpu
; j
++) {
463 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
464 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
467 /* init irq resource stuff */
468 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
469 for(j
= 0; j
<nb_irq
; j
++) {
470 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
471 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
474 /* init bdev resource stuff */
475 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
477 restore_init_state(tcs
);
478 for(j
= 0 ; j
< nb_tracefile
; j
++) {
480 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
481 LttvTracefileContext
*, j
));
482 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
483 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
484 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
485 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
486 /* It's a Usertrace */
487 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
488 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
490 if(!usertrace_tree
) {
491 usertrace_tree
= g_tree_new_full(compare_usertraces
,
492 NULL
, free_usertrace_key
, NULL
);
493 g_hash_table_insert(tcs
->usertraces
,
494 (gpointer
)tid
, usertrace_tree
);
496 LttTime
*timestamp
= g_new(LttTime
, 1);
497 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
498 ltt_tracefile_creation(tfcs
->parent
.tf
));
499 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
503 /* See if the trace has saved states */
504 state_load_saved_states(tcs
);
509 fini(LttvTracesetState
*self
)
515 LttvTracefileState
*tfcs
;
517 LttvAttributeValue v
;
519 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
520 for(i
= 0 ; i
< nb_trace
; i
++) {
521 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
522 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
525 g_assert(*(v
.v_uint
) != 0);
528 if(*(v
.v_uint
) == 0) {
529 free_name_tables(tcs
);
531 free_saved_state(tcs
);
533 g_free(tcs
->running_process
);
534 tcs
->running_process
= NULL
;
535 lttv_state_free_process_table(tcs
->processes
);
536 lttv_state_free_usertraces(tcs
->usertraces
);
537 tcs
->processes
= NULL
;
538 tcs
->usertraces
= NULL
;
540 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
541 fini((LttvTracesetContext
*)self
);
545 static LttvTracesetContext
*
546 new_traceset_context(LttvTracesetContext
*self
)
548 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
552 static LttvTraceContext
*
553 new_trace_context(LttvTracesetContext
*self
)
555 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
559 static LttvTracefileContext
*
560 new_tracefile_context(LttvTracesetContext
*self
)
562 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
566 /* Write the process state of the trace */
568 static void write_process_state(gpointer key
, gpointer value
,
571 LttvProcessState
*process
;
573 LttvExecutionState
*es
;
575 FILE *fp
= (FILE *)user_data
;
580 process
= (LttvProcessState
*)value
;
582 " <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",
583 process
, process
->pid
, process
->tgid
, process
->ppid
,
584 g_quark_to_string(process
->type
),
585 process
->creation_time
.tv_sec
,
586 process
->creation_time
.tv_nsec
,
587 process
->insertion_time
.tv_sec
,
588 process
->insertion_time
.tv_nsec
,
589 g_quark_to_string(process
->name
),
590 g_quark_to_string(process
->brand
),
593 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
594 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
595 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
596 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
597 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
598 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
599 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
602 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
603 address
= &g_array_index(process
->user_stack
, guint64
, i
);
604 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
608 if(process
->usertrace
) {
609 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
610 g_quark_to_string(process
->usertrace
->tracefile_name
),
611 process
->usertrace
->cpu
);
615 fprintf(fp
, " </PROCESS>\n");
619 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
621 guint i
, nb_tracefile
, nb_block
, offset
;
624 LttvTracefileState
*tfcs
;
628 LttEventPosition
*ep
;
632 ep
= ltt_event_position_new();
634 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
636 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
638 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
639 for(i
=0;i
<nb_cpus
;i
++) {
640 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
641 i
, self
->running_process
[i
]->pid
);
644 nb_tracefile
= self
->parent
.tracefiles
->len
;
646 for(i
= 0 ; i
< nb_tracefile
; i
++) {
648 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
649 LttvTracefileContext
*, i
));
650 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
651 tfcs
->parent
.timestamp
.tv_sec
,
652 tfcs
->parent
.timestamp
.tv_nsec
);
653 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
654 if(e
== NULL
) fprintf(fp
,"/>\n");
656 ltt_event_position(e
, ep
);
657 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
658 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
663 fprintf(fp
,"</PROCESS_STATE>\n");
667 static void write_process_state_raw(gpointer key
, gpointer value
,
670 LttvProcessState
*process
;
672 LttvExecutionState
*es
;
674 FILE *fp
= (FILE *)user_data
;
679 process
= (LttvProcessState
*)value
;
680 fputc(HDR_PROCESS
, fp
);
681 //fwrite(&header, sizeof(header), 1, fp);
682 //fprintf(fp, "%s", g_quark_to_string(process->type));
684 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
685 //fprintf(fp, "%s", g_quark_to_string(process->name));
687 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
688 //fprintf(fp, "%s", g_quark_to_string(process->brand));
690 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
691 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
692 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
693 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
694 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
695 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
696 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
700 " <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",
701 process
, process
->pid
, process
->tgid
, process
->ppid
,
702 g_quark_to_string(process
->type
),
703 process
->creation_time
.tv_sec
,
704 process
->creation_time
.tv_nsec
,
705 process
->insertion_time
.tv_sec
,
706 process
->insertion_time
.tv_nsec
,
707 g_quark_to_string(process
->name
),
708 g_quark_to_string(process
->brand
),
712 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
713 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
716 //fprintf(fp, "%s", g_quark_to_string(es->t));
718 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
719 //fprintf(fp, "%s", g_quark_to_string(es->n));
721 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
722 //fprintf(fp, "%s", g_quark_to_string(es->s));
724 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
725 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
726 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
727 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
729 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
730 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
731 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
732 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
733 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
737 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
738 address
= &g_array_index(process
->user_stack
, guint64
, i
);
739 fputc(HDR_USER_STACK
, fp
);
740 fwrite(&address
, sizeof(address
), 1, fp
);
742 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
747 if(process
->usertrace
) {
748 fputc(HDR_USERTRACE
, fp
);
749 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
751 fwrite(&process
->usertrace
->tracefile_name
,
752 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
753 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
755 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
756 g_quark_to_string(process
->usertrace
->tracefile_name
),
757 process
->usertrace
->cpu
);
764 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
766 guint i
, nb_tracefile
, nb_block
, offset
;
769 LttvTracefileState
*tfcs
;
773 LttEventPosition
*ep
;
777 ep
= ltt_event_position_new();
779 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
780 fputc(HDR_PROCESS_STATE
, fp
);
781 fwrite(&t
, sizeof(t
), 1, fp
);
783 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
785 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
786 for(i
=0;i
<nb_cpus
;i
++) {
788 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
789 fwrite(&self
->running_process
[i
]->pid
,
790 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
791 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
792 // i, self->running_process[i]->pid);
795 nb_tracefile
= self
->parent
.tracefiles
->len
;
797 for(i
= 0 ; i
< nb_tracefile
; i
++) {
799 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
800 LttvTracefileContext
*, i
));
801 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
802 // tfcs->parent.timestamp.tv_sec,
803 // tfcs->parent.timestamp.tv_nsec);
804 fputc(HDR_TRACEFILE
, fp
);
805 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
806 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
807 * position following : end of trace */
808 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
810 ltt_event_position(e
, ep
);
811 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
812 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
814 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
815 fwrite(&offset
, sizeof(offset
), 1, fp
);
816 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
823 /* Read process state from a file */
825 /* Called because a HDR_PROCESS was found */
826 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
827 GPtrArray
*quarktable
)
829 LttvExecutionState
*es
;
830 LttvProcessState
*process
, *parent_process
;
831 LttvProcessState tmp
;
838 /* TODO : check return value */
839 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
840 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
841 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
842 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
843 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
844 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
845 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
846 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
847 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
850 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
852 /* We must link to the parent */
853 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
855 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
856 if(process
== NULL
) {
857 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
859 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
863 process
->insertion_time
= tmp
.insertion_time
;
864 process
->creation_time
= tmp
.creation_time
;
865 process
->type
= g_quark_from_string(
866 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
867 process
->tgid
= tmp
.tgid
;
868 process
->ppid
= tmp
.ppid
;
869 process
->brand
= g_quark_from_string(
870 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
872 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
876 if(feof(fp
) || ferror(fp
)) goto end_loop
;
878 gint hdr
= fgetc(fp
);
879 if(hdr
== EOF
) goto end_loop
;
883 process
->execution_stack
=
884 g_array_set_size(process
->execution_stack
,
885 process
->execution_stack
->len
+ 1);
886 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
887 process
->execution_stack
->len
-1);
890 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
891 es
->t
= g_quark_from_string(
892 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
893 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
894 es
->n
= g_quark_from_string(
895 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
896 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
897 es
->s
= g_quark_from_string(
898 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
899 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
900 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
901 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
904 process
->user_stack
= g_array_set_size(process
->user_stack
,
905 process
->user_stack
->len
+ 1);
906 address
= &g_array_index(process
->user_stack
, guint64
,
907 process
->user_stack
->len
-1);
908 fread(address
, sizeof(address
), 1, fp
);
909 process
->current_function
= *address
;
912 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
913 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
925 /* Called because a HDR_PROCESS_STATE was found */
926 /* Append a saved state to the trace states */
927 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
929 guint i
, nb_tracefile
, nb_block
, offset
;
931 LttvTracefileState
*tfcs
;
933 LttEventPosition
*ep
;
941 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
943 LttvAttributeValue value
;
944 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
945 ep
= ltt_event_position_new();
947 restore_init_state(self
);
949 fread(&t
, sizeof(t
), 1, fp
);
952 if(feof(fp
) || ferror(fp
)) goto end_loop
;
954 if(hdr
== EOF
) goto end_loop
;
958 /* Call read_process_state_raw */
959 read_process_state_raw(self
, fp
, quarktable
);
969 case HDR_PROCESS_STATE
:
975 g_error("Error while parsing saved state file : unknown data header %d",
981 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
982 for(i
=0;i
<nb_cpus
;i
++) {
985 g_assert(hdr
== HDR_CPU
);
986 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
987 g_assert(i
== cpu_num
);
988 fread(&self
->running_process
[i
]->pid
,
989 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
992 nb_tracefile
= self
->parent
.tracefiles
->len
;
994 for(i
= 0 ; i
< nb_tracefile
; i
++) {
996 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
997 LttvTracefileContext
*, i
));
998 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
999 // tfcs->parent.timestamp.tv_sec,
1000 // tfcs->parent.timestamp.tv_nsec);
1001 g_tree_remove(pqueue
, &tfcs
->parent
);
1003 g_assert(hdr
== HDR_TRACEFILE
);
1004 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1005 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1006 * position following : end of trace */
1007 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1008 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1009 fread(&offset
, sizeof(offset
), 1, fp
);
1010 fread(&tsc
, sizeof(tsc
), 1, fp
);
1011 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1012 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1014 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1019 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1020 LTTV_STATE_SAVED_STATES
);
1021 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1022 value
= lttv_attribute_add(saved_states_tree
,
1023 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1024 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1025 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1026 *(value
.v_time
) = t
;
1027 lttv_state_save(self
, saved_state_tree
);
1028 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1031 *(self
->max_time_state_recomputed_in_seek
) = t
;
1035 /* Called when a HDR_TRACE is found */
1036 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1037 GPtrArray
*quarktable
)
1042 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1044 if(hdr
== EOF
) goto end_loop
;
1047 case HDR_PROCESS_STATE
:
1048 /* Call read_process_state_raw */
1049 lttv_state_read_raw(tcs
, fp
, quarktable
);
1057 case HDR_USER_STACK
:
1061 g_error("Error while parsing saved state file :"
1062 " unexpected data header %d",
1066 g_error("Error while parsing saved state file : unknown data header %d",
1071 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1072 restore_init_state(tcs
);
1073 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1079 /* Copy each process from an existing hash table to a new one */
1081 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1083 LttvProcessState
*process
, *new_process
;
1085 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1089 process
= (LttvProcessState
*)value
;
1090 new_process
= g_new(LttvProcessState
, 1);
1091 *new_process
= *process
;
1092 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1093 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1094 new_process
->execution_stack
=
1095 g_array_set_size(new_process
->execution_stack
,
1096 process
->execution_stack
->len
);
1097 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1098 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1099 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1101 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1102 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1103 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1104 sizeof(guint64
), 0);
1105 new_process
->user_stack
=
1106 g_array_set_size(new_process
->user_stack
,
1107 process
->user_stack
->len
);
1108 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1109 g_array_index(new_process
->user_stack
, guint64
, i
) =
1110 g_array_index(process
->user_stack
, guint64
, i
);
1112 new_process
->current_function
= process
->current_function
;
1113 g_hash_table_insert(new_processes
, new_process
, new_process
);
1117 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1119 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1121 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1122 return new_processes
;
1125 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1128 LttvCPUState
*retval
;
1130 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1132 for(i
=0; i
<n
; i
++) {
1133 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1134 retval
[i
].last_irq
= states
[i
].last_irq
;
1135 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1136 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1137 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1144 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1148 for(i
=0; i
<n
; i
++) {
1149 g_array_free(states
[i
].mode_stack
, FALSE
);
1155 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1158 LttvIRQState
*retval
;
1160 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1162 for(i
=0; i
<n
; i
++) {
1163 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1164 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1165 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1166 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1173 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1177 for(i
=0; i
<n
; i
++) {
1178 g_array_free(states
[i
].mode_stack
, FALSE
);
1184 /* The saved state for each trace contains a member "processes", which
1185 stores a copy of the process table, and a member "tracefiles" with
1186 one entry per tracefile. Each tracefile has a "process" member pointing
1187 to the current process and a "position" member storing the tracefile
1188 position (needed to seek to the current "next" event. */
1190 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1192 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1194 LttvTracefileState
*tfcs
;
1196 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1198 guint
*running_process
;
1200 LttvAttributeType type
;
1202 LttvAttributeValue value
;
1204 LttvAttributeName name
;
1206 LttEventPosition
*ep
;
1208 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1209 LTTV_STATE_TRACEFILES
);
1211 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1213 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1215 /* Add the currently running processes array */
1216 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1217 running_process
= g_new(guint
, nb_cpus
);
1218 for(i
=0;i
<nb_cpus
;i
++) {
1219 running_process
[i
] = self
->running_process
[i
]->pid
;
1221 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1223 *(value
.v_pointer
) = running_process
;
1225 g_info("State save");
1227 nb_tracefile
= self
->parent
.tracefiles
->len
;
1229 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1231 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1232 LttvTracefileContext
*, i
));
1233 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1234 value
= lttv_attribute_add(tracefiles_tree
, i
,
1236 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1238 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1240 *(value
.v_uint
) = tfcs
->process
->pid
;
1242 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1244 /* Only save the position if the tfs has not infinite time. */
1245 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1246 // && current_tfcs != tfcs) {
1247 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1248 *(value
.v_pointer
) = NULL
;
1250 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1251 ep
= ltt_event_position_new();
1252 ltt_event_position(e
, ep
);
1253 *(value
.v_pointer
) = ep
;
1255 guint nb_block
, offset
;
1258 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1259 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1261 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1265 /* save the cpu state */
1267 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1268 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1270 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1273 /* save the irq state */
1274 nb_irqs
= self
->nb_irqs
;
1276 guint size
= sizeof(LttvCPUState
)*nb_irqs
;
1277 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1279 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1284 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1286 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1288 LttvTracefileState
*tfcs
;
1290 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1292 guint
*running_process
;
1294 LttvAttributeType type
;
1296 LttvAttributeValue value
;
1298 LttvAttributeName name
;
1302 LttEventPosition
*ep
;
1304 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1306 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1307 LTTV_STATE_TRACEFILES
);
1309 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1311 g_assert(type
== LTTV_POINTER
);
1312 lttv_state_free_process_table(self
->processes
);
1313 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1315 /* Add the currently running processes array */
1316 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1317 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1319 g_assert(type
== LTTV_POINTER
);
1320 running_process
= *(value
.v_pointer
);
1321 for(i
=0;i
<nb_cpus
;i
++) {
1322 pid
= running_process
[i
];
1323 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1324 g_assert(self
->running_process
[i
] != NULL
);
1327 nb_tracefile
= self
->parent
.tracefiles
->len
;
1329 //g_tree_destroy(tsc->pqueue);
1330 //tsc->pqueue = g_tree_new(compare_tracefile);
1332 /* restore cpu resource states */
1333 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1334 g_assert(type
== LTTV_POINTER
);
1335 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1336 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1338 /* restore irq resource states */
1339 nb_irqs
= self
->nb_irqs
;
1340 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1341 g_assert(type
== LTTV_POINTER
);
1342 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1343 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1345 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1347 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1348 LttvTracefileContext
*, i
));
1349 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1350 g_assert(type
== LTTV_GOBJECT
);
1351 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1353 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1355 g_assert(type
== LTTV_UINT
);
1356 pid
= *(value
.v_uint
);
1357 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1359 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1361 g_assert(type
== LTTV_POINTER
);
1362 //g_assert(*(value.v_pointer) != NULL);
1363 ep
= *(value
.v_pointer
);
1364 g_assert(tfcs
->parent
.t_context
!= NULL
);
1366 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1368 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1369 g_tree_remove(tsc
->pqueue
, tfc
);
1372 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1373 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1374 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1375 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1376 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1378 tfc
->timestamp
= ltt_time_infinite
;
1384 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1386 guint i
, nb_tracefile
, nb_cpus
;
1388 LttvTracefileState
*tfcs
;
1390 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1392 guint
*running_process
;
1394 LttvAttributeType type
;
1396 LttvAttributeValue value
;
1398 LttvAttributeName name
;
1402 LttEventPosition
*ep
;
1404 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1405 LTTV_STATE_TRACEFILES
);
1406 g_object_ref(G_OBJECT(tracefiles_tree
));
1407 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1409 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1411 g_assert(type
== LTTV_POINTER
);
1412 lttv_state_free_process_table(*(value
.v_pointer
));
1413 *(value
.v_pointer
) = NULL
;
1414 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1416 /* Free running processes array */
1417 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1418 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1420 g_assert(type
== LTTV_POINTER
);
1421 running_process
= *(value
.v_pointer
);
1422 g_free(running_process
);
1424 nb_tracefile
= self
->parent
.tracefiles
->len
;
1426 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1428 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1429 LttvTracefileContext
*, i
));
1430 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1431 g_assert(type
== LTTV_GOBJECT
);
1432 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1434 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1436 g_assert(type
== LTTV_POINTER
);
1437 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1439 g_object_unref(G_OBJECT(tracefiles_tree
));
1443 static void free_saved_state(LttvTraceState
*self
)
1447 LttvAttributeType type
;
1449 LttvAttributeValue value
;
1451 LttvAttributeName name
;
1455 LttvAttribute
*saved_states
;
1457 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1458 LTTV_STATE_SAVED_STATES
);
1460 nb
= lttv_attribute_get_number(saved_states
);
1461 for(i
= 0 ; i
< nb
; i
++) {
1462 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1463 g_assert(type
== LTTV_GOBJECT
);
1464 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1467 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1472 create_max_time(LttvTraceState
*tcs
)
1474 LttvAttributeValue v
;
1476 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1478 g_assert(*(v
.v_pointer
) == NULL
);
1479 *(v
.v_pointer
) = g_new(LttTime
,1);
1480 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1485 get_max_time(LttvTraceState
*tcs
)
1487 LttvAttributeValue v
;
1489 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1491 g_assert(*(v
.v_pointer
) != NULL
);
1492 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1497 free_max_time(LttvTraceState
*tcs
)
1499 LttvAttributeValue v
;
1501 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1503 g_free(*(v
.v_pointer
));
1504 *(v
.v_pointer
) = NULL
;
1508 typedef struct _LttvNameTables
{
1509 // FIXME GQuark *eventtype_names;
1510 GQuark
*syscall_names
;
1516 GQuark
*soft_irq_names
;
1522 create_name_tables(LttvTraceState
*tcs
)
1526 GQuark f_name
, e_name
;
1530 LttvTraceHookByFacility
*thf
;
1536 GString
*fe_name
= g_string_new("");
1538 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1540 LttvAttributeValue v
;
1542 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1544 g_assert(*(v
.v_pointer
) == NULL
);
1545 *(v
.v_pointer
) = name_tables
;
1546 #if 0 // Use iteration over the facilities_by_name and then list all event
1547 // types of each facility
1548 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1549 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1550 for(i
= 0 ; i
< nb
; i
++) {
1551 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1552 e_name
= ltt_eventtype_name(et
);
1553 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1554 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1555 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1558 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1559 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1560 LTT_FIELD_SYSCALL_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
);
1570 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1571 name_tables
->nb_syscalls
= nb
;
1573 for(i
= 0 ; i
< nb
; i
++) {
1574 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1575 if(!name_tables
->syscall_names
[i
]) {
1576 GString
*string
= g_string_new("");
1577 g_string_printf(string
, "syscall %u", i
);
1578 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1579 g_string_free(string
, TRUE
);
1583 //name_tables->syscall_names = g_new(GQuark, 256);
1584 //for(i = 0 ; i < 256 ; i++) {
1585 // g_string_printf(fe_name, "syscall %d", i);
1586 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1589 name_tables
->syscall_names
= NULL
;
1590 name_tables
->nb_syscalls
= 0;
1593 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1594 LTT_EVENT_TRAP_ENTRY
,
1595 LTT_FIELD_TRAP_ID
, 0, 0,
1598 thf
= lttv_trace_hook_get_first(&h
);
1600 t
= ltt_field_type(thf
->f1
);
1601 //nb = ltt_type_element_number(t);
1603 lttv_trace_hook_destroy(&h
);
1606 name_tables->trap_names = g_new(GQuark, nb);
1607 for(i = 0 ; i < nb ; i++) {
1608 name_tables->trap_names[i] = g_quark_from_string(
1609 ltt_enum_string_get(t, i));
1612 name_tables
->nb_traps
= 256;
1613 name_tables
->trap_names
= g_new(GQuark
, 256);
1614 for(i
= 0 ; i
< 256 ; i
++) {
1615 g_string_printf(fe_name
, "trap %d", i
);
1616 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1619 name_tables
->trap_names
= NULL
;
1620 name_tables
->nb_traps
= 0;
1623 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1624 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1625 LTT_FIELD_IRQ_ID
, 0, 0,
1628 thf
= lttv_trace_hook_get_first(&h
);
1630 t
= ltt_field_type(thf
->f1
);
1631 //nb = ltt_type_element_number(t);
1633 lttv_trace_hook_destroy(&h
);
1636 name_tables->irq_names = g_new(GQuark, nb);
1637 for(i = 0 ; i < nb ; i++) {
1638 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1642 name_tables
->nb_irqs
= 256;
1643 name_tables
->irq_names
= g_new(GQuark
, 256);
1644 for(i
= 0 ; i
< 256 ; i
++) {
1645 g_string_printf(fe_name
, "irq %d", i
);
1646 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1649 name_tables
->nb_irqs
= 0;
1650 name_tables
->irq_names
= NULL
;
1653 name_tables->soft_irq_names = g_new(GQuark, nb);
1654 for(i = 0 ; i < nb ; i++) {
1655 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1659 name_tables
->nb_softirqs
= 256;
1660 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1661 for(i
= 0 ; i
< 256 ; i
++) {
1662 g_string_printf(fe_name
, "softirq %d", i
);
1663 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1667 g_string_free(fe_name
, TRUE
);
1672 get_name_tables(LttvTraceState
*tcs
)
1674 LttvNameTables
*name_tables
;
1676 LttvAttributeValue v
;
1678 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1680 g_assert(*(v
.v_pointer
) != NULL
);
1681 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1682 //tcs->eventtype_names = name_tables->eventtype_names;
1683 tcs
->syscall_names
= name_tables
->syscall_names
;
1684 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1685 tcs
->trap_names
= name_tables
->trap_names
;
1686 tcs
->nb_traps
= name_tables
->nb_traps
;
1687 tcs
->irq_names
= name_tables
->irq_names
;
1688 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1689 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1690 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1695 free_name_tables(LttvTraceState
*tcs
)
1697 LttvNameTables
*name_tables
;
1699 LttvAttributeValue v
;
1701 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1703 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1704 *(v
.v_pointer
) = NULL
;
1706 // g_free(name_tables->eventtype_names);
1707 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1708 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1709 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1710 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1711 if(name_tables
) g_free(name_tables
);
1714 #ifdef HASH_TABLE_DEBUG
1716 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1718 LttvProcessState
*process
= (LttvProcessState
*)value
;
1720 /* Test for process corruption */
1721 guint stack_len
= process
->execution_stack
->len
;
1724 static void hash_table_check(GHashTable
*table
)
1726 g_hash_table_foreach(table
, test_process
, NULL
);
1732 /* clears the stack and sets the state passed as argument */
1733 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1735 g_array_set_size(cpust
->mode_stack
, 1);
1736 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1739 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1741 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1742 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1745 static void cpu_pop_mode(LttvCPUState
*cpust
)
1747 if(cpust
->mode_stack
->len
<= 1)
1748 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1750 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1753 /* clears the stack and sets the state passed as argument */
1754 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1756 g_array_set_size(bdevst
->mode_stack
, 1);
1757 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1760 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1762 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1763 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1766 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1768 if(bdevst
->mode_stack
->len
<= 1)
1769 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1771 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1774 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1776 g_array_set_size(irqst
->mode_stack
, 1);
1777 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1780 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1782 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1783 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1786 static void irq_pop_mode(LttvIRQState
*irqst
)
1788 if(irqst
->mode_stack
->len
<= 1)
1789 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1791 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1794 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1797 LttvExecutionState
*es
;
1799 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1800 guint cpu
= tfs
->cpu
;
1802 #ifdef HASH_TABLE_DEBUG
1803 hash_table_check(ts
->processes
);
1805 LttvProcessState
*process
= ts
->running_process
[cpu
];
1807 guint depth
= process
->execution_stack
->len
;
1809 process
->execution_stack
=
1810 g_array_set_size(process
->execution_stack
, depth
+ 1);
1813 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1815 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1818 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1819 es
->cum_cpu_time
= ltt_time_zero
;
1820 es
->s
= process
->state
->s
;
1821 process
->state
= es
;
1825 * return 1 when empty, else 0 */
1826 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1827 LttvTracefileState
*tfs
)
1829 guint cpu
= tfs
->cpu
;
1830 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1832 guint depth
= process
->execution_stack
->len
;
1838 process
->execution_stack
=
1839 g_array_set_size(process
->execution_stack
, depth
- 1);
1840 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1842 process
->state
->change
= tfs
->parent
.timestamp
;
1847 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1849 guint cpu
= tfs
->cpu
;
1850 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1851 LttvProcessState
*process
= ts
->running_process
[cpu
];
1853 guint depth
= process
->execution_stack
->len
;
1855 if(process
->state
->t
!= t
){
1856 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1857 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1858 g_info("process state has %s when pop_int is %s\n",
1859 g_quark_to_string(process
->state
->t
),
1860 g_quark_to_string(t
));
1861 g_info("{ %u, %u, %s, %s, %s }\n",
1864 g_quark_to_string(process
->name
),
1865 g_quark_to_string(process
->brand
),
1866 g_quark_to_string(process
->state
->s
));
1871 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1872 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1876 process
->execution_stack
=
1877 g_array_set_size(process
->execution_stack
, depth
- 1);
1878 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1880 process
->state
->change
= tfs
->parent
.timestamp
;
1883 struct search_result
{
1884 const LttTime
*time
; /* Requested time */
1885 LttTime
*best
; /* Best result */
1888 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1890 const LttTime
*elem_time
= (const LttTime
*)a
;
1891 /* Explicit non const cast */
1892 struct search_result
*res
= (struct search_result
*)b
;
1894 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1895 /* The usertrace was created before the schedchange */
1896 /* Get larger keys */
1898 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1899 /* The usertrace was created after the schedchange time */
1900 /* Get smaller keys */
1902 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1903 res
->best
= elem_time
;
1906 res
->best
= elem_time
;
1913 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1914 guint pid
, const LttTime
*timestamp
)
1916 LttvTracefileState
*tfs
= NULL
;
1917 struct search_result res
;
1918 /* Find the usertrace associated with a pid and time interval.
1919 * Search in the usertraces by PID (within a hash) and then, for each
1920 * corresponding element of the array, find the first one with creation
1921 * timestamp the lowest, but higher or equal to "timestamp". */
1922 res
.time
= timestamp
;
1924 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1925 if(usertrace_tree
) {
1926 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1928 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1936 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1937 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1939 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1941 LttvExecutionState
*es
;
1943 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1948 process
->tgid
= tgid
;
1950 process
->name
= name
;
1951 process
->brand
= LTTV_STATE_UNBRANDED
;
1952 //process->last_cpu = tfs->cpu_name;
1953 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1954 process
->type
= LTTV_STATE_USER_THREAD
;
1955 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1956 process
->current_function
= 0; //function 0x0 by default.
1958 g_info("Process %u, core %p", process
->pid
, process
);
1959 g_hash_table_insert(tcs
->processes
, process
, process
);
1962 process
->ppid
= parent
->pid
;
1963 process
->creation_time
= *timestamp
;
1966 /* No parent. This process exists but we are missing all information about
1967 its creation. The birth time is set to zero but we remember the time of
1972 process
->creation_time
= ltt_time_zero
;
1975 process
->insertion_time
= *timestamp
;
1976 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1977 process
->creation_time
.tv_nsec
);
1978 process
->pid_time
= g_quark_from_string(buffer
);
1980 //process->last_cpu = tfs->cpu_name;
1981 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1982 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1983 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1984 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1985 es
= process
->state
= &g_array_index(process
->execution_stack
,
1986 LttvExecutionState
, 0);
1987 es
->t
= LTTV_STATE_USER_MODE
;
1988 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1989 es
->entry
= *timestamp
;
1990 //g_assert(timestamp->tv_sec != 0);
1991 es
->change
= *timestamp
;
1992 es
->cum_cpu_time
= ltt_time_zero
;
1993 es
->s
= LTTV_STATE_RUN
;
1995 es
= process
->state
= &g_array_index(process
->execution_stack
,
1996 LttvExecutionState
, 1);
1997 es
->t
= LTTV_STATE_SYSCALL
;
1998 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1999 es
->entry
= *timestamp
;
2000 //g_assert(timestamp->tv_sec != 0);
2001 es
->change
= *timestamp
;
2002 es
->cum_cpu_time
= ltt_time_zero
;
2003 es
->s
= LTTV_STATE_WAIT_FORK
;
2005 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2006 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2007 sizeof(guint64
), 0);
2012 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2015 LttvProcessState key
;
2016 LttvProcessState
*process
;
2020 process
= g_hash_table_lookup(ts
->processes
, &key
);
2025 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2026 const LttTime
*timestamp
)
2028 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2029 LttvExecutionState
*es
;
2031 /* Put ltt_time_zero creation time for unexisting processes */
2032 if(unlikely(process
== NULL
)) {
2033 process
= lttv_state_create_process(ts
,
2034 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2035 /* We are not sure is it's a kernel thread or normal thread, put the
2036 * bottom stack state to unknown */
2037 process
->execution_stack
=
2038 g_array_set_size(process
->execution_stack
, 1);
2039 process
->state
= es
=
2040 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2041 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2042 es
->s
= LTTV_STATE_UNNAMED
;
2047 /* FIXME : this function should be called when we receive an event telling that
2048 * release_task has been called in the kernel. In happens generally when
2049 * the parent waits for its child terminaison, but may also happen in special
2050 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2051 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2052 * of a killed thread ground, but isn't the leader.
2054 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2056 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2057 LttvProcessState key
;
2059 key
.pid
= process
->pid
;
2060 key
.cpu
= process
->cpu
;
2061 g_hash_table_remove(ts
->processes
, &key
);
2062 g_array_free(process
->execution_stack
, TRUE
);
2063 g_array_free(process
->user_stack
, TRUE
);
2068 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2070 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2071 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2076 static void lttv_state_free_process_table(GHashTable
*processes
)
2078 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2079 g_hash_table_destroy(processes
);
2083 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2085 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2087 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2088 LttvProcessState
*process
= ts
->running_process
[cpu
];
2089 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2090 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2091 LttField
*f
= thf
->f1
;
2093 LttvExecutionSubmode submode
;
2095 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2096 guint syscall
= ltt_event_get_unsigned(e
, f
);
2098 if(syscall
< nb_syscalls
) {
2099 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2102 /* Fixup an incomplete syscall table */
2103 GString
*string
= g_string_new("");
2104 g_string_printf(string
, "syscall %u", syscall
);
2105 submode
= g_quark_from_string(string
->str
);
2106 g_string_free(string
, TRUE
);
2108 /* There can be no system call from PID 0 : unknown state */
2109 if(process
->pid
!= 0)
2110 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2115 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2117 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2119 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2120 LttvProcessState
*process
= ts
->running_process
[cpu
];
2122 /* There can be no system call from PID 0 : unknown state */
2123 if(process
->pid
!= 0)
2124 pop_state(s
, LTTV_STATE_SYSCALL
);
2129 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2131 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2132 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2133 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2134 LttField
*f
= thf
->f1
;
2136 LttvExecutionSubmode submode
;
2138 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2139 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2141 if(trap
< nb_traps
) {
2142 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2144 /* Fixup an incomplete trap table */
2145 GString
*string
= g_string_new("");
2146 g_string_printf(string
, "trap %llu", trap
);
2147 submode
= g_quark_from_string(string
->str
);
2148 g_string_free(string
, TRUE
);
2151 push_state(s
, LTTV_STATE_TRAP
, submode
);
2153 /* update cpu status */
2154 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2159 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2161 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2163 pop_state(s
, LTTV_STATE_TRAP
);
2165 /* update cpu status */
2166 cpu_pop_mode(s
->cpu_state
);
2171 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2173 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2174 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2175 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2176 guint8 fac_id
= ltt_event_facility_id(e
);
2177 guint8 ev_id
= ltt_event_eventtype_id(e
);
2178 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2179 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2180 g_assert(thf
->f1
!= NULL
);
2181 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2182 LttField
*f
= thf
->f1
;
2184 LttvExecutionSubmode submode
;
2185 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2186 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2190 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2192 /* Fixup an incomplete irq table */
2193 GString
*string
= g_string_new("");
2194 g_string_printf(string
, "irq %llu", irq
);
2195 submode
= g_quark_from_string(string
->str
);
2196 g_string_free(string
, TRUE
);
2199 /* Do something with the info about being in user or system mode when int? */
2200 push_state(s
, LTTV_STATE_IRQ
, submode
);
2202 /* update cpu status */
2203 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2205 /* update irq status */
2206 s
->cpu_state
->last_irq
= irq
;
2207 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2212 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2214 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2216 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2222 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2225 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2227 pop_state(s
, LTTV_STATE_IRQ
);
2229 /* update cpu status */
2230 cpu_pop_mode(s
->cpu_state
);
2232 /* update irq status */
2233 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2238 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2240 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2241 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2242 guint8 fac_id
= ltt_event_facility_id(e
);
2243 guint8 ev_id
= ltt_event_eventtype_id(e
);
2244 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2245 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2246 g_assert(thf
->f1
!= NULL
);
2247 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2248 LttField
*f
= thf
->f1
;
2250 LttvExecutionSubmode submode
;
2251 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2252 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2255 if(softirq
< nb_softirqs
) {
2256 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2258 /* Fixup an incomplete irq table */
2259 GString
*string
= g_string_new("");
2260 g_string_printf(string
, "softirq %llu", softirq
);
2261 submode
= g_quark_from_string(string
->str
);
2262 g_string_free(string
, TRUE
);
2265 /* Do something with the info about being in user or system mode when int? */
2266 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2270 static LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
)
2272 gint devcode_gint
= devcode
;
2273 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2275 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
2276 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
2278 gint
* key
= g_malloc(sizeof(gint
));
2280 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
2281 printf("adding key %u to hash table\n", *key
);
2289 static void bdev_state_free(gpointer key
, gpointer value
, gpointer user_data
)
2291 LttvBdevState
*bds
= (LttvBdevState
*) value
;
2293 g_array_free(bds
->mode_stack
, FALSE
);
2297 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2299 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2300 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2301 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2302 guint8 fac_id
= ltt_event_facility_id(e
);
2303 guint8 ev_id
= ltt_event_eventtype_id(e
);
2304 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2306 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2307 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2308 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2309 guint16 devcode
= MKDEV(major
,minor
);
2311 /* have we seen this block device before? */
2312 gpointer bdev
= bdev_state_get(ts
, devcode
);
2315 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2317 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2322 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2324 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2325 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2326 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2327 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2329 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2330 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2331 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2332 guint16 devcode
= MKDEV(major
,minor
);
2334 /* have we seen this block device before? */
2335 gpointer bdev
= bdev_state_get(ts
, devcode
);
2337 /* update block device */
2338 bdev_pop_mode(bdev
);
2343 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2347 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2348 guint cpu
= tfs
->cpu
;
2349 LttvProcessState
*process
= ts
->running_process
[cpu
];
2351 guint depth
= process
->user_stack
->len
;
2353 process
->user_stack
=
2354 g_array_set_size(process
->user_stack
, depth
+ 1);
2356 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2357 *new_func
= funcptr
;
2358 process
->current_function
= funcptr
;
2361 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2363 guint cpu
= tfs
->cpu
;
2364 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2365 LttvProcessState
*process
= ts
->running_process
[cpu
];
2367 if(process
->current_function
!= funcptr
){
2368 g_info("Different functions (%lu.%09lu): ignore it\n",
2369 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2370 g_info("process state has %llu when pop_function is %llu\n",
2371 process
->current_function
, funcptr
);
2372 g_info("{ %u, %u, %s, %s, %s }\n",
2375 g_quark_to_string(process
->name
),
2376 g_quark_to_string(process
->brand
),
2377 g_quark_to_string(process
->state
->s
));
2380 guint depth
= process
->user_stack
->len
;
2383 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2384 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2388 process
->user_stack
=
2389 g_array_set_size(process
->user_stack
, depth
- 1);
2390 process
->current_function
=
2391 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2395 static gboolean
function_entry(void *hook_data
, void *call_data
)
2397 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2398 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2399 guint8 fac_id
= ltt_event_facility_id(e
);
2400 guint8 ev_id
= ltt_event_eventtype_id(e
);
2401 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2402 g_assert(thf
->f1
!= NULL
);
2403 LttField
*f
= thf
->f1
;
2404 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2406 push_function(s
, funcptr
);
2410 static gboolean
function_exit(void *hook_data
, void *call_data
)
2412 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2413 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2414 guint8 fac_id
= ltt_event_facility_id(e
);
2415 guint8 ev_id
= ltt_event_eventtype_id(e
);
2416 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2417 g_assert(thf
->f1
!= NULL
);
2418 LttField
*f
= thf
->f1
;
2419 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2421 LttvExecutionSubmode submode
;
2423 pop_function(s
, funcptr
);
2427 static gboolean
schedchange(void *hook_data
, void *call_data
)
2429 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2431 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2432 LttvProcessState
*process
= ts
->running_process
[cpu
];
2433 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2435 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2436 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2437 guint pid_in
, pid_out
;
2440 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2441 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2442 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2444 if(likely(process
!= NULL
)) {
2446 /* We could not know but it was not the idle process executing.
2447 This should only happen at the beginning, before the first schedule
2448 event, and when the initial information (current process for each CPU)
2449 is missing. It is not obvious how we could, after the fact, compensate
2450 the wrongly attributed statistics. */
2452 //This test only makes sense once the state is known and if there is no
2453 //missing events. We need to silently ignore schedchange coming after a
2454 //process_free, or it causes glitches. (FIXME)
2455 //if(unlikely(process->pid != pid_out)) {
2456 // g_assert(process->pid == 0);
2458 if(process
->pid
== 0
2459 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2461 /* Scheduling out of pid 0 at beginning of the trace :
2462 * we know for sure it is in syscall mode at this point. */
2463 g_assert(process
->execution_stack
->len
== 1);
2464 process
->state
->t
= LTTV_STATE_SYSCALL
;
2465 process
->state
->s
= LTTV_STATE_WAIT
;
2466 process
->state
->change
= s
->parent
.timestamp
;
2467 process
->state
->entry
= s
->parent
.timestamp
;
2470 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2471 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2472 process
->state
->change
= s
->parent
.timestamp
;
2474 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2475 else process
->state
->s
= LTTV_STATE_WAIT
;
2476 process
->state
->change
= s
->parent
.timestamp
;
2479 if(state_out
== 32 || state_out
== 128)
2480 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2481 /* see sched.h for states */
2484 process
= ts
->running_process
[cpu
] =
2485 lttv_state_find_process_or_create(
2486 (LttvTraceState
*)s
->parent
.t_context
,
2488 &s
->parent
.timestamp
);
2489 process
->state
->s
= LTTV_STATE_RUN
;
2491 if(process
->usertrace
)
2492 process
->usertrace
->cpu
= cpu
;
2493 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2494 process
->state
->change
= s
->parent
.timestamp
;
2496 /* update cpu status */
2498 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2500 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2505 static gboolean
process_fork(void *hook_data
, void *call_data
)
2507 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2508 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2509 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2511 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2512 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2513 LttvProcessState
*zombie_process
;
2515 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2516 LttvProcessState
*process
= ts
->running_process
[cpu
];
2517 LttvProcessState
*child_process
;
2520 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2523 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2524 s
->parent
.target_pid
= child_pid
;
2527 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2528 else child_tgid
= 0;
2530 /* Mathieu : it seems like the process might have been scheduled in before the
2531 * fork, and, in a rare case, might be the current process. This might happen
2532 * in a SMP case where we don't have enough precision on the clocks.
2534 * Test reenabled after precision fixes on time. (Mathieu) */
2536 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2538 if(unlikely(zombie_process
!= NULL
)) {
2539 /* Reutilisation of PID. Only now we are sure that the old PID
2540 * has been released. FIXME : should know when release_task happens instead.
2542 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2544 for(i
=0; i
< num_cpus
; i
++) {
2545 g_assert(zombie_process
!= ts
->running_process
[i
]);
2548 exit_process(s
, zombie_process
);
2551 g_assert(process
->pid
!= child_pid
);
2552 // FIXME : Add this test in the "known state" section
2553 // g_assert(process->pid == parent_pid);
2554 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2555 if(child_process
== NULL
) {
2556 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2557 child_pid
, child_tgid
,
2558 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2560 /* The process has already been created : due to time imprecision between
2561 * multiple CPUs : it has been scheduled in before creation. Note that we
2562 * shouldn't have this kind of imprecision.
2564 * Simply put a correct parent.
2566 g_assert(0); /* This is a problematic case : the process has been created
2567 before the fork event */
2568 child_process
->ppid
= process
->pid
;
2569 child_process
->tgid
= child_tgid
;
2571 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2572 child_process
->name
= process
->name
;
2573 child_process
->brand
= process
->brand
;
2578 /* We stamp a newly created process as kernel_thread.
2579 * The thread should not be running yet. */
2580 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2582 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2583 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2584 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2587 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2588 LttvProcessState
*process
;
2589 LttvExecutionState
*es
;
2592 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2593 s
->parent
.target_pid
= pid
;
2595 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2597 process
->execution_stack
=
2598 g_array_set_size(process
->execution_stack
, 1);
2599 es
= process
->state
=
2600 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2601 es
->t
= LTTV_STATE_SYSCALL
;
2602 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2607 static gboolean
process_exit(void *hook_data
, void *call_data
)
2609 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2610 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2611 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2615 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2616 LttvProcessState
*process
; // = ts->running_process[cpu];
2618 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2619 s
->parent
.target_pid
= pid
;
2621 // FIXME : Add this test in the "known state" section
2622 // g_assert(process->pid == pid);
2624 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2625 if(likely(process
!= NULL
)) {
2626 process
->state
->s
= LTTV_STATE_EXIT
;
2631 static gboolean
process_free(void *hook_data
, void *call_data
)
2633 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2634 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2635 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2636 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2638 LttvProcessState
*process
;
2640 /* PID of the process to release */
2641 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2642 s
->parent
.target_pid
= release_pid
;
2644 g_assert(release_pid
!= 0);
2646 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2648 if(likely(process
!= NULL
)) {
2649 /* release_task is happening at kernel level : we can now safely release
2650 * the data structure of the process */
2651 //This test is fun, though, as it may happen that
2652 //at time t : CPU 0 : process_free
2653 //at time t+150ns : CPU 1 : schedule out
2654 //Clearly due to time imprecision, we disable it. (Mathieu)
2655 //If this weird case happen, we have no choice but to put the
2656 //Currently running process on the cpu to 0.
2657 //I re-enable it following time precision fixes. (Mathieu)
2658 //Well, in the case where an process is freed by a process on another CPU
2659 //and still scheduled, it happens that this is the schedchange that will
2660 //drop the last reference count. Do not free it here!
2661 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2663 for(i
=0; i
< num_cpus
; i
++) {
2664 //g_assert(process != ts->running_process[i]);
2665 if(process
== ts
->running_process
[i
]) {
2666 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2670 if(i
== num_cpus
) /* process is not scheduled */
2671 exit_process(s
, process
);
2678 static gboolean
process_exec(void *hook_data
, void *call_data
)
2680 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2681 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2682 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2683 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2686 LttvProcessState
*process
= ts
->running_process
[cpu
];
2688 #if 0//how to use a sequence that must be transformed in a string
2689 /* PID of the process to release */
2690 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2691 //name = ltt_event_get_string(e, thf->f1);
2692 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2694 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2695 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2696 memcpy(null_term_name
, name_begin
, name_len
);
2697 null_term_name
[name_len
] = '\0';
2698 process
->name
= g_quark_from_string(null_term_name
);
2701 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2702 process
->brand
= LTTV_STATE_UNBRANDED
;
2703 //g_free(null_term_name);
2707 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2709 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2710 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2711 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2712 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2715 LttvProcessState
*process
= ts
->running_process
[cpu
];
2717 name
= ltt_event_get_string(e
, thf
->f1
);
2718 process
->brand
= g_quark_from_string(name
);
2723 static void fix_process(gpointer key
, gpointer value
,
2726 LttvProcessState
*process
;
2727 LttvExecutionState
*es
;
2728 process
= (LttvProcessState
*)value
;
2729 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2730 LttTime
*timestamp
= (LttTime
*)user_data
;
2732 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2733 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2734 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2735 es
->t
= LTTV_STATE_SYSCALL
;
2736 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2737 es
->entry
= *timestamp
;
2738 es
->change
= *timestamp
;
2739 es
->cum_cpu_time
= ltt_time_zero
;
2740 if(es
->s
== LTTV_STATE_UNNAMED
)
2741 es
->s
= LTTV_STATE_WAIT
;
2744 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2745 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2746 es
->t
= LTTV_STATE_USER_MODE
;
2747 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2748 es
->entry
= *timestamp
;
2749 //g_assert(timestamp->tv_sec != 0);
2750 es
->change
= *timestamp
;
2751 es
->cum_cpu_time
= ltt_time_zero
;
2752 if(es
->s
== LTTV_STATE_UNNAMED
)
2753 es
->s
= LTTV_STATE_RUN
;
2755 if(process
->execution_stack
->len
== 1) {
2756 /* Still in bottom unknown mode, means never did a system call
2757 * May be either in user mode, syscall mode, running or waiting.*/
2758 /* FIXME : we may be tagging syscall mode when being user mode */
2759 process
->execution_stack
=
2760 g_array_set_size(process
->execution_stack
, 2);
2761 es
= process
->state
= &g_array_index(process
->execution_stack
,
2762 LttvExecutionState
, 1);
2763 es
->t
= LTTV_STATE_SYSCALL
;
2764 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2765 es
->entry
= *timestamp
;
2766 //g_assert(timestamp->tv_sec != 0);
2767 es
->change
= *timestamp
;
2768 es
->cum_cpu_time
= ltt_time_zero
;
2769 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2770 es
->s
= LTTV_STATE_WAIT
;
2776 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2778 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2779 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2780 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2781 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2782 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2784 /* For all processes */
2785 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2786 /* else, if stack[0] is unknown, set to user mode, running */
2788 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2791 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2793 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2794 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2795 //It's slow : optimise later by doing this before reading trace.
2796 LttEventType
*et
= ltt_event_eventtype(e
);
2798 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2804 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2805 LttvProcessState
*process
= ts
->running_process
[cpu
];
2806 LttvProcessState
*parent_process
;
2807 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2808 GQuark type
, mode
, submode
, status
;
2809 LttvExecutionState
*es
;
2813 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2814 s
->parent
.target_pid
= pid
;
2817 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2820 command
= ltt_event_get_string(e
, thf
->f3
);
2823 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2824 type
= ltt_enum_string_get(ltt_field_type(f4
),
2825 ltt_event_get_unsigned(e
, f4
));
2828 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2829 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2830 ltt_event_get_unsigned(e
, f5
));
2833 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2834 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2835 ltt_event_get_unsigned(e
, f6
));
2838 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2839 status
= ltt_enum_string_get(ltt_field_type(f7
),
2840 ltt_event_get_unsigned(e
, f7
));
2843 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2844 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2849 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2850 for(i
=0; i
<nb_cpus
; i
++) {
2851 process
= lttv_state_find_process(ts
, i
, pid
);
2852 g_assert(process
!= NULL
);
2854 process
->ppid
= parent_pid
;
2855 process
->tgid
= tgid
;
2856 process
->name
= g_quark_from_string(command
);
2858 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2859 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2863 /* The process might exist if a process was forked while performing the
2865 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2866 if(process
== NULL
) {
2867 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2868 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2869 pid
, tgid
, g_quark_from_string(command
),
2870 &s
->parent
.timestamp
);
2872 /* Keep the stack bottom : a running user mode */
2873 /* Disabled because of inconsistencies in the current statedump states. */
2874 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2875 /* Only keep the bottom
2876 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2877 /* Will cause expected trap when in fact being syscall (even after end of
2879 * Will cause expected interrupt when being syscall. (only before end of
2880 * statedump event) */
2881 // This will cause a "popping last state on stack, ignoring it."
2882 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2883 es
= process
->state
= &g_array_index(process
->execution_stack
,
2884 LttvExecutionState
, 0);
2885 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2886 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2887 es
->s
= LTTV_STATE_UNNAMED
;
2888 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2890 es
->t
= LTTV_STATE_SYSCALL
;
2895 /* User space process :
2896 * bottom : user mode
2897 * either currently running or scheduled out.
2898 * can be scheduled out because interrupted in (user mode or in syscall)
2899 * or because of an explicit call to the scheduler in syscall. Note that
2900 * the scheduler call comes after the irq_exit, so never in interrupt
2902 // temp workaround : set size to 1 : only have user mode bottom of stack.
2903 // will cause g_info message of expected syscall mode when in fact being
2904 // in user mode. Can also cause expected trap when in fact being user
2905 // mode in the event of a page fault reenabling interrupts in the handler.
2906 // Expected syscall and trap can also happen after the end of statedump
2907 // This will cause a "popping last state on stack, ignoring it."
2908 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2909 es
= process
->state
= &g_array_index(process
->execution_stack
,
2910 LttvExecutionState
, 0);
2911 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2912 es
->s
= LTTV_STATE_UNNAMED
;
2913 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2915 es
->t
= LTTV_STATE_USER_MODE
;
2923 es
= process
->state
= &g_array_index(process
->execution_stack
,
2924 LttvExecutionState
, 1);
2925 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2926 es
->s
= LTTV_STATE_UNNAMED
;
2927 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2931 /* The process has already been created :
2932 * Probably was forked while dumping the process state or
2933 * was simply scheduled in prior to get the state dump event.
2935 process
->ppid
= parent_pid
;
2936 process
->tgid
= tgid
;
2937 process
->name
= g_quark_from_string(command
);
2938 process
->type
= type
;
2940 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2942 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2943 if(type
== LTTV_STATE_KERNEL_THREAD
)
2944 es
->t
= LTTV_STATE_SYSCALL
;
2946 es
->t
= LTTV_STATE_USER_MODE
;
2949 /* Don't mess around with the stack, it will eventually become
2950 * ok after the end of state dump. */
2957 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2959 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2961 lttv_state_add_event_hooks(tss
);
2966 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2968 LttvTraceset
*traceset
= self
->parent
.ts
;
2970 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2974 LttvTracefileState
*tfs
;
2978 LttvTraceHookByFacility
*thf
;
2980 LttvTraceHook
*hook
;
2982 LttvAttributeValue val
;
2987 nb_trace
= lttv_traceset_number(traceset
);
2988 for(i
= 0 ; i
< nb_trace
; i
++) {
2989 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2991 /* Find the eventtype id for the following events and register the
2992 associated by id hooks. */
2994 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2995 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2998 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2999 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3000 LTT_FIELD_SYSCALL_ID
, 0, 0,
3001 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3004 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3005 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3007 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3010 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3011 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
3012 LTT_FIELD_TRAP_ID
, 0, 0,
3013 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3016 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3017 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3019 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3022 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3023 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3024 LTT_FIELD_IRQ_ID
, 0, 0,
3025 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3028 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3029 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3031 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3034 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3035 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3036 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3037 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3040 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3041 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3043 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3046 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3047 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3048 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3049 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3052 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3053 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3054 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3055 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3058 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3059 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3060 LTT_FIELD_PID
, 0, 0,
3061 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3065 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3066 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3067 LTT_FIELD_PID
, 0, 0,
3068 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3071 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3072 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3073 LTT_FIELD_PID
, 0, 0,
3074 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3077 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3078 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3079 LTT_FIELD_FILENAME
, 0, 0,
3080 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3083 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3084 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3085 LTT_FIELD_NAME
, 0, 0,
3086 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3089 /* statedump-related hooks */
3090 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3091 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3092 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3093 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3096 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3097 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3099 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3102 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3103 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3104 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3105 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3108 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3109 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3110 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3111 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3114 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3115 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3116 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3117 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3120 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3121 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3122 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3123 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3126 hooks
= g_array_set_size(hooks
, hn
);
3128 /* Add these hooks to each event_by_id hooks list */
3130 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3132 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3134 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3135 LttvTracefileContext
*, j
));
3137 for(k
= 0 ; k
< hooks
->len
; k
++) {
3138 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3139 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3140 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3142 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3149 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3150 *(val
.v_pointer
) = hooks
;
3154 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3156 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3158 lttv_state_remove_event_hooks(tss
);
3163 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3165 LttvTraceset
*traceset
= self
->parent
.ts
;
3167 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3171 LttvTracefileState
*tfs
;
3175 LttvTraceHook
*hook
;
3177 LttvTraceHookByFacility
*thf
;
3179 LttvAttributeValue val
;
3181 nb_trace
= lttv_traceset_number(traceset
);
3182 for(i
= 0 ; i
< nb_trace
; i
++) {
3183 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3185 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3186 hooks
= *(val
.v_pointer
);
3188 /* Remove these hooks from each event_by_id hooks list */
3190 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3192 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3194 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3195 LttvTracefileContext
*, j
));
3197 for(k
= 0 ; k
< hooks
->len
; k
++) {
3198 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3199 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3200 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3202 lttv_hooks_remove_data(
3203 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3209 for(k
= 0 ; k
< hooks
->len
; k
++)
3210 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3211 g_array_free(hooks
, TRUE
);
3215 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3217 guint
*event_count
= (guint
*)hook_data
;
3219 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3220 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3225 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3227 LttvTracefileState
*tfcs
;
3229 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3231 LttEventPosition
*ep
;
3237 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3239 LttvAttributeValue value
;
3241 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3242 LTTV_STATE_SAVED_STATES
);
3243 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3244 value
= lttv_attribute_add(saved_states_tree
,
3245 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3246 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3247 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3248 *(value
.v_time
) = self
->parent
.timestamp
;
3249 lttv_state_save(tcs
, saved_state_tree
);
3250 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3251 self
->parent
.timestamp
.tv_nsec
);
3253 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3258 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3260 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3262 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3267 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3275 static gboolean
block_start(void *hook_data
, void *call_data
)
3277 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3279 LttvTracefileState
*tfcs
;
3281 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3283 LttEventPosition
*ep
;
3285 guint i
, nb_block
, nb_event
, nb_tracefile
;
3289 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3291 LttvAttributeValue value
;
3293 ep
= ltt_event_position_new();
3295 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3297 /* Count the number of events added since the last block end in any
3300 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3302 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3303 LttvTracefileContext
, i
));
3304 ltt_event_position(tfcs
->parent
.e
, ep
);
3305 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3306 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3307 tfcs
->saved_position
= nb_event
;
3311 if(tcs
->nb_event
>= tcs
->save_interval
) {
3312 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3313 LTTV_STATE_SAVED_STATES
);
3314 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3315 value
= lttv_attribute_add(saved_states_tree
,
3316 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3317 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3318 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3319 *(value
.v_time
) = self
->parent
.timestamp
;
3320 lttv_state_save(tcs
, saved_state_tree
);
3322 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3323 self
->parent
.timestamp
.tv_nsec
);
3325 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3331 static gboolean
block_end(void *hook_data
, void *call_data
)
3333 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3335 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3339 LttEventPosition
*ep
;
3341 guint nb_block
, nb_event
;
3343 ep
= ltt_event_position_new();
3344 ltt_event_position(self
->parent
.e
, ep
);
3345 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3346 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3347 self
->saved_position
= 0;
3348 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3355 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3357 LttvTraceset
*traceset
= self
->parent
.ts
;
3359 guint i
, j
, nb_trace
, nb_tracefile
;
3363 LttvTracefileState
*tfs
;
3365 LttvTraceHook hook_start
, hook_end
;
3367 nb_trace
= lttv_traceset_number(traceset
);
3368 for(i
= 0 ; i
< nb_trace
; i
++) {
3369 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3371 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3372 NULL
, NULL
, block_start
, &hook_start
);
3373 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3374 NULL
, NULL
, block_end
, &hook_end
);
3376 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3378 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3380 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3381 LttvTracefileContext
, j
));
3382 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3383 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3384 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3385 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3391 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3393 LttvTraceset
*traceset
= self
->parent
.ts
;
3395 guint i
, j
, nb_trace
, nb_tracefile
;
3399 LttvTracefileState
*tfs
;
3402 nb_trace
= lttv_traceset_number(traceset
);
3403 for(i
= 0 ; i
< nb_trace
; i
++) {
3405 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3406 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3408 if(ts
->has_precomputed_states
) continue;
3410 guint
*event_count
= g_new(guint
, 1);
3413 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3415 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3416 LttvTracefileContext
*, j
));
3417 lttv_hooks_add(tfs
->parent
.event
,
3418 state_save_event_hook
,
3425 lttv_process_traceset_begin(&self
->parent
,
3426 NULL
, NULL
, NULL
, NULL
, NULL
);
3430 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3432 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3434 lttv_state_save_add_event_hooks(tss
);
3441 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3443 LttvTraceset
*traceset
= self
->parent
.ts
;
3445 guint i
, j
, nb_trace
, nb_tracefile
;
3449 LttvTracefileState
*tfs
;
3451 LttvTraceHook hook_start
, hook_end
;
3453 nb_trace
= lttv_traceset_number(traceset
);
3454 for(i
= 0 ; i
< nb_trace
; i
++) {
3455 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3457 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3458 NULL
, NULL
, block_start
, &hook_start
);
3460 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3461 NULL
, NULL
, block_end
, &hook_end
);
3463 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3465 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3467 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3468 LttvTracefileContext
, j
));
3469 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3470 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3471 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3472 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3478 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3480 LttvTraceset
*traceset
= self
->parent
.ts
;
3482 guint i
, j
, nb_trace
, nb_tracefile
;
3486 LttvTracefileState
*tfs
;
3488 LttvHooks
*after_trace
= lttv_hooks_new();
3490 lttv_hooks_add(after_trace
,
3491 state_save_after_trace_hook
,
3496 lttv_process_traceset_end(&self
->parent
,
3497 NULL
, after_trace
, NULL
, NULL
, NULL
);
3499 lttv_hooks_destroy(after_trace
);
3501 nb_trace
= lttv_traceset_number(traceset
);
3502 for(i
= 0 ; i
< nb_trace
; i
++) {
3504 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3505 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3507 if(ts
->has_precomputed_states
) continue;
3509 guint
*event_count
= NULL
;
3511 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3513 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3514 LttvTracefileContext
*, j
));
3515 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3516 state_save_event_hook
);
3518 if(event_count
) g_free(event_count
);
3522 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3524 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3526 lttv_state_save_remove_event_hooks(tss
);
3531 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3533 LttvTraceset
*traceset
= self
->parent
.ts
;
3537 int min_pos
, mid_pos
, max_pos
;
3539 guint call_rest
= 0;
3541 LttvTraceState
*tcs
;
3543 LttvAttributeValue value
;
3545 LttvAttributeType type
;
3547 LttvAttributeName name
;
3551 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3553 //g_tree_destroy(self->parent.pqueue);
3554 //self->parent.pqueue = g_tree_new(compare_tracefile);
3556 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3558 nb_trace
= lttv_traceset_number(traceset
);
3559 for(i
= 0 ; i
< nb_trace
; i
++) {
3560 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3562 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3563 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3564 LTTV_STATE_SAVED_STATES
);
3567 if(saved_states_tree
) {
3568 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3569 mid_pos
= max_pos
/ 2;
3570 while(min_pos
< max_pos
) {
3571 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3573 g_assert(type
== LTTV_GOBJECT
);
3574 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3575 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3577 g_assert(type
== LTTV_TIME
);
3578 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3580 closest_tree
= saved_state_tree
;
3582 else max_pos
= mid_pos
- 1;
3584 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3588 /* restore the closest earlier saved state */
3590 lttv_state_restore(tcs
, closest_tree
);
3594 /* There is no saved state, yet we want to have it. Restart at T0 */
3596 restore_init_state(tcs
);
3597 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3600 /* We want to seek quickly without restoring/updating the state */
3602 restore_init_state(tcs
);
3603 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3606 if(!call_rest
) g_info("NOT Calling restore");
3611 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3617 traceset_state_finalize (LttvTracesetState
*self
)
3619 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3620 finalize(G_OBJECT(self
));
3625 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3627 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3629 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3630 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3631 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3632 klass
->new_traceset_context
= new_traceset_context
;
3633 klass
->new_trace_context
= new_trace_context
;
3634 klass
->new_tracefile_context
= new_tracefile_context
;
3639 lttv_traceset_state_get_type(void)
3641 static GType type
= 0;
3643 static const GTypeInfo info
= {
3644 sizeof (LttvTracesetStateClass
),
3645 NULL
, /* base_init */
3646 NULL
, /* base_finalize */
3647 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3648 NULL
, /* class_finalize */
3649 NULL
, /* class_data */
3650 sizeof (LttvTracesetState
),
3651 0, /* n_preallocs */
3652 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3653 NULL
/* value handling */
3656 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3664 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3670 trace_state_finalize (LttvTraceState
*self
)
3672 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3673 finalize(G_OBJECT(self
));
3678 trace_state_class_init (LttvTraceStateClass
*klass
)
3680 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3682 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3683 klass
->state_save
= state_save
;
3684 klass
->state_restore
= state_restore
;
3685 klass
->state_saved_free
= state_saved_free
;
3690 lttv_trace_state_get_type(void)
3692 static GType type
= 0;
3694 static const GTypeInfo info
= {
3695 sizeof (LttvTraceStateClass
),
3696 NULL
, /* base_init */
3697 NULL
, /* base_finalize */
3698 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3699 NULL
, /* class_finalize */
3700 NULL
, /* class_data */
3701 sizeof (LttvTraceState
),
3702 0, /* n_preallocs */
3703 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3704 NULL
/* value handling */
3707 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3708 "LttvTraceStateType", &info
, 0);
3715 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3721 tracefile_state_finalize (LttvTracefileState
*self
)
3723 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3724 finalize(G_OBJECT(self
));
3729 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3731 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3733 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3738 lttv_tracefile_state_get_type(void)
3740 static GType type
= 0;
3742 static const GTypeInfo info
= {
3743 sizeof (LttvTracefileStateClass
),
3744 NULL
, /* base_init */
3745 NULL
, /* base_finalize */
3746 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3747 NULL
, /* class_finalize */
3748 NULL
, /* class_data */
3749 sizeof (LttvTracefileState
),
3750 0, /* n_preallocs */
3751 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3752 NULL
/* value handling */
3755 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3756 "LttvTracefileStateType", &info
, 0);
3762 static void module_init()
3764 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3765 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3766 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3767 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3768 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3769 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3770 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3771 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3772 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3773 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3774 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3775 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3776 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3777 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3778 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3779 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3780 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3781 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3782 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3783 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3784 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3785 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3786 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3787 LTTV_STATE_EVENT
= g_quark_from_string("event");
3788 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3789 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3790 LTTV_STATE_TIME
= g_quark_from_string("time");
3791 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3792 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3793 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3794 g_quark_from_string("trace_state_use_count");
3795 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3798 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3799 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3800 LTT_FACILITY_FS
= g_quark_from_string("fs");
3801 LTT_FACILITY_LIST
= g_quark_from_string("list");
3802 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3803 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3806 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3807 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3808 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3809 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3810 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3811 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3812 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3813 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3814 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3815 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3816 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3817 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3818 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3819 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3820 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3821 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3822 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3823 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3824 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3825 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3826 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3829 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3830 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3831 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3832 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3833 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3834 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3835 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3836 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3837 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3838 LTT_FIELD_PID
= g_quark_from_string("pid");
3839 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3840 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3841 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3842 LTT_FIELD_NAME
= g_quark_from_string("name");
3843 LTT_FIELD_TYPE
= g_quark_from_string("type");
3844 LTT_FIELD_MODE
= g_quark_from_string("mode");
3845 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3846 LTT_FIELD_STATUS
= g_quark_from_string("status");
3847 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3848 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3849 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3850 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3851 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3853 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3854 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3855 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3856 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3857 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3859 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3860 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3861 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3863 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3864 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3865 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3866 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3869 static void module_destroy()
3874 LTTV_MODULE("state", "State computation", \
3875 "Update the system state, possibly saving it at intervals", \
3876 module_init
, module_destroy
)