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
;
138 LTTV_STATE_TRACEFILES
,
139 LTTV_STATE_PROCESSES
,
141 LTTV_STATE_RUNNING_PROCESS
,
143 LTTV_STATE_SAVED_STATES
,
144 LTTV_STATE_SAVED_STATES_TIME
,
147 LTTV_STATE_NAME_TABLES
,
148 LTTV_STATE_TRACE_STATE_USE_COUNT
;
150 static void create_max_time(LttvTraceState
*tcs
);
152 static void get_max_time(LttvTraceState
*tcs
);
154 static void free_max_time(LttvTraceState
*tcs
);
156 static void create_name_tables(LttvTraceState
*tcs
);
158 static void get_name_tables(LttvTraceState
*tcs
);
160 static void free_name_tables(LttvTraceState
*tcs
);
162 static void free_saved_state(LttvTraceState
*tcs
);
164 static void lttv_state_free_process_table(GHashTable
*processes
);
166 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
167 GPtrArray
*quarktable
);
169 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
171 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
175 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
177 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
181 void lttv_state_state_saved_free(LttvTraceState
*self
,
182 LttvAttribute
*container
)
184 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
188 guint
process_hash(gconstpointer key
)
190 guint pid
= ((const LttvProcessState
*)key
)->pid
;
191 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
195 /* If the hash table hash function is well distributed,
196 * the process_equal should compare different pid */
197 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
199 const LttvProcessState
*process_a
, *process_b
;
202 process_a
= (const LttvProcessState
*)a
;
203 process_b
= (const LttvProcessState
*)b
;
205 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
206 else if(likely(process_a
->pid
== 0 &&
207 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
212 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
214 g_tree_destroy((GTree
*)value
);
217 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
219 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
220 g_hash_table_destroy(usertraces
);
226 restore_init_state(LttvTraceState
*self
)
230 LttvTracefileState
*tfcs
;
232 LttTime start_time
, end_time
;
234 /* Free the process tables */
235 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
236 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
237 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
238 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
241 /* Seek time to beginning */
242 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
243 // closest. It's the tracecontext job to seek the trace to the beginning
244 // anyway : the init state might be used at the middle of the trace as well...
245 //g_tree_destroy(self->parent.ts_context->pqueue);
246 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
248 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
250 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
252 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
254 /* Put the per cpu running_process to beginning state : process 0. */
255 for(i
=0; i
< nb_cpus
; i
++) {
256 LttvExecutionState
*es
;
257 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
258 LTTV_STATE_UNNAMED
, &start_time
);
259 /* We are not sure is it's a kernel thread or normal thread, put the
260 * bottom stack state to unknown */
261 self
->running_process
[i
]->execution_stack
=
262 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
263 es
= self
->running_process
[i
]->state
=
264 &g_array_index(self
->running_process
[i
]->execution_stack
,
265 LttvExecutionState
, 0);
266 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
267 es
->s
= LTTV_STATE_UNNAMED
;
269 //self->running_process[i]->state->s = LTTV_STATE_RUN;
270 self
->running_process
[i
]->cpu
= i
;
274 nb_tracefile
= self
->parent
.tracefiles
->len
;
276 for(i
= 0 ; i
< nb_tracefile
; i
++) {
278 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
279 LttvTracefileContext
*, i
));
280 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
281 // tfcs->saved_position = 0;
282 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
283 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
284 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
285 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
290 //static LttTime time_zero = {0,0};
292 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
295 const LttTime
*t1
= (const LttTime
*)a
;
296 const LttTime
*t2
= (const LttTime
*)b
;
298 return ltt_time_compare(*t1
, *t2
);
301 static void free_usertrace_key(gpointer data
)
306 #define MAX_STRING_LEN 4096
309 state_load_saved_states(LttvTraceState
*tcs
)
312 GPtrArray
*quarktable
;
317 tcs
->has_precomputed_states
= FALSE
;
321 gchar buf
[MAX_STRING_LEN
];
324 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
325 strncpy(path
, trace_path
, PATH_MAX
-1);
326 count
= strnlen(trace_path
, PATH_MAX
-1);
327 // quarktable : open, test
328 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
329 fp
= fopen(path
, "r");
331 quarktable
= g_ptr_array_sized_new(4096);
333 /* Index 0 is null */
335 if(hdr
== EOF
) return;
336 g_assert(hdr
== HDR_QUARKS
);
340 if(hdr
== EOF
) break;
341 g_assert(hdr
== HDR_QUARK
);
342 g_ptr_array_set_size(quarktable
, q
+1);
345 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
346 if(buf
[i
] == '\0' || feof(fp
)) break;
349 len
= strnlen(buf
, MAX_STRING_LEN
-1);
350 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
351 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
357 // saved_states : open, test
358 strncpy(path
, trace_path
, PATH_MAX
-1);
359 count
= strnlen(trace_path
, PATH_MAX
-1);
360 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
361 fp
= fopen(path
, "r");
365 if(hdr
!= HDR_TRACE
) goto end
;
367 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
369 tcs
->has_precomputed_states
= TRUE
;
374 /* Free the quarktable */
375 for(i
=0; i
<quarktable
->len
; i
++) {
376 string
= g_ptr_array_index (quarktable
, i
);
379 g_ptr_array_free(quarktable
, TRUE
);
384 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
386 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
388 LttvTraceContext
*tc
;
392 LttvTracefileState
*tfcs
;
394 LttvAttributeValue v
;
396 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
397 init((LttvTracesetContext
*)self
, ts
);
399 nb_trace
= lttv_traceset_number(ts
);
400 for(i
= 0 ; i
< nb_trace
; i
++) {
401 tc
= self
->parent
.traces
[i
];
402 tcs
= LTTV_TRACE_STATE(tc
);
403 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
404 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
408 if(*(v
.v_uint
) == 1) {
409 create_name_tables(tcs
);
410 create_max_time(tcs
);
412 get_name_tables(tcs
);
415 nb_tracefile
= tc
->tracefiles
->len
;
416 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
417 tcs
->processes
= NULL
;
418 tcs
->usertraces
= NULL
;
419 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
420 /* init cpu resource stuff */
421 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
422 for(j
= 0; j
<nb_cpu
; j
++) {
423 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
424 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
427 restore_init_state(tcs
);
428 for(j
= 0 ; j
< nb_tracefile
; j
++) {
430 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
431 LttvTracefileContext
*, j
));
432 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
433 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
434 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
435 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
436 /* It's a Usertrace */
437 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
438 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
440 if(!usertrace_tree
) {
441 usertrace_tree
= g_tree_new_full(compare_usertraces
,
442 NULL
, free_usertrace_key
, NULL
);
443 g_hash_table_insert(tcs
->usertraces
,
444 (gpointer
)tid
, usertrace_tree
);
446 LttTime
*timestamp
= g_new(LttTime
, 1);
447 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
448 ltt_tracefile_creation(tfcs
->parent
.tf
));
449 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
453 /* See if the trace has saved states */
454 state_load_saved_states(tcs
);
459 fini(LttvTracesetState
*self
)
465 LttvTracefileState
*tfcs
;
467 LttvAttributeValue v
;
469 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
470 for(i
= 0 ; i
< nb_trace
; i
++) {
471 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
472 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
475 g_assert(*(v
.v_uint
) != 0);
478 if(*(v
.v_uint
) == 0) {
479 free_name_tables(tcs
);
481 free_saved_state(tcs
);
483 g_free(tcs
->running_process
);
484 tcs
->running_process
= NULL
;
485 lttv_state_free_process_table(tcs
->processes
);
486 lttv_state_free_usertraces(tcs
->usertraces
);
487 tcs
->processes
= NULL
;
488 tcs
->usertraces
= NULL
;
490 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
491 fini((LttvTracesetContext
*)self
);
495 static LttvTracesetContext
*
496 new_traceset_context(LttvTracesetContext
*self
)
498 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
502 static LttvTraceContext
*
503 new_trace_context(LttvTracesetContext
*self
)
505 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
509 static LttvTracefileContext
*
510 new_tracefile_context(LttvTracesetContext
*self
)
512 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
516 /* Write the process state of the trace */
518 static void write_process_state(gpointer key
, gpointer value
,
521 LttvProcessState
*process
;
523 LttvExecutionState
*es
;
525 FILE *fp
= (FILE *)user_data
;
530 process
= (LttvProcessState
*)value
;
532 " <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",
533 process
, process
->pid
, process
->tgid
, process
->ppid
,
534 g_quark_to_string(process
->type
),
535 process
->creation_time
.tv_sec
,
536 process
->creation_time
.tv_nsec
,
537 process
->insertion_time
.tv_sec
,
538 process
->insertion_time
.tv_nsec
,
539 g_quark_to_string(process
->name
),
540 g_quark_to_string(process
->brand
),
543 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
544 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
545 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
546 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
547 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
548 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
549 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
552 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
553 address
= &g_array_index(process
->user_stack
, guint64
, i
);
554 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
558 if(process
->usertrace
) {
559 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
560 g_quark_to_string(process
->usertrace
->tracefile_name
),
561 process
->usertrace
->cpu
);
565 fprintf(fp
, " </PROCESS>\n");
569 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
571 guint i
, nb_tracefile
, nb_block
, offset
;
574 LttvTracefileState
*tfcs
;
578 LttEventPosition
*ep
;
582 ep
= ltt_event_position_new();
584 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
586 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
588 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
589 for(i
=0;i
<nb_cpus
;i
++) {
590 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
591 i
, self
->running_process
[i
]->pid
);
594 nb_tracefile
= self
->parent
.tracefiles
->len
;
596 for(i
= 0 ; i
< nb_tracefile
; i
++) {
598 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
599 LttvTracefileContext
*, i
));
600 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
601 tfcs
->parent
.timestamp
.tv_sec
,
602 tfcs
->parent
.timestamp
.tv_nsec
);
603 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
604 if(e
== NULL
) fprintf(fp
,"/>\n");
606 ltt_event_position(e
, ep
);
607 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
608 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
613 fprintf(fp
,"</PROCESS_STATE>\n");
617 static void write_process_state_raw(gpointer key
, gpointer value
,
620 LttvProcessState
*process
;
622 LttvExecutionState
*es
;
624 FILE *fp
= (FILE *)user_data
;
629 process
= (LttvProcessState
*)value
;
630 fputc(HDR_PROCESS
, fp
);
631 //fwrite(&header, sizeof(header), 1, fp);
632 //fprintf(fp, "%s", g_quark_to_string(process->type));
634 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
635 //fprintf(fp, "%s", g_quark_to_string(process->name));
637 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
638 //fprintf(fp, "%s", g_quark_to_string(process->brand));
640 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
641 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
642 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
643 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
644 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
645 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
646 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
650 " <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",
651 process
, process
->pid
, process
->tgid
, process
->ppid
,
652 g_quark_to_string(process
->type
),
653 process
->creation_time
.tv_sec
,
654 process
->creation_time
.tv_nsec
,
655 process
->insertion_time
.tv_sec
,
656 process
->insertion_time
.tv_nsec
,
657 g_quark_to_string(process
->name
),
658 g_quark_to_string(process
->brand
),
662 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
663 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
666 //fprintf(fp, "%s", g_quark_to_string(es->t));
668 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
669 //fprintf(fp, "%s", g_quark_to_string(es->n));
671 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
672 //fprintf(fp, "%s", g_quark_to_string(es->s));
674 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
675 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
676 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
677 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
679 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
680 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
681 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
682 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
683 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
687 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
688 address
= &g_array_index(process
->user_stack
, guint64
, i
);
689 fputc(HDR_USER_STACK
, fp
);
690 fwrite(&address
, sizeof(address
), 1, fp
);
692 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
697 if(process
->usertrace
) {
698 fputc(HDR_USERTRACE
, fp
);
699 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
701 fwrite(&process
->usertrace
->tracefile_name
,
702 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
703 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
705 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
706 g_quark_to_string(process
->usertrace
->tracefile_name
),
707 process
->usertrace
->cpu
);
714 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
716 guint i
, nb_tracefile
, nb_block
, offset
;
719 LttvTracefileState
*tfcs
;
723 LttEventPosition
*ep
;
727 ep
= ltt_event_position_new();
729 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
730 fputc(HDR_PROCESS_STATE
, fp
);
731 fwrite(&t
, sizeof(t
), 1, fp
);
733 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
735 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
736 for(i
=0;i
<nb_cpus
;i
++) {
738 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
739 fwrite(&self
->running_process
[i
]->pid
,
740 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
741 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
742 // i, self->running_process[i]->pid);
745 nb_tracefile
= self
->parent
.tracefiles
->len
;
747 for(i
= 0 ; i
< nb_tracefile
; i
++) {
749 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
750 LttvTracefileContext
*, i
));
751 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
752 // tfcs->parent.timestamp.tv_sec,
753 // tfcs->parent.timestamp.tv_nsec);
754 fputc(HDR_TRACEFILE
, fp
);
755 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
756 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
757 * position following : end of trace */
758 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
760 ltt_event_position(e
, ep
);
761 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
762 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
764 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
765 fwrite(&offset
, sizeof(offset
), 1, fp
);
766 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
773 /* Read process state from a file */
775 /* Called because a HDR_PROCESS was found */
776 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
777 GPtrArray
*quarktable
)
779 LttvExecutionState
*es
;
780 LttvProcessState
*process
, *parent_process
;
781 LttvProcessState tmp
;
788 /* TODO : check return value */
789 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
790 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
791 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
792 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
793 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
794 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
795 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
796 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
797 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
800 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
802 /* We must link to the parent */
803 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
805 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
806 if(process
== NULL
) {
807 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
809 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
813 process
->insertion_time
= tmp
.insertion_time
;
814 process
->creation_time
= tmp
.creation_time
;
815 process
->type
= g_quark_from_string(
816 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
817 process
->tgid
= tmp
.tgid
;
818 process
->ppid
= tmp
.ppid
;
819 process
->brand
= g_quark_from_string(
820 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
822 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
826 if(feof(fp
) || ferror(fp
)) goto end_loop
;
828 gint hdr
= fgetc(fp
);
829 if(hdr
== EOF
) goto end_loop
;
833 process
->execution_stack
=
834 g_array_set_size(process
->execution_stack
,
835 process
->execution_stack
->len
+ 1);
836 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
837 process
->execution_stack
->len
-1);
840 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
841 es
->t
= g_quark_from_string(
842 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
843 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
844 es
->n
= g_quark_from_string(
845 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
846 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
847 es
->s
= g_quark_from_string(
848 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
849 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
850 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
851 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
854 process
->user_stack
= g_array_set_size(process
->user_stack
,
855 process
->user_stack
->len
+ 1);
856 address
= &g_array_index(process
->user_stack
, guint64
,
857 process
->user_stack
->len
-1);
858 fread(address
, sizeof(address
), 1, fp
);
859 process
->current_function
= *address
;
862 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
863 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
875 /* Called because a HDR_PROCESS_STATE was found */
876 /* Append a saved state to the trace states */
877 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
879 guint i
, nb_tracefile
, nb_block
, offset
;
881 LttvTracefileState
*tfcs
;
883 LttEventPosition
*ep
;
891 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
893 LttvAttributeValue value
;
894 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
895 ep
= ltt_event_position_new();
897 restore_init_state(self
);
899 fread(&t
, sizeof(t
), 1, fp
);
902 if(feof(fp
) || ferror(fp
)) goto end_loop
;
904 if(hdr
== EOF
) goto end_loop
;
908 /* Call read_process_state_raw */
909 read_process_state_raw(self
, fp
, quarktable
);
919 case HDR_PROCESS_STATE
:
925 g_error("Error while parsing saved state file : unknown data header %d",
931 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
932 for(i
=0;i
<nb_cpus
;i
++) {
935 g_assert(hdr
== HDR_CPU
);
936 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
937 g_assert(i
== cpu_num
);
938 fread(&self
->running_process
[i
]->pid
,
939 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
942 nb_tracefile
= self
->parent
.tracefiles
->len
;
944 for(i
= 0 ; i
< nb_tracefile
; i
++) {
946 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
947 LttvTracefileContext
*, i
));
948 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
949 // tfcs->parent.timestamp.tv_sec,
950 // tfcs->parent.timestamp.tv_nsec);
951 g_tree_remove(pqueue
, &tfcs
->parent
);
953 g_assert(hdr
== HDR_TRACEFILE
);
954 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
955 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
956 * position following : end of trace */
957 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
958 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
959 fread(&offset
, sizeof(offset
), 1, fp
);
960 fread(&tsc
, sizeof(tsc
), 1, fp
);
961 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
962 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
964 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
969 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
970 LTTV_STATE_SAVED_STATES
);
971 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
972 value
= lttv_attribute_add(saved_states_tree
,
973 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
974 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
975 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
977 lttv_state_save(self
, saved_state_tree
);
978 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
981 *(self
->max_time_state_recomputed_in_seek
) = t
;
985 /* Called when a HDR_TRACE is found */
986 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
987 GPtrArray
*quarktable
)
992 if(feof(fp
) || ferror(fp
)) goto end_loop
;
994 if(hdr
== EOF
) goto end_loop
;
997 case HDR_PROCESS_STATE
:
998 /* Call read_process_state_raw */
999 lttv_state_read_raw(tcs
, fp
, quarktable
);
1007 case HDR_USER_STACK
:
1011 g_error("Error while parsing saved state file :"
1012 " unexpected data header %d",
1016 g_error("Error while parsing saved state file : unknown data header %d",
1021 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1022 restore_init_state(tcs
);
1023 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1029 /* Copy each process from an existing hash table to a new one */
1031 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1033 LttvProcessState
*process
, *new_process
;
1035 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1039 process
= (LttvProcessState
*)value
;
1040 new_process
= g_new(LttvProcessState
, 1);
1041 *new_process
= *process
;
1042 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1043 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1044 new_process
->execution_stack
=
1045 g_array_set_size(new_process
->execution_stack
,
1046 process
->execution_stack
->len
);
1047 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1048 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1049 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1051 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1052 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1053 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1054 sizeof(guint64
), 0);
1055 new_process
->user_stack
=
1056 g_array_set_size(new_process
->user_stack
,
1057 process
->user_stack
->len
);
1058 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1059 g_array_index(new_process
->user_stack
, guint64
, i
) =
1060 g_array_index(process
->user_stack
, guint64
, i
);
1062 new_process
->current_function
= process
->current_function
;
1063 g_hash_table_insert(new_processes
, new_process
, new_process
);
1067 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1069 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1071 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1072 return new_processes
;
1076 /* The saved state for each trace contains a member "processes", which
1077 stores a copy of the process table, and a member "tracefiles" with
1078 one entry per tracefile. Each tracefile has a "process" member pointing
1079 to the current process and a "position" member storing the tracefile
1080 position (needed to seek to the current "next" event. */
1082 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1084 guint i
, nb_tracefile
, nb_cpus
;
1086 LttvTracefileState
*tfcs
;
1088 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1090 guint
*running_process
;
1092 LttvAttributeType type
;
1094 LttvAttributeValue value
;
1096 LttvAttributeName name
;
1098 LttEventPosition
*ep
;
1100 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1101 LTTV_STATE_TRACEFILES
);
1103 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1105 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1107 /* Add the currently running processes array */
1108 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1109 running_process
= g_new(guint
, nb_cpus
);
1110 for(i
=0;i
<nb_cpus
;i
++) {
1111 running_process
[i
] = self
->running_process
[i
]->pid
;
1113 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1115 *(value
.v_pointer
) = running_process
;
1117 g_info("State save");
1119 nb_tracefile
= self
->parent
.tracefiles
->len
;
1121 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1123 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1124 LttvTracefileContext
*, i
));
1125 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1126 value
= lttv_attribute_add(tracefiles_tree
, i
,
1128 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1130 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1132 *(value
.v_uint
) = tfcs
->process
->pid
;
1134 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1136 /* Only save the position if the tfs has not infinite time. */
1137 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1138 // && current_tfcs != tfcs) {
1139 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1140 *(value
.v_pointer
) = NULL
;
1142 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1143 ep
= ltt_event_position_new();
1144 ltt_event_position(e
, ep
);
1145 *(value
.v_pointer
) = ep
;
1147 guint nb_block
, offset
;
1150 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1151 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1153 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1159 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1161 guint i
, nb_tracefile
, pid
, nb_cpus
;
1163 LttvTracefileState
*tfcs
;
1165 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1167 guint
*running_process
;
1169 LttvAttributeType type
;
1171 LttvAttributeValue value
;
1173 LttvAttributeName name
;
1177 LttEventPosition
*ep
;
1179 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1181 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1182 LTTV_STATE_TRACEFILES
);
1184 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1186 g_assert(type
== LTTV_POINTER
);
1187 lttv_state_free_process_table(self
->processes
);
1188 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1190 /* Add the currently running processes array */
1191 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1192 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1194 g_assert(type
== LTTV_POINTER
);
1195 running_process
= *(value
.v_pointer
);
1196 for(i
=0;i
<nb_cpus
;i
++) {
1197 pid
= running_process
[i
];
1198 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1199 g_assert(self
->running_process
[i
] != NULL
);
1203 nb_tracefile
= self
->parent
.tracefiles
->len
;
1205 //g_tree_destroy(tsc->pqueue);
1206 //tsc->pqueue = g_tree_new(compare_tracefile);
1208 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1210 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1211 LttvTracefileContext
*, i
));
1212 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1213 g_assert(type
== LTTV_GOBJECT
);
1214 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1216 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1218 g_assert(type
== LTTV_UINT
);
1219 pid
= *(value
.v_uint
);
1220 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1222 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1224 g_assert(type
== LTTV_POINTER
);
1225 //g_assert(*(value.v_pointer) != NULL);
1226 ep
= *(value
.v_pointer
);
1227 g_assert(tfcs
->parent
.t_context
!= NULL
);
1229 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1230 g_tree_remove(tsc
->pqueue
, tfc
);
1233 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1234 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1235 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1236 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1237 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1239 tfc
->timestamp
= ltt_time_infinite
;
1245 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1247 guint i
, nb_tracefile
, nb_cpus
;
1249 LttvTracefileState
*tfcs
;
1251 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1253 guint
*running_process
;
1255 LttvAttributeType type
;
1257 LttvAttributeValue value
;
1259 LttvAttributeName name
;
1263 LttEventPosition
*ep
;
1265 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1266 LTTV_STATE_TRACEFILES
);
1267 g_object_ref(G_OBJECT(tracefiles_tree
));
1268 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1270 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1272 g_assert(type
== LTTV_POINTER
);
1273 lttv_state_free_process_table(*(value
.v_pointer
));
1274 *(value
.v_pointer
) = NULL
;
1275 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1277 /* Free running processes array */
1278 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1279 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1281 g_assert(type
== LTTV_POINTER
);
1282 running_process
= *(value
.v_pointer
);
1283 g_free(running_process
);
1285 nb_tracefile
= self
->parent
.tracefiles
->len
;
1287 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1289 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1290 LttvTracefileContext
*, i
));
1291 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1292 g_assert(type
== LTTV_GOBJECT
);
1293 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1295 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1297 g_assert(type
== LTTV_POINTER
);
1298 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1300 g_object_unref(G_OBJECT(tracefiles_tree
));
1304 static void free_saved_state(LttvTraceState
*self
)
1308 LttvAttributeType type
;
1310 LttvAttributeValue value
;
1312 LttvAttributeName name
;
1316 LttvAttribute
*saved_states
;
1318 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1319 LTTV_STATE_SAVED_STATES
);
1321 nb
= lttv_attribute_get_number(saved_states
);
1322 for(i
= 0 ; i
< nb
; i
++) {
1323 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1324 g_assert(type
== LTTV_GOBJECT
);
1325 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1328 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1333 create_max_time(LttvTraceState
*tcs
)
1335 LttvAttributeValue v
;
1337 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1339 g_assert(*(v
.v_pointer
) == NULL
);
1340 *(v
.v_pointer
) = g_new(LttTime
,1);
1341 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1346 get_max_time(LttvTraceState
*tcs
)
1348 LttvAttributeValue v
;
1350 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1352 g_assert(*(v
.v_pointer
) != NULL
);
1353 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1358 free_max_time(LttvTraceState
*tcs
)
1360 LttvAttributeValue v
;
1362 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1364 g_free(*(v
.v_pointer
));
1365 *(v
.v_pointer
) = NULL
;
1369 typedef struct _LttvNameTables
{
1370 // FIXME GQuark *eventtype_names;
1371 GQuark
*syscall_names
;
1377 GQuark
*soft_irq_names
;
1383 create_name_tables(LttvTraceState
*tcs
)
1387 GQuark f_name
, e_name
;
1391 LttvTraceHookByFacility
*thf
;
1397 GString
*fe_name
= g_string_new("");
1399 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1401 LttvAttributeValue v
;
1403 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1405 g_assert(*(v
.v_pointer
) == NULL
);
1406 *(v
.v_pointer
) = name_tables
;
1407 #if 0 // Use iteration over the facilities_by_name and then list all event
1408 // types of each facility
1409 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1410 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1411 for(i
= 0 ; i
< nb
; i
++) {
1412 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1413 e_name
= ltt_eventtype_name(et
);
1414 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1415 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1416 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1419 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1420 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1421 LTT_FIELD_SYSCALL_ID
, 0, 0,
1424 thf
= lttv_trace_hook_get_first(&h
);
1426 t
= ltt_field_type(thf
->f1
);
1427 nb
= ltt_type_element_number(t
);
1429 lttv_trace_hook_destroy(&h
);
1431 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1432 name_tables
->nb_syscalls
= nb
;
1434 for(i
= 0 ; i
< nb
; i
++) {
1435 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1436 if(!name_tables
->syscall_names
[i
]) {
1437 GString
*string
= g_string_new("");
1438 g_string_printf(string
, "syscall %u", i
);
1439 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1440 g_string_free(string
, TRUE
);
1444 //name_tables->syscall_names = g_new(GQuark, 256);
1445 //for(i = 0 ; i < 256 ; i++) {
1446 // g_string_printf(fe_name, "syscall %d", i);
1447 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1450 name_tables
->syscall_names
= NULL
;
1451 name_tables
->nb_syscalls
= 0;
1454 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1455 LTT_EVENT_TRAP_ENTRY
,
1456 LTT_FIELD_TRAP_ID
, 0, 0,
1459 thf
= lttv_trace_hook_get_first(&h
);
1461 t
= ltt_field_type(thf
->f1
);
1462 //nb = ltt_type_element_number(t);
1464 lttv_trace_hook_destroy(&h
);
1467 name_tables->trap_names = g_new(GQuark, nb);
1468 for(i = 0 ; i < nb ; i++) {
1469 name_tables->trap_names[i] = g_quark_from_string(
1470 ltt_enum_string_get(t, i));
1473 name_tables
->nb_traps
= 256;
1474 name_tables
->trap_names
= g_new(GQuark
, 256);
1475 for(i
= 0 ; i
< 256 ; i
++) {
1476 g_string_printf(fe_name
, "trap %d", i
);
1477 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1480 name_tables
->trap_names
= NULL
;
1481 name_tables
->nb_traps
= 0;
1484 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1485 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1486 LTT_FIELD_IRQ_ID
, 0, 0,
1489 thf
= lttv_trace_hook_get_first(&h
);
1491 t
= ltt_field_type(thf
->f1
);
1492 //nb = ltt_type_element_number(t);
1494 lttv_trace_hook_destroy(&h
);
1497 name_tables->irq_names = g_new(GQuark, nb);
1498 for(i = 0 ; i < nb ; i++) {
1499 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1503 name_tables
->nb_irqs
= 256;
1504 name_tables
->irq_names
= g_new(GQuark
, 256);
1505 for(i
= 0 ; i
< 256 ; i
++) {
1506 g_string_printf(fe_name
, "irq %d", i
);
1507 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1510 name_tables
->nb_irqs
= 0;
1511 name_tables
->irq_names
= NULL
;
1514 name_tables->soft_irq_names = g_new(GQuark, nb);
1515 for(i = 0 ; i < nb ; i++) {
1516 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1520 name_tables
->nb_softirqs
= 256;
1521 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1522 for(i
= 0 ; i
< 256 ; i
++) {
1523 g_string_printf(fe_name
, "softirq %d", i
);
1524 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1528 g_string_free(fe_name
, TRUE
);
1533 get_name_tables(LttvTraceState
*tcs
)
1535 LttvNameTables
*name_tables
;
1537 LttvAttributeValue v
;
1539 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1541 g_assert(*(v
.v_pointer
) != NULL
);
1542 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1543 //tcs->eventtype_names = name_tables->eventtype_names;
1544 tcs
->syscall_names
= name_tables
->syscall_names
;
1545 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1546 tcs
->trap_names
= name_tables
->trap_names
;
1547 tcs
->nb_traps
= name_tables
->nb_traps
;
1548 tcs
->irq_names
= name_tables
->irq_names
;
1549 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1550 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1551 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1556 free_name_tables(LttvTraceState
*tcs
)
1558 LttvNameTables
*name_tables
;
1560 LttvAttributeValue v
;
1562 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1564 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1565 *(v
.v_pointer
) = NULL
;
1567 // g_free(name_tables->eventtype_names);
1568 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1569 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1570 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1571 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1572 if(name_tables
) g_free(name_tables
);
1575 #ifdef HASH_TABLE_DEBUG
1577 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1579 LttvProcessState
*process
= (LttvProcessState
*)value
;
1581 /* Test for process corruption */
1582 guint stack_len
= process
->execution_stack
->len
;
1585 static void hash_table_check(GHashTable
*table
)
1587 g_hash_table_foreach(table
, test_process
, NULL
);
1593 /* clears the stack and sets the state passed as argument */
1594 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1596 g_array_set_size(cpust
->mode_stack
, 1);
1597 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1600 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1602 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1603 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1606 static void cpu_pop_mode(LttvCPUState
*cpust
)
1608 if(cpust
->mode_stack
->len
== 1)
1609 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1611 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1614 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1617 LttvExecutionState
*es
;
1619 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1620 guint cpu
= tfs
->cpu
;
1622 #ifdef HASH_TABLE_DEBUG
1623 hash_table_check(ts
->processes
);
1625 LttvProcessState
*process
= ts
->running_process
[cpu
];
1627 guint depth
= process
->execution_stack
->len
;
1629 process
->execution_stack
=
1630 g_array_set_size(process
->execution_stack
, depth
+ 1);
1633 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1635 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1638 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1639 es
->cum_cpu_time
= ltt_time_zero
;
1640 es
->s
= process
->state
->s
;
1641 process
->state
= es
;
1645 * return 1 when empty, else 0 */
1646 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1647 LttvTracefileState
*tfs
)
1649 guint cpu
= tfs
->cpu
;
1650 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1652 guint depth
= process
->execution_stack
->len
;
1658 process
->execution_stack
=
1659 g_array_set_size(process
->execution_stack
, depth
- 1);
1660 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1662 process
->state
->change
= tfs
->parent
.timestamp
;
1667 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1669 guint cpu
= tfs
->cpu
;
1670 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1671 LttvProcessState
*process
= ts
->running_process
[cpu
];
1673 guint depth
= process
->execution_stack
->len
;
1675 if(process
->state
->t
!= t
){
1676 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1677 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1678 g_info("process state has %s when pop_int is %s\n",
1679 g_quark_to_string(process
->state
->t
),
1680 g_quark_to_string(t
));
1681 g_info("{ %u, %u, %s, %s, %s }\n",
1684 g_quark_to_string(process
->name
),
1685 g_quark_to_string(process
->brand
),
1686 g_quark_to_string(process
->state
->s
));
1691 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1692 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1696 process
->execution_stack
=
1697 g_array_set_size(process
->execution_stack
, depth
- 1);
1698 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1700 process
->state
->change
= tfs
->parent
.timestamp
;
1703 struct search_result
{
1704 const LttTime
*time
; /* Requested time */
1705 LttTime
*best
; /* Best result */
1708 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1710 const LttTime
*elem_time
= (const LttTime
*)a
;
1711 /* Explicit non const cast */
1712 struct search_result
*res
= (struct search_result
*)b
;
1714 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1715 /* The usertrace was created before the schedchange */
1716 /* Get larger keys */
1718 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1719 /* The usertrace was created after the schedchange time */
1720 /* Get smaller keys */
1722 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1723 res
->best
= elem_time
;
1726 res
->best
= elem_time
;
1733 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1734 guint pid
, const LttTime
*timestamp
)
1736 LttvTracefileState
*tfs
= NULL
;
1737 struct search_result res
;
1738 /* Find the usertrace associated with a pid and time interval.
1739 * Search in the usertraces by PID (within a hash) and then, for each
1740 * corresponding element of the array, find the first one with creation
1741 * timestamp the lowest, but higher or equal to "timestamp". */
1742 res
.time
= timestamp
;
1744 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1745 if(usertrace_tree
) {
1746 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1748 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1756 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1757 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1759 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1761 LttvExecutionState
*es
;
1763 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1768 process
->tgid
= tgid
;
1770 process
->name
= name
;
1771 process
->brand
= LTTV_STATE_UNBRANDED
;
1772 //process->last_cpu = tfs->cpu_name;
1773 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1774 process
->type
= LTTV_STATE_USER_THREAD
;
1775 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1776 process
->current_function
= 0; //function 0x0 by default.
1778 g_info("Process %u, core %p", process
->pid
, process
);
1779 g_hash_table_insert(tcs
->processes
, process
, process
);
1782 process
->ppid
= parent
->pid
;
1783 process
->creation_time
= *timestamp
;
1786 /* No parent. This process exists but we are missing all information about
1787 its creation. The birth time is set to zero but we remember the time of
1792 process
->creation_time
= ltt_time_zero
;
1795 process
->insertion_time
= *timestamp
;
1796 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1797 process
->creation_time
.tv_nsec
);
1798 process
->pid_time
= g_quark_from_string(buffer
);
1800 //process->last_cpu = tfs->cpu_name;
1801 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1802 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1803 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1804 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1805 es
= process
->state
= &g_array_index(process
->execution_stack
,
1806 LttvExecutionState
, 0);
1807 es
->t
= LTTV_STATE_USER_MODE
;
1808 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1809 es
->entry
= *timestamp
;
1810 //g_assert(timestamp->tv_sec != 0);
1811 es
->change
= *timestamp
;
1812 es
->cum_cpu_time
= ltt_time_zero
;
1813 es
->s
= LTTV_STATE_RUN
;
1815 es
= process
->state
= &g_array_index(process
->execution_stack
,
1816 LttvExecutionState
, 1);
1817 es
->t
= LTTV_STATE_SYSCALL
;
1818 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1819 es
->entry
= *timestamp
;
1820 //g_assert(timestamp->tv_sec != 0);
1821 es
->change
= *timestamp
;
1822 es
->cum_cpu_time
= ltt_time_zero
;
1823 es
->s
= LTTV_STATE_WAIT_FORK
;
1825 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1826 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1827 sizeof(guint64
), 0);
1832 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1835 LttvProcessState key
;
1836 LttvProcessState
*process
;
1840 process
= g_hash_table_lookup(ts
->processes
, &key
);
1845 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1846 const LttTime
*timestamp
)
1848 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1849 LttvExecutionState
*es
;
1851 /* Put ltt_time_zero creation time for unexisting processes */
1852 if(unlikely(process
== NULL
)) {
1853 process
= lttv_state_create_process(ts
,
1854 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1855 /* We are not sure is it's a kernel thread or normal thread, put the
1856 * bottom stack state to unknown */
1857 process
->execution_stack
=
1858 g_array_set_size(process
->execution_stack
, 1);
1859 process
->state
= es
=
1860 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1861 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1862 es
->s
= LTTV_STATE_UNNAMED
;
1867 /* FIXME : this function should be called when we receive an event telling that
1868 * release_task has been called in the kernel. In happens generally when
1869 * the parent waits for its child terminaison, but may also happen in special
1870 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1871 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1872 * of a killed thread ground, but isn't the leader.
1874 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1876 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1877 LttvProcessState key
;
1879 key
.pid
= process
->pid
;
1880 key
.cpu
= process
->cpu
;
1881 g_hash_table_remove(ts
->processes
, &key
);
1882 g_array_free(process
->execution_stack
, TRUE
);
1883 g_array_free(process
->user_stack
, TRUE
);
1888 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1890 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1891 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1896 static void lttv_state_free_process_table(GHashTable
*processes
)
1898 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1899 g_hash_table_destroy(processes
);
1903 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1905 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1907 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1908 LttvProcessState
*process
= ts
->running_process
[cpu
];
1909 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1910 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1911 LttField
*f
= thf
->f1
;
1913 LttvExecutionSubmode submode
;
1915 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1916 guint syscall
= ltt_event_get_unsigned(e
, f
);
1918 if(syscall
< nb_syscalls
) {
1919 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1922 /* Fixup an incomplete syscall table */
1923 GString
*string
= g_string_new("");
1924 g_string_printf(string
, "syscall %u", syscall
);
1925 submode
= g_quark_from_string(string
->str
);
1926 g_string_free(string
, TRUE
);
1928 /* There can be no system call from PID 0 : unknown state */
1929 if(process
->pid
!= 0)
1930 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1935 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1937 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1939 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1940 LttvProcessState
*process
= ts
->running_process
[cpu
];
1942 /* There can be no system call from PID 0 : unknown state */
1943 if(process
->pid
!= 0)
1944 pop_state(s
, LTTV_STATE_SYSCALL
);
1949 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1951 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1952 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1953 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1954 LttField
*f
= thf
->f1
;
1956 LttvExecutionSubmode submode
;
1958 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1959 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1961 if(trap
< nb_traps
) {
1962 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1964 /* Fixup an incomplete trap table */
1965 GString
*string
= g_string_new("");
1966 g_string_printf(string
, "trap %llu", trap
);
1967 submode
= g_quark_from_string(string
->str
);
1968 g_string_free(string
, TRUE
);
1971 push_state(s
, LTTV_STATE_TRAP
, submode
);
1973 /* update cpu status */
1974 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
1979 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1981 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1983 pop_state(s
, LTTV_STATE_TRAP
);
1985 /* update cpu status */
1986 cpu_pop_mode(s
->cpu_state
);
1991 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1993 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1994 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1995 guint8 fac_id
= ltt_event_facility_id(e
);
1996 guint8 ev_id
= ltt_event_eventtype_id(e
);
1997 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1998 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1999 g_assert(thf
->f1
!= NULL
);
2000 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2001 LttField
*f
= thf
->f1
;
2003 LttvExecutionSubmode submode
;
2004 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2005 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2009 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2011 /* Fixup an incomplete irq table */
2012 GString
*string
= g_string_new("");
2013 g_string_printf(string
, "irq %llu", irq
);
2014 submode
= g_quark_from_string(string
->str
);
2015 g_string_free(string
, TRUE
);
2018 /* Do something with the info about being in user or system mode when int? */
2019 push_state(s
, LTTV_STATE_IRQ
, submode
);
2021 /* update cpu status */
2022 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2027 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2029 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2031 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2037 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2039 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2041 pop_state(s
, LTTV_STATE_IRQ
);
2043 /* update cpu status */
2044 cpu_pop_mode(s
->cpu_state
);
2049 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2051 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2052 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2053 guint8 fac_id
= ltt_event_facility_id(e
);
2054 guint8 ev_id
= ltt_event_eventtype_id(e
);
2055 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2056 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2057 g_assert(thf
->f1
!= NULL
);
2058 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2059 LttField
*f
= thf
->f1
;
2061 LttvExecutionSubmode submode
;
2062 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2063 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2066 if(softirq
< nb_softirqs
) {
2067 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2069 /* Fixup an incomplete irq table */
2070 GString
*string
= g_string_new("");
2071 g_string_printf(string
, "softirq %llu", softirq
);
2072 submode
= g_quark_from_string(string
->str
);
2073 g_string_free(string
, TRUE
);
2076 /* Do something with the info about being in user or system mode when int? */
2077 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2081 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2085 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2086 guint cpu
= tfs
->cpu
;
2087 LttvProcessState
*process
= ts
->running_process
[cpu
];
2089 guint depth
= process
->user_stack
->len
;
2091 process
->user_stack
=
2092 g_array_set_size(process
->user_stack
, depth
+ 1);
2094 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2095 *new_func
= funcptr
;
2096 process
->current_function
= funcptr
;
2099 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2101 guint cpu
= tfs
->cpu
;
2102 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2103 LttvProcessState
*process
= ts
->running_process
[cpu
];
2105 if(process
->current_function
!= funcptr
){
2106 g_info("Different functions (%lu.%09lu): ignore it\n",
2107 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2108 g_info("process state has %llu when pop_function is %llu\n",
2109 process
->current_function
, funcptr
);
2110 g_info("{ %u, %u, %s, %s, %s }\n",
2113 g_quark_to_string(process
->name
),
2114 g_quark_to_string(process
->brand
),
2115 g_quark_to_string(process
->state
->s
));
2118 guint depth
= process
->user_stack
->len
;
2121 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2122 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2126 process
->user_stack
=
2127 g_array_set_size(process
->user_stack
, depth
- 1);
2128 process
->current_function
=
2129 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2133 static gboolean
function_entry(void *hook_data
, void *call_data
)
2135 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2136 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2137 guint8 fac_id
= ltt_event_facility_id(e
);
2138 guint8 ev_id
= ltt_event_eventtype_id(e
);
2139 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2140 g_assert(thf
->f1
!= NULL
);
2141 LttField
*f
= thf
->f1
;
2142 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2144 push_function(s
, funcptr
);
2148 static gboolean
function_exit(void *hook_data
, void *call_data
)
2150 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2151 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2152 guint8 fac_id
= ltt_event_facility_id(e
);
2153 guint8 ev_id
= ltt_event_eventtype_id(e
);
2154 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2155 g_assert(thf
->f1
!= NULL
);
2156 LttField
*f
= thf
->f1
;
2157 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2159 LttvExecutionSubmode submode
;
2161 pop_function(s
, funcptr
);
2165 static gboolean
schedchange(void *hook_data
, void *call_data
)
2167 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2169 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2170 LttvProcessState
*process
= ts
->running_process
[cpu
];
2171 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2173 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2174 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2175 guint pid_in
, pid_out
;
2178 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2179 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2180 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2182 if(likely(process
!= NULL
)) {
2184 /* We could not know but it was not the idle process executing.
2185 This should only happen at the beginning, before the first schedule
2186 event, and when the initial information (current process for each CPU)
2187 is missing. It is not obvious how we could, after the fact, compensate
2188 the wrongly attributed statistics. */
2190 //This test only makes sense once the state is known and if there is no
2191 //missing events. We need to silently ignore schedchange coming after a
2192 //process_free, or it causes glitches. (FIXME)
2193 //if(unlikely(process->pid != pid_out)) {
2194 // g_assert(process->pid == 0);
2196 if(process
->pid
== 0
2197 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2199 /* Scheduling out of pid 0 at beginning of the trace :
2200 * we know for sure it is in syscall mode at this point. */
2201 g_assert(process
->execution_stack
->len
== 1);
2202 process
->state
->t
= LTTV_STATE_SYSCALL
;
2203 process
->state
->s
= LTTV_STATE_WAIT
;
2204 process
->state
->change
= s
->parent
.timestamp
;
2205 process
->state
->entry
= s
->parent
.timestamp
;
2208 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2209 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2210 process
->state
->change
= s
->parent
.timestamp
;
2212 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2213 else process
->state
->s
= LTTV_STATE_WAIT
;
2214 process
->state
->change
= s
->parent
.timestamp
;
2217 if(state_out
== 32 || state_out
== 128)
2218 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2219 /* see sched.h for states */
2222 process
= ts
->running_process
[cpu
] =
2223 lttv_state_find_process_or_create(
2224 (LttvTraceState
*)s
->parent
.t_context
,
2226 &s
->parent
.timestamp
);
2227 process
->state
->s
= LTTV_STATE_RUN
;
2229 if(process
->usertrace
)
2230 process
->usertrace
->cpu
= cpu
;
2231 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2232 process
->state
->change
= s
->parent
.timestamp
;
2234 /* update cpu status */
2236 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2238 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2243 static gboolean
process_fork(void *hook_data
, void *call_data
)
2245 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2246 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2247 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2249 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2250 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2251 LttvProcessState
*zombie_process
;
2253 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2254 LttvProcessState
*process
= ts
->running_process
[cpu
];
2255 LttvProcessState
*child_process
;
2258 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2261 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2262 s
->parent
.target_pid
= child_pid
;
2265 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2266 else child_tgid
= 0;
2268 /* Mathieu : it seems like the process might have been scheduled in before the
2269 * fork, and, in a rare case, might be the current process. This might happen
2270 * in a SMP case where we don't have enough precision on the clocks.
2272 * Test reenabled after precision fixes on time. (Mathieu) */
2274 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2276 if(unlikely(zombie_process
!= NULL
)) {
2277 /* Reutilisation of PID. Only now we are sure that the old PID
2278 * has been released. FIXME : should know when release_task happens instead.
2280 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2282 for(i
=0; i
< num_cpus
; i
++) {
2283 g_assert(zombie_process
!= ts
->running_process
[i
]);
2286 exit_process(s
, zombie_process
);
2289 g_assert(process
->pid
!= child_pid
);
2290 // FIXME : Add this test in the "known state" section
2291 // g_assert(process->pid == parent_pid);
2292 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2293 if(child_process
== NULL
) {
2294 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2295 child_pid
, child_tgid
,
2296 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2298 /* The process has already been created : due to time imprecision between
2299 * multiple CPUs : it has been scheduled in before creation. Note that we
2300 * shouldn't have this kind of imprecision.
2302 * Simply put a correct parent.
2304 g_assert(0); /* This is a problematic case : the process has been created
2305 before the fork event */
2306 child_process
->ppid
= process
->pid
;
2307 child_process
->tgid
= child_tgid
;
2309 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2310 child_process
->name
= process
->name
;
2311 child_process
->brand
= process
->brand
;
2316 /* We stamp a newly created process as kernel_thread.
2317 * The thread should not be running yet. */
2318 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2320 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2321 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2322 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2325 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2326 LttvProcessState
*process
;
2327 LttvExecutionState
*es
;
2330 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2331 s
->parent
.target_pid
= pid
;
2333 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2335 process
->execution_stack
=
2336 g_array_set_size(process
->execution_stack
, 1);
2337 es
= process
->state
=
2338 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2339 es
->t
= LTTV_STATE_SYSCALL
;
2340 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2345 static gboolean
process_exit(void *hook_data
, void *call_data
)
2347 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2348 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2349 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2353 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2354 LttvProcessState
*process
; // = ts->running_process[cpu];
2356 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2357 s
->parent
.target_pid
= pid
;
2359 // FIXME : Add this test in the "known state" section
2360 // g_assert(process->pid == pid);
2362 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2363 if(likely(process
!= NULL
)) {
2364 process
->state
->s
= LTTV_STATE_EXIT
;
2369 static gboolean
process_free(void *hook_data
, void *call_data
)
2371 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2372 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2373 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2374 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2376 LttvProcessState
*process
;
2378 /* PID of the process to release */
2379 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2380 s
->parent
.target_pid
= release_pid
;
2382 g_assert(release_pid
!= 0);
2384 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2386 if(likely(process
!= NULL
)) {
2387 /* release_task is happening at kernel level : we can now safely release
2388 * the data structure of the process */
2389 //This test is fun, though, as it may happen that
2390 //at time t : CPU 0 : process_free
2391 //at time t+150ns : CPU 1 : schedule out
2392 //Clearly due to time imprecision, we disable it. (Mathieu)
2393 //If this weird case happen, we have no choice but to put the
2394 //Currently running process on the cpu to 0.
2395 //I re-enable it following time precision fixes. (Mathieu)
2396 //Well, in the case where an process is freed by a process on another CPU
2397 //and still scheduled, it happens that this is the schedchange that will
2398 //drop the last reference count. Do not free it here!
2399 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2401 for(i
=0; i
< num_cpus
; i
++) {
2402 //g_assert(process != ts->running_process[i]);
2403 if(process
== ts
->running_process
[i
]) {
2404 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2408 if(i
== num_cpus
) /* process is not scheduled */
2409 exit_process(s
, process
);
2416 static gboolean
process_exec(void *hook_data
, void *call_data
)
2418 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2419 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2420 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2421 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2424 LttvProcessState
*process
= ts
->running_process
[cpu
];
2426 #if 0//how to use a sequence that must be transformed in a string
2427 /* PID of the process to release */
2428 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2429 //name = ltt_event_get_string(e, thf->f1);
2430 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2432 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2433 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2434 memcpy(null_term_name
, name_begin
, name_len
);
2435 null_term_name
[name_len
] = '\0';
2436 process
->name
= g_quark_from_string(null_term_name
);
2439 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2440 process
->brand
= LTTV_STATE_UNBRANDED
;
2441 //g_free(null_term_name);
2445 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2447 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2448 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2449 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2450 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2453 LttvProcessState
*process
= ts
->running_process
[cpu
];
2455 name
= ltt_event_get_string(e
, thf
->f1
);
2456 process
->brand
= g_quark_from_string(name
);
2461 static void fix_process(gpointer key
, gpointer value
,
2464 LttvProcessState
*process
;
2465 LttvExecutionState
*es
;
2466 process
= (LttvProcessState
*)value
;
2467 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2468 LttTime
*timestamp
= (LttTime
*)user_data
;
2470 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2471 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2472 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2473 es
->t
= LTTV_STATE_SYSCALL
;
2474 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2475 es
->entry
= *timestamp
;
2476 es
->change
= *timestamp
;
2477 es
->cum_cpu_time
= ltt_time_zero
;
2478 if(es
->s
== LTTV_STATE_UNNAMED
)
2479 es
->s
= LTTV_STATE_WAIT
;
2482 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2483 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2484 es
->t
= LTTV_STATE_USER_MODE
;
2485 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2486 es
->entry
= *timestamp
;
2487 //g_assert(timestamp->tv_sec != 0);
2488 es
->change
= *timestamp
;
2489 es
->cum_cpu_time
= ltt_time_zero
;
2490 if(es
->s
== LTTV_STATE_UNNAMED
)
2491 es
->s
= LTTV_STATE_RUN
;
2493 if(process
->execution_stack
->len
== 1) {
2494 /* Still in bottom unknown mode, means never did a system call
2495 * May be either in user mode, syscall mode, running or waiting.*/
2496 /* FIXME : we may be tagging syscall mode when being user mode */
2497 process
->execution_stack
=
2498 g_array_set_size(process
->execution_stack
, 2);
2499 es
= process
->state
= &g_array_index(process
->execution_stack
,
2500 LttvExecutionState
, 1);
2501 es
->t
= LTTV_STATE_SYSCALL
;
2502 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2503 es
->entry
= *timestamp
;
2504 //g_assert(timestamp->tv_sec != 0);
2505 es
->change
= *timestamp
;
2506 es
->cum_cpu_time
= ltt_time_zero
;
2507 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2508 es
->s
= LTTV_STATE_WAIT
;
2514 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2516 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2517 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2518 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2519 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2520 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2522 /* For all processes */
2523 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2524 /* else, if stack[0] is unknown, set to user mode, running */
2526 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2529 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2531 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2532 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2533 //It's slow : optimise later by doing this before reading trace.
2534 LttEventType
*et
= ltt_event_eventtype(e
);
2536 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2542 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2543 LttvProcessState
*process
= ts
->running_process
[cpu
];
2544 LttvProcessState
*parent_process
;
2545 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2546 GQuark type
, mode
, submode
, status
;
2547 LttvExecutionState
*es
;
2551 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2552 s
->parent
.target_pid
= pid
;
2555 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2558 command
= ltt_event_get_string(e
, thf
->f3
);
2561 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2562 type
= ltt_enum_string_get(ltt_field_type(f4
),
2563 ltt_event_get_unsigned(e
, f4
));
2566 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2567 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2568 ltt_event_get_unsigned(e
, f5
));
2571 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2572 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2573 ltt_event_get_unsigned(e
, f6
));
2576 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2577 status
= ltt_enum_string_get(ltt_field_type(f7
),
2578 ltt_event_get_unsigned(e
, f7
));
2581 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2582 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2587 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2588 for(i
=0; i
<nb_cpus
; i
++) {
2589 process
= lttv_state_find_process(ts
, i
, pid
);
2590 g_assert(process
!= NULL
);
2592 process
->ppid
= parent_pid
;
2593 process
->tgid
= tgid
;
2594 process
->name
= g_quark_from_string(command
);
2596 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2597 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2601 /* The process might exist if a process was forked while performing the
2603 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2604 if(process
== NULL
) {
2605 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2606 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2607 pid
, tgid
, g_quark_from_string(command
),
2608 &s
->parent
.timestamp
);
2610 /* Keep the stack bottom : a running user mode */
2611 /* Disabled because of inconsistencies in the current statedump states. */
2612 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2613 /* Only keep the bottom
2614 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2615 /* Will cause expected trap when in fact being syscall (even after end of
2617 * Will cause expected interrupt when being syscall. (only before end of
2618 * statedump event) */
2619 // This will cause a "popping last state on stack, ignoring it."
2620 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2621 es
= process
->state
= &g_array_index(process
->execution_stack
,
2622 LttvExecutionState
, 0);
2623 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2624 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2625 es
->s
= LTTV_STATE_UNNAMED
;
2626 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2628 es
->t
= LTTV_STATE_SYSCALL
;
2633 /* User space process :
2634 * bottom : user mode
2635 * either currently running or scheduled out.
2636 * can be scheduled out because interrupted in (user mode or in syscall)
2637 * or because of an explicit call to the scheduler in syscall. Note that
2638 * the scheduler call comes after the irq_exit, so never in interrupt
2640 // temp workaround : set size to 1 : only have user mode bottom of stack.
2641 // will cause g_info message of expected syscall mode when in fact being
2642 // in user mode. Can also cause expected trap when in fact being user
2643 // mode in the event of a page fault reenabling interrupts in the handler.
2644 // Expected syscall and trap can also happen after the end of statedump
2645 // This will cause a "popping last state on stack, ignoring it."
2646 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2647 es
= process
->state
= &g_array_index(process
->execution_stack
,
2648 LttvExecutionState
, 0);
2649 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2650 es
->s
= LTTV_STATE_UNNAMED
;
2651 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2653 es
->t
= LTTV_STATE_USER_MODE
;
2661 es
= process
->state
= &g_array_index(process
->execution_stack
,
2662 LttvExecutionState
, 1);
2663 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2664 es
->s
= LTTV_STATE_UNNAMED
;
2665 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2669 /* The process has already been created :
2670 * Probably was forked while dumping the process state or
2671 * was simply scheduled in prior to get the state dump event.
2673 process
->ppid
= parent_pid
;
2674 process
->tgid
= tgid
;
2675 process
->name
= g_quark_from_string(command
);
2676 process
->type
= type
;
2678 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2680 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2681 if(type
== LTTV_STATE_KERNEL_THREAD
)
2682 es
->t
= LTTV_STATE_SYSCALL
;
2684 es
->t
= LTTV_STATE_USER_MODE
;
2687 /* Don't mess around with the stack, it will eventually become
2688 * ok after the end of state dump. */
2695 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2697 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2699 lttv_state_add_event_hooks(tss
);
2704 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2706 LttvTraceset
*traceset
= self
->parent
.ts
;
2708 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2712 LttvTracefileState
*tfs
;
2716 LttvTraceHookByFacility
*thf
;
2718 LttvTraceHook
*hook
;
2720 LttvAttributeValue val
;
2725 nb_trace
= lttv_traceset_number(traceset
);
2726 for(i
= 0 ; i
< nb_trace
; i
++) {
2727 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2729 /* Find the eventtype id for the following events and register the
2730 associated by id hooks. */
2732 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2733 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2736 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2737 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2738 LTT_FIELD_SYSCALL_ID
, 0, 0,
2739 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2742 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2743 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2745 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2748 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2749 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2750 LTT_FIELD_TRAP_ID
, 0, 0,
2751 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2754 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2755 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2757 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2760 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2761 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2762 LTT_FIELD_IRQ_ID
, 0, 0,
2763 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2766 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2767 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2769 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2772 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2773 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2774 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2775 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2778 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2779 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2781 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2784 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2785 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2786 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2787 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2790 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2791 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2792 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2793 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2796 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2797 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2798 LTT_FIELD_PID
, 0, 0,
2799 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2803 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2804 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2805 LTT_FIELD_PID
, 0, 0,
2806 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2809 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2810 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
2811 LTT_FIELD_PID
, 0, 0,
2812 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2815 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2816 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2817 LTT_FIELD_FILENAME
, 0, 0,
2818 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2821 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2822 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2823 LTT_FIELD_NAME
, 0, 0,
2824 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2827 /* statedump-related hooks */
2828 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2829 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
2830 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2831 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2834 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2835 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
2837 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2840 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2841 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2842 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2843 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2846 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2847 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2848 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2849 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2852 hooks
= g_array_set_size(hooks
, hn
);
2854 /* Add these hooks to each event_by_id hooks list */
2856 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2858 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2860 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2861 LttvTracefileContext
*, j
));
2863 for(k
= 0 ; k
< hooks
->len
; k
++) {
2864 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2865 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2866 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2868 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2875 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2876 *(val
.v_pointer
) = hooks
;
2880 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2882 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2884 lttv_state_remove_event_hooks(tss
);
2889 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2891 LttvTraceset
*traceset
= self
->parent
.ts
;
2893 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2897 LttvTracefileState
*tfs
;
2901 LttvTraceHook
*hook
;
2903 LttvTraceHookByFacility
*thf
;
2905 LttvAttributeValue val
;
2907 nb_trace
= lttv_traceset_number(traceset
);
2908 for(i
= 0 ; i
< nb_trace
; i
++) {
2909 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2911 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2912 hooks
= *(val
.v_pointer
);
2914 /* Remove these hooks from each event_by_id hooks list */
2916 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2918 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2920 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2921 LttvTracefileContext
*, j
));
2923 for(k
= 0 ; k
< hooks
->len
; k
++) {
2924 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2925 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2926 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2928 lttv_hooks_remove_data(
2929 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2935 for(k
= 0 ; k
< hooks
->len
; k
++)
2936 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2937 g_array_free(hooks
, TRUE
);
2941 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2943 guint
*event_count
= (guint
*)hook_data
;
2945 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2946 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2951 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2953 LttvTracefileState
*tfcs
;
2955 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2957 LttEventPosition
*ep
;
2963 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2965 LttvAttributeValue value
;
2967 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2968 LTTV_STATE_SAVED_STATES
);
2969 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2970 value
= lttv_attribute_add(saved_states_tree
,
2971 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2972 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2973 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2974 *(value
.v_time
) = self
->parent
.timestamp
;
2975 lttv_state_save(tcs
, saved_state_tree
);
2976 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2977 self
->parent
.timestamp
.tv_nsec
);
2979 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2984 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2986 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2988 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2993 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3001 static gboolean
block_start(void *hook_data
, void *call_data
)
3003 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3005 LttvTracefileState
*tfcs
;
3007 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3009 LttEventPosition
*ep
;
3011 guint i
, nb_block
, nb_event
, nb_tracefile
;
3015 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3017 LttvAttributeValue value
;
3019 ep
= ltt_event_position_new();
3021 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3023 /* Count the number of events added since the last block end in any
3026 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3028 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3029 LttvTracefileContext
, i
));
3030 ltt_event_position(tfcs
->parent
.e
, ep
);
3031 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3032 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3033 tfcs
->saved_position
= nb_event
;
3037 if(tcs
->nb_event
>= tcs
->save_interval
) {
3038 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3039 LTTV_STATE_SAVED_STATES
);
3040 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3041 value
= lttv_attribute_add(saved_states_tree
,
3042 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3043 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3044 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3045 *(value
.v_time
) = self
->parent
.timestamp
;
3046 lttv_state_save(tcs
, saved_state_tree
);
3048 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3049 self
->parent
.timestamp
.tv_nsec
);
3051 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3057 static gboolean
block_end(void *hook_data
, void *call_data
)
3059 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3061 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3065 LttEventPosition
*ep
;
3067 guint nb_block
, nb_event
;
3069 ep
= ltt_event_position_new();
3070 ltt_event_position(self
->parent
.e
, ep
);
3071 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3072 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3073 self
->saved_position
= 0;
3074 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3081 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3083 LttvTraceset
*traceset
= self
->parent
.ts
;
3085 guint i
, j
, nb_trace
, nb_tracefile
;
3089 LttvTracefileState
*tfs
;
3091 LttvTraceHook hook_start
, hook_end
;
3093 nb_trace
= lttv_traceset_number(traceset
);
3094 for(i
= 0 ; i
< nb_trace
; i
++) {
3095 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3097 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3098 NULL
, NULL
, block_start
, &hook_start
);
3099 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3100 NULL
, NULL
, block_end
, &hook_end
);
3102 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3104 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3106 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3107 LttvTracefileContext
, j
));
3108 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3109 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3110 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3111 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3117 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3119 LttvTraceset
*traceset
= self
->parent
.ts
;
3121 guint i
, j
, nb_trace
, nb_tracefile
;
3125 LttvTracefileState
*tfs
;
3128 nb_trace
= lttv_traceset_number(traceset
);
3129 for(i
= 0 ; i
< nb_trace
; i
++) {
3131 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3132 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3134 if(ts
->has_precomputed_states
) continue;
3136 guint
*event_count
= g_new(guint
, 1);
3139 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3141 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3142 LttvTracefileContext
*, j
));
3143 lttv_hooks_add(tfs
->parent
.event
,
3144 state_save_event_hook
,
3151 lttv_process_traceset_begin(&self
->parent
,
3152 NULL
, NULL
, NULL
, NULL
, NULL
);
3156 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3158 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3160 lttv_state_save_add_event_hooks(tss
);
3167 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3169 LttvTraceset
*traceset
= self
->parent
.ts
;
3171 guint i
, j
, nb_trace
, nb_tracefile
;
3175 LttvTracefileState
*tfs
;
3177 LttvTraceHook hook_start
, hook_end
;
3179 nb_trace
= lttv_traceset_number(traceset
);
3180 for(i
= 0 ; i
< nb_trace
; i
++) {
3181 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3183 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3184 NULL
, NULL
, block_start
, &hook_start
);
3186 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3187 NULL
, NULL
, block_end
, &hook_end
);
3189 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3191 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3193 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3194 LttvTracefileContext
, j
));
3195 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3196 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3197 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3198 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3204 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3206 LttvTraceset
*traceset
= self
->parent
.ts
;
3208 guint i
, j
, nb_trace
, nb_tracefile
;
3212 LttvTracefileState
*tfs
;
3214 LttvHooks
*after_trace
= lttv_hooks_new();
3216 lttv_hooks_add(after_trace
,
3217 state_save_after_trace_hook
,
3222 lttv_process_traceset_end(&self
->parent
,
3223 NULL
, after_trace
, NULL
, NULL
, NULL
);
3225 lttv_hooks_destroy(after_trace
);
3227 nb_trace
= lttv_traceset_number(traceset
);
3228 for(i
= 0 ; i
< nb_trace
; i
++) {
3230 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3231 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3233 if(ts
->has_precomputed_states
) continue;
3235 guint
*event_count
= NULL
;
3237 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3239 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3240 LttvTracefileContext
*, j
));
3241 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3242 state_save_event_hook
);
3244 if(event_count
) g_free(event_count
);
3248 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3250 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3252 lttv_state_save_remove_event_hooks(tss
);
3257 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3259 LttvTraceset
*traceset
= self
->parent
.ts
;
3263 int min_pos
, mid_pos
, max_pos
;
3265 guint call_rest
= 0;
3267 LttvTraceState
*tcs
;
3269 LttvAttributeValue value
;
3271 LttvAttributeType type
;
3273 LttvAttributeName name
;
3277 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3279 //g_tree_destroy(self->parent.pqueue);
3280 //self->parent.pqueue = g_tree_new(compare_tracefile);
3282 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3284 nb_trace
= lttv_traceset_number(traceset
);
3285 for(i
= 0 ; i
< nb_trace
; i
++) {
3286 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3288 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3289 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3290 LTTV_STATE_SAVED_STATES
);
3293 if(saved_states_tree
) {
3294 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3295 mid_pos
= max_pos
/ 2;
3296 while(min_pos
< max_pos
) {
3297 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3299 g_assert(type
== LTTV_GOBJECT
);
3300 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3301 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3303 g_assert(type
== LTTV_TIME
);
3304 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3306 closest_tree
= saved_state_tree
;
3308 else max_pos
= mid_pos
- 1;
3310 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3314 /* restore the closest earlier saved state */
3316 lttv_state_restore(tcs
, closest_tree
);
3320 /* There is no saved state, yet we want to have it. Restart at T0 */
3322 restore_init_state(tcs
);
3323 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3326 /* We want to seek quickly without restoring/updating the state */
3328 restore_init_state(tcs
);
3329 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3332 if(!call_rest
) g_info("NOT Calling restore");
3337 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3343 traceset_state_finalize (LttvTracesetState
*self
)
3345 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3346 finalize(G_OBJECT(self
));
3351 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3353 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3355 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3356 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3357 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3358 klass
->new_traceset_context
= new_traceset_context
;
3359 klass
->new_trace_context
= new_trace_context
;
3360 klass
->new_tracefile_context
= new_tracefile_context
;
3365 lttv_traceset_state_get_type(void)
3367 static GType type
= 0;
3369 static const GTypeInfo info
= {
3370 sizeof (LttvTracesetStateClass
),
3371 NULL
, /* base_init */
3372 NULL
, /* base_finalize */
3373 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3374 NULL
, /* class_finalize */
3375 NULL
, /* class_data */
3376 sizeof (LttvTracesetState
),
3377 0, /* n_preallocs */
3378 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3379 NULL
/* value handling */
3382 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3390 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3396 trace_state_finalize (LttvTraceState
*self
)
3398 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3399 finalize(G_OBJECT(self
));
3404 trace_state_class_init (LttvTraceStateClass
*klass
)
3406 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3408 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3409 klass
->state_save
= state_save
;
3410 klass
->state_restore
= state_restore
;
3411 klass
->state_saved_free
= state_saved_free
;
3416 lttv_trace_state_get_type(void)
3418 static GType type
= 0;
3420 static const GTypeInfo info
= {
3421 sizeof (LttvTraceStateClass
),
3422 NULL
, /* base_init */
3423 NULL
, /* base_finalize */
3424 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3425 NULL
, /* class_finalize */
3426 NULL
, /* class_data */
3427 sizeof (LttvTraceState
),
3428 0, /* n_preallocs */
3429 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3430 NULL
/* value handling */
3433 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3434 "LttvTraceStateType", &info
, 0);
3441 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3447 tracefile_state_finalize (LttvTracefileState
*self
)
3449 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3450 finalize(G_OBJECT(self
));
3455 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3457 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3459 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3464 lttv_tracefile_state_get_type(void)
3466 static GType type
= 0;
3468 static const GTypeInfo info
= {
3469 sizeof (LttvTracefileStateClass
),
3470 NULL
, /* base_init */
3471 NULL
, /* base_finalize */
3472 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3473 NULL
, /* class_finalize */
3474 NULL
, /* class_data */
3475 sizeof (LttvTracefileState
),
3476 0, /* n_preallocs */
3477 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3478 NULL
/* value handling */
3481 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3482 "LttvTracefileStateType", &info
, 0);
3488 static void module_init()
3490 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3491 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3492 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3493 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3494 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3495 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3496 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3497 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3498 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3499 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3500 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3501 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3502 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3503 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3504 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3505 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3506 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3507 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3508 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3509 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3510 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3511 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3512 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3513 LTTV_STATE_EVENT
= g_quark_from_string("event");
3514 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3515 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3516 LTTV_STATE_TIME
= g_quark_from_string("time");
3517 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3518 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3519 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3520 g_quark_from_string("trace_state_use_count");
3523 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3524 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3525 LTT_FACILITY_FS
= g_quark_from_string("fs");
3526 LTT_FACILITY_LIST
= g_quark_from_string("list");
3527 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3530 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3531 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3532 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3533 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3534 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3535 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3536 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3537 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3538 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3539 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3540 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3541 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3542 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3543 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3544 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3545 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3546 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3547 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3548 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3551 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3552 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3553 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3554 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3555 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3556 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3557 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3558 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3559 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3560 LTT_FIELD_PID
= g_quark_from_string("pid");
3561 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3562 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3563 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3564 LTT_FIELD_NAME
= g_quark_from_string("name");
3565 LTT_FIELD_TYPE
= g_quark_from_string("type");
3566 LTT_FIELD_MODE
= g_quark_from_string("mode");
3567 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3568 LTT_FIELD_STATUS
= g_quark_from_string("status");
3569 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3570 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3572 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3573 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3574 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3575 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3576 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3579 static void module_destroy()
3584 LTTV_MODULE("state", "State computation", \
3585 "Update the system state, possibly saving it at intervals", \
3586 module_init
, module_destroy
)