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
;
136 LTTV_STATE_TRACEFILES
,
137 LTTV_STATE_PROCESSES
,
139 LTTV_STATE_RUNNING_PROCESS
,
141 LTTV_STATE_SAVED_STATES
,
142 LTTV_STATE_SAVED_STATES_TIME
,
145 LTTV_STATE_NAME_TABLES
,
146 LTTV_STATE_TRACE_STATE_USE_COUNT
;
148 static void create_max_time(LttvTraceState
*tcs
);
150 static void get_max_time(LttvTraceState
*tcs
);
152 static void free_max_time(LttvTraceState
*tcs
);
154 static void create_name_tables(LttvTraceState
*tcs
);
156 static void get_name_tables(LttvTraceState
*tcs
);
158 static void free_name_tables(LttvTraceState
*tcs
);
160 static void free_saved_state(LttvTraceState
*tcs
);
162 static void lttv_state_free_process_table(GHashTable
*processes
);
164 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
165 GPtrArray
*quarktable
);
167 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
169 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
173 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
175 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
179 void lttv_state_state_saved_free(LttvTraceState
*self
,
180 LttvAttribute
*container
)
182 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
186 guint
process_hash(gconstpointer key
)
188 guint pid
= ((const LttvProcessState
*)key
)->pid
;
189 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
193 /* If the hash table hash function is well distributed,
194 * the process_equal should compare different pid */
195 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
197 const LttvProcessState
*process_a
, *process_b
;
200 process_a
= (const LttvProcessState
*)a
;
201 process_b
= (const LttvProcessState
*)b
;
203 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
204 else if(likely(process_a
->pid
== 0 &&
205 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
210 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
212 g_tree_destroy((GTree
*)value
);
215 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
217 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
218 g_hash_table_destroy(usertraces
);
224 restore_init_state(LttvTraceState
*self
)
228 LttvTracefileState
*tfcs
;
230 LttTime start_time
, end_time
;
232 /* Free the process tables */
233 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
234 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
235 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
236 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
239 /* Seek time to beginning */
240 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
241 // closest. It's the tracecontext job to seek the trace to the beginning
242 // anyway : the init state might be used at the middle of the trace as well...
243 //g_tree_destroy(self->parent.ts_context->pqueue);
244 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
246 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
248 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
250 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
252 /* Put the per cpu running_process to beginning state : process 0. */
253 for(i
=0; i
< nb_cpus
; i
++) {
254 LttvExecutionState
*es
;
255 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
256 LTTV_STATE_UNNAMED
, &start_time
);
257 /* We are not sure is it's a kernel thread or normal thread, put the
258 * bottom stack state to unknown */
259 self
->running_process
[i
]->execution_stack
=
260 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
261 es
= self
->running_process
[i
]->state
=
262 &g_array_index(self
->running_process
[i
]->execution_stack
,
263 LttvExecutionState
, 0);
264 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
265 es
->s
= LTTV_STATE_UNNAMED
;
267 //self->running_process[i]->state->s = LTTV_STATE_RUN;
268 self
->running_process
[i
]->cpu
= i
;
272 nb_tracefile
= self
->parent
.tracefiles
->len
;
274 for(i
= 0 ; i
< nb_tracefile
; i
++) {
276 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
277 LttvTracefileContext
*, i
));
278 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
279 // tfcs->saved_position = 0;
280 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
281 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
282 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
283 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
288 //static LttTime time_zero = {0,0};
290 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
293 const LttTime
*t1
= (const LttTime
*)a
;
294 const LttTime
*t2
= (const LttTime
*)b
;
296 return ltt_time_compare(*t1
, *t2
);
299 static void free_usertrace_key(gpointer data
)
304 #define MAX_STRING_LEN 4096
307 state_load_saved_states(LttvTraceState
*tcs
)
310 GPtrArray
*quarktable
;
315 tcs
->has_precomputed_states
= FALSE
;
319 gchar buf
[MAX_STRING_LEN
];
322 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
323 strncpy(path
, trace_path
, PATH_MAX
-1);
324 count
= strnlen(trace_path
, PATH_MAX
-1);
325 // quarktable : open, test
326 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
327 fp
= fopen(path
, "r");
329 quarktable
= g_ptr_array_sized_new(4096);
331 /* Index 0 is null */
333 if(hdr
== EOF
) return;
334 g_assert(hdr
== HDR_QUARKS
);
338 if(hdr
== EOF
) break;
339 g_assert(hdr
== HDR_QUARK
);
340 g_ptr_array_set_size(quarktable
, q
+1);
343 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
344 if(buf
[i
] == '\0' || feof(fp
)) break;
347 len
= strnlen(buf
, MAX_STRING_LEN
-1);
348 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
349 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
355 // saved_states : open, test
356 strncpy(path
, trace_path
, PATH_MAX
-1);
357 count
= strnlen(trace_path
, PATH_MAX
-1);
358 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
359 fp
= fopen(path
, "r");
363 if(hdr
!= HDR_TRACE
) goto end
;
365 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
367 tcs
->has_precomputed_states
= TRUE
;
372 /* Free the quarktable */
373 for(i
=0; i
<quarktable
->len
; i
++) {
374 string
= g_ptr_array_index (quarktable
, i
);
377 g_ptr_array_free(quarktable
, TRUE
);
382 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
384 guint i
, j
, nb_trace
, nb_tracefile
;
386 LttvTraceContext
*tc
;
390 LttvTracefileState
*tfcs
;
392 LttvAttributeValue v
;
394 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
395 init((LttvTracesetContext
*)self
, ts
);
397 nb_trace
= lttv_traceset_number(ts
);
398 for(i
= 0 ; i
< nb_trace
; i
++) {
399 tc
= self
->parent
.traces
[i
];
400 tcs
= LTTV_TRACE_STATE(tc
);
401 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
402 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
406 if(*(v
.v_uint
) == 1) {
407 create_name_tables(tcs
);
408 create_max_time(tcs
);
410 get_name_tables(tcs
);
413 nb_tracefile
= tc
->tracefiles
->len
;
414 tcs
->processes
= NULL
;
415 tcs
->usertraces
= NULL
;
416 tcs
->running_process
= g_new(LttvProcessState
*,
417 ltt_trace_get_num_cpu(tc
->t
));
418 tcs
->cpu_states
= g_new(LttvCPUState
,
419 ltt_trace_get_num_cpu(tc
->t
));
420 restore_init_state(tcs
);
421 for(j
= 0 ; j
< nb_tracefile
; j
++) {
423 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
424 LttvTracefileContext
*, j
));
425 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
426 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
427 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
428 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
429 /* It's a Usertrace */
430 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
431 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
433 if(!usertrace_tree
) {
434 usertrace_tree
= g_tree_new_full(compare_usertraces
,
435 NULL
, free_usertrace_key
, NULL
);
436 g_hash_table_insert(tcs
->usertraces
,
437 (gpointer
)tid
, usertrace_tree
);
439 LttTime
*timestamp
= g_new(LttTime
, 1);
440 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
441 ltt_tracefile_creation(tfcs
->parent
.tf
));
442 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
446 /* See if the trace has saved states */
447 state_load_saved_states(tcs
);
452 fini(LttvTracesetState
*self
)
458 LttvTracefileState
*tfcs
;
460 LttvAttributeValue v
;
462 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
463 for(i
= 0 ; i
< nb_trace
; i
++) {
464 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
465 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
468 g_assert(*(v
.v_uint
) != 0);
471 if(*(v
.v_uint
) == 0) {
472 free_name_tables(tcs
);
474 free_saved_state(tcs
);
476 g_free(tcs
->running_process
);
477 tcs
->running_process
= NULL
;
478 lttv_state_free_process_table(tcs
->processes
);
479 lttv_state_free_usertraces(tcs
->usertraces
);
480 tcs
->processes
= NULL
;
481 tcs
->usertraces
= NULL
;
483 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
484 fini((LttvTracesetContext
*)self
);
488 static LttvTracesetContext
*
489 new_traceset_context(LttvTracesetContext
*self
)
491 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
495 static LttvTraceContext
*
496 new_trace_context(LttvTracesetContext
*self
)
498 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
502 static LttvTracefileContext
*
503 new_tracefile_context(LttvTracesetContext
*self
)
505 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
509 /* Write the process state of the trace */
511 static void write_process_state(gpointer key
, gpointer value
,
514 LttvProcessState
*process
;
516 LttvExecutionState
*es
;
518 FILE *fp
= (FILE *)user_data
;
523 process
= (LttvProcessState
*)value
;
525 " <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",
526 process
, process
->pid
, process
->tgid
, process
->ppid
,
527 g_quark_to_string(process
->type
),
528 process
->creation_time
.tv_sec
,
529 process
->creation_time
.tv_nsec
,
530 process
->insertion_time
.tv_sec
,
531 process
->insertion_time
.tv_nsec
,
532 g_quark_to_string(process
->name
),
533 g_quark_to_string(process
->brand
),
536 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
537 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
538 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
539 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
540 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
541 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
542 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
545 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
546 address
= &g_array_index(process
->user_stack
, guint64
, i
);
547 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
551 if(process
->usertrace
) {
552 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
553 g_quark_to_string(process
->usertrace
->tracefile_name
),
554 process
->usertrace
->cpu
);
558 fprintf(fp
, " </PROCESS>\n");
562 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
564 guint i
, nb_tracefile
, nb_block
, offset
;
567 LttvTracefileState
*tfcs
;
571 LttEventPosition
*ep
;
575 ep
= ltt_event_position_new();
577 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
579 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
581 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
582 for(i
=0;i
<nb_cpus
;i
++) {
583 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
584 i
, self
->running_process
[i
]->pid
);
587 nb_tracefile
= self
->parent
.tracefiles
->len
;
589 for(i
= 0 ; i
< nb_tracefile
; i
++) {
591 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
592 LttvTracefileContext
*, i
));
593 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
594 tfcs
->parent
.timestamp
.tv_sec
,
595 tfcs
->parent
.timestamp
.tv_nsec
);
596 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
597 if(e
== NULL
) fprintf(fp
,"/>\n");
599 ltt_event_position(e
, ep
);
600 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
601 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
606 fprintf(fp
,"</PROCESS_STATE>\n");
610 static void write_process_state_raw(gpointer key
, gpointer value
,
613 LttvProcessState
*process
;
615 LttvExecutionState
*es
;
617 FILE *fp
= (FILE *)user_data
;
622 process
= (LttvProcessState
*)value
;
623 fputc(HDR_PROCESS
, fp
);
624 //fwrite(&header, sizeof(header), 1, fp);
625 //fprintf(fp, "%s", g_quark_to_string(process->type));
627 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
628 //fprintf(fp, "%s", g_quark_to_string(process->name));
630 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
631 //fprintf(fp, "%s", g_quark_to_string(process->brand));
633 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
634 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
635 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
636 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
637 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
638 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
639 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
643 " <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",
644 process
, process
->pid
, process
->tgid
, process
->ppid
,
645 g_quark_to_string(process
->type
),
646 process
->creation_time
.tv_sec
,
647 process
->creation_time
.tv_nsec
,
648 process
->insertion_time
.tv_sec
,
649 process
->insertion_time
.tv_nsec
,
650 g_quark_to_string(process
->name
),
651 g_quark_to_string(process
->brand
),
655 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
656 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
659 //fprintf(fp, "%s", g_quark_to_string(es->t));
661 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
662 //fprintf(fp, "%s", g_quark_to_string(es->n));
664 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
665 //fprintf(fp, "%s", g_quark_to_string(es->s));
667 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
668 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
669 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
670 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
672 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
673 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
674 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
675 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
676 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
680 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
681 address
= &g_array_index(process
->user_stack
, guint64
, i
);
682 fputc(HDR_USER_STACK
, fp
);
683 fwrite(&address
, sizeof(address
), 1, fp
);
685 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
690 if(process
->usertrace
) {
691 fputc(HDR_USERTRACE
, fp
);
692 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
694 fwrite(&process
->usertrace
->tracefile_name
,
695 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
696 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
698 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
699 g_quark_to_string(process
->usertrace
->tracefile_name
),
700 process
->usertrace
->cpu
);
707 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
709 guint i
, nb_tracefile
, nb_block
, offset
;
712 LttvTracefileState
*tfcs
;
716 LttEventPosition
*ep
;
720 ep
= ltt_event_position_new();
722 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
723 fputc(HDR_PROCESS_STATE
, fp
);
724 fwrite(&t
, sizeof(t
), 1, fp
);
726 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
728 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
729 for(i
=0;i
<nb_cpus
;i
++) {
731 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
732 fwrite(&self
->running_process
[i
]->pid
,
733 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
734 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
735 // i, self->running_process[i]->pid);
738 nb_tracefile
= self
->parent
.tracefiles
->len
;
740 for(i
= 0 ; i
< nb_tracefile
; i
++) {
742 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
743 LttvTracefileContext
*, i
));
744 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
745 // tfcs->parent.timestamp.tv_sec,
746 // tfcs->parent.timestamp.tv_nsec);
747 fputc(HDR_TRACEFILE
, fp
);
748 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
749 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
750 * position following : end of trace */
751 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
753 ltt_event_position(e
, ep
);
754 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
755 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
757 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
758 fwrite(&offset
, sizeof(offset
), 1, fp
);
759 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
766 /* Read process state from a file */
768 /* Called because a HDR_PROCESS was found */
769 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
770 GPtrArray
*quarktable
)
772 LttvExecutionState
*es
;
773 LttvProcessState
*process
, *parent_process
;
774 LttvProcessState tmp
;
781 /* TODO : check return value */
782 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
783 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
784 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
785 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
786 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
787 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
788 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
789 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
790 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
793 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
795 /* We must link to the parent */
796 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
798 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
799 if(process
== NULL
) {
800 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
802 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
806 process
->insertion_time
= tmp
.insertion_time
;
807 process
->creation_time
= tmp
.creation_time
;
808 process
->type
= g_quark_from_string(
809 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
810 process
->tgid
= tmp
.tgid
;
811 process
->ppid
= tmp
.ppid
;
812 process
->brand
= g_quark_from_string(
813 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
815 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
819 if(feof(fp
) || ferror(fp
)) goto end_loop
;
821 gint hdr
= fgetc(fp
);
822 if(hdr
== EOF
) goto end_loop
;
826 process
->execution_stack
=
827 g_array_set_size(process
->execution_stack
,
828 process
->execution_stack
->len
+ 1);
829 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
830 process
->execution_stack
->len
-1);
833 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
834 es
->t
= g_quark_from_string(
835 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
836 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
837 es
->n
= g_quark_from_string(
838 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
839 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
840 es
->s
= g_quark_from_string(
841 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
842 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
843 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
844 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
847 process
->user_stack
= g_array_set_size(process
->user_stack
,
848 process
->user_stack
->len
+ 1);
849 address
= &g_array_index(process
->user_stack
, guint64
,
850 process
->user_stack
->len
-1);
851 fread(address
, sizeof(address
), 1, fp
);
852 process
->current_function
= *address
;
855 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
856 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
868 /* Called because a HDR_PROCESS_STATE was found */
869 /* Append a saved state to the trace states */
870 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
872 guint i
, nb_tracefile
, nb_block
, offset
;
874 LttvTracefileState
*tfcs
;
876 LttEventPosition
*ep
;
884 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
886 LttvAttributeValue value
;
887 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
888 ep
= ltt_event_position_new();
890 restore_init_state(self
);
892 fread(&t
, sizeof(t
), 1, fp
);
895 if(feof(fp
) || ferror(fp
)) goto end_loop
;
897 if(hdr
== EOF
) goto end_loop
;
901 /* Call read_process_state_raw */
902 read_process_state_raw(self
, fp
, quarktable
);
912 case HDR_PROCESS_STATE
:
918 g_error("Error while parsing saved state file : unknown data header %d",
924 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
925 for(i
=0;i
<nb_cpus
;i
++) {
928 g_assert(hdr
== HDR_CPU
);
929 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
930 g_assert(i
== cpu_num
);
931 fread(&self
->running_process
[i
]->pid
,
932 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
935 nb_tracefile
= self
->parent
.tracefiles
->len
;
937 for(i
= 0 ; i
< nb_tracefile
; i
++) {
939 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
940 LttvTracefileContext
*, i
));
941 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
942 // tfcs->parent.timestamp.tv_sec,
943 // tfcs->parent.timestamp.tv_nsec);
944 g_tree_remove(pqueue
, &tfcs
->parent
);
946 g_assert(hdr
== HDR_TRACEFILE
);
947 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
948 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
949 * position following : end of trace */
950 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
951 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
952 fread(&offset
, sizeof(offset
), 1, fp
);
953 fread(&tsc
, sizeof(tsc
), 1, fp
);
954 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
955 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
957 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
962 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
963 LTTV_STATE_SAVED_STATES
);
964 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
965 value
= lttv_attribute_add(saved_states_tree
,
966 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
967 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
968 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
970 lttv_state_save(self
, saved_state_tree
);
971 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
974 *(self
->max_time_state_recomputed_in_seek
) = t
;
978 /* Called when a HDR_TRACE is found */
979 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
980 GPtrArray
*quarktable
)
985 if(feof(fp
) || ferror(fp
)) goto end_loop
;
987 if(hdr
== EOF
) goto end_loop
;
990 case HDR_PROCESS_STATE
:
991 /* Call read_process_state_raw */
992 lttv_state_read_raw(tcs
, fp
, quarktable
);
1000 case HDR_USER_STACK
:
1004 g_error("Error while parsing saved state file :"
1005 " unexpected data header %d",
1009 g_error("Error while parsing saved state file : unknown data header %d",
1014 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1015 restore_init_state(tcs
);
1016 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1022 /* Copy each process from an existing hash table to a new one */
1024 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1026 LttvProcessState
*process
, *new_process
;
1028 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1032 process
= (LttvProcessState
*)value
;
1033 new_process
= g_new(LttvProcessState
, 1);
1034 *new_process
= *process
;
1035 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1036 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1037 new_process
->execution_stack
=
1038 g_array_set_size(new_process
->execution_stack
,
1039 process
->execution_stack
->len
);
1040 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1041 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1042 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1044 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1045 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1046 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1047 sizeof(guint64
), 0);
1048 new_process
->user_stack
=
1049 g_array_set_size(new_process
->user_stack
,
1050 process
->user_stack
->len
);
1051 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1052 g_array_index(new_process
->user_stack
, guint64
, i
) =
1053 g_array_index(process
->user_stack
, guint64
, i
);
1055 new_process
->current_function
= process
->current_function
;
1056 g_hash_table_insert(new_processes
, new_process
, new_process
);
1060 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1062 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1064 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1065 return new_processes
;
1069 /* The saved state for each trace contains a member "processes", which
1070 stores a copy of the process table, and a member "tracefiles" with
1071 one entry per tracefile. Each tracefile has a "process" member pointing
1072 to the current process and a "position" member storing the tracefile
1073 position (needed to seek to the current "next" event. */
1075 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1077 guint i
, nb_tracefile
, nb_cpus
;
1079 LttvTracefileState
*tfcs
;
1081 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1083 guint
*running_process
;
1085 LttvAttributeType type
;
1087 LttvAttributeValue value
;
1089 LttvAttributeName name
;
1091 LttEventPosition
*ep
;
1093 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1094 LTTV_STATE_TRACEFILES
);
1096 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1098 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1100 /* Add the currently running processes array */
1101 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1102 running_process
= g_new(guint
, nb_cpus
);
1103 for(i
=0;i
<nb_cpus
;i
++) {
1104 running_process
[i
] = self
->running_process
[i
]->pid
;
1106 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1108 *(value
.v_pointer
) = running_process
;
1110 g_info("State save");
1112 nb_tracefile
= self
->parent
.tracefiles
->len
;
1114 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1116 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1117 LttvTracefileContext
*, i
));
1118 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1119 value
= lttv_attribute_add(tracefiles_tree
, i
,
1121 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1123 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1125 *(value
.v_uint
) = tfcs
->process
->pid
;
1127 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1129 /* Only save the position if the tfs has not infinite time. */
1130 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1131 // && current_tfcs != tfcs) {
1132 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1133 *(value
.v_pointer
) = NULL
;
1135 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1136 ep
= ltt_event_position_new();
1137 ltt_event_position(e
, ep
);
1138 *(value
.v_pointer
) = ep
;
1140 guint nb_block
, offset
;
1143 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1144 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1146 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1152 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1154 guint i
, nb_tracefile
, pid
, nb_cpus
;
1156 LttvTracefileState
*tfcs
;
1158 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1160 guint
*running_process
;
1162 LttvAttributeType type
;
1164 LttvAttributeValue value
;
1166 LttvAttributeName name
;
1170 LttEventPosition
*ep
;
1172 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1174 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1175 LTTV_STATE_TRACEFILES
);
1177 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1179 g_assert(type
== LTTV_POINTER
);
1180 lttv_state_free_process_table(self
->processes
);
1181 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1183 /* Add the currently running processes array */
1184 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1185 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1187 g_assert(type
== LTTV_POINTER
);
1188 running_process
= *(value
.v_pointer
);
1189 for(i
=0;i
<nb_cpus
;i
++) {
1190 pid
= running_process
[i
];
1191 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1192 g_assert(self
->running_process
[i
] != NULL
);
1196 nb_tracefile
= self
->parent
.tracefiles
->len
;
1198 //g_tree_destroy(tsc->pqueue);
1199 //tsc->pqueue = g_tree_new(compare_tracefile);
1201 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1203 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1204 LttvTracefileContext
*, i
));
1205 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1206 g_assert(type
== LTTV_GOBJECT
);
1207 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1209 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1211 g_assert(type
== LTTV_UINT
);
1212 pid
= *(value
.v_uint
);
1213 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1215 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1217 g_assert(type
== LTTV_POINTER
);
1218 //g_assert(*(value.v_pointer) != NULL);
1219 ep
= *(value
.v_pointer
);
1220 g_assert(tfcs
->parent
.t_context
!= NULL
);
1222 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1223 g_tree_remove(tsc
->pqueue
, tfc
);
1226 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1227 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1228 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1229 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1230 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1232 tfc
->timestamp
= ltt_time_infinite
;
1238 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1240 guint i
, nb_tracefile
, nb_cpus
;
1242 LttvTracefileState
*tfcs
;
1244 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1246 guint
*running_process
;
1248 LttvAttributeType type
;
1250 LttvAttributeValue value
;
1252 LttvAttributeName name
;
1256 LttEventPosition
*ep
;
1258 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1259 LTTV_STATE_TRACEFILES
);
1260 g_object_ref(G_OBJECT(tracefiles_tree
));
1261 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1263 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1265 g_assert(type
== LTTV_POINTER
);
1266 lttv_state_free_process_table(*(value
.v_pointer
));
1267 *(value
.v_pointer
) = NULL
;
1268 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1270 /* Free running processes array */
1271 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1272 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1274 g_assert(type
== LTTV_POINTER
);
1275 running_process
= *(value
.v_pointer
);
1276 g_free(running_process
);
1278 nb_tracefile
= self
->parent
.tracefiles
->len
;
1280 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1282 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1283 LttvTracefileContext
*, i
));
1284 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1285 g_assert(type
== LTTV_GOBJECT
);
1286 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1288 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1290 g_assert(type
== LTTV_POINTER
);
1291 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1293 g_object_unref(G_OBJECT(tracefiles_tree
));
1297 static void free_saved_state(LttvTraceState
*self
)
1301 LttvAttributeType type
;
1303 LttvAttributeValue value
;
1305 LttvAttributeName name
;
1309 LttvAttribute
*saved_states
;
1311 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1312 LTTV_STATE_SAVED_STATES
);
1314 nb
= lttv_attribute_get_number(saved_states
);
1315 for(i
= 0 ; i
< nb
; i
++) {
1316 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1317 g_assert(type
== LTTV_GOBJECT
);
1318 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1321 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1326 create_max_time(LttvTraceState
*tcs
)
1328 LttvAttributeValue v
;
1330 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1332 g_assert(*(v
.v_pointer
) == NULL
);
1333 *(v
.v_pointer
) = g_new(LttTime
,1);
1334 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1339 get_max_time(LttvTraceState
*tcs
)
1341 LttvAttributeValue v
;
1343 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1345 g_assert(*(v
.v_pointer
) != NULL
);
1346 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1351 free_max_time(LttvTraceState
*tcs
)
1353 LttvAttributeValue v
;
1355 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1357 g_free(*(v
.v_pointer
));
1358 *(v
.v_pointer
) = NULL
;
1362 typedef struct _LttvNameTables
{
1363 // FIXME GQuark *eventtype_names;
1364 GQuark
*syscall_names
;
1370 GQuark
*soft_irq_names
;
1376 create_name_tables(LttvTraceState
*tcs
)
1380 GQuark f_name
, e_name
;
1384 LttvTraceHookByFacility
*thf
;
1390 GString
*fe_name
= g_string_new("");
1392 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1394 LttvAttributeValue v
;
1396 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1398 g_assert(*(v
.v_pointer
) == NULL
);
1399 *(v
.v_pointer
) = name_tables
;
1400 #if 0 // Use iteration over the facilities_by_name and then list all event
1401 // types of each facility
1402 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1403 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1404 for(i
= 0 ; i
< nb
; i
++) {
1405 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1406 e_name
= ltt_eventtype_name(et
);
1407 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1408 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1409 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1412 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1413 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1414 LTT_FIELD_SYSCALL_ID
, 0, 0,
1417 thf
= lttv_trace_hook_get_first(&h
);
1419 t
= ltt_field_type(thf
->f1
);
1420 nb
= ltt_type_element_number(t
);
1422 lttv_trace_hook_destroy(&h
);
1424 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1425 name_tables
->nb_syscalls
= nb
;
1427 for(i
= 0 ; i
< nb
; i
++) {
1428 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1429 if(!name_tables
->syscall_names
[i
]) {
1430 GString
*string
= g_string_new("");
1431 g_string_printf(string
, "syscall %u", i
);
1432 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1433 g_string_free(string
, TRUE
);
1437 //name_tables->syscall_names = g_new(GQuark, 256);
1438 //for(i = 0 ; i < 256 ; i++) {
1439 // g_string_printf(fe_name, "syscall %d", i);
1440 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1443 name_tables
->syscall_names
= NULL
;
1444 name_tables
->nb_syscalls
= 0;
1447 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1448 LTT_EVENT_TRAP_ENTRY
,
1449 LTT_FIELD_TRAP_ID
, 0, 0,
1452 thf
= lttv_trace_hook_get_first(&h
);
1454 t
= ltt_field_type(thf
->f1
);
1455 //nb = ltt_type_element_number(t);
1457 lttv_trace_hook_destroy(&h
);
1460 name_tables->trap_names = g_new(GQuark, nb);
1461 for(i = 0 ; i < nb ; i++) {
1462 name_tables->trap_names[i] = g_quark_from_string(
1463 ltt_enum_string_get(t, i));
1466 name_tables
->nb_traps
= 256;
1467 name_tables
->trap_names
= g_new(GQuark
, 256);
1468 for(i
= 0 ; i
< 256 ; i
++) {
1469 g_string_printf(fe_name
, "trap %d", i
);
1470 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1473 name_tables
->trap_names
= NULL
;
1474 name_tables
->nb_traps
= 0;
1477 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1478 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1479 LTT_FIELD_IRQ_ID
, 0, 0,
1482 thf
= lttv_trace_hook_get_first(&h
);
1484 t
= ltt_field_type(thf
->f1
);
1485 //nb = ltt_type_element_number(t);
1487 lttv_trace_hook_destroy(&h
);
1490 name_tables->irq_names = g_new(GQuark, nb);
1491 for(i = 0 ; i < nb ; i++) {
1492 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1496 name_tables
->nb_irqs
= 256;
1497 name_tables
->irq_names
= g_new(GQuark
, 256);
1498 for(i
= 0 ; i
< 256 ; i
++) {
1499 g_string_printf(fe_name
, "irq %d", i
);
1500 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1503 name_tables
->nb_irqs
= 0;
1504 name_tables
->irq_names
= NULL
;
1507 name_tables->soft_irq_names = g_new(GQuark, nb);
1508 for(i = 0 ; i < nb ; i++) {
1509 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1513 name_tables
->nb_softirqs
= 256;
1514 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1515 for(i
= 0 ; i
< 256 ; i
++) {
1516 g_string_printf(fe_name
, "softirq %d", i
);
1517 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1521 g_string_free(fe_name
, TRUE
);
1526 get_name_tables(LttvTraceState
*tcs
)
1528 LttvNameTables
*name_tables
;
1530 LttvAttributeValue v
;
1532 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1534 g_assert(*(v
.v_pointer
) != NULL
);
1535 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1536 //tcs->eventtype_names = name_tables->eventtype_names;
1537 tcs
->syscall_names
= name_tables
->syscall_names
;
1538 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1539 tcs
->trap_names
= name_tables
->trap_names
;
1540 tcs
->nb_traps
= name_tables
->nb_traps
;
1541 tcs
->irq_names
= name_tables
->irq_names
;
1542 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1543 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1544 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1549 free_name_tables(LttvTraceState
*tcs
)
1551 LttvNameTables
*name_tables
;
1553 LttvAttributeValue v
;
1555 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1557 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1558 *(v
.v_pointer
) = NULL
;
1560 // g_free(name_tables->eventtype_names);
1561 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1562 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1563 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1564 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1565 if(name_tables
) g_free(name_tables
);
1568 #ifdef HASH_TABLE_DEBUG
1570 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1572 LttvProcessState
*process
= (LttvProcessState
*)value
;
1574 /* Test for process corruption */
1575 guint stack_len
= process
->execution_stack
->len
;
1578 static void hash_table_check(GHashTable
*table
)
1580 g_hash_table_foreach(table
, test_process
, NULL
);
1587 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1590 LttvExecutionState
*es
;
1592 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1593 guint cpu
= tfs
->cpu
;
1595 #ifdef HASH_TABLE_DEBUG
1596 hash_table_check(ts
->processes
);
1598 LttvProcessState
*process
= ts
->running_process
[cpu
];
1600 guint depth
= process
->execution_stack
->len
;
1602 process
->execution_stack
=
1603 g_array_set_size(process
->execution_stack
, depth
+ 1);
1606 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1608 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1611 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1612 es
->cum_cpu_time
= ltt_time_zero
;
1613 es
->s
= process
->state
->s
;
1614 process
->state
= es
;
1618 * return 1 when empty, else 0 */
1619 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1620 LttvTracefileState
*tfs
)
1622 guint cpu
= tfs
->cpu
;
1623 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1625 guint depth
= process
->execution_stack
->len
;
1631 process
->execution_stack
=
1632 g_array_set_size(process
->execution_stack
, depth
- 1);
1633 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1635 process
->state
->change
= tfs
->parent
.timestamp
;
1640 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1642 guint cpu
= tfs
->cpu
;
1643 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1644 LttvProcessState
*process
= ts
->running_process
[cpu
];
1646 guint depth
= process
->execution_stack
->len
;
1648 if(process
->state
->t
!= t
){
1649 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1650 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1651 g_info("process state has %s when pop_int is %s\n",
1652 g_quark_to_string(process
->state
->t
),
1653 g_quark_to_string(t
));
1654 g_info("{ %u, %u, %s, %s, %s }\n",
1657 g_quark_to_string(process
->name
),
1658 g_quark_to_string(process
->brand
),
1659 g_quark_to_string(process
->state
->s
));
1664 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1665 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1669 process
->execution_stack
=
1670 g_array_set_size(process
->execution_stack
, depth
- 1);
1671 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1673 process
->state
->change
= tfs
->parent
.timestamp
;
1676 struct search_result
{
1677 const LttTime
*time
; /* Requested time */
1678 LttTime
*best
; /* Best result */
1681 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1683 const LttTime
*elem_time
= (const LttTime
*)a
;
1684 /* Explicit non const cast */
1685 struct search_result
*res
= (struct search_result
*)b
;
1687 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1688 /* The usertrace was created before the schedchange */
1689 /* Get larger keys */
1691 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1692 /* The usertrace was created after the schedchange time */
1693 /* Get smaller keys */
1695 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1696 res
->best
= elem_time
;
1699 res
->best
= elem_time
;
1706 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1707 guint pid
, const LttTime
*timestamp
)
1709 LttvTracefileState
*tfs
= NULL
;
1710 struct search_result res
;
1711 /* Find the usertrace associated with a pid and time interval.
1712 * Search in the usertraces by PID (within a hash) and then, for each
1713 * corresponding element of the array, find the first one with creation
1714 * timestamp the lowest, but higher or equal to "timestamp". */
1715 res
.time
= timestamp
;
1717 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1718 if(usertrace_tree
) {
1719 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1721 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1729 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1730 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1732 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1734 LttvExecutionState
*es
;
1736 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1741 process
->tgid
= tgid
;
1743 process
->name
= name
;
1744 process
->brand
= LTTV_STATE_UNBRANDED
;
1745 //process->last_cpu = tfs->cpu_name;
1746 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1747 process
->type
= LTTV_STATE_USER_THREAD
;
1748 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1749 process
->current_function
= 0; //function 0x0 by default.
1751 g_info("Process %u, core %p", process
->pid
, process
);
1752 g_hash_table_insert(tcs
->processes
, process
, process
);
1755 process
->ppid
= parent
->pid
;
1756 process
->creation_time
= *timestamp
;
1759 /* No parent. This process exists but we are missing all information about
1760 its creation. The birth time is set to zero but we remember the time of
1765 process
->creation_time
= ltt_time_zero
;
1768 process
->insertion_time
= *timestamp
;
1769 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1770 process
->creation_time
.tv_nsec
);
1771 process
->pid_time
= g_quark_from_string(buffer
);
1773 //process->last_cpu = tfs->cpu_name;
1774 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1775 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1776 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1777 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1778 es
= process
->state
= &g_array_index(process
->execution_stack
,
1779 LttvExecutionState
, 0);
1780 es
->t
= LTTV_STATE_USER_MODE
;
1781 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1782 es
->entry
= *timestamp
;
1783 //g_assert(timestamp->tv_sec != 0);
1784 es
->change
= *timestamp
;
1785 es
->cum_cpu_time
= ltt_time_zero
;
1786 es
->s
= LTTV_STATE_RUN
;
1788 es
= process
->state
= &g_array_index(process
->execution_stack
,
1789 LttvExecutionState
, 1);
1790 es
->t
= LTTV_STATE_SYSCALL
;
1791 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1792 es
->entry
= *timestamp
;
1793 //g_assert(timestamp->tv_sec != 0);
1794 es
->change
= *timestamp
;
1795 es
->cum_cpu_time
= ltt_time_zero
;
1796 es
->s
= LTTV_STATE_WAIT_FORK
;
1798 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1799 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1800 sizeof(guint64
), 0);
1805 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1808 LttvProcessState key
;
1809 LttvProcessState
*process
;
1813 process
= g_hash_table_lookup(ts
->processes
, &key
);
1818 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1819 const LttTime
*timestamp
)
1821 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1822 LttvExecutionState
*es
;
1824 /* Put ltt_time_zero creation time for unexisting processes */
1825 if(unlikely(process
== NULL
)) {
1826 process
= lttv_state_create_process(ts
,
1827 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1828 /* We are not sure is it's a kernel thread or normal thread, put the
1829 * bottom stack state to unknown */
1830 process
->execution_stack
=
1831 g_array_set_size(process
->execution_stack
, 1);
1832 process
->state
= es
=
1833 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1834 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1835 es
->s
= LTTV_STATE_UNNAMED
;
1840 /* FIXME : this function should be called when we receive an event telling that
1841 * release_task has been called in the kernel. In happens generally when
1842 * the parent waits for its child terminaison, but may also happen in special
1843 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1844 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1845 * of a killed thread ground, but isn't the leader.
1847 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1849 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1850 LttvProcessState key
;
1852 key
.pid
= process
->pid
;
1853 key
.cpu
= process
->cpu
;
1854 g_hash_table_remove(ts
->processes
, &key
);
1855 g_array_free(process
->execution_stack
, TRUE
);
1856 g_array_free(process
->user_stack
, TRUE
);
1861 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1863 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1864 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1869 static void lttv_state_free_process_table(GHashTable
*processes
)
1871 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1872 g_hash_table_destroy(processes
);
1876 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1878 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1880 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1881 LttvProcessState
*process
= ts
->running_process
[cpu
];
1882 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1883 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1884 LttField
*f
= thf
->f1
;
1886 LttvExecutionSubmode submode
;
1888 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1889 guint syscall
= ltt_event_get_unsigned(e
, f
);
1891 if(syscall
< nb_syscalls
) {
1892 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1895 /* Fixup an incomplete syscall table */
1896 GString
*string
= g_string_new("");
1897 g_string_printf(string
, "syscall %u", syscall
);
1898 submode
= g_quark_from_string(string
->str
);
1899 g_string_free(string
, TRUE
);
1901 /* There can be no system call from PID 0 : unknown state */
1902 if(process
->pid
!= 0)
1903 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1908 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1910 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1912 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1913 LttvProcessState
*process
= ts
->running_process
[cpu
];
1915 /* There can be no system call from PID 0 : unknown state */
1916 if(process
->pid
!= 0)
1917 pop_state(s
, LTTV_STATE_SYSCALL
);
1922 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1924 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1925 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1926 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1927 LttField
*f
= thf
->f1
;
1929 LttvExecutionSubmode submode
;
1931 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1932 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1934 if(trap
< nb_traps
) {
1935 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1937 /* Fixup an incomplete trap table */
1938 GString
*string
= g_string_new("");
1939 g_string_printf(string
, "trap %llu", trap
);
1940 submode
= g_quark_from_string(string
->str
);
1941 g_string_free(string
, TRUE
);
1944 push_state(s
, LTTV_STATE_TRAP
, submode
);
1949 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1951 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1953 pop_state(s
, LTTV_STATE_TRAP
);
1958 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1960 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1961 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1962 guint8 fac_id
= ltt_event_facility_id(e
);
1963 guint8 ev_id
= ltt_event_eventtype_id(e
);
1964 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1965 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1966 g_assert(thf
->f1
!= NULL
);
1967 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1968 LttField
*f
= thf
->f1
;
1970 LttvExecutionSubmode submode
;
1971 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
1972 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
1976 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
1978 /* Fixup an incomplete irq table */
1979 GString
*string
= g_string_new("");
1980 g_string_printf(string
, "irq %llu", irq
);
1981 submode
= g_quark_from_string(string
->str
);
1982 g_string_free(string
, TRUE
);
1985 /* Do something with the info about being in user or system mode when int? */
1986 push_state(s
, LTTV_STATE_IRQ
, submode
);
1990 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1992 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1994 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2000 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2002 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2004 pop_state(s
, LTTV_STATE_IRQ
);
2008 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2010 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2011 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2012 guint8 fac_id
= ltt_event_facility_id(e
);
2013 guint8 ev_id
= ltt_event_eventtype_id(e
);
2014 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2015 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2016 g_assert(thf
->f1
!= NULL
);
2017 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2018 LttField
*f
= thf
->f1
;
2020 LttvExecutionSubmode submode
;
2021 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2022 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2025 if(softirq
< nb_softirqs
) {
2026 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2028 /* Fixup an incomplete irq table */
2029 GString
*string
= g_string_new("");
2030 g_string_printf(string
, "softirq %llu", softirq
);
2031 submode
= g_quark_from_string(string
->str
);
2032 g_string_free(string
, TRUE
);
2035 /* Do something with the info about being in user or system mode when int? */
2036 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2040 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2044 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2045 guint cpu
= tfs
->cpu
;
2046 LttvProcessState
*process
= ts
->running_process
[cpu
];
2048 guint depth
= process
->user_stack
->len
;
2050 process
->user_stack
=
2051 g_array_set_size(process
->user_stack
, depth
+ 1);
2053 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2054 *new_func
= funcptr
;
2055 process
->current_function
= funcptr
;
2058 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2060 guint cpu
= tfs
->cpu
;
2061 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2062 LttvProcessState
*process
= ts
->running_process
[cpu
];
2064 if(process
->current_function
!= funcptr
){
2065 g_info("Different functions (%lu.%09lu): ignore it\n",
2066 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2067 g_info("process state has %llu when pop_function is %llu\n",
2068 process
->current_function
, funcptr
);
2069 g_info("{ %u, %u, %s, %s, %s }\n",
2072 g_quark_to_string(process
->name
),
2073 g_quark_to_string(process
->brand
),
2074 g_quark_to_string(process
->state
->s
));
2077 guint depth
= process
->user_stack
->len
;
2080 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2081 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2085 process
->user_stack
=
2086 g_array_set_size(process
->user_stack
, depth
- 1);
2087 process
->current_function
=
2088 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2092 static gboolean
function_entry(void *hook_data
, void *call_data
)
2094 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2095 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2096 guint8 fac_id
= ltt_event_facility_id(e
);
2097 guint8 ev_id
= ltt_event_eventtype_id(e
);
2098 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2099 g_assert(thf
->f1
!= NULL
);
2100 LttField
*f
= thf
->f1
;
2101 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2103 push_function(s
, funcptr
);
2107 static gboolean
function_exit(void *hook_data
, void *call_data
)
2109 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2110 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2111 guint8 fac_id
= ltt_event_facility_id(e
);
2112 guint8 ev_id
= ltt_event_eventtype_id(e
);
2113 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2114 g_assert(thf
->f1
!= NULL
);
2115 LttField
*f
= thf
->f1
;
2116 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2118 LttvExecutionSubmode submode
;
2120 pop_function(s
, funcptr
);
2124 static gboolean
schedchange(void *hook_data
, void *call_data
)
2126 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2128 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2129 LttvProcessState
*process
= ts
->running_process
[cpu
];
2130 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2132 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2133 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2134 guint pid_in
, pid_out
;
2137 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2138 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2139 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2141 if(likely(process
!= NULL
)) {
2143 /* We could not know but it was not the idle process executing.
2144 This should only happen at the beginning, before the first schedule
2145 event, and when the initial information (current process for each CPU)
2146 is missing. It is not obvious how we could, after the fact, compensate
2147 the wrongly attributed statistics. */
2149 //This test only makes sense once the state is known and if there is no
2150 //missing events. We need to silently ignore schedchange coming after a
2151 //process_free, or it causes glitches. (FIXME)
2152 //if(unlikely(process->pid != pid_out)) {
2153 // g_assert(process->pid == 0);
2155 if(process
->pid
== 0
2156 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2158 /* Scheduling out of pid 0 at beginning of the trace :
2159 * we know for sure it is in syscall mode at this point. */
2160 g_assert(process
->execution_stack
->len
== 1);
2161 process
->state
->t
= LTTV_STATE_SYSCALL
;
2162 process
->state
->s
= LTTV_STATE_WAIT
;
2163 process
->state
->change
= s
->parent
.timestamp
;
2164 process
->state
->entry
= s
->parent
.timestamp
;
2167 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2168 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2169 process
->state
->change
= s
->parent
.timestamp
;
2171 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2172 else process
->state
->s
= LTTV_STATE_WAIT
;
2173 process
->state
->change
= s
->parent
.timestamp
;
2176 if(state_out
== 32 || state_out
== 128)
2177 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2178 /* see sched.h for states */
2181 process
= ts
->running_process
[cpu
] =
2182 lttv_state_find_process_or_create(
2183 (LttvTraceState
*)s
->parent
.t_context
,
2185 &s
->parent
.timestamp
);
2186 process
->state
->s
= LTTV_STATE_RUN
;
2188 if(process
->usertrace
)
2189 process
->usertrace
->cpu
= cpu
;
2190 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2191 process
->state
->change
= s
->parent
.timestamp
;
2193 /* update cpu status */
2195 s
->cpu_state
->present_state
= LTTV_CPU_IDLE
;
2197 s
->cpu_state
->present_state
= LTTV_CPU_BUSY
;
2202 static gboolean
process_fork(void *hook_data
, void *call_data
)
2204 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2205 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2206 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2208 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2209 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2210 LttvProcessState
*zombie_process
;
2212 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2213 LttvProcessState
*process
= ts
->running_process
[cpu
];
2214 LttvProcessState
*child_process
;
2217 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2220 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2221 s
->parent
.target_pid
= child_pid
;
2224 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2225 else child_tgid
= 0;
2227 /* Mathieu : it seems like the process might have been scheduled in before the
2228 * fork, and, in a rare case, might be the current process. This might happen
2229 * in a SMP case where we don't have enough precision on the clocks.
2231 * Test reenabled after precision fixes on time. (Mathieu) */
2233 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2235 if(unlikely(zombie_process
!= NULL
)) {
2236 /* Reutilisation of PID. Only now we are sure that the old PID
2237 * has been released. FIXME : should know when release_task happens instead.
2239 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2241 for(i
=0; i
< num_cpus
; i
++) {
2242 g_assert(zombie_process
!= ts
->running_process
[i
]);
2245 exit_process(s
, zombie_process
);
2248 g_assert(process
->pid
!= child_pid
);
2249 // FIXME : Add this test in the "known state" section
2250 // g_assert(process->pid == parent_pid);
2251 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2252 if(child_process
== NULL
) {
2253 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2254 child_pid
, child_tgid
,
2255 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2257 /* The process has already been created : due to time imprecision between
2258 * multiple CPUs : it has been scheduled in before creation. Note that we
2259 * shouldn't have this kind of imprecision.
2261 * Simply put a correct parent.
2263 g_assert(0); /* This is a problematic case : the process has been created
2264 before the fork event */
2265 child_process
->ppid
= process
->pid
;
2266 child_process
->tgid
= child_tgid
;
2268 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2269 child_process
->name
= process
->name
;
2270 child_process
->brand
= process
->brand
;
2275 /* We stamp a newly created process as kernel_thread.
2276 * The thread should not be running yet. */
2277 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2279 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2280 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2281 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2284 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2285 LttvProcessState
*process
;
2286 LttvExecutionState
*es
;
2289 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2290 s
->parent
.target_pid
= pid
;
2292 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2294 process
->execution_stack
=
2295 g_array_set_size(process
->execution_stack
, 1);
2296 es
= process
->state
=
2297 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2298 es
->t
= LTTV_STATE_SYSCALL
;
2299 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2304 static gboolean
process_exit(void *hook_data
, void *call_data
)
2306 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2307 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2308 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2312 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2313 LttvProcessState
*process
; // = ts->running_process[cpu];
2315 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2316 s
->parent
.target_pid
= pid
;
2318 // FIXME : Add this test in the "known state" section
2319 // g_assert(process->pid == pid);
2321 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2322 if(likely(process
!= NULL
)) {
2323 process
->state
->s
= LTTV_STATE_EXIT
;
2328 static gboolean
process_free(void *hook_data
, void *call_data
)
2330 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2331 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2332 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2333 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2335 LttvProcessState
*process
;
2337 /* PID of the process to release */
2338 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2339 s
->parent
.target_pid
= release_pid
;
2341 g_assert(release_pid
!= 0);
2343 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2345 if(likely(process
!= NULL
)) {
2346 /* release_task is happening at kernel level : we can now safely release
2347 * the data structure of the process */
2348 //This test is fun, though, as it may happen that
2349 //at time t : CPU 0 : process_free
2350 //at time t+150ns : CPU 1 : schedule out
2351 //Clearly due to time imprecision, we disable it. (Mathieu)
2352 //If this weird case happen, we have no choice but to put the
2353 //Currently running process on the cpu to 0.
2354 //I re-enable it following time precision fixes. (Mathieu)
2355 //Well, in the case where an process is freed by a process on another CPU
2356 //and still scheduled, it happens that this is the schedchange that will
2357 //drop the last reference count. Do not free it here!
2358 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2360 for(i
=0; i
< num_cpus
; i
++) {
2361 //g_assert(process != ts->running_process[i]);
2362 if(process
== ts
->running_process
[i
]) {
2363 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2367 if(i
== num_cpus
) /* process is not scheduled */
2368 exit_process(s
, process
);
2375 static gboolean
process_exec(void *hook_data
, void *call_data
)
2377 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2378 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2379 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2380 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2383 LttvProcessState
*process
= ts
->running_process
[cpu
];
2385 #if 0//how to use a sequence that must be transformed in a string
2386 /* PID of the process to release */
2387 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2388 //name = ltt_event_get_string(e, thf->f1);
2389 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2391 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2392 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2393 memcpy(null_term_name
, name_begin
, name_len
);
2394 null_term_name
[name_len
] = '\0';
2395 process
->name
= g_quark_from_string(null_term_name
);
2398 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2399 process
->brand
= LTTV_STATE_UNBRANDED
;
2400 //g_free(null_term_name);
2404 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2406 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2407 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2408 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2409 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2412 LttvProcessState
*process
= ts
->running_process
[cpu
];
2414 name
= ltt_event_get_string(e
, thf
->f1
);
2415 process
->brand
= g_quark_from_string(name
);
2420 static void fix_process(gpointer key
, gpointer value
,
2423 LttvProcessState
*process
;
2424 LttvExecutionState
*es
;
2425 process
= (LttvProcessState
*)value
;
2426 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2427 LttTime
*timestamp
= (LttTime
*)user_data
;
2429 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2430 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2431 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2432 es
->t
= LTTV_STATE_SYSCALL
;
2433 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2434 es
->entry
= *timestamp
;
2435 es
->change
= *timestamp
;
2436 es
->cum_cpu_time
= ltt_time_zero
;
2437 if(es
->s
== LTTV_STATE_UNNAMED
)
2438 es
->s
= LTTV_STATE_WAIT
;
2441 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2442 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2443 es
->t
= LTTV_STATE_USER_MODE
;
2444 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2445 es
->entry
= *timestamp
;
2446 //g_assert(timestamp->tv_sec != 0);
2447 es
->change
= *timestamp
;
2448 es
->cum_cpu_time
= ltt_time_zero
;
2449 if(es
->s
== LTTV_STATE_UNNAMED
)
2450 es
->s
= LTTV_STATE_RUN
;
2452 if(process
->execution_stack
->len
== 1) {
2453 /* Still in bottom unknown mode, means never did a system call
2454 * May be either in user mode, syscall mode, running or waiting.*/
2455 /* FIXME : we may be tagging syscall mode when being user mode */
2456 process
->execution_stack
=
2457 g_array_set_size(process
->execution_stack
, 2);
2458 es
= process
->state
= &g_array_index(process
->execution_stack
,
2459 LttvExecutionState
, 1);
2460 es
->t
= LTTV_STATE_SYSCALL
;
2461 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2462 es
->entry
= *timestamp
;
2463 //g_assert(timestamp->tv_sec != 0);
2464 es
->change
= *timestamp
;
2465 es
->cum_cpu_time
= ltt_time_zero
;
2466 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2467 es
->s
= LTTV_STATE_WAIT
;
2473 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2475 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2476 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2477 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2478 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2479 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2481 /* For all processes */
2482 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2483 /* else, if stack[0] is unknown, set to user mode, running */
2485 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2488 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2490 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2491 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2492 //It's slow : optimise later by doing this before reading trace.
2493 LttEventType
*et
= ltt_event_eventtype(e
);
2495 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2501 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2502 LttvProcessState
*process
= ts
->running_process
[cpu
];
2503 LttvProcessState
*parent_process
;
2504 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2505 GQuark type
, mode
, submode
, status
;
2506 LttvExecutionState
*es
;
2510 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2511 s
->parent
.target_pid
= pid
;
2514 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2517 command
= ltt_event_get_string(e
, thf
->f3
);
2520 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2521 type
= ltt_enum_string_get(ltt_field_type(f4
),
2522 ltt_event_get_unsigned(e
, f4
));
2525 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2526 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2527 ltt_event_get_unsigned(e
, f5
));
2530 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2531 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2532 ltt_event_get_unsigned(e
, f6
));
2535 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2536 status
= ltt_enum_string_get(ltt_field_type(f7
),
2537 ltt_event_get_unsigned(e
, f7
));
2540 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2541 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2546 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2547 for(i
=0; i
<nb_cpus
; i
++) {
2548 process
= lttv_state_find_process(ts
, i
, pid
);
2549 g_assert(process
!= NULL
);
2551 process
->ppid
= parent_pid
;
2552 process
->tgid
= tgid
;
2553 process
->name
= g_quark_from_string(command
);
2555 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2556 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2560 /* The process might exist if a process was forked while performing the
2562 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2563 if(process
== NULL
) {
2564 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2565 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2566 pid
, tgid
, g_quark_from_string(command
),
2567 &s
->parent
.timestamp
);
2569 /* Keep the stack bottom : a running user mode */
2570 /* Disabled because of inconsistencies in the current statedump states. */
2571 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2572 /* Only keep the bottom
2573 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2574 /* Will cause expected trap when in fact being syscall (even after end of
2576 * Will cause expected interrupt when being syscall. (only before end of
2577 * statedump event) */
2578 // This will cause a "popping last state on stack, ignoring it."
2579 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2580 es
= process
->state
= &g_array_index(process
->execution_stack
,
2581 LttvExecutionState
, 0);
2582 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2583 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2584 es
->s
= LTTV_STATE_UNNAMED
;
2585 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2587 es
->t
= LTTV_STATE_SYSCALL
;
2592 /* User space process :
2593 * bottom : user mode
2594 * either currently running or scheduled out.
2595 * can be scheduled out because interrupted in (user mode or in syscall)
2596 * or because of an explicit call to the scheduler in syscall. Note that
2597 * the scheduler call comes after the irq_exit, so never in interrupt
2599 // temp workaround : set size to 1 : only have user mode bottom of stack.
2600 // will cause g_info message of expected syscall mode when in fact being
2601 // in user mode. Can also cause expected trap when in fact being user
2602 // mode in the event of a page fault reenabling interrupts in the handler.
2603 // Expected syscall and trap can also happen after the end of statedump
2604 // This will cause a "popping last state on stack, ignoring it."
2605 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2606 es
= process
->state
= &g_array_index(process
->execution_stack
,
2607 LttvExecutionState
, 0);
2608 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2609 es
->s
= LTTV_STATE_UNNAMED
;
2610 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2612 es
->t
= LTTV_STATE_USER_MODE
;
2620 es
= process
->state
= &g_array_index(process
->execution_stack
,
2621 LttvExecutionState
, 1);
2622 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2623 es
->s
= LTTV_STATE_UNNAMED
;
2624 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2628 /* The process has already been created :
2629 * Probably was forked while dumping the process state or
2630 * was simply scheduled in prior to get the state dump event.
2632 process
->ppid
= parent_pid
;
2633 process
->tgid
= tgid
;
2634 process
->name
= g_quark_from_string(command
);
2635 process
->type
= type
;
2637 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2639 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2640 if(type
== LTTV_STATE_KERNEL_THREAD
)
2641 es
->t
= LTTV_STATE_SYSCALL
;
2643 es
->t
= LTTV_STATE_USER_MODE
;
2646 /* Don't mess around with the stack, it will eventually become
2647 * ok after the end of state dump. */
2654 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2656 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2658 lttv_state_add_event_hooks(tss
);
2663 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2665 LttvTraceset
*traceset
= self
->parent
.ts
;
2667 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2671 LttvTracefileState
*tfs
;
2675 LttvTraceHookByFacility
*thf
;
2677 LttvTraceHook
*hook
;
2679 LttvAttributeValue val
;
2684 nb_trace
= lttv_traceset_number(traceset
);
2685 for(i
= 0 ; i
< nb_trace
; i
++) {
2686 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2688 /* Find the eventtype id for the following events and register the
2689 associated by id hooks. */
2691 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2692 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2695 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2696 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2697 LTT_FIELD_SYSCALL_ID
, 0, 0,
2698 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2701 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2702 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2704 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2707 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2708 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2709 LTT_FIELD_TRAP_ID
, 0, 0,
2710 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2713 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2714 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2716 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2719 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2720 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2721 LTT_FIELD_IRQ_ID
, 0, 0,
2722 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2725 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2726 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2728 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2731 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2732 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2733 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2734 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2737 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2738 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2740 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2743 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2744 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2745 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2746 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2749 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2750 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2751 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2752 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2755 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2756 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2757 LTT_FIELD_PID
, 0, 0,
2758 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2762 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2763 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2764 LTT_FIELD_PID
, 0, 0,
2765 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2768 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2769 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
2770 LTT_FIELD_PID
, 0, 0,
2771 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2774 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2775 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2776 LTT_FIELD_FILENAME
, 0, 0,
2777 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2780 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2781 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2782 LTT_FIELD_NAME
, 0, 0,
2783 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2786 /* statedump-related hooks */
2787 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2788 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
2789 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2790 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2793 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2794 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
2796 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2799 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2800 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2801 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2802 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2805 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2806 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2807 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2808 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2811 hooks
= g_array_set_size(hooks
, hn
);
2813 /* Add these hooks to each event_by_id hooks list */
2815 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2817 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2819 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2820 LttvTracefileContext
*, j
));
2822 for(k
= 0 ; k
< hooks
->len
; k
++) {
2823 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2824 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2825 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2827 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2834 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2835 *(val
.v_pointer
) = hooks
;
2839 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2841 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2843 lttv_state_remove_event_hooks(tss
);
2848 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2850 LttvTraceset
*traceset
= self
->parent
.ts
;
2852 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2856 LttvTracefileState
*tfs
;
2860 LttvTraceHook
*hook
;
2862 LttvTraceHookByFacility
*thf
;
2864 LttvAttributeValue val
;
2866 nb_trace
= lttv_traceset_number(traceset
);
2867 for(i
= 0 ; i
< nb_trace
; i
++) {
2868 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2870 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2871 hooks
= *(val
.v_pointer
);
2873 /* Remove these hooks from each event_by_id hooks list */
2875 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2877 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2879 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2880 LttvTracefileContext
*, j
));
2882 for(k
= 0 ; k
< hooks
->len
; k
++) {
2883 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2884 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2885 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2887 lttv_hooks_remove_data(
2888 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2894 for(k
= 0 ; k
< hooks
->len
; k
++)
2895 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2896 g_array_free(hooks
, TRUE
);
2900 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2902 guint
*event_count
= (guint
*)hook_data
;
2904 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2905 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2910 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2912 LttvTracefileState
*tfcs
;
2914 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2916 LttEventPosition
*ep
;
2922 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2924 LttvAttributeValue value
;
2926 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2927 LTTV_STATE_SAVED_STATES
);
2928 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2929 value
= lttv_attribute_add(saved_states_tree
,
2930 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2931 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2932 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2933 *(value
.v_time
) = self
->parent
.timestamp
;
2934 lttv_state_save(tcs
, saved_state_tree
);
2935 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2936 self
->parent
.timestamp
.tv_nsec
);
2938 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2943 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2945 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2947 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2952 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2960 static gboolean
block_start(void *hook_data
, void *call_data
)
2962 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2964 LttvTracefileState
*tfcs
;
2966 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2968 LttEventPosition
*ep
;
2970 guint i
, nb_block
, nb_event
, nb_tracefile
;
2974 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2976 LttvAttributeValue value
;
2978 ep
= ltt_event_position_new();
2980 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2982 /* Count the number of events added since the last block end in any
2985 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2987 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2988 LttvTracefileContext
, i
));
2989 ltt_event_position(tfcs
->parent
.e
, ep
);
2990 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2991 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2992 tfcs
->saved_position
= nb_event
;
2996 if(tcs
->nb_event
>= tcs
->save_interval
) {
2997 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2998 LTTV_STATE_SAVED_STATES
);
2999 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3000 value
= lttv_attribute_add(saved_states_tree
,
3001 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3002 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3003 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3004 *(value
.v_time
) = self
->parent
.timestamp
;
3005 lttv_state_save(tcs
, saved_state_tree
);
3007 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3008 self
->parent
.timestamp
.tv_nsec
);
3010 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3016 static gboolean
block_end(void *hook_data
, void *call_data
)
3018 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3020 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3024 LttEventPosition
*ep
;
3026 guint nb_block
, nb_event
;
3028 ep
= ltt_event_position_new();
3029 ltt_event_position(self
->parent
.e
, ep
);
3030 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3031 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3032 self
->saved_position
= 0;
3033 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3040 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3042 LttvTraceset
*traceset
= self
->parent
.ts
;
3044 guint i
, j
, nb_trace
, nb_tracefile
;
3048 LttvTracefileState
*tfs
;
3050 LttvTraceHook hook_start
, hook_end
;
3052 nb_trace
= lttv_traceset_number(traceset
);
3053 for(i
= 0 ; i
< nb_trace
; i
++) {
3054 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3056 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3057 NULL
, NULL
, block_start
, &hook_start
);
3058 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3059 NULL
, NULL
, block_end
, &hook_end
);
3061 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3063 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3065 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3066 LttvTracefileContext
, j
));
3067 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3068 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3069 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3070 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3076 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3078 LttvTraceset
*traceset
= self
->parent
.ts
;
3080 guint i
, j
, nb_trace
, nb_tracefile
;
3084 LttvTracefileState
*tfs
;
3087 nb_trace
= lttv_traceset_number(traceset
);
3088 for(i
= 0 ; i
< nb_trace
; i
++) {
3090 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3091 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3093 if(ts
->has_precomputed_states
) continue;
3095 guint
*event_count
= g_new(guint
, 1);
3098 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3100 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3101 LttvTracefileContext
*, j
));
3102 lttv_hooks_add(tfs
->parent
.event
,
3103 state_save_event_hook
,
3110 lttv_process_traceset_begin(&self
->parent
,
3111 NULL
, NULL
, NULL
, NULL
, NULL
);
3115 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3117 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3119 lttv_state_save_add_event_hooks(tss
);
3126 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3128 LttvTraceset
*traceset
= self
->parent
.ts
;
3130 guint i
, j
, nb_trace
, nb_tracefile
;
3134 LttvTracefileState
*tfs
;
3136 LttvTraceHook hook_start
, hook_end
;
3138 nb_trace
= lttv_traceset_number(traceset
);
3139 for(i
= 0 ; i
< nb_trace
; i
++) {
3140 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3142 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3143 NULL
, NULL
, block_start
, &hook_start
);
3145 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3146 NULL
, NULL
, block_end
, &hook_end
);
3148 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3150 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3152 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3153 LttvTracefileContext
, j
));
3154 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3155 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3156 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3157 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3163 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3165 LttvTraceset
*traceset
= self
->parent
.ts
;
3167 guint i
, j
, nb_trace
, nb_tracefile
;
3171 LttvTracefileState
*tfs
;
3173 LttvHooks
*after_trace
= lttv_hooks_new();
3175 lttv_hooks_add(after_trace
,
3176 state_save_after_trace_hook
,
3181 lttv_process_traceset_end(&self
->parent
,
3182 NULL
, after_trace
, NULL
, NULL
, NULL
);
3184 lttv_hooks_destroy(after_trace
);
3186 nb_trace
= lttv_traceset_number(traceset
);
3187 for(i
= 0 ; i
< nb_trace
; i
++) {
3189 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3190 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3192 if(ts
->has_precomputed_states
) continue;
3194 guint
*event_count
= NULL
;
3196 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3198 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3199 LttvTracefileContext
*, j
));
3200 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3201 state_save_event_hook
);
3203 if(event_count
) g_free(event_count
);
3207 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3209 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3211 lttv_state_save_remove_event_hooks(tss
);
3216 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3218 LttvTraceset
*traceset
= self
->parent
.ts
;
3222 int min_pos
, mid_pos
, max_pos
;
3224 guint call_rest
= 0;
3226 LttvTraceState
*tcs
;
3228 LttvAttributeValue value
;
3230 LttvAttributeType type
;
3232 LttvAttributeName name
;
3236 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3238 //g_tree_destroy(self->parent.pqueue);
3239 //self->parent.pqueue = g_tree_new(compare_tracefile);
3241 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3243 nb_trace
= lttv_traceset_number(traceset
);
3244 for(i
= 0 ; i
< nb_trace
; i
++) {
3245 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3247 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3248 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3249 LTTV_STATE_SAVED_STATES
);
3252 if(saved_states_tree
) {
3253 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3254 mid_pos
= max_pos
/ 2;
3255 while(min_pos
< max_pos
) {
3256 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3258 g_assert(type
== LTTV_GOBJECT
);
3259 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3260 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3262 g_assert(type
== LTTV_TIME
);
3263 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3265 closest_tree
= saved_state_tree
;
3267 else max_pos
= mid_pos
- 1;
3269 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3273 /* restore the closest earlier saved state */
3275 lttv_state_restore(tcs
, closest_tree
);
3279 /* There is no saved state, yet we want to have it. Restart at T0 */
3281 restore_init_state(tcs
);
3282 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3285 /* We want to seek quickly without restoring/updating the state */
3287 restore_init_state(tcs
);
3288 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3291 if(!call_rest
) g_info("NOT Calling restore");
3296 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3302 traceset_state_finalize (LttvTracesetState
*self
)
3304 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3305 finalize(G_OBJECT(self
));
3310 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3312 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3314 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3315 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3316 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3317 klass
->new_traceset_context
= new_traceset_context
;
3318 klass
->new_trace_context
= new_trace_context
;
3319 klass
->new_tracefile_context
= new_tracefile_context
;
3324 lttv_traceset_state_get_type(void)
3326 static GType type
= 0;
3328 static const GTypeInfo info
= {
3329 sizeof (LttvTracesetStateClass
),
3330 NULL
, /* base_init */
3331 NULL
, /* base_finalize */
3332 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3333 NULL
, /* class_finalize */
3334 NULL
, /* class_data */
3335 sizeof (LttvTracesetState
),
3336 0, /* n_preallocs */
3337 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3338 NULL
/* value handling */
3341 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3349 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3355 trace_state_finalize (LttvTraceState
*self
)
3357 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3358 finalize(G_OBJECT(self
));
3363 trace_state_class_init (LttvTraceStateClass
*klass
)
3365 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3367 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3368 klass
->state_save
= state_save
;
3369 klass
->state_restore
= state_restore
;
3370 klass
->state_saved_free
= state_saved_free
;
3375 lttv_trace_state_get_type(void)
3377 static GType type
= 0;
3379 static const GTypeInfo info
= {
3380 sizeof (LttvTraceStateClass
),
3381 NULL
, /* base_init */
3382 NULL
, /* base_finalize */
3383 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3384 NULL
, /* class_finalize */
3385 NULL
, /* class_data */
3386 sizeof (LttvTraceState
),
3387 0, /* n_preallocs */
3388 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3389 NULL
/* value handling */
3392 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3393 "LttvTraceStateType", &info
, 0);
3400 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3406 tracefile_state_finalize (LttvTracefileState
*self
)
3408 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3409 finalize(G_OBJECT(self
));
3414 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3416 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3418 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3423 lttv_tracefile_state_get_type(void)
3425 static GType type
= 0;
3427 static const GTypeInfo info
= {
3428 sizeof (LttvTracefileStateClass
),
3429 NULL
, /* base_init */
3430 NULL
, /* base_finalize */
3431 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3432 NULL
, /* class_finalize */
3433 NULL
, /* class_data */
3434 sizeof (LttvTracefileState
),
3435 0, /* n_preallocs */
3436 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3437 NULL
/* value handling */
3440 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3441 "LttvTracefileStateType", &info
, 0);
3447 static void module_init()
3449 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3450 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3451 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3452 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3453 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3454 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3455 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3456 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3457 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3458 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3459 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3460 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3461 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3462 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3463 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3464 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3465 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3466 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3467 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3468 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3469 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3470 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3471 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3472 LTTV_STATE_EVENT
= g_quark_from_string("event");
3473 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3474 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3475 LTTV_STATE_TIME
= g_quark_from_string("time");
3476 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3477 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3478 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3479 g_quark_from_string("trace_state_use_count");
3482 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3483 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3484 LTT_FACILITY_FS
= g_quark_from_string("fs");
3485 LTT_FACILITY_LIST
= g_quark_from_string("list");
3486 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3489 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3490 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3491 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3492 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3493 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3494 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3495 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3496 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3497 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3498 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3499 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3500 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3501 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3502 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3503 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3504 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3505 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3506 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3507 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3510 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3511 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3512 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3513 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3514 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3515 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3516 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3517 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3518 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3519 LTT_FIELD_PID
= g_quark_from_string("pid");
3520 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3521 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3522 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3523 LTT_FIELD_NAME
= g_quark_from_string("name");
3524 LTT_FIELD_TYPE
= g_quark_from_string("type");
3525 LTT_FIELD_MODE
= g_quark_from_string("mode");
3526 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3527 LTT_FIELD_STATUS
= g_quark_from_string("status");
3528 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3529 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3531 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3532 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3533 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3536 static void module_destroy()
3541 LTTV_MODULE("state", "State computation", \
3542 "Update the system state, possibly saving it at intervals", \
3543 module_init
, module_destroy
)