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
;
57 LTT_EVENT_SYSCALL_ENTRY
,
58 LTT_EVENT_SYSCALL_EXIT
,
63 LTT_EVENT_SOFT_IRQ_ENTRY
,
64 LTT_EVENT_SOFT_IRQ_EXIT
,
65 LTT_EVENT_SCHED_SCHEDULE
,
66 LTT_EVENT_PROCESS_FORK
,
67 LTT_EVENT_KTHREAD_CREATE
,
68 LTT_EVENT_PROCESS_EXIT
,
69 LTT_EVENT_PROCESS_FREE
,
71 LTT_EVENT_PROCESS_STATE
,
72 LTT_EVENT_STATEDUMP_END
,
73 LTT_EVENT_FUNCTION_ENTRY
,
74 LTT_EVENT_FUNCTION_EXIT
,
75 LTT_EVENT_THREAD_BRAND
;
83 LTT_FIELD_SOFT_IRQ_ID
,
102 LTTV_STATE_MODE_UNKNOWN
,
103 LTTV_STATE_USER_MODE
,
110 LTTV_STATE_SUBMODE_UNKNOWN
,
111 LTTV_STATE_SUBMODE_NONE
;
115 LTTV_STATE_WAIT_FORK
,
124 LTTV_STATE_UNBRANDED
;
127 LTTV_STATE_USER_THREAD
,
128 LTTV_STATE_KERNEL_THREAD
;
143 LTTV_STATE_TRACEFILES
,
144 LTTV_STATE_PROCESSES
,
146 LTTV_STATE_RUNNING_PROCESS
,
148 LTTV_STATE_SAVED_STATES
,
149 LTTV_STATE_SAVED_STATES_TIME
,
152 LTTV_STATE_NAME_TABLES
,
153 LTTV_STATE_TRACE_STATE_USE_COUNT
;
155 static void create_max_time(LttvTraceState
*tcs
);
157 static void get_max_time(LttvTraceState
*tcs
);
159 static void free_max_time(LttvTraceState
*tcs
);
161 static void create_name_tables(LttvTraceState
*tcs
);
163 static void get_name_tables(LttvTraceState
*tcs
);
165 static void free_name_tables(LttvTraceState
*tcs
);
167 static void free_saved_state(LttvTraceState
*tcs
);
169 static void lttv_state_free_process_table(GHashTable
*processes
);
171 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
172 GPtrArray
*quarktable
);
174 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
176 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
180 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
182 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
186 void lttv_state_state_saved_free(LttvTraceState
*self
,
187 LttvAttribute
*container
)
189 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
193 guint
process_hash(gconstpointer key
)
195 guint pid
= ((const LttvProcessState
*)key
)->pid
;
196 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
200 /* If the hash table hash function is well distributed,
201 * the process_equal should compare different pid */
202 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
204 const LttvProcessState
*process_a
, *process_b
;
207 process_a
= (const LttvProcessState
*)a
;
208 process_b
= (const LttvProcessState
*)b
;
210 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
211 else if(likely(process_a
->pid
== 0 &&
212 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
217 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
219 g_tree_destroy((GTree
*)value
);
222 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
224 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
225 g_hash_table_destroy(usertraces
);
231 restore_init_state(LttvTraceState
*self
)
235 LttvTracefileState
*tfcs
;
237 LttTime start_time
, end_time
;
239 /* Free the process tables */
240 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
241 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
242 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
243 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
246 /* Seek time to beginning */
247 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
248 // closest. It's the tracecontext job to seek the trace to the beginning
249 // anyway : the init state might be used at the middle of the trace as well...
250 //g_tree_destroy(self->parent.ts_context->pqueue);
251 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
253 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
255 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
257 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
259 /* Put the per cpu running_process to beginning state : process 0. */
260 for(i
=0; i
< nb_cpus
; i
++) {
261 LttvExecutionState
*es
;
262 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
263 LTTV_STATE_UNNAMED
, &start_time
);
264 /* We are not sure is it's a kernel thread or normal thread, put the
265 * bottom stack state to unknown */
266 self
->running_process
[i
]->execution_stack
=
267 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
268 es
= self
->running_process
[i
]->state
=
269 &g_array_index(self
->running_process
[i
]->execution_stack
,
270 LttvExecutionState
, 0);
271 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
272 es
->s
= LTTV_STATE_UNNAMED
;
274 //self->running_process[i]->state->s = LTTV_STATE_RUN;
275 self
->running_process
[i
]->cpu
= i
;
279 nb_tracefile
= self
->parent
.tracefiles
->len
;
281 for(i
= 0 ; i
< nb_tracefile
; i
++) {
283 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
284 LttvTracefileContext
*, i
));
285 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
286 // tfcs->saved_position = 0;
287 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
288 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
289 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
290 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
295 //static LttTime time_zero = {0,0};
297 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
300 const LttTime
*t1
= (const LttTime
*)a
;
301 const LttTime
*t2
= (const LttTime
*)b
;
303 return ltt_time_compare(*t1
, *t2
);
306 static void free_usertrace_key(gpointer data
)
311 #define MAX_STRING_LEN 4096
314 state_load_saved_states(LttvTraceState
*tcs
)
317 GPtrArray
*quarktable
;
322 tcs
->has_precomputed_states
= FALSE
;
326 gchar buf
[MAX_STRING_LEN
];
329 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
330 strncpy(path
, trace_path
, PATH_MAX
-1);
331 count
= strnlen(trace_path
, PATH_MAX
-1);
332 // quarktable : open, test
333 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
334 fp
= fopen(path
, "r");
336 quarktable
= g_ptr_array_sized_new(4096);
338 /* Index 0 is null */
340 if(hdr
== EOF
) return;
341 g_assert(hdr
== HDR_QUARKS
);
345 if(hdr
== EOF
) break;
346 g_assert(hdr
== HDR_QUARK
);
347 g_ptr_array_set_size(quarktable
, q
+1);
350 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
351 if(buf
[i
] == '\0' || feof(fp
)) break;
354 len
= strnlen(buf
, MAX_STRING_LEN
-1);
355 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
356 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
362 // saved_states : open, test
363 strncpy(path
, trace_path
, PATH_MAX
-1);
364 count
= strnlen(trace_path
, PATH_MAX
-1);
365 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
366 fp
= fopen(path
, "r");
370 if(hdr
!= HDR_TRACE
) goto end
;
372 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
374 tcs
->has_precomputed_states
= TRUE
;
379 /* Free the quarktable */
380 for(i
=0; i
<quarktable
->len
; i
++) {
381 string
= g_ptr_array_index (quarktable
, i
);
384 g_ptr_array_free(quarktable
, TRUE
);
389 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
391 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
394 LttvTraceContext
*tc
;
398 LttvTracefileState
*tfcs
;
400 LttvAttributeValue v
;
402 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
403 init((LttvTracesetContext
*)self
, ts
);
405 nb_trace
= lttv_traceset_number(ts
);
406 for(i
= 0 ; i
< nb_trace
; i
++) {
407 tc
= self
->parent
.traces
[i
];
408 tcs
= LTTV_TRACE_STATE(tc
);
409 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
410 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
414 if(*(v
.v_uint
) == 1) {
415 create_name_tables(tcs
);
416 create_max_time(tcs
);
418 get_name_tables(tcs
);
421 nb_tracefile
= tc
->tracefiles
->len
;
422 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
423 nb_irq
= tcs
->nb_irqs
;
424 tcs
->processes
= NULL
;
425 tcs
->usertraces
= NULL
;
426 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
428 /* init cpu resource stuff */
429 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
430 for(j
= 0; j
<nb_cpu
; j
++) {
431 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
432 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
435 /* init irq resource stuff */
436 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
437 for(j
= 0; j
<nb_irq
; j
++) {
438 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
439 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
442 restore_init_state(tcs
);
443 for(j
= 0 ; j
< nb_tracefile
; j
++) {
445 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
446 LttvTracefileContext
*, j
));
447 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
448 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
449 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
450 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
451 /* It's a Usertrace */
452 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
453 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
455 if(!usertrace_tree
) {
456 usertrace_tree
= g_tree_new_full(compare_usertraces
,
457 NULL
, free_usertrace_key
, NULL
);
458 g_hash_table_insert(tcs
->usertraces
,
459 (gpointer
)tid
, usertrace_tree
);
461 LttTime
*timestamp
= g_new(LttTime
, 1);
462 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
463 ltt_tracefile_creation(tfcs
->parent
.tf
));
464 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
468 /* See if the trace has saved states */
469 state_load_saved_states(tcs
);
474 fini(LttvTracesetState
*self
)
480 LttvTracefileState
*tfcs
;
482 LttvAttributeValue v
;
484 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
485 for(i
= 0 ; i
< nb_trace
; i
++) {
486 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
487 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
490 g_assert(*(v
.v_uint
) != 0);
493 if(*(v
.v_uint
) == 0) {
494 free_name_tables(tcs
);
496 free_saved_state(tcs
);
498 g_free(tcs
->running_process
);
499 tcs
->running_process
= NULL
;
500 lttv_state_free_process_table(tcs
->processes
);
501 lttv_state_free_usertraces(tcs
->usertraces
);
502 tcs
->processes
= NULL
;
503 tcs
->usertraces
= NULL
;
505 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
506 fini((LttvTracesetContext
*)self
);
510 static LttvTracesetContext
*
511 new_traceset_context(LttvTracesetContext
*self
)
513 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
517 static LttvTraceContext
*
518 new_trace_context(LttvTracesetContext
*self
)
520 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
524 static LttvTracefileContext
*
525 new_tracefile_context(LttvTracesetContext
*self
)
527 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
531 /* Write the process state of the trace */
533 static void write_process_state(gpointer key
, gpointer value
,
536 LttvProcessState
*process
;
538 LttvExecutionState
*es
;
540 FILE *fp
= (FILE *)user_data
;
545 process
= (LttvProcessState
*)value
;
547 " <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",
548 process
, process
->pid
, process
->tgid
, process
->ppid
,
549 g_quark_to_string(process
->type
),
550 process
->creation_time
.tv_sec
,
551 process
->creation_time
.tv_nsec
,
552 process
->insertion_time
.tv_sec
,
553 process
->insertion_time
.tv_nsec
,
554 g_quark_to_string(process
->name
),
555 g_quark_to_string(process
->brand
),
558 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
559 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
560 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
561 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
562 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
563 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
564 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
567 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
568 address
= &g_array_index(process
->user_stack
, guint64
, i
);
569 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
573 if(process
->usertrace
) {
574 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
575 g_quark_to_string(process
->usertrace
->tracefile_name
),
576 process
->usertrace
->cpu
);
580 fprintf(fp
, " </PROCESS>\n");
584 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
586 guint i
, nb_tracefile
, nb_block
, offset
;
589 LttvTracefileState
*tfcs
;
593 LttEventPosition
*ep
;
597 ep
= ltt_event_position_new();
599 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
601 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
603 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
604 for(i
=0;i
<nb_cpus
;i
++) {
605 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
606 i
, self
->running_process
[i
]->pid
);
609 nb_tracefile
= self
->parent
.tracefiles
->len
;
611 for(i
= 0 ; i
< nb_tracefile
; i
++) {
613 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
614 LttvTracefileContext
*, i
));
615 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
616 tfcs
->parent
.timestamp
.tv_sec
,
617 tfcs
->parent
.timestamp
.tv_nsec
);
618 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
619 if(e
== NULL
) fprintf(fp
,"/>\n");
621 ltt_event_position(e
, ep
);
622 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
623 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
628 fprintf(fp
,"</PROCESS_STATE>\n");
632 static void write_process_state_raw(gpointer key
, gpointer value
,
635 LttvProcessState
*process
;
637 LttvExecutionState
*es
;
639 FILE *fp
= (FILE *)user_data
;
644 process
= (LttvProcessState
*)value
;
645 fputc(HDR_PROCESS
, fp
);
646 //fwrite(&header, sizeof(header), 1, fp);
647 //fprintf(fp, "%s", g_quark_to_string(process->type));
649 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
650 //fprintf(fp, "%s", g_quark_to_string(process->name));
652 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
653 //fprintf(fp, "%s", g_quark_to_string(process->brand));
655 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
656 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
657 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
658 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
659 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
660 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
661 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
665 " <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",
666 process
, process
->pid
, process
->tgid
, process
->ppid
,
667 g_quark_to_string(process
->type
),
668 process
->creation_time
.tv_sec
,
669 process
->creation_time
.tv_nsec
,
670 process
->insertion_time
.tv_sec
,
671 process
->insertion_time
.tv_nsec
,
672 g_quark_to_string(process
->name
),
673 g_quark_to_string(process
->brand
),
677 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
678 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
681 //fprintf(fp, "%s", g_quark_to_string(es->t));
683 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
684 //fprintf(fp, "%s", g_quark_to_string(es->n));
686 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
687 //fprintf(fp, "%s", g_quark_to_string(es->s));
689 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
690 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
691 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
692 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
694 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
695 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
696 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
697 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
698 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
702 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
703 address
= &g_array_index(process
->user_stack
, guint64
, i
);
704 fputc(HDR_USER_STACK
, fp
);
705 fwrite(&address
, sizeof(address
), 1, fp
);
707 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
712 if(process
->usertrace
) {
713 fputc(HDR_USERTRACE
, fp
);
714 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
716 fwrite(&process
->usertrace
->tracefile_name
,
717 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
718 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
720 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
721 g_quark_to_string(process
->usertrace
->tracefile_name
),
722 process
->usertrace
->cpu
);
729 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
731 guint i
, nb_tracefile
, nb_block
, offset
;
734 LttvTracefileState
*tfcs
;
738 LttEventPosition
*ep
;
742 ep
= ltt_event_position_new();
744 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
745 fputc(HDR_PROCESS_STATE
, fp
);
746 fwrite(&t
, sizeof(t
), 1, fp
);
748 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
750 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
751 for(i
=0;i
<nb_cpus
;i
++) {
753 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
754 fwrite(&self
->running_process
[i
]->pid
,
755 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
756 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
757 // i, self->running_process[i]->pid);
760 nb_tracefile
= self
->parent
.tracefiles
->len
;
762 for(i
= 0 ; i
< nb_tracefile
; i
++) {
764 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
765 LttvTracefileContext
*, i
));
766 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
767 // tfcs->parent.timestamp.tv_sec,
768 // tfcs->parent.timestamp.tv_nsec);
769 fputc(HDR_TRACEFILE
, fp
);
770 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
771 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
772 * position following : end of trace */
773 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
775 ltt_event_position(e
, ep
);
776 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
777 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
779 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
780 fwrite(&offset
, sizeof(offset
), 1, fp
);
781 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
788 /* Read process state from a file */
790 /* Called because a HDR_PROCESS was found */
791 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
792 GPtrArray
*quarktable
)
794 LttvExecutionState
*es
;
795 LttvProcessState
*process
, *parent_process
;
796 LttvProcessState tmp
;
803 /* TODO : check return value */
804 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
805 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
806 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
807 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
808 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
809 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
810 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
811 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
812 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
815 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
817 /* We must link to the parent */
818 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
820 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
821 if(process
== NULL
) {
822 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
824 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
828 process
->insertion_time
= tmp
.insertion_time
;
829 process
->creation_time
= tmp
.creation_time
;
830 process
->type
= g_quark_from_string(
831 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
832 process
->tgid
= tmp
.tgid
;
833 process
->ppid
= tmp
.ppid
;
834 process
->brand
= g_quark_from_string(
835 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
837 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
841 if(feof(fp
) || ferror(fp
)) goto end_loop
;
843 gint hdr
= fgetc(fp
);
844 if(hdr
== EOF
) goto end_loop
;
848 process
->execution_stack
=
849 g_array_set_size(process
->execution_stack
,
850 process
->execution_stack
->len
+ 1);
851 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
852 process
->execution_stack
->len
-1);
855 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
856 es
->t
= g_quark_from_string(
857 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
858 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
859 es
->n
= g_quark_from_string(
860 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
861 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
862 es
->s
= g_quark_from_string(
863 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
864 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
865 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
866 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
869 process
->user_stack
= g_array_set_size(process
->user_stack
,
870 process
->user_stack
->len
+ 1);
871 address
= &g_array_index(process
->user_stack
, guint64
,
872 process
->user_stack
->len
-1);
873 fread(address
, sizeof(address
), 1, fp
);
874 process
->current_function
= *address
;
877 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
878 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
890 /* Called because a HDR_PROCESS_STATE was found */
891 /* Append a saved state to the trace states */
892 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
894 guint i
, nb_tracefile
, nb_block
, offset
;
896 LttvTracefileState
*tfcs
;
898 LttEventPosition
*ep
;
906 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
908 LttvAttributeValue value
;
909 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
910 ep
= ltt_event_position_new();
912 restore_init_state(self
);
914 fread(&t
, sizeof(t
), 1, fp
);
917 if(feof(fp
) || ferror(fp
)) goto end_loop
;
919 if(hdr
== EOF
) goto end_loop
;
923 /* Call read_process_state_raw */
924 read_process_state_raw(self
, fp
, quarktable
);
934 case HDR_PROCESS_STATE
:
940 g_error("Error while parsing saved state file : unknown data header %d",
946 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
947 for(i
=0;i
<nb_cpus
;i
++) {
950 g_assert(hdr
== HDR_CPU
);
951 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
952 g_assert(i
== cpu_num
);
953 fread(&self
->running_process
[i
]->pid
,
954 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
957 nb_tracefile
= self
->parent
.tracefiles
->len
;
959 for(i
= 0 ; i
< nb_tracefile
; i
++) {
961 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
962 LttvTracefileContext
*, i
));
963 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
964 // tfcs->parent.timestamp.tv_sec,
965 // tfcs->parent.timestamp.tv_nsec);
966 g_tree_remove(pqueue
, &tfcs
->parent
);
968 g_assert(hdr
== HDR_TRACEFILE
);
969 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
970 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
971 * position following : end of trace */
972 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
973 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
974 fread(&offset
, sizeof(offset
), 1, fp
);
975 fread(&tsc
, sizeof(tsc
), 1, fp
);
976 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
977 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
979 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
984 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
985 LTTV_STATE_SAVED_STATES
);
986 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
987 value
= lttv_attribute_add(saved_states_tree
,
988 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
989 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
990 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
992 lttv_state_save(self
, saved_state_tree
);
993 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
996 *(self
->max_time_state_recomputed_in_seek
) = t
;
1000 /* Called when a HDR_TRACE is found */
1001 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1002 GPtrArray
*quarktable
)
1007 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1009 if(hdr
== EOF
) goto end_loop
;
1012 case HDR_PROCESS_STATE
:
1013 /* Call read_process_state_raw */
1014 lttv_state_read_raw(tcs
, fp
, quarktable
);
1022 case HDR_USER_STACK
:
1026 g_error("Error while parsing saved state file :"
1027 " unexpected data header %d",
1031 g_error("Error while parsing saved state file : unknown data header %d",
1036 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1037 restore_init_state(tcs
);
1038 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1044 /* Copy each process from an existing hash table to a new one */
1046 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1048 LttvProcessState
*process
, *new_process
;
1050 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1054 process
= (LttvProcessState
*)value
;
1055 new_process
= g_new(LttvProcessState
, 1);
1056 *new_process
= *process
;
1057 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1058 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1059 new_process
->execution_stack
=
1060 g_array_set_size(new_process
->execution_stack
,
1061 process
->execution_stack
->len
);
1062 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1063 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1064 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1066 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1067 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1068 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1069 sizeof(guint64
), 0);
1070 new_process
->user_stack
=
1071 g_array_set_size(new_process
->user_stack
,
1072 process
->user_stack
->len
);
1073 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1074 g_array_index(new_process
->user_stack
, guint64
, i
) =
1075 g_array_index(process
->user_stack
, guint64
, i
);
1077 new_process
->current_function
= process
->current_function
;
1078 g_hash_table_insert(new_processes
, new_process
, new_process
);
1082 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1084 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1086 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1087 return new_processes
;
1091 /* The saved state for each trace contains a member "processes", which
1092 stores a copy of the process table, and a member "tracefiles" with
1093 one entry per tracefile. Each tracefile has a "process" member pointing
1094 to the current process and a "position" member storing the tracefile
1095 position (needed to seek to the current "next" event. */
1097 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1099 guint i
, nb_tracefile
, nb_cpus
;
1101 LttvTracefileState
*tfcs
;
1103 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1105 guint
*running_process
;
1107 LttvAttributeType type
;
1109 LttvAttributeValue value
;
1111 LttvAttributeName name
;
1113 LttEventPosition
*ep
;
1115 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1116 LTTV_STATE_TRACEFILES
);
1118 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1120 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1122 /* Add the currently running processes array */
1123 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1124 running_process
= g_new(guint
, nb_cpus
);
1125 for(i
=0;i
<nb_cpus
;i
++) {
1126 running_process
[i
] = self
->running_process
[i
]->pid
;
1128 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1130 *(value
.v_pointer
) = running_process
;
1132 g_info("State save");
1134 nb_tracefile
= self
->parent
.tracefiles
->len
;
1136 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1138 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1139 LttvTracefileContext
*, i
));
1140 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1141 value
= lttv_attribute_add(tracefiles_tree
, i
,
1143 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1145 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1147 *(value
.v_uint
) = tfcs
->process
->pid
;
1149 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1151 /* Only save the position if the tfs has not infinite time. */
1152 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1153 // && current_tfcs != tfcs) {
1154 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1155 *(value
.v_pointer
) = NULL
;
1157 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1158 ep
= ltt_event_position_new();
1159 ltt_event_position(e
, ep
);
1160 *(value
.v_pointer
) = ep
;
1162 guint nb_block
, offset
;
1165 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1166 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1168 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1174 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1176 guint i
, nb_tracefile
, pid
, nb_cpus
;
1178 LttvTracefileState
*tfcs
;
1180 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1182 guint
*running_process
;
1184 LttvAttributeType type
;
1186 LttvAttributeValue value
;
1188 LttvAttributeName name
;
1192 LttEventPosition
*ep
;
1194 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1196 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1197 LTTV_STATE_TRACEFILES
);
1199 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1201 g_assert(type
== LTTV_POINTER
);
1202 lttv_state_free_process_table(self
->processes
);
1203 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1205 /* Add the currently running processes array */
1206 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1207 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1209 g_assert(type
== LTTV_POINTER
);
1210 running_process
= *(value
.v_pointer
);
1211 for(i
=0;i
<nb_cpus
;i
++) {
1212 pid
= running_process
[i
];
1213 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1214 g_assert(self
->running_process
[i
] != NULL
);
1218 nb_tracefile
= self
->parent
.tracefiles
->len
;
1220 //g_tree_destroy(tsc->pqueue);
1221 //tsc->pqueue = g_tree_new(compare_tracefile);
1223 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1225 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1226 LttvTracefileContext
*, i
));
1227 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1228 g_assert(type
== LTTV_GOBJECT
);
1229 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1231 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1233 g_assert(type
== LTTV_UINT
);
1234 pid
= *(value
.v_uint
);
1235 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1237 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1239 g_assert(type
== LTTV_POINTER
);
1240 //g_assert(*(value.v_pointer) != NULL);
1241 ep
= *(value
.v_pointer
);
1242 g_assert(tfcs
->parent
.t_context
!= NULL
);
1244 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1245 g_tree_remove(tsc
->pqueue
, tfc
);
1248 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1249 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1250 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1251 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1252 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1254 tfc
->timestamp
= ltt_time_infinite
;
1260 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1262 guint i
, nb_tracefile
, nb_cpus
;
1264 LttvTracefileState
*tfcs
;
1266 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1268 guint
*running_process
;
1270 LttvAttributeType type
;
1272 LttvAttributeValue value
;
1274 LttvAttributeName name
;
1278 LttEventPosition
*ep
;
1280 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1281 LTTV_STATE_TRACEFILES
);
1282 g_object_ref(G_OBJECT(tracefiles_tree
));
1283 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1285 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1287 g_assert(type
== LTTV_POINTER
);
1288 lttv_state_free_process_table(*(value
.v_pointer
));
1289 *(value
.v_pointer
) = NULL
;
1290 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1292 /* Free running processes array */
1293 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1294 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1296 g_assert(type
== LTTV_POINTER
);
1297 running_process
= *(value
.v_pointer
);
1298 g_free(running_process
);
1300 nb_tracefile
= self
->parent
.tracefiles
->len
;
1302 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1304 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1305 LttvTracefileContext
*, i
));
1306 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1307 g_assert(type
== LTTV_GOBJECT
);
1308 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1310 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1312 g_assert(type
== LTTV_POINTER
);
1313 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1315 g_object_unref(G_OBJECT(tracefiles_tree
));
1319 static void free_saved_state(LttvTraceState
*self
)
1323 LttvAttributeType type
;
1325 LttvAttributeValue value
;
1327 LttvAttributeName name
;
1331 LttvAttribute
*saved_states
;
1333 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1334 LTTV_STATE_SAVED_STATES
);
1336 nb
= lttv_attribute_get_number(saved_states
);
1337 for(i
= 0 ; i
< nb
; i
++) {
1338 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1339 g_assert(type
== LTTV_GOBJECT
);
1340 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1343 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1348 create_max_time(LttvTraceState
*tcs
)
1350 LttvAttributeValue v
;
1352 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1354 g_assert(*(v
.v_pointer
) == NULL
);
1355 *(v
.v_pointer
) = g_new(LttTime
,1);
1356 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1361 get_max_time(LttvTraceState
*tcs
)
1363 LttvAttributeValue v
;
1365 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1367 g_assert(*(v
.v_pointer
) != NULL
);
1368 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1373 free_max_time(LttvTraceState
*tcs
)
1375 LttvAttributeValue v
;
1377 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1379 g_free(*(v
.v_pointer
));
1380 *(v
.v_pointer
) = NULL
;
1384 typedef struct _LttvNameTables
{
1385 // FIXME GQuark *eventtype_names;
1386 GQuark
*syscall_names
;
1392 GQuark
*soft_irq_names
;
1398 create_name_tables(LttvTraceState
*tcs
)
1402 GQuark f_name
, e_name
;
1406 LttvTraceHookByFacility
*thf
;
1412 GString
*fe_name
= g_string_new("");
1414 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1416 LttvAttributeValue v
;
1418 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1420 g_assert(*(v
.v_pointer
) == NULL
);
1421 *(v
.v_pointer
) = name_tables
;
1422 #if 0 // Use iteration over the facilities_by_name and then list all event
1423 // types of each facility
1424 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1425 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1426 for(i
= 0 ; i
< nb
; i
++) {
1427 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1428 e_name
= ltt_eventtype_name(et
);
1429 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1430 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1431 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1434 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1435 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1436 LTT_FIELD_SYSCALL_ID
, 0, 0,
1439 thf
= lttv_trace_hook_get_first(&h
);
1441 t
= ltt_field_type(thf
->f1
);
1442 nb
= ltt_type_element_number(t
);
1444 lttv_trace_hook_destroy(&h
);
1446 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1447 name_tables
->nb_syscalls
= nb
;
1449 for(i
= 0 ; i
< nb
; i
++) {
1450 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1451 if(!name_tables
->syscall_names
[i
]) {
1452 GString
*string
= g_string_new("");
1453 g_string_printf(string
, "syscall %u", i
);
1454 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1455 g_string_free(string
, TRUE
);
1459 //name_tables->syscall_names = g_new(GQuark, 256);
1460 //for(i = 0 ; i < 256 ; i++) {
1461 // g_string_printf(fe_name, "syscall %d", i);
1462 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1465 name_tables
->syscall_names
= NULL
;
1466 name_tables
->nb_syscalls
= 0;
1469 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1470 LTT_EVENT_TRAP_ENTRY
,
1471 LTT_FIELD_TRAP_ID
, 0, 0,
1474 thf
= lttv_trace_hook_get_first(&h
);
1476 t
= ltt_field_type(thf
->f1
);
1477 //nb = ltt_type_element_number(t);
1479 lttv_trace_hook_destroy(&h
);
1482 name_tables->trap_names = g_new(GQuark, nb);
1483 for(i = 0 ; i < nb ; i++) {
1484 name_tables->trap_names[i] = g_quark_from_string(
1485 ltt_enum_string_get(t, i));
1488 name_tables
->nb_traps
= 256;
1489 name_tables
->trap_names
= g_new(GQuark
, 256);
1490 for(i
= 0 ; i
< 256 ; i
++) {
1491 g_string_printf(fe_name
, "trap %d", i
);
1492 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1495 name_tables
->trap_names
= NULL
;
1496 name_tables
->nb_traps
= 0;
1499 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1500 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1501 LTT_FIELD_IRQ_ID
, 0, 0,
1504 thf
= lttv_trace_hook_get_first(&h
);
1506 t
= ltt_field_type(thf
->f1
);
1507 //nb = ltt_type_element_number(t);
1509 lttv_trace_hook_destroy(&h
);
1512 name_tables->irq_names = g_new(GQuark, nb);
1513 for(i = 0 ; i < nb ; i++) {
1514 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1518 name_tables
->nb_irqs
= 256;
1519 name_tables
->irq_names
= g_new(GQuark
, 256);
1520 for(i
= 0 ; i
< 256 ; i
++) {
1521 g_string_printf(fe_name
, "irq %d", i
);
1522 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1525 name_tables
->nb_irqs
= 0;
1526 name_tables
->irq_names
= NULL
;
1529 name_tables->soft_irq_names = g_new(GQuark, nb);
1530 for(i = 0 ; i < nb ; i++) {
1531 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1535 name_tables
->nb_softirqs
= 256;
1536 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1537 for(i
= 0 ; i
< 256 ; i
++) {
1538 g_string_printf(fe_name
, "softirq %d", i
);
1539 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1543 g_string_free(fe_name
, TRUE
);
1548 get_name_tables(LttvTraceState
*tcs
)
1550 LttvNameTables
*name_tables
;
1552 LttvAttributeValue v
;
1554 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1556 g_assert(*(v
.v_pointer
) != NULL
);
1557 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1558 //tcs->eventtype_names = name_tables->eventtype_names;
1559 tcs
->syscall_names
= name_tables
->syscall_names
;
1560 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1561 tcs
->trap_names
= name_tables
->trap_names
;
1562 tcs
->nb_traps
= name_tables
->nb_traps
;
1563 tcs
->irq_names
= name_tables
->irq_names
;
1564 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1565 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1566 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1571 free_name_tables(LttvTraceState
*tcs
)
1573 LttvNameTables
*name_tables
;
1575 LttvAttributeValue v
;
1577 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1579 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1580 *(v
.v_pointer
) = NULL
;
1582 // g_free(name_tables->eventtype_names);
1583 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1584 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1585 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1586 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1587 if(name_tables
) g_free(name_tables
);
1590 #ifdef HASH_TABLE_DEBUG
1592 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1594 LttvProcessState
*process
= (LttvProcessState
*)value
;
1596 /* Test for process corruption */
1597 guint stack_len
= process
->execution_stack
->len
;
1600 static void hash_table_check(GHashTable
*table
)
1602 g_hash_table_foreach(table
, test_process
, NULL
);
1608 /* clears the stack and sets the state passed as argument */
1609 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1611 g_array_set_size(cpust
->mode_stack
, 1);
1612 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1615 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1617 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1618 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1621 static void cpu_pop_mode(LttvCPUState
*cpust
)
1623 if(cpust
->mode_stack
->len
== 1)
1624 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1626 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1629 /* clears the stack and sets the state passed as argument */
1630 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1632 g_array_set_size(irqst
->mode_stack
, 1);
1633 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1636 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1638 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1639 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1642 static void irq_pop_mode(LttvIRQState
*irqst
)
1644 if(irqst
->mode_stack
->len
== 1)
1645 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1647 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1650 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1653 LttvExecutionState
*es
;
1655 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1656 guint cpu
= tfs
->cpu
;
1658 #ifdef HASH_TABLE_DEBUG
1659 hash_table_check(ts
->processes
);
1661 LttvProcessState
*process
= ts
->running_process
[cpu
];
1663 guint depth
= process
->execution_stack
->len
;
1665 process
->execution_stack
=
1666 g_array_set_size(process
->execution_stack
, depth
+ 1);
1669 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1671 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1674 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1675 es
->cum_cpu_time
= ltt_time_zero
;
1676 es
->s
= process
->state
->s
;
1677 process
->state
= es
;
1681 * return 1 when empty, else 0 */
1682 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1683 LttvTracefileState
*tfs
)
1685 guint cpu
= tfs
->cpu
;
1686 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1688 guint depth
= process
->execution_stack
->len
;
1694 process
->execution_stack
=
1695 g_array_set_size(process
->execution_stack
, depth
- 1);
1696 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1698 process
->state
->change
= tfs
->parent
.timestamp
;
1703 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1705 guint cpu
= tfs
->cpu
;
1706 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1707 LttvProcessState
*process
= ts
->running_process
[cpu
];
1709 guint depth
= process
->execution_stack
->len
;
1711 if(process
->state
->t
!= t
){
1712 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1713 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1714 g_info("process state has %s when pop_int is %s\n",
1715 g_quark_to_string(process
->state
->t
),
1716 g_quark_to_string(t
));
1717 g_info("{ %u, %u, %s, %s, %s }\n",
1720 g_quark_to_string(process
->name
),
1721 g_quark_to_string(process
->brand
),
1722 g_quark_to_string(process
->state
->s
));
1727 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1728 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1732 process
->execution_stack
=
1733 g_array_set_size(process
->execution_stack
, depth
- 1);
1734 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1736 process
->state
->change
= tfs
->parent
.timestamp
;
1739 struct search_result
{
1740 const LttTime
*time
; /* Requested time */
1741 LttTime
*best
; /* Best result */
1744 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1746 const LttTime
*elem_time
= (const LttTime
*)a
;
1747 /* Explicit non const cast */
1748 struct search_result
*res
= (struct search_result
*)b
;
1750 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1751 /* The usertrace was created before the schedchange */
1752 /* Get larger keys */
1754 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1755 /* The usertrace was created after the schedchange time */
1756 /* Get smaller keys */
1758 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1759 res
->best
= elem_time
;
1762 res
->best
= elem_time
;
1769 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1770 guint pid
, const LttTime
*timestamp
)
1772 LttvTracefileState
*tfs
= NULL
;
1773 struct search_result res
;
1774 /* Find the usertrace associated with a pid and time interval.
1775 * Search in the usertraces by PID (within a hash) and then, for each
1776 * corresponding element of the array, find the first one with creation
1777 * timestamp the lowest, but higher or equal to "timestamp". */
1778 res
.time
= timestamp
;
1780 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1781 if(usertrace_tree
) {
1782 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1784 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1792 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1793 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1795 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1797 LttvExecutionState
*es
;
1799 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1804 process
->tgid
= tgid
;
1806 process
->name
= name
;
1807 process
->brand
= LTTV_STATE_UNBRANDED
;
1808 //process->last_cpu = tfs->cpu_name;
1809 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1810 process
->type
= LTTV_STATE_USER_THREAD
;
1811 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1812 process
->current_function
= 0; //function 0x0 by default.
1814 g_info("Process %u, core %p", process
->pid
, process
);
1815 g_hash_table_insert(tcs
->processes
, process
, process
);
1818 process
->ppid
= parent
->pid
;
1819 process
->creation_time
= *timestamp
;
1822 /* No parent. This process exists but we are missing all information about
1823 its creation. The birth time is set to zero but we remember the time of
1828 process
->creation_time
= ltt_time_zero
;
1831 process
->insertion_time
= *timestamp
;
1832 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1833 process
->creation_time
.tv_nsec
);
1834 process
->pid_time
= g_quark_from_string(buffer
);
1836 //process->last_cpu = tfs->cpu_name;
1837 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1838 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1839 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1840 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1841 es
= process
->state
= &g_array_index(process
->execution_stack
,
1842 LttvExecutionState
, 0);
1843 es
->t
= LTTV_STATE_USER_MODE
;
1844 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1845 es
->entry
= *timestamp
;
1846 //g_assert(timestamp->tv_sec != 0);
1847 es
->change
= *timestamp
;
1848 es
->cum_cpu_time
= ltt_time_zero
;
1849 es
->s
= LTTV_STATE_RUN
;
1851 es
= process
->state
= &g_array_index(process
->execution_stack
,
1852 LttvExecutionState
, 1);
1853 es
->t
= LTTV_STATE_SYSCALL
;
1854 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1855 es
->entry
= *timestamp
;
1856 //g_assert(timestamp->tv_sec != 0);
1857 es
->change
= *timestamp
;
1858 es
->cum_cpu_time
= ltt_time_zero
;
1859 es
->s
= LTTV_STATE_WAIT_FORK
;
1861 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1862 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1863 sizeof(guint64
), 0);
1868 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1871 LttvProcessState key
;
1872 LttvProcessState
*process
;
1876 process
= g_hash_table_lookup(ts
->processes
, &key
);
1881 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1882 const LttTime
*timestamp
)
1884 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1885 LttvExecutionState
*es
;
1887 /* Put ltt_time_zero creation time for unexisting processes */
1888 if(unlikely(process
== NULL
)) {
1889 process
= lttv_state_create_process(ts
,
1890 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1891 /* We are not sure is it's a kernel thread or normal thread, put the
1892 * bottom stack state to unknown */
1893 process
->execution_stack
=
1894 g_array_set_size(process
->execution_stack
, 1);
1895 process
->state
= es
=
1896 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1897 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1898 es
->s
= LTTV_STATE_UNNAMED
;
1903 /* FIXME : this function should be called when we receive an event telling that
1904 * release_task has been called in the kernel. In happens generally when
1905 * the parent waits for its child terminaison, but may also happen in special
1906 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1907 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1908 * of a killed thread ground, but isn't the leader.
1910 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1912 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1913 LttvProcessState key
;
1915 key
.pid
= process
->pid
;
1916 key
.cpu
= process
->cpu
;
1917 g_hash_table_remove(ts
->processes
, &key
);
1918 g_array_free(process
->execution_stack
, TRUE
);
1919 g_array_free(process
->user_stack
, TRUE
);
1924 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1926 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1927 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1932 static void lttv_state_free_process_table(GHashTable
*processes
)
1934 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1935 g_hash_table_destroy(processes
);
1939 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1941 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1943 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1944 LttvProcessState
*process
= ts
->running_process
[cpu
];
1945 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1946 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1947 LttField
*f
= thf
->f1
;
1949 LttvExecutionSubmode submode
;
1951 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1952 guint syscall
= ltt_event_get_unsigned(e
, f
);
1954 if(syscall
< nb_syscalls
) {
1955 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1958 /* Fixup an incomplete syscall table */
1959 GString
*string
= g_string_new("");
1960 g_string_printf(string
, "syscall %u", syscall
);
1961 submode
= g_quark_from_string(string
->str
);
1962 g_string_free(string
, TRUE
);
1964 /* There can be no system call from PID 0 : unknown state */
1965 if(process
->pid
!= 0)
1966 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1971 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1973 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1975 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1976 LttvProcessState
*process
= ts
->running_process
[cpu
];
1978 /* There can be no system call from PID 0 : unknown state */
1979 if(process
->pid
!= 0)
1980 pop_state(s
, LTTV_STATE_SYSCALL
);
1985 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1987 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1988 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1989 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1990 LttField
*f
= thf
->f1
;
1992 LttvExecutionSubmode submode
;
1994 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1995 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1997 if(trap
< nb_traps
) {
1998 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2000 /* Fixup an incomplete trap table */
2001 GString
*string
= g_string_new("");
2002 g_string_printf(string
, "trap %llu", trap
);
2003 submode
= g_quark_from_string(string
->str
);
2004 g_string_free(string
, TRUE
);
2007 push_state(s
, LTTV_STATE_TRAP
, submode
);
2009 /* update cpu status */
2010 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2015 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2017 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2019 pop_state(s
, LTTV_STATE_TRAP
);
2021 /* update cpu status */
2022 cpu_pop_mode(s
->cpu_state
);
2027 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2029 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2030 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2031 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2032 guint8 fac_id
= ltt_event_facility_id(e
);
2033 guint8 ev_id
= ltt_event_eventtype_id(e
);
2034 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2035 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2036 g_assert(thf
->f1
!= NULL
);
2037 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2038 LttField
*f
= thf
->f1
;
2040 LttvExecutionSubmode submode
;
2041 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2042 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2046 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2048 /* Fixup an incomplete irq table */
2049 GString
*string
= g_string_new("");
2050 g_string_printf(string
, "irq %llu", irq
);
2051 submode
= g_quark_from_string(string
->str
);
2052 g_string_free(string
, TRUE
);
2055 /* Do something with the info about being in user or system mode when int? */
2056 push_state(s
, LTTV_STATE_IRQ
, submode
);
2058 /* update cpu status */
2059 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2061 /* update irq status */
2062 s
->cpu_state
->last_irq
= irq
;
2063 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2068 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2070 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2072 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2078 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2080 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2081 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2083 pop_state(s
, LTTV_STATE_IRQ
);
2085 /* update cpu status */
2086 cpu_pop_mode(s
->cpu_state
);
2088 /* update irq status */
2089 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2094 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2096 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2097 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2098 guint8 fac_id
= ltt_event_facility_id(e
);
2099 guint8 ev_id
= ltt_event_eventtype_id(e
);
2100 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2101 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2102 g_assert(thf
->f1
!= NULL
);
2103 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2104 LttField
*f
= thf
->f1
;
2106 LttvExecutionSubmode submode
;
2107 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2108 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2111 if(softirq
< nb_softirqs
) {
2112 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2114 /* Fixup an incomplete irq table */
2115 GString
*string
= g_string_new("");
2116 g_string_printf(string
, "softirq %llu", softirq
);
2117 submode
= g_quark_from_string(string
->str
);
2118 g_string_free(string
, TRUE
);
2121 /* Do something with the info about being in user or system mode when int? */
2122 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2126 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2130 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2131 guint cpu
= tfs
->cpu
;
2132 LttvProcessState
*process
= ts
->running_process
[cpu
];
2134 guint depth
= process
->user_stack
->len
;
2136 process
->user_stack
=
2137 g_array_set_size(process
->user_stack
, depth
+ 1);
2139 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2140 *new_func
= funcptr
;
2141 process
->current_function
= funcptr
;
2144 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2146 guint cpu
= tfs
->cpu
;
2147 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2148 LttvProcessState
*process
= ts
->running_process
[cpu
];
2150 if(process
->current_function
!= funcptr
){
2151 g_info("Different functions (%lu.%09lu): ignore it\n",
2152 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2153 g_info("process state has %llu when pop_function is %llu\n",
2154 process
->current_function
, funcptr
);
2155 g_info("{ %u, %u, %s, %s, %s }\n",
2158 g_quark_to_string(process
->name
),
2159 g_quark_to_string(process
->brand
),
2160 g_quark_to_string(process
->state
->s
));
2163 guint depth
= process
->user_stack
->len
;
2166 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2167 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2171 process
->user_stack
=
2172 g_array_set_size(process
->user_stack
, depth
- 1);
2173 process
->current_function
=
2174 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2178 static gboolean
function_entry(void *hook_data
, void *call_data
)
2180 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2181 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2182 guint8 fac_id
= ltt_event_facility_id(e
);
2183 guint8 ev_id
= ltt_event_eventtype_id(e
);
2184 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2185 g_assert(thf
->f1
!= NULL
);
2186 LttField
*f
= thf
->f1
;
2187 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2189 push_function(s
, funcptr
);
2193 static gboolean
function_exit(void *hook_data
, void *call_data
)
2195 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2196 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2197 guint8 fac_id
= ltt_event_facility_id(e
);
2198 guint8 ev_id
= ltt_event_eventtype_id(e
);
2199 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2200 g_assert(thf
->f1
!= NULL
);
2201 LttField
*f
= thf
->f1
;
2202 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2204 LttvExecutionSubmode submode
;
2206 pop_function(s
, funcptr
);
2210 static gboolean
schedchange(void *hook_data
, void *call_data
)
2212 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2214 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2215 LttvProcessState
*process
= ts
->running_process
[cpu
];
2216 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2218 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2219 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2220 guint pid_in
, pid_out
;
2223 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2224 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2225 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2227 if(likely(process
!= NULL
)) {
2229 /* We could not know but it was not the idle process executing.
2230 This should only happen at the beginning, before the first schedule
2231 event, and when the initial information (current process for each CPU)
2232 is missing. It is not obvious how we could, after the fact, compensate
2233 the wrongly attributed statistics. */
2235 //This test only makes sense once the state is known and if there is no
2236 //missing events. We need to silently ignore schedchange coming after a
2237 //process_free, or it causes glitches. (FIXME)
2238 //if(unlikely(process->pid != pid_out)) {
2239 // g_assert(process->pid == 0);
2241 if(process
->pid
== 0
2242 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2244 /* Scheduling out of pid 0 at beginning of the trace :
2245 * we know for sure it is in syscall mode at this point. */
2246 g_assert(process
->execution_stack
->len
== 1);
2247 process
->state
->t
= LTTV_STATE_SYSCALL
;
2248 process
->state
->s
= LTTV_STATE_WAIT
;
2249 process
->state
->change
= s
->parent
.timestamp
;
2250 process
->state
->entry
= s
->parent
.timestamp
;
2253 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2254 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2255 process
->state
->change
= s
->parent
.timestamp
;
2257 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2258 else process
->state
->s
= LTTV_STATE_WAIT
;
2259 process
->state
->change
= s
->parent
.timestamp
;
2262 if(state_out
== 32 || state_out
== 128)
2263 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2264 /* see sched.h for states */
2267 process
= ts
->running_process
[cpu
] =
2268 lttv_state_find_process_or_create(
2269 (LttvTraceState
*)s
->parent
.t_context
,
2271 &s
->parent
.timestamp
);
2272 process
->state
->s
= LTTV_STATE_RUN
;
2274 if(process
->usertrace
)
2275 process
->usertrace
->cpu
= cpu
;
2276 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2277 process
->state
->change
= s
->parent
.timestamp
;
2279 /* update cpu status */
2281 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2283 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2288 static gboolean
process_fork(void *hook_data
, void *call_data
)
2290 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2291 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2292 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2294 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2295 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2296 LttvProcessState
*zombie_process
;
2298 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2299 LttvProcessState
*process
= ts
->running_process
[cpu
];
2300 LttvProcessState
*child_process
;
2303 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2306 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2307 s
->parent
.target_pid
= child_pid
;
2310 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2311 else child_tgid
= 0;
2313 /* Mathieu : it seems like the process might have been scheduled in before the
2314 * fork, and, in a rare case, might be the current process. This might happen
2315 * in a SMP case where we don't have enough precision on the clocks.
2317 * Test reenabled after precision fixes on time. (Mathieu) */
2319 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2321 if(unlikely(zombie_process
!= NULL
)) {
2322 /* Reutilisation of PID. Only now we are sure that the old PID
2323 * has been released. FIXME : should know when release_task happens instead.
2325 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2327 for(i
=0; i
< num_cpus
; i
++) {
2328 g_assert(zombie_process
!= ts
->running_process
[i
]);
2331 exit_process(s
, zombie_process
);
2334 g_assert(process
->pid
!= child_pid
);
2335 // FIXME : Add this test in the "known state" section
2336 // g_assert(process->pid == parent_pid);
2337 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2338 if(child_process
== NULL
) {
2339 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2340 child_pid
, child_tgid
,
2341 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2343 /* The process has already been created : due to time imprecision between
2344 * multiple CPUs : it has been scheduled in before creation. Note that we
2345 * shouldn't have this kind of imprecision.
2347 * Simply put a correct parent.
2349 g_assert(0); /* This is a problematic case : the process has been created
2350 before the fork event */
2351 child_process
->ppid
= process
->pid
;
2352 child_process
->tgid
= child_tgid
;
2354 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2355 child_process
->name
= process
->name
;
2356 child_process
->brand
= process
->brand
;
2361 /* We stamp a newly created process as kernel_thread.
2362 * The thread should not be running yet. */
2363 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2365 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2366 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2367 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2370 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2371 LttvProcessState
*process
;
2372 LttvExecutionState
*es
;
2375 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2376 s
->parent
.target_pid
= pid
;
2378 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2380 process
->execution_stack
=
2381 g_array_set_size(process
->execution_stack
, 1);
2382 es
= process
->state
=
2383 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2384 es
->t
= LTTV_STATE_SYSCALL
;
2385 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2390 static gboolean
process_exit(void *hook_data
, void *call_data
)
2392 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2393 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2394 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2398 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2399 LttvProcessState
*process
; // = ts->running_process[cpu];
2401 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2402 s
->parent
.target_pid
= pid
;
2404 // FIXME : Add this test in the "known state" section
2405 // g_assert(process->pid == pid);
2407 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2408 if(likely(process
!= NULL
)) {
2409 process
->state
->s
= LTTV_STATE_EXIT
;
2414 static gboolean
process_free(void *hook_data
, void *call_data
)
2416 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2417 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2418 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2419 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2421 LttvProcessState
*process
;
2423 /* PID of the process to release */
2424 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2425 s
->parent
.target_pid
= release_pid
;
2427 g_assert(release_pid
!= 0);
2429 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2431 if(likely(process
!= NULL
)) {
2432 /* release_task is happening at kernel level : we can now safely release
2433 * the data structure of the process */
2434 //This test is fun, though, as it may happen that
2435 //at time t : CPU 0 : process_free
2436 //at time t+150ns : CPU 1 : schedule out
2437 //Clearly due to time imprecision, we disable it. (Mathieu)
2438 //If this weird case happen, we have no choice but to put the
2439 //Currently running process on the cpu to 0.
2440 //I re-enable it following time precision fixes. (Mathieu)
2441 //Well, in the case where an process is freed by a process on another CPU
2442 //and still scheduled, it happens that this is the schedchange that will
2443 //drop the last reference count. Do not free it here!
2444 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2446 for(i
=0; i
< num_cpus
; i
++) {
2447 //g_assert(process != ts->running_process[i]);
2448 if(process
== ts
->running_process
[i
]) {
2449 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2453 if(i
== num_cpus
) /* process is not scheduled */
2454 exit_process(s
, process
);
2461 static gboolean
process_exec(void *hook_data
, void *call_data
)
2463 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2464 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2465 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2466 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2469 LttvProcessState
*process
= ts
->running_process
[cpu
];
2471 #if 0//how to use a sequence that must be transformed in a string
2472 /* PID of the process to release */
2473 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2474 //name = ltt_event_get_string(e, thf->f1);
2475 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2477 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2478 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2479 memcpy(null_term_name
, name_begin
, name_len
);
2480 null_term_name
[name_len
] = '\0';
2481 process
->name
= g_quark_from_string(null_term_name
);
2484 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2485 process
->brand
= LTTV_STATE_UNBRANDED
;
2486 //g_free(null_term_name);
2490 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2492 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2493 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2494 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2495 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2498 LttvProcessState
*process
= ts
->running_process
[cpu
];
2500 name
= ltt_event_get_string(e
, thf
->f1
);
2501 process
->brand
= g_quark_from_string(name
);
2506 static void fix_process(gpointer key
, gpointer value
,
2509 LttvProcessState
*process
;
2510 LttvExecutionState
*es
;
2511 process
= (LttvProcessState
*)value
;
2512 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2513 LttTime
*timestamp
= (LttTime
*)user_data
;
2515 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2516 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2517 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2518 es
->t
= LTTV_STATE_SYSCALL
;
2519 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2520 es
->entry
= *timestamp
;
2521 es
->change
= *timestamp
;
2522 es
->cum_cpu_time
= ltt_time_zero
;
2523 if(es
->s
== LTTV_STATE_UNNAMED
)
2524 es
->s
= LTTV_STATE_WAIT
;
2527 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2528 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2529 es
->t
= LTTV_STATE_USER_MODE
;
2530 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2531 es
->entry
= *timestamp
;
2532 //g_assert(timestamp->tv_sec != 0);
2533 es
->change
= *timestamp
;
2534 es
->cum_cpu_time
= ltt_time_zero
;
2535 if(es
->s
== LTTV_STATE_UNNAMED
)
2536 es
->s
= LTTV_STATE_RUN
;
2538 if(process
->execution_stack
->len
== 1) {
2539 /* Still in bottom unknown mode, means never did a system call
2540 * May be either in user mode, syscall mode, running or waiting.*/
2541 /* FIXME : we may be tagging syscall mode when being user mode */
2542 process
->execution_stack
=
2543 g_array_set_size(process
->execution_stack
, 2);
2544 es
= process
->state
= &g_array_index(process
->execution_stack
,
2545 LttvExecutionState
, 1);
2546 es
->t
= LTTV_STATE_SYSCALL
;
2547 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2548 es
->entry
= *timestamp
;
2549 //g_assert(timestamp->tv_sec != 0);
2550 es
->change
= *timestamp
;
2551 es
->cum_cpu_time
= ltt_time_zero
;
2552 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2553 es
->s
= LTTV_STATE_WAIT
;
2559 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2561 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2562 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2563 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2564 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2565 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2567 /* For all processes */
2568 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2569 /* else, if stack[0] is unknown, set to user mode, running */
2571 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2574 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2576 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2577 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2578 //It's slow : optimise later by doing this before reading trace.
2579 LttEventType
*et
= ltt_event_eventtype(e
);
2581 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2587 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2588 LttvProcessState
*process
= ts
->running_process
[cpu
];
2589 LttvProcessState
*parent_process
;
2590 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2591 GQuark type
, mode
, submode
, status
;
2592 LttvExecutionState
*es
;
2596 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2597 s
->parent
.target_pid
= pid
;
2600 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2603 command
= ltt_event_get_string(e
, thf
->f3
);
2606 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2607 type
= ltt_enum_string_get(ltt_field_type(f4
),
2608 ltt_event_get_unsigned(e
, f4
));
2611 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2612 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2613 ltt_event_get_unsigned(e
, f5
));
2616 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2617 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2618 ltt_event_get_unsigned(e
, f6
));
2621 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2622 status
= ltt_enum_string_get(ltt_field_type(f7
),
2623 ltt_event_get_unsigned(e
, f7
));
2626 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2627 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2632 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2633 for(i
=0; i
<nb_cpus
; i
++) {
2634 process
= lttv_state_find_process(ts
, i
, pid
);
2635 g_assert(process
!= NULL
);
2637 process
->ppid
= parent_pid
;
2638 process
->tgid
= tgid
;
2639 process
->name
= g_quark_from_string(command
);
2641 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2642 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2646 /* The process might exist if a process was forked while performing the
2648 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2649 if(process
== NULL
) {
2650 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2651 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2652 pid
, tgid
, g_quark_from_string(command
),
2653 &s
->parent
.timestamp
);
2655 /* Keep the stack bottom : a running user mode */
2656 /* Disabled because of inconsistencies in the current statedump states. */
2657 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2658 /* Only keep the bottom
2659 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2660 /* Will cause expected trap when in fact being syscall (even after end of
2662 * Will cause expected interrupt when being syscall. (only before end of
2663 * statedump event) */
2664 // This will cause a "popping last state on stack, ignoring it."
2665 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2666 es
= process
->state
= &g_array_index(process
->execution_stack
,
2667 LttvExecutionState
, 0);
2668 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2669 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2670 es
->s
= LTTV_STATE_UNNAMED
;
2671 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2673 es
->t
= LTTV_STATE_SYSCALL
;
2678 /* User space process :
2679 * bottom : user mode
2680 * either currently running or scheduled out.
2681 * can be scheduled out because interrupted in (user mode or in syscall)
2682 * or because of an explicit call to the scheduler in syscall. Note that
2683 * the scheduler call comes after the irq_exit, so never in interrupt
2685 // temp workaround : set size to 1 : only have user mode bottom of stack.
2686 // will cause g_info message of expected syscall mode when in fact being
2687 // in user mode. Can also cause expected trap when in fact being user
2688 // mode in the event of a page fault reenabling interrupts in the handler.
2689 // Expected syscall and trap can also happen after the end of statedump
2690 // This will cause a "popping last state on stack, ignoring it."
2691 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2692 es
= process
->state
= &g_array_index(process
->execution_stack
,
2693 LttvExecutionState
, 0);
2694 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2695 es
->s
= LTTV_STATE_UNNAMED
;
2696 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2698 es
->t
= LTTV_STATE_USER_MODE
;
2706 es
= process
->state
= &g_array_index(process
->execution_stack
,
2707 LttvExecutionState
, 1);
2708 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2709 es
->s
= LTTV_STATE_UNNAMED
;
2710 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2714 /* The process has already been created :
2715 * Probably was forked while dumping the process state or
2716 * was simply scheduled in prior to get the state dump event.
2718 process
->ppid
= parent_pid
;
2719 process
->tgid
= tgid
;
2720 process
->name
= g_quark_from_string(command
);
2721 process
->type
= type
;
2723 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2725 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2726 if(type
== LTTV_STATE_KERNEL_THREAD
)
2727 es
->t
= LTTV_STATE_SYSCALL
;
2729 es
->t
= LTTV_STATE_USER_MODE
;
2732 /* Don't mess around with the stack, it will eventually become
2733 * ok after the end of state dump. */
2740 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2742 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2744 lttv_state_add_event_hooks(tss
);
2749 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2751 LttvTraceset
*traceset
= self
->parent
.ts
;
2753 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2757 LttvTracefileState
*tfs
;
2761 LttvTraceHookByFacility
*thf
;
2763 LttvTraceHook
*hook
;
2765 LttvAttributeValue val
;
2770 nb_trace
= lttv_traceset_number(traceset
);
2771 for(i
= 0 ; i
< nb_trace
; i
++) {
2772 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2774 /* Find the eventtype id for the following events and register the
2775 associated by id hooks. */
2777 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2778 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2781 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2782 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2783 LTT_FIELD_SYSCALL_ID
, 0, 0,
2784 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2787 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2788 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2790 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2793 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2794 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2795 LTT_FIELD_TRAP_ID
, 0, 0,
2796 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2799 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2800 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2802 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2805 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2806 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2807 LTT_FIELD_IRQ_ID
, 0, 0,
2808 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2811 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2812 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2814 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2817 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2818 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2819 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2820 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2823 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2824 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2826 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2829 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2830 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2831 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2832 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2835 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2836 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2837 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2838 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2841 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2842 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2843 LTT_FIELD_PID
, 0, 0,
2844 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2848 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2849 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2850 LTT_FIELD_PID
, 0, 0,
2851 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2854 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2855 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
2856 LTT_FIELD_PID
, 0, 0,
2857 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2860 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2861 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2862 LTT_FIELD_FILENAME
, 0, 0,
2863 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2866 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2867 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2868 LTT_FIELD_NAME
, 0, 0,
2869 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2872 /* statedump-related hooks */
2873 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2874 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
2875 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2876 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2879 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2880 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
2882 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2885 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2886 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2887 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2888 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2891 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2892 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2893 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2894 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2897 hooks
= g_array_set_size(hooks
, hn
);
2899 /* Add these hooks to each event_by_id hooks list */
2901 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2903 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2905 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2906 LttvTracefileContext
*, j
));
2908 for(k
= 0 ; k
< hooks
->len
; k
++) {
2909 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2910 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2911 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2913 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2920 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2921 *(val
.v_pointer
) = hooks
;
2925 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2927 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2929 lttv_state_remove_event_hooks(tss
);
2934 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2936 LttvTraceset
*traceset
= self
->parent
.ts
;
2938 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2942 LttvTracefileState
*tfs
;
2946 LttvTraceHook
*hook
;
2948 LttvTraceHookByFacility
*thf
;
2950 LttvAttributeValue val
;
2952 nb_trace
= lttv_traceset_number(traceset
);
2953 for(i
= 0 ; i
< nb_trace
; i
++) {
2954 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2956 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2957 hooks
= *(val
.v_pointer
);
2959 /* Remove these hooks from each event_by_id hooks list */
2961 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2963 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2965 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2966 LttvTracefileContext
*, j
));
2968 for(k
= 0 ; k
< hooks
->len
; k
++) {
2969 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2970 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2971 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2973 lttv_hooks_remove_data(
2974 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2980 for(k
= 0 ; k
< hooks
->len
; k
++)
2981 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2982 g_array_free(hooks
, TRUE
);
2986 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2988 guint
*event_count
= (guint
*)hook_data
;
2990 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2991 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2996 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2998 LttvTracefileState
*tfcs
;
3000 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3002 LttEventPosition
*ep
;
3008 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3010 LttvAttributeValue value
;
3012 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3013 LTTV_STATE_SAVED_STATES
);
3014 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3015 value
= lttv_attribute_add(saved_states_tree
,
3016 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3017 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3018 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3019 *(value
.v_time
) = self
->parent
.timestamp
;
3020 lttv_state_save(tcs
, saved_state_tree
);
3021 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3022 self
->parent
.timestamp
.tv_nsec
);
3024 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3029 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3031 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3033 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3038 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3046 static gboolean
block_start(void *hook_data
, void *call_data
)
3048 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3050 LttvTracefileState
*tfcs
;
3052 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3054 LttEventPosition
*ep
;
3056 guint i
, nb_block
, nb_event
, nb_tracefile
;
3060 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3062 LttvAttributeValue value
;
3064 ep
= ltt_event_position_new();
3066 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3068 /* Count the number of events added since the last block end in any
3071 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3073 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3074 LttvTracefileContext
, i
));
3075 ltt_event_position(tfcs
->parent
.e
, ep
);
3076 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3077 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3078 tfcs
->saved_position
= nb_event
;
3082 if(tcs
->nb_event
>= tcs
->save_interval
) {
3083 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3084 LTTV_STATE_SAVED_STATES
);
3085 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3086 value
= lttv_attribute_add(saved_states_tree
,
3087 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3088 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3089 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3090 *(value
.v_time
) = self
->parent
.timestamp
;
3091 lttv_state_save(tcs
, saved_state_tree
);
3093 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3094 self
->parent
.timestamp
.tv_nsec
);
3096 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3102 static gboolean
block_end(void *hook_data
, void *call_data
)
3104 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3106 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3110 LttEventPosition
*ep
;
3112 guint nb_block
, nb_event
;
3114 ep
= ltt_event_position_new();
3115 ltt_event_position(self
->parent
.e
, ep
);
3116 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3117 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3118 self
->saved_position
= 0;
3119 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3126 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3128 LttvTraceset
*traceset
= self
->parent
.ts
;
3130 guint i
, j
, nb_trace
, nb_tracefile
;
3134 LttvTracefileState
*tfs
;
3136 LttvTraceHook hook_start
, hook_end
;
3138 nb_trace
= lttv_traceset_number(traceset
);
3139 for(i
= 0 ; i
< nb_trace
; i
++) {
3140 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3142 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3143 NULL
, NULL
, block_start
, &hook_start
);
3144 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3145 NULL
, NULL
, block_end
, &hook_end
);
3147 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3149 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3151 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3152 LttvTracefileContext
, j
));
3153 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3154 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3155 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3156 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3162 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3164 LttvTraceset
*traceset
= self
->parent
.ts
;
3166 guint i
, j
, nb_trace
, nb_tracefile
;
3170 LttvTracefileState
*tfs
;
3173 nb_trace
= lttv_traceset_number(traceset
);
3174 for(i
= 0 ; i
< nb_trace
; i
++) {
3176 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3177 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3179 if(ts
->has_precomputed_states
) continue;
3181 guint
*event_count
= g_new(guint
, 1);
3184 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3186 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3187 LttvTracefileContext
*, j
));
3188 lttv_hooks_add(tfs
->parent
.event
,
3189 state_save_event_hook
,
3196 lttv_process_traceset_begin(&self
->parent
,
3197 NULL
, NULL
, NULL
, NULL
, NULL
);
3201 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3203 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3205 lttv_state_save_add_event_hooks(tss
);
3212 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3214 LttvTraceset
*traceset
= self
->parent
.ts
;
3216 guint i
, j
, nb_trace
, nb_tracefile
;
3220 LttvTracefileState
*tfs
;
3222 LttvTraceHook hook_start
, hook_end
;
3224 nb_trace
= lttv_traceset_number(traceset
);
3225 for(i
= 0 ; i
< nb_trace
; i
++) {
3226 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3228 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3229 NULL
, NULL
, block_start
, &hook_start
);
3231 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3232 NULL
, NULL
, block_end
, &hook_end
);
3234 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3236 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3238 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3239 LttvTracefileContext
, j
));
3240 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3241 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3242 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3243 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3249 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3251 LttvTraceset
*traceset
= self
->parent
.ts
;
3253 guint i
, j
, nb_trace
, nb_tracefile
;
3257 LttvTracefileState
*tfs
;
3259 LttvHooks
*after_trace
= lttv_hooks_new();
3261 lttv_hooks_add(after_trace
,
3262 state_save_after_trace_hook
,
3267 lttv_process_traceset_end(&self
->parent
,
3268 NULL
, after_trace
, NULL
, NULL
, NULL
);
3270 lttv_hooks_destroy(after_trace
);
3272 nb_trace
= lttv_traceset_number(traceset
);
3273 for(i
= 0 ; i
< nb_trace
; i
++) {
3275 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3276 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3278 if(ts
->has_precomputed_states
) continue;
3280 guint
*event_count
= NULL
;
3282 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3284 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3285 LttvTracefileContext
*, j
));
3286 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3287 state_save_event_hook
);
3289 if(event_count
) g_free(event_count
);
3293 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3295 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3297 lttv_state_save_remove_event_hooks(tss
);
3302 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3304 LttvTraceset
*traceset
= self
->parent
.ts
;
3308 int min_pos
, mid_pos
, max_pos
;
3310 guint call_rest
= 0;
3312 LttvTraceState
*tcs
;
3314 LttvAttributeValue value
;
3316 LttvAttributeType type
;
3318 LttvAttributeName name
;
3322 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3324 //g_tree_destroy(self->parent.pqueue);
3325 //self->parent.pqueue = g_tree_new(compare_tracefile);
3327 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3329 nb_trace
= lttv_traceset_number(traceset
);
3330 for(i
= 0 ; i
< nb_trace
; i
++) {
3331 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3333 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3334 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3335 LTTV_STATE_SAVED_STATES
);
3338 if(saved_states_tree
) {
3339 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3340 mid_pos
= max_pos
/ 2;
3341 while(min_pos
< max_pos
) {
3342 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3344 g_assert(type
== LTTV_GOBJECT
);
3345 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3346 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3348 g_assert(type
== LTTV_TIME
);
3349 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3351 closest_tree
= saved_state_tree
;
3353 else max_pos
= mid_pos
- 1;
3355 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3359 /* restore the closest earlier saved state */
3361 lttv_state_restore(tcs
, closest_tree
);
3365 /* There is no saved state, yet we want to have it. Restart at T0 */
3367 restore_init_state(tcs
);
3368 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3371 /* We want to seek quickly without restoring/updating the state */
3373 restore_init_state(tcs
);
3374 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3377 if(!call_rest
) g_info("NOT Calling restore");
3382 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3388 traceset_state_finalize (LttvTracesetState
*self
)
3390 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3391 finalize(G_OBJECT(self
));
3396 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3398 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3400 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3401 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3402 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3403 klass
->new_traceset_context
= new_traceset_context
;
3404 klass
->new_trace_context
= new_trace_context
;
3405 klass
->new_tracefile_context
= new_tracefile_context
;
3410 lttv_traceset_state_get_type(void)
3412 static GType type
= 0;
3414 static const GTypeInfo info
= {
3415 sizeof (LttvTracesetStateClass
),
3416 NULL
, /* base_init */
3417 NULL
, /* base_finalize */
3418 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3419 NULL
, /* class_finalize */
3420 NULL
, /* class_data */
3421 sizeof (LttvTracesetState
),
3422 0, /* n_preallocs */
3423 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3424 NULL
/* value handling */
3427 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3435 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3441 trace_state_finalize (LttvTraceState
*self
)
3443 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3444 finalize(G_OBJECT(self
));
3449 trace_state_class_init (LttvTraceStateClass
*klass
)
3451 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3453 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3454 klass
->state_save
= state_save
;
3455 klass
->state_restore
= state_restore
;
3456 klass
->state_saved_free
= state_saved_free
;
3461 lttv_trace_state_get_type(void)
3463 static GType type
= 0;
3465 static const GTypeInfo info
= {
3466 sizeof (LttvTraceStateClass
),
3467 NULL
, /* base_init */
3468 NULL
, /* base_finalize */
3469 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3470 NULL
, /* class_finalize */
3471 NULL
, /* class_data */
3472 sizeof (LttvTraceState
),
3473 0, /* n_preallocs */
3474 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3475 NULL
/* value handling */
3478 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3479 "LttvTraceStateType", &info
, 0);
3486 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3492 tracefile_state_finalize (LttvTracefileState
*self
)
3494 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3495 finalize(G_OBJECT(self
));
3500 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3502 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3504 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3509 lttv_tracefile_state_get_type(void)
3511 static GType type
= 0;
3513 static const GTypeInfo info
= {
3514 sizeof (LttvTracefileStateClass
),
3515 NULL
, /* base_init */
3516 NULL
, /* base_finalize */
3517 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3518 NULL
, /* class_finalize */
3519 NULL
, /* class_data */
3520 sizeof (LttvTracefileState
),
3521 0, /* n_preallocs */
3522 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3523 NULL
/* value handling */
3526 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3527 "LttvTracefileStateType", &info
, 0);
3533 static void module_init()
3535 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3536 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3537 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3538 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3539 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3540 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3541 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3542 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3543 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3544 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3545 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3546 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3547 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3548 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3549 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3550 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3551 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3552 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3553 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3554 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3555 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3556 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3557 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3558 LTTV_STATE_EVENT
= g_quark_from_string("event");
3559 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3560 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3561 LTTV_STATE_TIME
= g_quark_from_string("time");
3562 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3563 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3564 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3565 g_quark_from_string("trace_state_use_count");
3568 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3569 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3570 LTT_FACILITY_FS
= g_quark_from_string("fs");
3571 LTT_FACILITY_LIST
= g_quark_from_string("list");
3572 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3575 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3576 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3577 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3578 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3579 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3580 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3581 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3582 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3583 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3584 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3585 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3586 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3587 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3588 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3589 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3590 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3591 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3592 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3593 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3596 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3597 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3598 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3599 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3600 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3601 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3602 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3603 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3604 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3605 LTT_FIELD_PID
= g_quark_from_string("pid");
3606 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3607 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3608 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3609 LTT_FIELD_NAME
= g_quark_from_string("name");
3610 LTT_FIELD_TYPE
= g_quark_from_string("type");
3611 LTT_FIELD_MODE
= g_quark_from_string("mode");
3612 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3613 LTT_FIELD_STATUS
= g_quark_from_string("status");
3614 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3615 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3617 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3618 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3619 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3620 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3621 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3623 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3624 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3625 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3628 static void module_destroy()
3633 LTTV_MODULE("state", "State computation", \
3634 "Update the system state, possibly saving it at intervals", \
3635 module_init
, module_destroy
)