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
;
137 LTTV_STATE_TRACEFILES
,
138 LTTV_STATE_PROCESSES
,
140 LTTV_STATE_RUNNING_PROCESS
,
142 LTTV_STATE_SAVED_STATES
,
143 LTTV_STATE_SAVED_STATES_TIME
,
146 LTTV_STATE_NAME_TABLES
,
147 LTTV_STATE_TRACE_STATE_USE_COUNT
;
149 static void create_max_time(LttvTraceState
*tcs
);
151 static void get_max_time(LttvTraceState
*tcs
);
153 static void free_max_time(LttvTraceState
*tcs
);
155 static void create_name_tables(LttvTraceState
*tcs
);
157 static void get_name_tables(LttvTraceState
*tcs
);
159 static void free_name_tables(LttvTraceState
*tcs
);
161 static void free_saved_state(LttvTraceState
*tcs
);
163 static void lttv_state_free_process_table(GHashTable
*processes
);
165 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
166 GPtrArray
*quarktable
);
168 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
170 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
174 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
176 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
180 void lttv_state_state_saved_free(LttvTraceState
*self
,
181 LttvAttribute
*container
)
183 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
187 guint
process_hash(gconstpointer key
)
189 guint pid
= ((const LttvProcessState
*)key
)->pid
;
190 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
194 /* If the hash table hash function is well distributed,
195 * the process_equal should compare different pid */
196 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
198 const LttvProcessState
*process_a
, *process_b
;
201 process_a
= (const LttvProcessState
*)a
;
202 process_b
= (const LttvProcessState
*)b
;
204 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
205 else if(likely(process_a
->pid
== 0 &&
206 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
211 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
213 g_tree_destroy((GTree
*)value
);
216 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
218 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
219 g_hash_table_destroy(usertraces
);
225 restore_init_state(LttvTraceState
*self
)
229 LttvTracefileState
*tfcs
;
231 LttTime start_time
, end_time
;
233 /* Free the process tables */
234 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
235 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
236 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
237 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
240 /* Seek time to beginning */
241 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
242 // closest. It's the tracecontext job to seek the trace to the beginning
243 // anyway : the init state might be used at the middle of the trace as well...
244 //g_tree_destroy(self->parent.ts_context->pqueue);
245 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
247 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
249 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
251 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
253 /* Put the per cpu running_process to beginning state : process 0. */
254 for(i
=0; i
< nb_cpus
; i
++) {
255 LttvExecutionState
*es
;
256 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
257 LTTV_STATE_UNNAMED
, &start_time
);
258 /* We are not sure is it's a kernel thread or normal thread, put the
259 * bottom stack state to unknown */
260 self
->running_process
[i
]->execution_stack
=
261 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
262 es
= self
->running_process
[i
]->state
=
263 &g_array_index(self
->running_process
[i
]->execution_stack
,
264 LttvExecutionState
, 0);
265 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
266 es
->s
= LTTV_STATE_UNNAMED
;
268 //self->running_process[i]->state->s = LTTV_STATE_RUN;
269 self
->running_process
[i
]->cpu
= i
;
273 nb_tracefile
= self
->parent
.tracefiles
->len
;
275 for(i
= 0 ; i
< nb_tracefile
; i
++) {
277 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
278 LttvTracefileContext
*, i
));
279 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
280 // tfcs->saved_position = 0;
281 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
282 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
283 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
284 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
289 //static LttTime time_zero = {0,0};
291 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
294 const LttTime
*t1
= (const LttTime
*)a
;
295 const LttTime
*t2
= (const LttTime
*)b
;
297 return ltt_time_compare(*t1
, *t2
);
300 static void free_usertrace_key(gpointer data
)
305 #define MAX_STRING_LEN 4096
308 state_load_saved_states(LttvTraceState
*tcs
)
311 GPtrArray
*quarktable
;
316 tcs
->has_precomputed_states
= FALSE
;
320 gchar buf
[MAX_STRING_LEN
];
323 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
324 strncpy(path
, trace_path
, PATH_MAX
-1);
325 count
= strnlen(trace_path
, PATH_MAX
-1);
326 // quarktable : open, test
327 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
328 fp
= fopen(path
, "r");
330 quarktable
= g_ptr_array_sized_new(4096);
332 /* Index 0 is null */
334 if(hdr
== EOF
) return;
335 g_assert(hdr
== HDR_QUARKS
);
339 if(hdr
== EOF
) break;
340 g_assert(hdr
== HDR_QUARK
);
341 g_ptr_array_set_size(quarktable
, q
+1);
344 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
345 if(buf
[i
] == '\0' || feof(fp
)) break;
348 len
= strnlen(buf
, MAX_STRING_LEN
-1);
349 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
350 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
356 // saved_states : open, test
357 strncpy(path
, trace_path
, PATH_MAX
-1);
358 count
= strnlen(trace_path
, PATH_MAX
-1);
359 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
360 fp
= fopen(path
, "r");
364 if(hdr
!= HDR_TRACE
) goto end
;
366 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
368 tcs
->has_precomputed_states
= TRUE
;
373 /* Free the quarktable */
374 for(i
=0; i
<quarktable
->len
; i
++) {
375 string
= g_ptr_array_index (quarktable
, i
);
378 g_ptr_array_free(quarktable
, TRUE
);
383 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
385 guint i
, j
, nb_trace
, nb_tracefile
;
387 LttvTraceContext
*tc
;
391 LttvTracefileState
*tfcs
;
393 LttvAttributeValue v
;
395 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
396 init((LttvTracesetContext
*)self
, ts
);
398 nb_trace
= lttv_traceset_number(ts
);
399 for(i
= 0 ; i
< nb_trace
; i
++) {
400 tc
= self
->parent
.traces
[i
];
401 tcs
= LTTV_TRACE_STATE(tc
);
402 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
403 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
407 if(*(v
.v_uint
) == 1) {
408 create_name_tables(tcs
);
409 create_max_time(tcs
);
411 get_name_tables(tcs
);
414 nb_tracefile
= tc
->tracefiles
->len
;
415 tcs
->processes
= NULL
;
416 tcs
->usertraces
= NULL
;
417 tcs
->running_process
= g_new(LttvProcessState
*,
418 ltt_trace_get_num_cpu(tc
->t
));
419 tcs
->cpu_states
= g_new(LttvCPUState
,
420 ltt_trace_get_num_cpu(tc
->t
));
421 restore_init_state(tcs
);
422 for(j
= 0 ; j
< nb_tracefile
; j
++) {
424 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
425 LttvTracefileContext
*, j
));
426 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
427 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
428 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
429 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
430 /* It's a Usertrace */
431 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
432 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
434 if(!usertrace_tree
) {
435 usertrace_tree
= g_tree_new_full(compare_usertraces
,
436 NULL
, free_usertrace_key
, NULL
);
437 g_hash_table_insert(tcs
->usertraces
,
438 (gpointer
)tid
, usertrace_tree
);
440 LttTime
*timestamp
= g_new(LttTime
, 1);
441 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
442 ltt_tracefile_creation(tfcs
->parent
.tf
));
443 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
447 /* See if the trace has saved states */
448 state_load_saved_states(tcs
);
453 fini(LttvTracesetState
*self
)
459 LttvTracefileState
*tfcs
;
461 LttvAttributeValue v
;
463 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
464 for(i
= 0 ; i
< nb_trace
; i
++) {
465 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
466 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
469 g_assert(*(v
.v_uint
) != 0);
472 if(*(v
.v_uint
) == 0) {
473 free_name_tables(tcs
);
475 free_saved_state(tcs
);
477 g_free(tcs
->running_process
);
478 tcs
->running_process
= NULL
;
479 lttv_state_free_process_table(tcs
->processes
);
480 lttv_state_free_usertraces(tcs
->usertraces
);
481 tcs
->processes
= NULL
;
482 tcs
->usertraces
= NULL
;
484 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
485 fini((LttvTracesetContext
*)self
);
489 static LttvTracesetContext
*
490 new_traceset_context(LttvTracesetContext
*self
)
492 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
496 static LttvTraceContext
*
497 new_trace_context(LttvTracesetContext
*self
)
499 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
503 static LttvTracefileContext
*
504 new_tracefile_context(LttvTracesetContext
*self
)
506 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
510 /* Write the process state of the trace */
512 static void write_process_state(gpointer key
, gpointer value
,
515 LttvProcessState
*process
;
517 LttvExecutionState
*es
;
519 FILE *fp
= (FILE *)user_data
;
524 process
= (LttvProcessState
*)value
;
526 " <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",
527 process
, process
->pid
, process
->tgid
, process
->ppid
,
528 g_quark_to_string(process
->type
),
529 process
->creation_time
.tv_sec
,
530 process
->creation_time
.tv_nsec
,
531 process
->insertion_time
.tv_sec
,
532 process
->insertion_time
.tv_nsec
,
533 g_quark_to_string(process
->name
),
534 g_quark_to_string(process
->brand
),
537 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
538 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
539 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
540 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
541 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
542 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
543 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
546 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
547 address
= &g_array_index(process
->user_stack
, guint64
, i
);
548 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
552 if(process
->usertrace
) {
553 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
554 g_quark_to_string(process
->usertrace
->tracefile_name
),
555 process
->usertrace
->cpu
);
559 fprintf(fp
, " </PROCESS>\n");
563 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
565 guint i
, nb_tracefile
, nb_block
, offset
;
568 LttvTracefileState
*tfcs
;
572 LttEventPosition
*ep
;
576 ep
= ltt_event_position_new();
578 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
580 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
582 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
583 for(i
=0;i
<nb_cpus
;i
++) {
584 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
585 i
, self
->running_process
[i
]->pid
);
588 nb_tracefile
= self
->parent
.tracefiles
->len
;
590 for(i
= 0 ; i
< nb_tracefile
; i
++) {
592 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
593 LttvTracefileContext
*, i
));
594 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
595 tfcs
->parent
.timestamp
.tv_sec
,
596 tfcs
->parent
.timestamp
.tv_nsec
);
597 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
598 if(e
== NULL
) fprintf(fp
,"/>\n");
600 ltt_event_position(e
, ep
);
601 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
602 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
607 fprintf(fp
,"</PROCESS_STATE>\n");
611 static void write_process_state_raw(gpointer key
, gpointer value
,
614 LttvProcessState
*process
;
616 LttvExecutionState
*es
;
618 FILE *fp
= (FILE *)user_data
;
623 process
= (LttvProcessState
*)value
;
624 fputc(HDR_PROCESS
, fp
);
625 //fwrite(&header, sizeof(header), 1, fp);
626 //fprintf(fp, "%s", g_quark_to_string(process->type));
628 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
629 //fprintf(fp, "%s", g_quark_to_string(process->name));
631 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
632 //fprintf(fp, "%s", g_quark_to_string(process->brand));
634 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
635 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
636 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
637 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
638 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
639 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
640 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
644 " <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",
645 process
, process
->pid
, process
->tgid
, process
->ppid
,
646 g_quark_to_string(process
->type
),
647 process
->creation_time
.tv_sec
,
648 process
->creation_time
.tv_nsec
,
649 process
->insertion_time
.tv_sec
,
650 process
->insertion_time
.tv_nsec
,
651 g_quark_to_string(process
->name
),
652 g_quark_to_string(process
->brand
),
656 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
657 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
660 //fprintf(fp, "%s", g_quark_to_string(es->t));
662 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
663 //fprintf(fp, "%s", g_quark_to_string(es->n));
665 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
666 //fprintf(fp, "%s", g_quark_to_string(es->s));
668 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
669 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
670 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
671 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
673 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
674 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
675 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
676 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
677 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
681 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
682 address
= &g_array_index(process
->user_stack
, guint64
, i
);
683 fputc(HDR_USER_STACK
, fp
);
684 fwrite(&address
, sizeof(address
), 1, fp
);
686 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
691 if(process
->usertrace
) {
692 fputc(HDR_USERTRACE
, fp
);
693 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
695 fwrite(&process
->usertrace
->tracefile_name
,
696 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
697 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
699 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
700 g_quark_to_string(process
->usertrace
->tracefile_name
),
701 process
->usertrace
->cpu
);
708 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
710 guint i
, nb_tracefile
, nb_block
, offset
;
713 LttvTracefileState
*tfcs
;
717 LttEventPosition
*ep
;
721 ep
= ltt_event_position_new();
723 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
724 fputc(HDR_PROCESS_STATE
, fp
);
725 fwrite(&t
, sizeof(t
), 1, fp
);
727 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
729 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
730 for(i
=0;i
<nb_cpus
;i
++) {
732 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
733 fwrite(&self
->running_process
[i
]->pid
,
734 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
735 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
736 // i, self->running_process[i]->pid);
739 nb_tracefile
= self
->parent
.tracefiles
->len
;
741 for(i
= 0 ; i
< nb_tracefile
; i
++) {
743 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
744 LttvTracefileContext
*, i
));
745 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
746 // tfcs->parent.timestamp.tv_sec,
747 // tfcs->parent.timestamp.tv_nsec);
748 fputc(HDR_TRACEFILE
, fp
);
749 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
750 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
751 * position following : end of trace */
752 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
754 ltt_event_position(e
, ep
);
755 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
756 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
758 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
759 fwrite(&offset
, sizeof(offset
), 1, fp
);
760 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
767 /* Read process state from a file */
769 /* Called because a HDR_PROCESS was found */
770 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
771 GPtrArray
*quarktable
)
773 LttvExecutionState
*es
;
774 LttvProcessState
*process
, *parent_process
;
775 LttvProcessState tmp
;
782 /* TODO : check return value */
783 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
784 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
785 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
786 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
787 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
788 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
789 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
790 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
791 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
794 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
796 /* We must link to the parent */
797 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
799 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
800 if(process
== NULL
) {
801 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
803 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
807 process
->insertion_time
= tmp
.insertion_time
;
808 process
->creation_time
= tmp
.creation_time
;
809 process
->type
= g_quark_from_string(
810 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
811 process
->tgid
= tmp
.tgid
;
812 process
->ppid
= tmp
.ppid
;
813 process
->brand
= g_quark_from_string(
814 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
816 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
820 if(feof(fp
) || ferror(fp
)) goto end_loop
;
822 gint hdr
= fgetc(fp
);
823 if(hdr
== EOF
) goto end_loop
;
827 process
->execution_stack
=
828 g_array_set_size(process
->execution_stack
,
829 process
->execution_stack
->len
+ 1);
830 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
831 process
->execution_stack
->len
-1);
834 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
835 es
->t
= g_quark_from_string(
836 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
837 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
838 es
->n
= g_quark_from_string(
839 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
840 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
841 es
->s
= g_quark_from_string(
842 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
843 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
844 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
845 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
848 process
->user_stack
= g_array_set_size(process
->user_stack
,
849 process
->user_stack
->len
+ 1);
850 address
= &g_array_index(process
->user_stack
, guint64
,
851 process
->user_stack
->len
-1);
852 fread(address
, sizeof(address
), 1, fp
);
853 process
->current_function
= *address
;
856 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
857 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
869 /* Called because a HDR_PROCESS_STATE was found */
870 /* Append a saved state to the trace states */
871 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
873 guint i
, nb_tracefile
, nb_block
, offset
;
875 LttvTracefileState
*tfcs
;
877 LttEventPosition
*ep
;
885 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
887 LttvAttributeValue value
;
888 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
889 ep
= ltt_event_position_new();
891 restore_init_state(self
);
893 fread(&t
, sizeof(t
), 1, fp
);
896 if(feof(fp
) || ferror(fp
)) goto end_loop
;
898 if(hdr
== EOF
) goto end_loop
;
902 /* Call read_process_state_raw */
903 read_process_state_raw(self
, fp
, quarktable
);
913 case HDR_PROCESS_STATE
:
919 g_error("Error while parsing saved state file : unknown data header %d",
925 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
926 for(i
=0;i
<nb_cpus
;i
++) {
929 g_assert(hdr
== HDR_CPU
);
930 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
931 g_assert(i
== cpu_num
);
932 fread(&self
->running_process
[i
]->pid
,
933 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
936 nb_tracefile
= self
->parent
.tracefiles
->len
;
938 for(i
= 0 ; i
< nb_tracefile
; i
++) {
940 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
941 LttvTracefileContext
*, i
));
942 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
943 // tfcs->parent.timestamp.tv_sec,
944 // tfcs->parent.timestamp.tv_nsec);
945 g_tree_remove(pqueue
, &tfcs
->parent
);
947 g_assert(hdr
== HDR_TRACEFILE
);
948 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
949 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
950 * position following : end of trace */
951 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
952 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
953 fread(&offset
, sizeof(offset
), 1, fp
);
954 fread(&tsc
, sizeof(tsc
), 1, fp
);
955 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
956 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
958 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
963 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
964 LTTV_STATE_SAVED_STATES
);
965 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
966 value
= lttv_attribute_add(saved_states_tree
,
967 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
968 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
969 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
971 lttv_state_save(self
, saved_state_tree
);
972 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
975 *(self
->max_time_state_recomputed_in_seek
) = t
;
979 /* Called when a HDR_TRACE is found */
980 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
981 GPtrArray
*quarktable
)
986 if(feof(fp
) || ferror(fp
)) goto end_loop
;
988 if(hdr
== EOF
) goto end_loop
;
991 case HDR_PROCESS_STATE
:
992 /* Call read_process_state_raw */
993 lttv_state_read_raw(tcs
, fp
, quarktable
);
1001 case HDR_USER_STACK
:
1005 g_error("Error while parsing saved state file :"
1006 " unexpected data header %d",
1010 g_error("Error while parsing saved state file : unknown data header %d",
1015 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1016 restore_init_state(tcs
);
1017 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1023 /* Copy each process from an existing hash table to a new one */
1025 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1027 LttvProcessState
*process
, *new_process
;
1029 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1033 process
= (LttvProcessState
*)value
;
1034 new_process
= g_new(LttvProcessState
, 1);
1035 *new_process
= *process
;
1036 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1037 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1038 new_process
->execution_stack
=
1039 g_array_set_size(new_process
->execution_stack
,
1040 process
->execution_stack
->len
);
1041 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1042 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1043 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1045 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1046 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1047 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1048 sizeof(guint64
), 0);
1049 new_process
->user_stack
=
1050 g_array_set_size(new_process
->user_stack
,
1051 process
->user_stack
->len
);
1052 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1053 g_array_index(new_process
->user_stack
, guint64
, i
) =
1054 g_array_index(process
->user_stack
, guint64
, i
);
1056 new_process
->current_function
= process
->current_function
;
1057 g_hash_table_insert(new_processes
, new_process
, new_process
);
1061 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1063 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1065 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1066 return new_processes
;
1070 /* The saved state for each trace contains a member "processes", which
1071 stores a copy of the process table, and a member "tracefiles" with
1072 one entry per tracefile. Each tracefile has a "process" member pointing
1073 to the current process and a "position" member storing the tracefile
1074 position (needed to seek to the current "next" event. */
1076 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1078 guint i
, nb_tracefile
, nb_cpus
;
1080 LttvTracefileState
*tfcs
;
1082 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1084 guint
*running_process
;
1086 LttvAttributeType type
;
1088 LttvAttributeValue value
;
1090 LttvAttributeName name
;
1092 LttEventPosition
*ep
;
1094 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1095 LTTV_STATE_TRACEFILES
);
1097 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1099 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1101 /* Add the currently running processes array */
1102 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1103 running_process
= g_new(guint
, nb_cpus
);
1104 for(i
=0;i
<nb_cpus
;i
++) {
1105 running_process
[i
] = self
->running_process
[i
]->pid
;
1107 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1109 *(value
.v_pointer
) = running_process
;
1111 g_info("State save");
1113 nb_tracefile
= self
->parent
.tracefiles
->len
;
1115 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1117 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1118 LttvTracefileContext
*, i
));
1119 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1120 value
= lttv_attribute_add(tracefiles_tree
, i
,
1122 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1124 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1126 *(value
.v_uint
) = tfcs
->process
->pid
;
1128 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1130 /* Only save the position if the tfs has not infinite time. */
1131 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1132 // && current_tfcs != tfcs) {
1133 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1134 *(value
.v_pointer
) = NULL
;
1136 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1137 ep
= ltt_event_position_new();
1138 ltt_event_position(e
, ep
);
1139 *(value
.v_pointer
) = ep
;
1141 guint nb_block
, offset
;
1144 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1145 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1147 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1153 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1155 guint i
, nb_tracefile
, pid
, nb_cpus
;
1157 LttvTracefileState
*tfcs
;
1159 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1161 guint
*running_process
;
1163 LttvAttributeType type
;
1165 LttvAttributeValue value
;
1167 LttvAttributeName name
;
1171 LttEventPosition
*ep
;
1173 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1175 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1176 LTTV_STATE_TRACEFILES
);
1178 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1180 g_assert(type
== LTTV_POINTER
);
1181 lttv_state_free_process_table(self
->processes
);
1182 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1184 /* Add the currently running processes array */
1185 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1186 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1188 g_assert(type
== LTTV_POINTER
);
1189 running_process
= *(value
.v_pointer
);
1190 for(i
=0;i
<nb_cpus
;i
++) {
1191 pid
= running_process
[i
];
1192 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1193 g_assert(self
->running_process
[i
] != NULL
);
1197 nb_tracefile
= self
->parent
.tracefiles
->len
;
1199 //g_tree_destroy(tsc->pqueue);
1200 //tsc->pqueue = g_tree_new(compare_tracefile);
1202 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1204 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1205 LttvTracefileContext
*, i
));
1206 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1207 g_assert(type
== LTTV_GOBJECT
);
1208 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1210 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1212 g_assert(type
== LTTV_UINT
);
1213 pid
= *(value
.v_uint
);
1214 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1216 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1218 g_assert(type
== LTTV_POINTER
);
1219 //g_assert(*(value.v_pointer) != NULL);
1220 ep
= *(value
.v_pointer
);
1221 g_assert(tfcs
->parent
.t_context
!= NULL
);
1223 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1224 g_tree_remove(tsc
->pqueue
, tfc
);
1227 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1228 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1229 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1230 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1231 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1233 tfc
->timestamp
= ltt_time_infinite
;
1239 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1241 guint i
, nb_tracefile
, nb_cpus
;
1243 LttvTracefileState
*tfcs
;
1245 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1247 guint
*running_process
;
1249 LttvAttributeType type
;
1251 LttvAttributeValue value
;
1253 LttvAttributeName name
;
1257 LttEventPosition
*ep
;
1259 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1260 LTTV_STATE_TRACEFILES
);
1261 g_object_ref(G_OBJECT(tracefiles_tree
));
1262 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1264 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1266 g_assert(type
== LTTV_POINTER
);
1267 lttv_state_free_process_table(*(value
.v_pointer
));
1268 *(value
.v_pointer
) = NULL
;
1269 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1271 /* Free running processes array */
1272 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1273 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1275 g_assert(type
== LTTV_POINTER
);
1276 running_process
= *(value
.v_pointer
);
1277 g_free(running_process
);
1279 nb_tracefile
= self
->parent
.tracefiles
->len
;
1281 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1283 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1284 LttvTracefileContext
*, i
));
1285 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1286 g_assert(type
== LTTV_GOBJECT
);
1287 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1289 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1291 g_assert(type
== LTTV_POINTER
);
1292 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1294 g_object_unref(G_OBJECT(tracefiles_tree
));
1298 static void free_saved_state(LttvTraceState
*self
)
1302 LttvAttributeType type
;
1304 LttvAttributeValue value
;
1306 LttvAttributeName name
;
1310 LttvAttribute
*saved_states
;
1312 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1313 LTTV_STATE_SAVED_STATES
);
1315 nb
= lttv_attribute_get_number(saved_states
);
1316 for(i
= 0 ; i
< nb
; i
++) {
1317 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1318 g_assert(type
== LTTV_GOBJECT
);
1319 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1322 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1327 create_max_time(LttvTraceState
*tcs
)
1329 LttvAttributeValue v
;
1331 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1333 g_assert(*(v
.v_pointer
) == NULL
);
1334 *(v
.v_pointer
) = g_new(LttTime
,1);
1335 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1340 get_max_time(LttvTraceState
*tcs
)
1342 LttvAttributeValue v
;
1344 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1346 g_assert(*(v
.v_pointer
) != NULL
);
1347 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1352 free_max_time(LttvTraceState
*tcs
)
1354 LttvAttributeValue v
;
1356 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1358 g_free(*(v
.v_pointer
));
1359 *(v
.v_pointer
) = NULL
;
1363 typedef struct _LttvNameTables
{
1364 // FIXME GQuark *eventtype_names;
1365 GQuark
*syscall_names
;
1371 GQuark
*soft_irq_names
;
1377 create_name_tables(LttvTraceState
*tcs
)
1381 GQuark f_name
, e_name
;
1385 LttvTraceHookByFacility
*thf
;
1391 GString
*fe_name
= g_string_new("");
1393 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1395 LttvAttributeValue v
;
1397 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1399 g_assert(*(v
.v_pointer
) == NULL
);
1400 *(v
.v_pointer
) = name_tables
;
1401 #if 0 // Use iteration over the facilities_by_name and then list all event
1402 // types of each facility
1403 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1404 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1405 for(i
= 0 ; i
< nb
; i
++) {
1406 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1407 e_name
= ltt_eventtype_name(et
);
1408 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1409 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1410 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1413 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1414 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1415 LTT_FIELD_SYSCALL_ID
, 0, 0,
1418 thf
= lttv_trace_hook_get_first(&h
);
1420 t
= ltt_field_type(thf
->f1
);
1421 nb
= ltt_type_element_number(t
);
1423 lttv_trace_hook_destroy(&h
);
1425 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1426 name_tables
->nb_syscalls
= nb
;
1428 for(i
= 0 ; i
< nb
; i
++) {
1429 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1430 if(!name_tables
->syscall_names
[i
]) {
1431 GString
*string
= g_string_new("");
1432 g_string_printf(string
, "syscall %u", i
);
1433 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1434 g_string_free(string
, TRUE
);
1438 //name_tables->syscall_names = g_new(GQuark, 256);
1439 //for(i = 0 ; i < 256 ; i++) {
1440 // g_string_printf(fe_name, "syscall %d", i);
1441 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1444 name_tables
->syscall_names
= NULL
;
1445 name_tables
->nb_syscalls
= 0;
1448 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1449 LTT_EVENT_TRAP_ENTRY
,
1450 LTT_FIELD_TRAP_ID
, 0, 0,
1453 thf
= lttv_trace_hook_get_first(&h
);
1455 t
= ltt_field_type(thf
->f1
);
1456 //nb = ltt_type_element_number(t);
1458 lttv_trace_hook_destroy(&h
);
1461 name_tables->trap_names = g_new(GQuark, nb);
1462 for(i = 0 ; i < nb ; i++) {
1463 name_tables->trap_names[i] = g_quark_from_string(
1464 ltt_enum_string_get(t, i));
1467 name_tables
->nb_traps
= 256;
1468 name_tables
->trap_names
= g_new(GQuark
, 256);
1469 for(i
= 0 ; i
< 256 ; i
++) {
1470 g_string_printf(fe_name
, "trap %d", i
);
1471 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1474 name_tables
->trap_names
= NULL
;
1475 name_tables
->nb_traps
= 0;
1478 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1479 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1480 LTT_FIELD_IRQ_ID
, 0, 0,
1483 thf
= lttv_trace_hook_get_first(&h
);
1485 t
= ltt_field_type(thf
->f1
);
1486 //nb = ltt_type_element_number(t);
1488 lttv_trace_hook_destroy(&h
);
1491 name_tables->irq_names = g_new(GQuark, nb);
1492 for(i = 0 ; i < nb ; i++) {
1493 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1497 name_tables
->nb_irqs
= 256;
1498 name_tables
->irq_names
= g_new(GQuark
, 256);
1499 for(i
= 0 ; i
< 256 ; i
++) {
1500 g_string_printf(fe_name
, "irq %d", i
);
1501 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1504 name_tables
->nb_irqs
= 0;
1505 name_tables
->irq_names
= NULL
;
1508 name_tables->soft_irq_names = g_new(GQuark, nb);
1509 for(i = 0 ; i < nb ; i++) {
1510 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1514 name_tables
->nb_softirqs
= 256;
1515 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1516 for(i
= 0 ; i
< 256 ; i
++) {
1517 g_string_printf(fe_name
, "softirq %d", i
);
1518 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1522 g_string_free(fe_name
, TRUE
);
1527 get_name_tables(LttvTraceState
*tcs
)
1529 LttvNameTables
*name_tables
;
1531 LttvAttributeValue v
;
1533 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1535 g_assert(*(v
.v_pointer
) != NULL
);
1536 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1537 //tcs->eventtype_names = name_tables->eventtype_names;
1538 tcs
->syscall_names
= name_tables
->syscall_names
;
1539 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1540 tcs
->trap_names
= name_tables
->trap_names
;
1541 tcs
->nb_traps
= name_tables
->nb_traps
;
1542 tcs
->irq_names
= name_tables
->irq_names
;
1543 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1544 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1545 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1550 free_name_tables(LttvTraceState
*tcs
)
1552 LttvNameTables
*name_tables
;
1554 LttvAttributeValue v
;
1556 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1558 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1559 *(v
.v_pointer
) = NULL
;
1561 // g_free(name_tables->eventtype_names);
1562 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1563 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1564 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1565 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1566 if(name_tables
) g_free(name_tables
);
1569 #ifdef HASH_TABLE_DEBUG
1571 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1573 LttvProcessState
*process
= (LttvProcessState
*)value
;
1575 /* Test for process corruption */
1576 guint stack_len
= process
->execution_stack
->len
;
1579 static void hash_table_check(GHashTable
*table
)
1581 g_hash_table_foreach(table
, test_process
, NULL
);
1588 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1591 LttvExecutionState
*es
;
1593 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1594 guint cpu
= tfs
->cpu
;
1596 #ifdef HASH_TABLE_DEBUG
1597 hash_table_check(ts
->processes
);
1599 LttvProcessState
*process
= ts
->running_process
[cpu
];
1601 guint depth
= process
->execution_stack
->len
;
1603 process
->execution_stack
=
1604 g_array_set_size(process
->execution_stack
, depth
+ 1);
1607 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1609 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1612 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1613 es
->cum_cpu_time
= ltt_time_zero
;
1614 es
->s
= process
->state
->s
;
1615 process
->state
= es
;
1619 * return 1 when empty, else 0 */
1620 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1621 LttvTracefileState
*tfs
)
1623 guint cpu
= tfs
->cpu
;
1624 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1626 guint depth
= process
->execution_stack
->len
;
1632 process
->execution_stack
=
1633 g_array_set_size(process
->execution_stack
, depth
- 1);
1634 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1636 process
->state
->change
= tfs
->parent
.timestamp
;
1641 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1643 guint cpu
= tfs
->cpu
;
1644 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1645 LttvProcessState
*process
= ts
->running_process
[cpu
];
1647 guint depth
= process
->execution_stack
->len
;
1649 if(process
->state
->t
!= t
){
1650 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1651 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1652 g_info("process state has %s when pop_int is %s\n",
1653 g_quark_to_string(process
->state
->t
),
1654 g_quark_to_string(t
));
1655 g_info("{ %u, %u, %s, %s, %s }\n",
1658 g_quark_to_string(process
->name
),
1659 g_quark_to_string(process
->brand
),
1660 g_quark_to_string(process
->state
->s
));
1665 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1666 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1670 process
->execution_stack
=
1671 g_array_set_size(process
->execution_stack
, depth
- 1);
1672 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1674 process
->state
->change
= tfs
->parent
.timestamp
;
1677 struct search_result
{
1678 const LttTime
*time
; /* Requested time */
1679 LttTime
*best
; /* Best result */
1682 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1684 const LttTime
*elem_time
= (const LttTime
*)a
;
1685 /* Explicit non const cast */
1686 struct search_result
*res
= (struct search_result
*)b
;
1688 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1689 /* The usertrace was created before the schedchange */
1690 /* Get larger keys */
1692 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1693 /* The usertrace was created after the schedchange time */
1694 /* Get smaller keys */
1696 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1697 res
->best
= elem_time
;
1700 res
->best
= elem_time
;
1707 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1708 guint pid
, const LttTime
*timestamp
)
1710 LttvTracefileState
*tfs
= NULL
;
1711 struct search_result res
;
1712 /* Find the usertrace associated with a pid and time interval.
1713 * Search in the usertraces by PID (within a hash) and then, for each
1714 * corresponding element of the array, find the first one with creation
1715 * timestamp the lowest, but higher or equal to "timestamp". */
1716 res
.time
= timestamp
;
1718 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1719 if(usertrace_tree
) {
1720 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1722 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1730 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1731 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1733 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1735 LttvExecutionState
*es
;
1737 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1742 process
->tgid
= tgid
;
1744 process
->name
= name
;
1745 process
->brand
= LTTV_STATE_UNBRANDED
;
1746 //process->last_cpu = tfs->cpu_name;
1747 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1748 process
->type
= LTTV_STATE_USER_THREAD
;
1749 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1750 process
->current_function
= 0; //function 0x0 by default.
1752 g_info("Process %u, core %p", process
->pid
, process
);
1753 g_hash_table_insert(tcs
->processes
, process
, process
);
1756 process
->ppid
= parent
->pid
;
1757 process
->creation_time
= *timestamp
;
1760 /* No parent. This process exists but we are missing all information about
1761 its creation. The birth time is set to zero but we remember the time of
1766 process
->creation_time
= ltt_time_zero
;
1769 process
->insertion_time
= *timestamp
;
1770 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1771 process
->creation_time
.tv_nsec
);
1772 process
->pid_time
= g_quark_from_string(buffer
);
1774 //process->last_cpu = tfs->cpu_name;
1775 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1776 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1777 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1778 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1779 es
= process
->state
= &g_array_index(process
->execution_stack
,
1780 LttvExecutionState
, 0);
1781 es
->t
= LTTV_STATE_USER_MODE
;
1782 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1783 es
->entry
= *timestamp
;
1784 //g_assert(timestamp->tv_sec != 0);
1785 es
->change
= *timestamp
;
1786 es
->cum_cpu_time
= ltt_time_zero
;
1787 es
->s
= LTTV_STATE_RUN
;
1789 es
= process
->state
= &g_array_index(process
->execution_stack
,
1790 LttvExecutionState
, 1);
1791 es
->t
= LTTV_STATE_SYSCALL
;
1792 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1793 es
->entry
= *timestamp
;
1794 //g_assert(timestamp->tv_sec != 0);
1795 es
->change
= *timestamp
;
1796 es
->cum_cpu_time
= ltt_time_zero
;
1797 es
->s
= LTTV_STATE_WAIT_FORK
;
1799 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1800 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1801 sizeof(guint64
), 0);
1806 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1809 LttvProcessState key
;
1810 LttvProcessState
*process
;
1814 process
= g_hash_table_lookup(ts
->processes
, &key
);
1819 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1820 const LttTime
*timestamp
)
1822 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1823 LttvExecutionState
*es
;
1825 /* Put ltt_time_zero creation time for unexisting processes */
1826 if(unlikely(process
== NULL
)) {
1827 process
= lttv_state_create_process(ts
,
1828 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1829 /* We are not sure is it's a kernel thread or normal thread, put the
1830 * bottom stack state to unknown */
1831 process
->execution_stack
=
1832 g_array_set_size(process
->execution_stack
, 1);
1833 process
->state
= es
=
1834 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1835 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1836 es
->s
= LTTV_STATE_UNNAMED
;
1841 /* FIXME : this function should be called when we receive an event telling that
1842 * release_task has been called in the kernel. In happens generally when
1843 * the parent waits for its child terminaison, but may also happen in special
1844 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1845 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1846 * of a killed thread ground, but isn't the leader.
1848 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1850 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1851 LttvProcessState key
;
1853 key
.pid
= process
->pid
;
1854 key
.cpu
= process
->cpu
;
1855 g_hash_table_remove(ts
->processes
, &key
);
1856 g_array_free(process
->execution_stack
, TRUE
);
1857 g_array_free(process
->user_stack
, TRUE
);
1862 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1864 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1865 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1870 static void lttv_state_free_process_table(GHashTable
*processes
)
1872 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1873 g_hash_table_destroy(processes
);
1877 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1879 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1881 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1882 LttvProcessState
*process
= ts
->running_process
[cpu
];
1883 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1884 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1885 LttField
*f
= thf
->f1
;
1887 LttvExecutionSubmode submode
;
1889 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1890 guint syscall
= ltt_event_get_unsigned(e
, f
);
1892 if(syscall
< nb_syscalls
) {
1893 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1896 /* Fixup an incomplete syscall table */
1897 GString
*string
= g_string_new("");
1898 g_string_printf(string
, "syscall %u", syscall
);
1899 submode
= g_quark_from_string(string
->str
);
1900 g_string_free(string
, TRUE
);
1902 /* There can be no system call from PID 0 : unknown state */
1903 if(process
->pid
!= 0)
1904 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1909 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1911 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1913 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1914 LttvProcessState
*process
= ts
->running_process
[cpu
];
1916 /* There can be no system call from PID 0 : unknown state */
1917 if(process
->pid
!= 0)
1918 pop_state(s
, LTTV_STATE_SYSCALL
);
1923 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1925 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1926 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1927 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1928 LttField
*f
= thf
->f1
;
1930 LttvExecutionSubmode submode
;
1932 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1933 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1935 if(trap
< nb_traps
) {
1936 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1938 /* Fixup an incomplete trap table */
1939 GString
*string
= g_string_new("");
1940 g_string_printf(string
, "trap %llu", trap
);
1941 submode
= g_quark_from_string(string
->str
);
1942 g_string_free(string
, TRUE
);
1945 push_state(s
, LTTV_STATE_TRAP
, submode
);
1950 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1952 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1954 pop_state(s
, LTTV_STATE_TRAP
);
1959 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1961 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1962 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1963 guint8 fac_id
= ltt_event_facility_id(e
);
1964 guint8 ev_id
= ltt_event_eventtype_id(e
);
1965 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1966 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1967 g_assert(thf
->f1
!= NULL
);
1968 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1969 LttField
*f
= thf
->f1
;
1971 LttvExecutionSubmode submode
;
1972 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
1973 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
1977 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
1979 /* Fixup an incomplete irq table */
1980 GString
*string
= g_string_new("");
1981 g_string_printf(string
, "irq %llu", irq
);
1982 submode
= g_quark_from_string(string
->str
);
1983 g_string_free(string
, TRUE
);
1986 /* Do something with the info about being in user or system mode when int? */
1987 push_state(s
, LTTV_STATE_IRQ
, submode
);
1989 /* update cpu status */
1990 s
->cpu_state
->previous_state
= s
->cpu_state
->present_state
;
1991 s
->cpu_state
->present_state
= LTTV_CPU_IRQ
;
1996 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1998 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2000 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2006 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2008 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2010 pop_state(s
, LTTV_STATE_IRQ
);
2012 /* update cpu status */
2013 s
->cpu_state
->present_state
= s
->cpu_state
->previous_state
;
2018 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2020 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2021 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2022 guint8 fac_id
= ltt_event_facility_id(e
);
2023 guint8 ev_id
= ltt_event_eventtype_id(e
);
2024 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2025 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2026 g_assert(thf
->f1
!= NULL
);
2027 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2028 LttField
*f
= thf
->f1
;
2030 LttvExecutionSubmode submode
;
2031 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2032 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2035 if(softirq
< nb_softirqs
) {
2036 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2038 /* Fixup an incomplete irq table */
2039 GString
*string
= g_string_new("");
2040 g_string_printf(string
, "softirq %llu", softirq
);
2041 submode
= g_quark_from_string(string
->str
);
2042 g_string_free(string
, TRUE
);
2045 /* Do something with the info about being in user or system mode when int? */
2046 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2050 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2054 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2055 guint cpu
= tfs
->cpu
;
2056 LttvProcessState
*process
= ts
->running_process
[cpu
];
2058 guint depth
= process
->user_stack
->len
;
2060 process
->user_stack
=
2061 g_array_set_size(process
->user_stack
, depth
+ 1);
2063 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2064 *new_func
= funcptr
;
2065 process
->current_function
= funcptr
;
2068 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2070 guint cpu
= tfs
->cpu
;
2071 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2072 LttvProcessState
*process
= ts
->running_process
[cpu
];
2074 if(process
->current_function
!= funcptr
){
2075 g_info("Different functions (%lu.%09lu): ignore it\n",
2076 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2077 g_info("process state has %llu when pop_function is %llu\n",
2078 process
->current_function
, funcptr
);
2079 g_info("{ %u, %u, %s, %s, %s }\n",
2082 g_quark_to_string(process
->name
),
2083 g_quark_to_string(process
->brand
),
2084 g_quark_to_string(process
->state
->s
));
2087 guint depth
= process
->user_stack
->len
;
2090 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2091 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2095 process
->user_stack
=
2096 g_array_set_size(process
->user_stack
, depth
- 1);
2097 process
->current_function
=
2098 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2102 static gboolean
function_entry(void *hook_data
, void *call_data
)
2104 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2105 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2106 guint8 fac_id
= ltt_event_facility_id(e
);
2107 guint8 ev_id
= ltt_event_eventtype_id(e
);
2108 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2109 g_assert(thf
->f1
!= NULL
);
2110 LttField
*f
= thf
->f1
;
2111 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2113 push_function(s
, funcptr
);
2117 static gboolean
function_exit(void *hook_data
, void *call_data
)
2119 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2120 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2121 guint8 fac_id
= ltt_event_facility_id(e
);
2122 guint8 ev_id
= ltt_event_eventtype_id(e
);
2123 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2124 g_assert(thf
->f1
!= NULL
);
2125 LttField
*f
= thf
->f1
;
2126 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2128 LttvExecutionSubmode submode
;
2130 pop_function(s
, funcptr
);
2134 static gboolean
schedchange(void *hook_data
, void *call_data
)
2136 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2138 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2139 LttvProcessState
*process
= ts
->running_process
[cpu
];
2140 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2142 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2143 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2144 guint pid_in
, pid_out
;
2147 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2148 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2149 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2151 if(likely(process
!= NULL
)) {
2153 /* We could not know but it was not the idle process executing.
2154 This should only happen at the beginning, before the first schedule
2155 event, and when the initial information (current process for each CPU)
2156 is missing. It is not obvious how we could, after the fact, compensate
2157 the wrongly attributed statistics. */
2159 //This test only makes sense once the state is known and if there is no
2160 //missing events. We need to silently ignore schedchange coming after a
2161 //process_free, or it causes glitches. (FIXME)
2162 //if(unlikely(process->pid != pid_out)) {
2163 // g_assert(process->pid == 0);
2165 if(process
->pid
== 0
2166 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2168 /* Scheduling out of pid 0 at beginning of the trace :
2169 * we know for sure it is in syscall mode at this point. */
2170 g_assert(process
->execution_stack
->len
== 1);
2171 process
->state
->t
= LTTV_STATE_SYSCALL
;
2172 process
->state
->s
= LTTV_STATE_WAIT
;
2173 process
->state
->change
= s
->parent
.timestamp
;
2174 process
->state
->entry
= s
->parent
.timestamp
;
2177 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2178 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2179 process
->state
->change
= s
->parent
.timestamp
;
2181 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2182 else process
->state
->s
= LTTV_STATE_WAIT
;
2183 process
->state
->change
= s
->parent
.timestamp
;
2186 if(state_out
== 32 || state_out
== 128)
2187 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2188 /* see sched.h for states */
2191 process
= ts
->running_process
[cpu
] =
2192 lttv_state_find_process_or_create(
2193 (LttvTraceState
*)s
->parent
.t_context
,
2195 &s
->parent
.timestamp
);
2196 process
->state
->s
= LTTV_STATE_RUN
;
2198 if(process
->usertrace
)
2199 process
->usertrace
->cpu
= cpu
;
2200 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2201 process
->state
->change
= s
->parent
.timestamp
;
2203 /* update cpu status */
2205 s
->cpu_state
->present_state
= LTTV_CPU_IDLE
;
2207 s
->cpu_state
->present_state
= LTTV_CPU_BUSY
;
2212 static gboolean
process_fork(void *hook_data
, void *call_data
)
2214 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2215 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2216 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2218 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2219 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2220 LttvProcessState
*zombie_process
;
2222 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2223 LttvProcessState
*process
= ts
->running_process
[cpu
];
2224 LttvProcessState
*child_process
;
2227 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2230 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2231 s
->parent
.target_pid
= child_pid
;
2234 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2235 else child_tgid
= 0;
2237 /* Mathieu : it seems like the process might have been scheduled in before the
2238 * fork, and, in a rare case, might be the current process. This might happen
2239 * in a SMP case where we don't have enough precision on the clocks.
2241 * Test reenabled after precision fixes on time. (Mathieu) */
2243 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2245 if(unlikely(zombie_process
!= NULL
)) {
2246 /* Reutilisation of PID. Only now we are sure that the old PID
2247 * has been released. FIXME : should know when release_task happens instead.
2249 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2251 for(i
=0; i
< num_cpus
; i
++) {
2252 g_assert(zombie_process
!= ts
->running_process
[i
]);
2255 exit_process(s
, zombie_process
);
2258 g_assert(process
->pid
!= child_pid
);
2259 // FIXME : Add this test in the "known state" section
2260 // g_assert(process->pid == parent_pid);
2261 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2262 if(child_process
== NULL
) {
2263 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2264 child_pid
, child_tgid
,
2265 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2267 /* The process has already been created : due to time imprecision between
2268 * multiple CPUs : it has been scheduled in before creation. Note that we
2269 * shouldn't have this kind of imprecision.
2271 * Simply put a correct parent.
2273 g_assert(0); /* This is a problematic case : the process has been created
2274 before the fork event */
2275 child_process
->ppid
= process
->pid
;
2276 child_process
->tgid
= child_tgid
;
2278 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2279 child_process
->name
= process
->name
;
2280 child_process
->brand
= process
->brand
;
2285 /* We stamp a newly created process as kernel_thread.
2286 * The thread should not be running yet. */
2287 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2289 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2290 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2291 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2294 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2295 LttvProcessState
*process
;
2296 LttvExecutionState
*es
;
2299 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2300 s
->parent
.target_pid
= pid
;
2302 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2304 process
->execution_stack
=
2305 g_array_set_size(process
->execution_stack
, 1);
2306 es
= process
->state
=
2307 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2308 es
->t
= LTTV_STATE_SYSCALL
;
2309 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2314 static gboolean
process_exit(void *hook_data
, void *call_data
)
2316 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2317 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2318 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2322 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2323 LttvProcessState
*process
; // = ts->running_process[cpu];
2325 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2326 s
->parent
.target_pid
= pid
;
2328 // FIXME : Add this test in the "known state" section
2329 // g_assert(process->pid == pid);
2331 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2332 if(likely(process
!= NULL
)) {
2333 process
->state
->s
= LTTV_STATE_EXIT
;
2338 static gboolean
process_free(void *hook_data
, void *call_data
)
2340 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2341 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2342 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2343 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2345 LttvProcessState
*process
;
2347 /* PID of the process to release */
2348 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2349 s
->parent
.target_pid
= release_pid
;
2351 g_assert(release_pid
!= 0);
2353 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2355 if(likely(process
!= NULL
)) {
2356 /* release_task is happening at kernel level : we can now safely release
2357 * the data structure of the process */
2358 //This test is fun, though, as it may happen that
2359 //at time t : CPU 0 : process_free
2360 //at time t+150ns : CPU 1 : schedule out
2361 //Clearly due to time imprecision, we disable it. (Mathieu)
2362 //If this weird case happen, we have no choice but to put the
2363 //Currently running process on the cpu to 0.
2364 //I re-enable it following time precision fixes. (Mathieu)
2365 //Well, in the case where an process is freed by a process on another CPU
2366 //and still scheduled, it happens that this is the schedchange that will
2367 //drop the last reference count. Do not free it here!
2368 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2370 for(i
=0; i
< num_cpus
; i
++) {
2371 //g_assert(process != ts->running_process[i]);
2372 if(process
== ts
->running_process
[i
]) {
2373 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2377 if(i
== num_cpus
) /* process is not scheduled */
2378 exit_process(s
, process
);
2385 static gboolean
process_exec(void *hook_data
, void *call_data
)
2387 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2388 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2389 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2390 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2393 LttvProcessState
*process
= ts
->running_process
[cpu
];
2395 #if 0//how to use a sequence that must be transformed in a string
2396 /* PID of the process to release */
2397 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2398 //name = ltt_event_get_string(e, thf->f1);
2399 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2401 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2402 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2403 memcpy(null_term_name
, name_begin
, name_len
);
2404 null_term_name
[name_len
] = '\0';
2405 process
->name
= g_quark_from_string(null_term_name
);
2408 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2409 process
->brand
= LTTV_STATE_UNBRANDED
;
2410 //g_free(null_term_name);
2414 static gboolean
thread_brand(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
;
2422 LttvProcessState
*process
= ts
->running_process
[cpu
];
2424 name
= ltt_event_get_string(e
, thf
->f1
);
2425 process
->brand
= g_quark_from_string(name
);
2430 static void fix_process(gpointer key
, gpointer value
,
2433 LttvProcessState
*process
;
2434 LttvExecutionState
*es
;
2435 process
= (LttvProcessState
*)value
;
2436 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2437 LttTime
*timestamp
= (LttTime
*)user_data
;
2439 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2440 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2441 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2442 es
->t
= LTTV_STATE_SYSCALL
;
2443 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2444 es
->entry
= *timestamp
;
2445 es
->change
= *timestamp
;
2446 es
->cum_cpu_time
= ltt_time_zero
;
2447 if(es
->s
== LTTV_STATE_UNNAMED
)
2448 es
->s
= LTTV_STATE_WAIT
;
2451 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2452 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2453 es
->t
= LTTV_STATE_USER_MODE
;
2454 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2455 es
->entry
= *timestamp
;
2456 //g_assert(timestamp->tv_sec != 0);
2457 es
->change
= *timestamp
;
2458 es
->cum_cpu_time
= ltt_time_zero
;
2459 if(es
->s
== LTTV_STATE_UNNAMED
)
2460 es
->s
= LTTV_STATE_RUN
;
2462 if(process
->execution_stack
->len
== 1) {
2463 /* Still in bottom unknown mode, means never did a system call
2464 * May be either in user mode, syscall mode, running or waiting.*/
2465 /* FIXME : we may be tagging syscall mode when being user mode */
2466 process
->execution_stack
=
2467 g_array_set_size(process
->execution_stack
, 2);
2468 es
= process
->state
= &g_array_index(process
->execution_stack
,
2469 LttvExecutionState
, 1);
2470 es
->t
= LTTV_STATE_SYSCALL
;
2471 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2472 es
->entry
= *timestamp
;
2473 //g_assert(timestamp->tv_sec != 0);
2474 es
->change
= *timestamp
;
2475 es
->cum_cpu_time
= ltt_time_zero
;
2476 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2477 es
->s
= LTTV_STATE_WAIT
;
2483 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2485 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2486 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2487 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2488 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2489 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2491 /* For all processes */
2492 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2493 /* else, if stack[0] is unknown, set to user mode, running */
2495 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2498 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2500 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2501 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2502 //It's slow : optimise later by doing this before reading trace.
2503 LttEventType
*et
= ltt_event_eventtype(e
);
2505 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2511 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2512 LttvProcessState
*process
= ts
->running_process
[cpu
];
2513 LttvProcessState
*parent_process
;
2514 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2515 GQuark type
, mode
, submode
, status
;
2516 LttvExecutionState
*es
;
2520 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2521 s
->parent
.target_pid
= pid
;
2524 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2527 command
= ltt_event_get_string(e
, thf
->f3
);
2530 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2531 type
= ltt_enum_string_get(ltt_field_type(f4
),
2532 ltt_event_get_unsigned(e
, f4
));
2535 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2536 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2537 ltt_event_get_unsigned(e
, f5
));
2540 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2541 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2542 ltt_event_get_unsigned(e
, f6
));
2545 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2546 status
= ltt_enum_string_get(ltt_field_type(f7
),
2547 ltt_event_get_unsigned(e
, f7
));
2550 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2551 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2556 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2557 for(i
=0; i
<nb_cpus
; i
++) {
2558 process
= lttv_state_find_process(ts
, i
, pid
);
2559 g_assert(process
!= NULL
);
2561 process
->ppid
= parent_pid
;
2562 process
->tgid
= tgid
;
2563 process
->name
= g_quark_from_string(command
);
2565 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2566 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2570 /* The process might exist if a process was forked while performing the
2572 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2573 if(process
== NULL
) {
2574 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2575 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2576 pid
, tgid
, g_quark_from_string(command
),
2577 &s
->parent
.timestamp
);
2579 /* Keep the stack bottom : a running user mode */
2580 /* Disabled because of inconsistencies in the current statedump states. */
2581 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2582 /* Only keep the bottom
2583 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2584 /* Will cause expected trap when in fact being syscall (even after end of
2586 * Will cause expected interrupt when being syscall. (only before end of
2587 * statedump event) */
2588 // This will cause a "popping last state on stack, ignoring it."
2589 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2590 es
= process
->state
= &g_array_index(process
->execution_stack
,
2591 LttvExecutionState
, 0);
2592 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2593 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2594 es
->s
= LTTV_STATE_UNNAMED
;
2595 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2597 es
->t
= LTTV_STATE_SYSCALL
;
2602 /* User space process :
2603 * bottom : user mode
2604 * either currently running or scheduled out.
2605 * can be scheduled out because interrupted in (user mode or in syscall)
2606 * or because of an explicit call to the scheduler in syscall. Note that
2607 * the scheduler call comes after the irq_exit, so never in interrupt
2609 // temp workaround : set size to 1 : only have user mode bottom of stack.
2610 // will cause g_info message of expected syscall mode when in fact being
2611 // in user mode. Can also cause expected trap when in fact being user
2612 // mode in the event of a page fault reenabling interrupts in the handler.
2613 // Expected syscall and trap can also happen after the end of statedump
2614 // This will cause a "popping last state on stack, ignoring it."
2615 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2616 es
= process
->state
= &g_array_index(process
->execution_stack
,
2617 LttvExecutionState
, 0);
2618 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2619 es
->s
= LTTV_STATE_UNNAMED
;
2620 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2622 es
->t
= LTTV_STATE_USER_MODE
;
2630 es
= process
->state
= &g_array_index(process
->execution_stack
,
2631 LttvExecutionState
, 1);
2632 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2633 es
->s
= LTTV_STATE_UNNAMED
;
2634 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2638 /* The process has already been created :
2639 * Probably was forked while dumping the process state or
2640 * was simply scheduled in prior to get the state dump event.
2642 process
->ppid
= parent_pid
;
2643 process
->tgid
= tgid
;
2644 process
->name
= g_quark_from_string(command
);
2645 process
->type
= type
;
2647 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2649 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2650 if(type
== LTTV_STATE_KERNEL_THREAD
)
2651 es
->t
= LTTV_STATE_SYSCALL
;
2653 es
->t
= LTTV_STATE_USER_MODE
;
2656 /* Don't mess around with the stack, it will eventually become
2657 * ok after the end of state dump. */
2664 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2666 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2668 lttv_state_add_event_hooks(tss
);
2673 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2675 LttvTraceset
*traceset
= self
->parent
.ts
;
2677 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2681 LttvTracefileState
*tfs
;
2685 LttvTraceHookByFacility
*thf
;
2687 LttvTraceHook
*hook
;
2689 LttvAttributeValue val
;
2694 nb_trace
= lttv_traceset_number(traceset
);
2695 for(i
= 0 ; i
< nb_trace
; i
++) {
2696 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2698 /* Find the eventtype id for the following events and register the
2699 associated by id hooks. */
2701 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2702 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2705 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2706 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2707 LTT_FIELD_SYSCALL_ID
, 0, 0,
2708 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2711 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2712 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2714 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2717 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2718 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2719 LTT_FIELD_TRAP_ID
, 0, 0,
2720 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2723 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2724 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2726 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2729 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2730 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2731 LTT_FIELD_IRQ_ID
, 0, 0,
2732 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2735 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2736 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2738 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2741 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2742 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2743 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2744 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2747 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2748 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2750 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2753 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2754 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2755 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2756 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2759 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2760 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2761 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2762 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2765 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2766 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2767 LTT_FIELD_PID
, 0, 0,
2768 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2772 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2773 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2774 LTT_FIELD_PID
, 0, 0,
2775 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2778 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2779 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
2780 LTT_FIELD_PID
, 0, 0,
2781 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2784 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2785 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2786 LTT_FIELD_FILENAME
, 0, 0,
2787 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2790 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2791 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2792 LTT_FIELD_NAME
, 0, 0,
2793 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2796 /* statedump-related hooks */
2797 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2798 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
2799 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2800 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2803 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2804 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
2806 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2809 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2810 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2811 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2812 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2815 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2816 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2817 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2818 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2821 hooks
= g_array_set_size(hooks
, hn
);
2823 /* Add these hooks to each event_by_id hooks list */
2825 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2827 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2829 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2830 LttvTracefileContext
*, j
));
2832 for(k
= 0 ; k
< hooks
->len
; k
++) {
2833 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2834 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2835 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2837 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2844 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2845 *(val
.v_pointer
) = hooks
;
2849 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2851 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2853 lttv_state_remove_event_hooks(tss
);
2858 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2860 LttvTraceset
*traceset
= self
->parent
.ts
;
2862 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2866 LttvTracefileState
*tfs
;
2870 LttvTraceHook
*hook
;
2872 LttvTraceHookByFacility
*thf
;
2874 LttvAttributeValue val
;
2876 nb_trace
= lttv_traceset_number(traceset
);
2877 for(i
= 0 ; i
< nb_trace
; i
++) {
2878 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2880 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2881 hooks
= *(val
.v_pointer
);
2883 /* Remove these hooks from each event_by_id hooks list */
2885 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2887 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2889 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2890 LttvTracefileContext
*, j
));
2892 for(k
= 0 ; k
< hooks
->len
; k
++) {
2893 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2894 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2895 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2897 lttv_hooks_remove_data(
2898 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2904 for(k
= 0 ; k
< hooks
->len
; k
++)
2905 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2906 g_array_free(hooks
, TRUE
);
2910 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2912 guint
*event_count
= (guint
*)hook_data
;
2914 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2915 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2920 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2922 LttvTracefileState
*tfcs
;
2924 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2926 LttEventPosition
*ep
;
2932 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2934 LttvAttributeValue value
;
2936 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2937 LTTV_STATE_SAVED_STATES
);
2938 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2939 value
= lttv_attribute_add(saved_states_tree
,
2940 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2941 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2942 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2943 *(value
.v_time
) = self
->parent
.timestamp
;
2944 lttv_state_save(tcs
, saved_state_tree
);
2945 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2946 self
->parent
.timestamp
.tv_nsec
);
2948 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2953 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2955 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2957 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2962 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2970 static gboolean
block_start(void *hook_data
, void *call_data
)
2972 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2974 LttvTracefileState
*tfcs
;
2976 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2978 LttEventPosition
*ep
;
2980 guint i
, nb_block
, nb_event
, nb_tracefile
;
2984 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2986 LttvAttributeValue value
;
2988 ep
= ltt_event_position_new();
2990 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2992 /* Count the number of events added since the last block end in any
2995 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2997 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2998 LttvTracefileContext
, i
));
2999 ltt_event_position(tfcs
->parent
.e
, ep
);
3000 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3001 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3002 tfcs
->saved_position
= nb_event
;
3006 if(tcs
->nb_event
>= tcs
->save_interval
) {
3007 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3008 LTTV_STATE_SAVED_STATES
);
3009 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3010 value
= lttv_attribute_add(saved_states_tree
,
3011 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3012 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3013 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3014 *(value
.v_time
) = self
->parent
.timestamp
;
3015 lttv_state_save(tcs
, saved_state_tree
);
3017 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3018 self
->parent
.timestamp
.tv_nsec
);
3020 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3026 static gboolean
block_end(void *hook_data
, void *call_data
)
3028 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3030 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3034 LttEventPosition
*ep
;
3036 guint nb_block
, nb_event
;
3038 ep
= ltt_event_position_new();
3039 ltt_event_position(self
->parent
.e
, ep
);
3040 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3041 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3042 self
->saved_position
= 0;
3043 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3050 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3052 LttvTraceset
*traceset
= self
->parent
.ts
;
3054 guint i
, j
, nb_trace
, nb_tracefile
;
3058 LttvTracefileState
*tfs
;
3060 LttvTraceHook hook_start
, hook_end
;
3062 nb_trace
= lttv_traceset_number(traceset
);
3063 for(i
= 0 ; i
< nb_trace
; i
++) {
3064 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3066 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3067 NULL
, NULL
, block_start
, &hook_start
);
3068 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3069 NULL
, NULL
, block_end
, &hook_end
);
3071 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3073 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3075 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3076 LttvTracefileContext
, j
));
3077 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3078 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3079 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3080 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3086 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3088 LttvTraceset
*traceset
= self
->parent
.ts
;
3090 guint i
, j
, nb_trace
, nb_tracefile
;
3094 LttvTracefileState
*tfs
;
3097 nb_trace
= lttv_traceset_number(traceset
);
3098 for(i
= 0 ; i
< nb_trace
; i
++) {
3100 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3101 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3103 if(ts
->has_precomputed_states
) continue;
3105 guint
*event_count
= g_new(guint
, 1);
3108 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3110 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3111 LttvTracefileContext
*, j
));
3112 lttv_hooks_add(tfs
->parent
.event
,
3113 state_save_event_hook
,
3120 lttv_process_traceset_begin(&self
->parent
,
3121 NULL
, NULL
, NULL
, NULL
, NULL
);
3125 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3127 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3129 lttv_state_save_add_event_hooks(tss
);
3136 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3138 LttvTraceset
*traceset
= self
->parent
.ts
;
3140 guint i
, j
, nb_trace
, nb_tracefile
;
3144 LttvTracefileState
*tfs
;
3146 LttvTraceHook hook_start
, hook_end
;
3148 nb_trace
= lttv_traceset_number(traceset
);
3149 for(i
= 0 ; i
< nb_trace
; i
++) {
3150 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3152 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3153 NULL
, NULL
, block_start
, &hook_start
);
3155 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3156 NULL
, NULL
, block_end
, &hook_end
);
3158 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3160 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3162 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3163 LttvTracefileContext
, j
));
3164 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3165 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3166 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3167 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3173 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3175 LttvTraceset
*traceset
= self
->parent
.ts
;
3177 guint i
, j
, nb_trace
, nb_tracefile
;
3181 LttvTracefileState
*tfs
;
3183 LttvHooks
*after_trace
= lttv_hooks_new();
3185 lttv_hooks_add(after_trace
,
3186 state_save_after_trace_hook
,
3191 lttv_process_traceset_end(&self
->parent
,
3192 NULL
, after_trace
, NULL
, NULL
, NULL
);
3194 lttv_hooks_destroy(after_trace
);
3196 nb_trace
= lttv_traceset_number(traceset
);
3197 for(i
= 0 ; i
< nb_trace
; i
++) {
3199 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3200 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3202 if(ts
->has_precomputed_states
) continue;
3204 guint
*event_count
= NULL
;
3206 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3208 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3209 LttvTracefileContext
*, j
));
3210 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3211 state_save_event_hook
);
3213 if(event_count
) g_free(event_count
);
3217 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3219 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3221 lttv_state_save_remove_event_hooks(tss
);
3226 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3228 LttvTraceset
*traceset
= self
->parent
.ts
;
3232 int min_pos
, mid_pos
, max_pos
;
3234 guint call_rest
= 0;
3236 LttvTraceState
*tcs
;
3238 LttvAttributeValue value
;
3240 LttvAttributeType type
;
3242 LttvAttributeName name
;
3246 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3248 //g_tree_destroy(self->parent.pqueue);
3249 //self->parent.pqueue = g_tree_new(compare_tracefile);
3251 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3253 nb_trace
= lttv_traceset_number(traceset
);
3254 for(i
= 0 ; i
< nb_trace
; i
++) {
3255 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3257 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3258 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3259 LTTV_STATE_SAVED_STATES
);
3262 if(saved_states_tree
) {
3263 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3264 mid_pos
= max_pos
/ 2;
3265 while(min_pos
< max_pos
) {
3266 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3268 g_assert(type
== LTTV_GOBJECT
);
3269 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3270 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3272 g_assert(type
== LTTV_TIME
);
3273 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3275 closest_tree
= saved_state_tree
;
3277 else max_pos
= mid_pos
- 1;
3279 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3283 /* restore the closest earlier saved state */
3285 lttv_state_restore(tcs
, closest_tree
);
3289 /* There is no saved state, yet we want to have it. Restart at T0 */
3291 restore_init_state(tcs
);
3292 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3295 /* We want to seek quickly without restoring/updating the state */
3297 restore_init_state(tcs
);
3298 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3301 if(!call_rest
) g_info("NOT Calling restore");
3306 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3312 traceset_state_finalize (LttvTracesetState
*self
)
3314 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3315 finalize(G_OBJECT(self
));
3320 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3322 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3324 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3325 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3326 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3327 klass
->new_traceset_context
= new_traceset_context
;
3328 klass
->new_trace_context
= new_trace_context
;
3329 klass
->new_tracefile_context
= new_tracefile_context
;
3334 lttv_traceset_state_get_type(void)
3336 static GType type
= 0;
3338 static const GTypeInfo info
= {
3339 sizeof (LttvTracesetStateClass
),
3340 NULL
, /* base_init */
3341 NULL
, /* base_finalize */
3342 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3343 NULL
, /* class_finalize */
3344 NULL
, /* class_data */
3345 sizeof (LttvTracesetState
),
3346 0, /* n_preallocs */
3347 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3348 NULL
/* value handling */
3351 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3359 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3365 trace_state_finalize (LttvTraceState
*self
)
3367 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3368 finalize(G_OBJECT(self
));
3373 trace_state_class_init (LttvTraceStateClass
*klass
)
3375 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3377 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3378 klass
->state_save
= state_save
;
3379 klass
->state_restore
= state_restore
;
3380 klass
->state_saved_free
= state_saved_free
;
3385 lttv_trace_state_get_type(void)
3387 static GType type
= 0;
3389 static const GTypeInfo info
= {
3390 sizeof (LttvTraceStateClass
),
3391 NULL
, /* base_init */
3392 NULL
, /* base_finalize */
3393 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3394 NULL
, /* class_finalize */
3395 NULL
, /* class_data */
3396 sizeof (LttvTraceState
),
3397 0, /* n_preallocs */
3398 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3399 NULL
/* value handling */
3402 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3403 "LttvTraceStateType", &info
, 0);
3410 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3416 tracefile_state_finalize (LttvTracefileState
*self
)
3418 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3419 finalize(G_OBJECT(self
));
3424 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3426 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3428 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3433 lttv_tracefile_state_get_type(void)
3435 static GType type
= 0;
3437 static const GTypeInfo info
= {
3438 sizeof (LttvTracefileStateClass
),
3439 NULL
, /* base_init */
3440 NULL
, /* base_finalize */
3441 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3442 NULL
, /* class_finalize */
3443 NULL
, /* class_data */
3444 sizeof (LttvTracefileState
),
3445 0, /* n_preallocs */
3446 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3447 NULL
/* value handling */
3450 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3451 "LttvTracefileStateType", &info
, 0);
3457 static void module_init()
3459 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3460 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3461 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3462 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3463 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3464 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3465 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3466 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3467 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3468 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3469 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3470 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3471 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3472 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3473 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3474 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3475 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3476 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3477 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3478 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3479 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3480 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3481 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3482 LTTV_STATE_EVENT
= g_quark_from_string("event");
3483 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3484 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3485 LTTV_STATE_TIME
= g_quark_from_string("time");
3486 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3487 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3488 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3489 g_quark_from_string("trace_state_use_count");
3492 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3493 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3494 LTT_FACILITY_FS
= g_quark_from_string("fs");
3495 LTT_FACILITY_LIST
= g_quark_from_string("list");
3496 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3499 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3500 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3501 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3502 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3503 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3504 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3505 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3506 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3507 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3508 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3509 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3510 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3511 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3512 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3513 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3514 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3515 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3516 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3517 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3520 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3521 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3522 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3523 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3524 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3525 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3526 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3527 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3528 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3529 LTT_FIELD_PID
= g_quark_from_string("pid");
3530 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3531 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3532 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3533 LTT_FIELD_NAME
= g_quark_from_string("name");
3534 LTT_FIELD_TYPE
= g_quark_from_string("type");
3535 LTT_FIELD_MODE
= g_quark_from_string("mode");
3536 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3537 LTT_FIELD_STATUS
= g_quark_from_string("status");
3538 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3539 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3541 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3542 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3543 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3544 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3547 static void module_destroy()
3552 LTTV_MODULE("state", "State computation", \
3553 "Update the system state, possibly saving it at intervals", \
3554 module_init
, module_destroy
)