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>
33 #define PREALLOCATED_EXECUTION_STACK 10
35 /* Facilities Quarks */
39 LTT_FACILITY_KERNEL_ARCH
,
42 LTT_FACILITY_STATEDUMP
,
43 LTT_FACILITY_USER_GENERIC
;
48 LTT_EVENT_SYSCALL_ENTRY
,
49 LTT_EVENT_SYSCALL_EXIT
,
54 LTT_EVENT_SOFT_IRQ_ENTRY
,
55 LTT_EVENT_SOFT_IRQ_EXIT
,
56 LTT_EVENT_SCHEDCHANGE
,
58 LTT_EVENT_KERNEL_THREAD
,
62 LTT_EVENT_ENUM_PROCESS_STATE
,
63 LTT_EVENT_FUNCTION_ENTRY
,
64 LTT_EVENT_FUNCTION_EXIT
,
65 LTT_EVENT_THREAD_BRAND
;
73 LTT_FIELD_SOFT_IRQ_ID
,
91 LTTV_STATE_MODE_UNKNOWN
,
99 LTTV_STATE_SUBMODE_UNKNOWN
,
100 LTTV_STATE_SUBMODE_NONE
;
104 LTTV_STATE_UNBRANDED
,
105 LTTV_STATE_WAIT_FORK
,
114 LTTV_STATE_USER_THREAD
,
115 LTTV_STATE_KERNEL_THREAD
;
118 LTTV_STATE_TRACEFILES
,
119 LTTV_STATE_PROCESSES
,
121 LTTV_STATE_RUNNING_PROCESS
,
123 LTTV_STATE_SAVED_STATES
,
124 LTTV_STATE_SAVED_STATES_TIME
,
127 LTTV_STATE_NAME_TABLES
,
128 LTTV_STATE_TRACE_STATE_USE_COUNT
;
130 static void create_max_time(LttvTraceState
*tcs
);
132 static void get_max_time(LttvTraceState
*tcs
);
134 static void free_max_time(LttvTraceState
*tcs
);
136 static void create_name_tables(LttvTraceState
*tcs
);
138 static void get_name_tables(LttvTraceState
*tcs
);
140 static void free_name_tables(LttvTraceState
*tcs
);
142 static void free_saved_state(LttvTraceState
*tcs
);
144 static void lttv_state_free_process_table(GHashTable
*processes
);
147 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
149 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
153 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
155 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
159 void lttv_state_state_saved_free(LttvTraceState
*self
,
160 LttvAttribute
*container
)
162 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
166 guint
process_hash(gconstpointer key
)
168 guint pid
= ((const LttvProcessState
*)key
)->pid
;
169 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
173 /* If the hash table hash function is well distributed,
174 * the process_equal should compare different pid */
175 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
177 const LttvProcessState
*process_a
, *process_b
;
180 process_a
= (const LttvProcessState
*)a
;
181 process_b
= (const LttvProcessState
*)b
;
183 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
184 else if(likely(process_a
->pid
== 0 &&
185 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
190 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
192 g_tree_destroy((GTree
*)value
);
195 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
197 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
198 g_hash_table_destroy(usertraces
);
204 restore_init_state(LttvTraceState
*self
)
208 LttvTracefileState
*tfcs
;
210 LttTime start_time
, end_time
;
212 /* Free the process tables */
213 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
214 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
215 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
216 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
219 /* Seek time to beginning */
220 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
221 // closest. It's the tracecontext job to seek the trace to the beginning
222 // anyway : the init state might be used at the middle of the trace as well...
223 //g_tree_destroy(self->parent.ts_context->pqueue);
224 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
226 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
228 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
230 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
232 /* Put the per cpu running_process to beginning state : process 0. */
233 for(i
=0; i
< nb_cpus
; i
++) {
234 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
235 LTTV_STATE_UNNAMED
, &start_time
);
236 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
237 self
->running_process
[i
]->cpu
= i
;
241 nb_tracefile
= self
->parent
.tracefiles
->len
;
243 for(i
= 0 ; i
< nb_tracefile
; i
++) {
245 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
246 LttvTracefileContext
*, i
));
247 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
248 // tfcs->saved_position = 0;
249 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
250 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
251 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
252 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
257 //static LttTime time_zero = {0,0};
259 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
262 const LttTime
*t1
= (const LttTime
*)a
;
263 const LttTime
*t2
= (const LttTime
*)b
;
265 return ltt_time_compare(*t1
, *t2
);
268 static void free_usertrace_key(gpointer data
)
274 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
276 guint i
, j
, nb_trace
, nb_tracefile
;
278 LttvTraceContext
*tc
;
282 LttvTracefileState
*tfcs
;
284 LttvAttributeValue v
;
286 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
287 init((LttvTracesetContext
*)self
, ts
);
289 nb_trace
= lttv_traceset_number(ts
);
290 for(i
= 0 ; i
< nb_trace
; i
++) {
291 tc
= self
->parent
.traces
[i
];
292 tcs
= LTTV_TRACE_STATE(tc
);
293 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
294 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
298 if(*(v
.v_uint
) == 1) {
299 create_name_tables(tcs
);
300 create_max_time(tcs
);
302 get_name_tables(tcs
);
305 nb_tracefile
= tc
->tracefiles
->len
;
306 tcs
->processes
= NULL
;
307 tcs
->usertraces
= NULL
;
308 tcs
->running_process
= g_new(LttvProcessState
*,
309 ltt_trace_get_num_cpu(tc
->t
));
310 restore_init_state(tcs
);
311 for(j
= 0 ; j
< nb_tracefile
; j
++) {
313 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
314 LttvTracefileContext
*, j
));
315 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
316 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
318 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
319 /* It's a Usertrace */
320 LttvProcessState
*process
;
322 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
323 ltt_tracefile_creation(tfcs
->parent
.tf
));
324 process
= lttv_state_find_process_or_create(
326 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
328 process
->usertrace
= tfcs
;
332 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
333 /* It's a Usertrace */
334 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
335 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
337 if(!usertrace_tree
) {
338 usertrace_tree
= g_tree_new_full(compare_usertraces
,
339 NULL
, free_usertrace_key
, NULL
);
340 g_hash_table_insert(tcs
->usertraces
,
341 (gpointer
)tid
, usertrace_tree
);
343 LttTime
*timestamp
= g_new(LttTime
, 1);
344 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
345 ltt_tracefile_creation(tfcs
->parent
.tf
));
346 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
354 fini(LttvTracesetState
*self
)
360 LttvTracefileState
*tfcs
;
362 LttvAttributeValue v
;
364 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
365 for(i
= 0 ; i
< nb_trace
; i
++) {
366 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
367 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
370 g_assert(*(v
.v_uint
) != 0);
373 if(*(v
.v_uint
) == 0) {
374 free_name_tables(tcs
);
376 free_saved_state(tcs
);
378 g_free(tcs
->running_process
);
379 tcs
->running_process
= NULL
;
380 lttv_state_free_process_table(tcs
->processes
);
381 lttv_state_free_usertraces(tcs
->usertraces
);
382 tcs
->processes
= NULL
;
383 tcs
->usertraces
= NULL
;
385 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
386 fini((LttvTracesetContext
*)self
);
390 static LttvTracesetContext
*
391 new_traceset_context(LttvTracesetContext
*self
)
393 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
397 static LttvTraceContext
*
398 new_trace_context(LttvTracesetContext
*self
)
400 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
404 static LttvTracefileContext
*
405 new_tracefile_context(LttvTracesetContext
*self
)
407 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
411 /* Write the process state of the trace */
413 static void write_process_state(gpointer key
, gpointer value
,
416 LttvProcessState
*process
;
418 LttvExecutionState
*es
;
420 FILE *fp
= (FILE *)user_data
;
425 process
= (LttvProcessState
*)value
;
427 " <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",
428 process
, process
->pid
, process
->tgid
, process
->ppid
,
429 g_quark_to_string(process
->type
),
430 process
->creation_time
.tv_sec
,
431 process
->creation_time
.tv_nsec
,
432 process
->insertion_time
.tv_sec
,
433 process
->insertion_time
.tv_nsec
,
434 g_quark_to_string(process
->name
),
435 g_quark_to_string(process
->brand
),
438 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
439 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
440 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
441 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
442 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
443 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
444 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
447 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
448 address
= &g_array_index(process
->user_stack
, guint64
, i
);
449 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
453 if(process
->usertrace
) {
454 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
455 g_quark_to_string(process
->usertrace
->tracefile_name
),
456 process
->usertrace
->cpu
);
460 fprintf(fp
, " </PROCESS>\n");
464 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
466 guint i
, nb_tracefile
, nb_block
, offset
;
469 LttvTracefileState
*tfcs
;
473 LttEventPosition
*ep
;
477 ep
= ltt_event_position_new();
479 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
481 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
483 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
484 for(i
=0;i
<nb_cpus
;i
++) {
485 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
486 i
, self
->running_process
[i
]->pid
);
489 nb_tracefile
= self
->parent
.tracefiles
->len
;
491 for(i
= 0 ; i
< nb_tracefile
; i
++) {
493 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
494 LttvTracefileContext
*, i
));
495 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
496 tfcs
->parent
.timestamp
.tv_sec
,
497 tfcs
->parent
.timestamp
.tv_nsec
);
498 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
499 if(e
== NULL
) fprintf(fp
,"/>\n");
501 ltt_event_position(e
, ep
);
502 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
503 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
508 fprintf(fp
,"</PROCESS_STATE>\n");
512 static void write_process_state_raw(gpointer key
, gpointer value
,
515 LttvProcessState
*process
;
517 LttvExecutionState
*es
;
519 FILE *fp
= (FILE *)user_data
;
524 process
= (LttvProcessState
*)value
;
525 fputc(HDR_PROCESS
, fp
);
526 //fwrite(&header, sizeof(header), 1, fp);
527 //fprintf(fp, "%s", g_quark_to_string(process->type));
529 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
530 //fprintf(fp, "%s", g_quark_to_string(process->name));
532 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
533 //fprintf(fp, "%s", g_quark_to_string(process->brand));
535 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
536 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
537 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
538 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
539 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
540 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
541 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
545 " <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",
546 process
, process
->pid
, process
->tgid
, process
->ppid
,
547 g_quark_to_string(process
->type
),
548 process
->creation_time
.tv_sec
,
549 process
->creation_time
.tv_nsec
,
550 process
->insertion_time
.tv_sec
,
551 process
->insertion_time
.tv_nsec
,
552 g_quark_to_string(process
->name
),
553 g_quark_to_string(process
->brand
),
557 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
558 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
561 //fprintf(fp, "%s", g_quark_to_string(es->t));
563 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
564 //fprintf(fp, "%s", g_quark_to_string(es->n));
566 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
567 //fprintf(fp, "%s", g_quark_to_string(es->s));
569 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
570 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
571 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
573 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
574 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
575 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
576 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
577 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
581 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
582 address
= &g_array_index(process
->user_stack
, guint64
, i
);
583 fputc(HDR_USER_STACK
, fp
);
584 fwrite(&address
, sizeof(address
), 1, fp
);
586 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
591 if(process
->usertrace
) {
592 fputc(HDR_USERTRACE
, fp
);
593 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
595 fwrite(&process
->usertrace
->tracefile_name
,
596 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
597 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
599 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
600 g_quark_to_string(process
->usertrace
->tracefile_name
),
601 process
->usertrace
->cpu
);
608 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
610 guint i
, nb_tracefile
, nb_block
, offset
;
613 LttvTracefileState
*tfcs
;
617 LttEventPosition
*ep
;
621 ep
= ltt_event_position_new();
623 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
624 fputc(HDR_PROCESS_STATE
, fp
);
625 fwrite(&t
, sizeof(t
), 1, fp
);
627 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
629 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
630 for(i
=0;i
<nb_cpus
;i
++) {
632 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
633 fwrite(&self
->running_process
[i
]->pid
,
634 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
635 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
636 // i, self->running_process[i]->pid);
639 nb_tracefile
= self
->parent
.tracefiles
->len
;
641 for(i
= 0 ; i
< nb_tracefile
; i
++) {
643 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
644 LttvTracefileContext
*, i
));
645 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
646 // tfcs->parent.timestamp.tv_sec,
647 // tfcs->parent.timestamp.tv_nsec);
648 fputc(HDR_TRACEFILE
, fp
);
649 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
650 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
651 * position following : end of trace */
652 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
654 ltt_event_position(e
, ep
);
655 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
656 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
658 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
659 fwrite(&offset
, sizeof(offset
), 1, fp
);
660 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
667 /* Read process state from a file */
669 /* Called because a HDR_PROCESS was found */
670 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
)
672 LttvExecutionState
*es
;
673 LttvProcessState
*process
, *parent_process
;
674 LttvProcessState tmp
;
676 FILE *fp
= (FILE *)user_data
;
682 /* TOOD : check return value */
683 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
684 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
685 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
686 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
687 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
688 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
689 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
690 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
691 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
694 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
,
697 /* We must link to the parent */
698 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
700 process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.pid
,
703 process
->creation_time
= tmp
.creation_time
;
704 process
->type
= tmp
.type
;
705 process
->brand
= tmp
.brand
;
706 process
->tgid
= tmp
.tgid
;
707 process
->cpu
= tmp
.cpu
;
710 if(feof(fp
) || ferror(fp
)) goto end_loop
;
721 case HDR_PROCESS_STATE
:
733 /* Called because a HDR_PROCESS_STATE was found */
734 /* Append a saved state to the trace states */
735 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
)
737 guint i
, nb_tracefile
, nb_block
, offset
;
741 LttEventPosition
*ep
;
749 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
751 LttvAttributeValue value
;
752 ep
= ltt_event_position_new();
754 restore_init_state(self
);
756 fread(&t
, sizeof(t
), 1, fp
);
759 if(feof(fp
) || ferror(fp
)) goto end_loop
;
764 /* Call read_process_state_raw */
765 read_process_state_raw(self
, fp
);
775 case HDR_PROCESS_STATE
:
777 g_error("Error while parsing saved state file :"
778 " unexpected data header %d",
782 g_error("Error while parsing saved state file : unknown data header %d",
788 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
789 for(i
=0;i
<nb_cpus
;i
++) {
792 g_assert(hdr
== HDR_CPU
);
793 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
794 g_assert(i
== cpu_num
);
795 fread(&self
->running_process
[i
]->pid
,
796 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
799 nb_tracefile
= self
->parent
.tracefiles
->len
;
801 for(i
= 0 ; i
< nb_tracefile
; i
++) {
803 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
804 LttvTracefileContext
*, i
));
805 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
806 // tfcs->parent.timestamp.tv_sec,
807 // tfcs->parent.timestamp.tv_nsec);
809 g_assert(hdr
== HDR_TRACEFILE
);
810 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
811 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
812 * position following : end of trace */
813 if(ltt_time_compare(tfcs
->parent
.timestamp
, LTT_TIME_INFINITE
) != 0) {
814 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
815 fread(&offset
, sizeof(offset
), 1, fp
);
816 fread(&tsc
, sizeof(tsc
), 1, fp
);
817 ltt_event_position_set(ep
, tf
, nb_block
, offset
, tsc
);
818 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
823 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
824 LTTV_STATE_SAVED_STATES
);
825 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
826 value
= lttv_attribute_add(saved_states_tree
,
827 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
828 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
829 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
831 lttv_state_save(tcs
, saved_state_tree
);
832 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
833 self
->parent
.timestamp
.tv_nsec
);
835 *(self
->max_time_state_recomputed_in_seek
) = t
;
838 /* Called when a HDR_TRACE is found */
839 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
)
844 if(feof(fp
) || ferror(fp
)) goto end_loop
;
848 case HDR_PROCESS_STATE
:
849 /* Call read_process_state_raw */
850 lttv_state_read_raw(tcs
, fp
);
862 g_error("Error while parsing saved state file :"
863 " unexpected data header %d",
867 g_error("Error while parsing saved state file : unknown data header %d",
873 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
878 /* Copy each process from an existing hash table to a new one */
880 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
882 LttvProcessState
*process
, *new_process
;
884 GHashTable
*new_processes
= (GHashTable
*)user_data
;
888 process
= (LttvProcessState
*)value
;
889 new_process
= g_new(LttvProcessState
, 1);
890 *new_process
= *process
;
891 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
892 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
893 new_process
->execution_stack
=
894 g_array_set_size(new_process
->execution_stack
,
895 process
->execution_stack
->len
);
896 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
897 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
898 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
900 new_process
->state
= &g_array_index(new_process
->execution_stack
,
901 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
902 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
904 new_process
->user_stack
=
905 g_array_set_size(new_process
->user_stack
,
906 process
->user_stack
->len
);
907 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
908 g_array_index(new_process
->user_stack
, guint64
, i
) =
909 g_array_index(process
->user_stack
, guint64
, i
);
911 new_process
->current_function
= process
->current_function
;
912 g_hash_table_insert(new_processes
, new_process
, new_process
);
916 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
918 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
920 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
921 return new_processes
;
925 /* The saved state for each trace contains a member "processes", which
926 stores a copy of the process table, and a member "tracefiles" with
927 one entry per tracefile. Each tracefile has a "process" member pointing
928 to the current process and a "position" member storing the tracefile
929 position (needed to seek to the current "next" event. */
931 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
933 guint i
, nb_tracefile
, nb_cpus
;
935 LttvTracefileState
*tfcs
;
937 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
939 guint
*running_process
;
941 LttvAttributeType type
;
943 LttvAttributeValue value
;
945 LttvAttributeName name
;
947 LttEventPosition
*ep
;
949 tracefiles_tree
= lttv_attribute_find_subdir(container
,
950 LTTV_STATE_TRACEFILES
);
952 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
954 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
956 /* Add the currently running processes array */
957 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
958 running_process
= g_new(guint
, nb_cpus
);
959 for(i
=0;i
<nb_cpus
;i
++) {
960 running_process
[i
] = self
->running_process
[i
]->pid
;
962 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
964 *(value
.v_pointer
) = running_process
;
966 g_info("State save");
968 nb_tracefile
= self
->parent
.tracefiles
->len
;
970 for(i
= 0 ; i
< nb_tracefile
; i
++) {
972 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
973 LttvTracefileContext
*, i
));
974 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
975 value
= lttv_attribute_add(tracefiles_tree
, i
,
977 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
979 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
981 *(value
.v_uint
) = tfcs
->process
->pid
;
983 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
985 /* Only save the position if the tfs has not infinite time. */
986 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
987 // && current_tfcs != tfcs) {
988 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
989 *(value
.v_pointer
) = NULL
;
991 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
992 ep
= ltt_event_position_new();
993 ltt_event_position(e
, ep
);
994 *(value
.v_pointer
) = ep
;
996 guint nb_block
, offset
;
999 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1000 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1002 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1008 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1010 guint i
, nb_tracefile
, pid
, nb_cpus
;
1012 LttvTracefileState
*tfcs
;
1014 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1016 guint
*running_process
;
1018 LttvAttributeType type
;
1020 LttvAttributeValue value
;
1022 LttvAttributeName name
;
1026 LttEventPosition
*ep
;
1028 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1030 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1031 LTTV_STATE_TRACEFILES
);
1033 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1035 g_assert(type
== LTTV_POINTER
);
1036 lttv_state_free_process_table(self
->processes
);
1037 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1039 /* Add the currently running processes array */
1040 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1041 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1043 g_assert(type
== LTTV_POINTER
);
1044 running_process
= *(value
.v_pointer
);
1045 for(i
=0;i
<nb_cpus
;i
++) {
1046 pid
= running_process
[i
];
1047 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1048 g_assert(self
->running_process
[i
] != NULL
);
1052 nb_tracefile
= self
->parent
.tracefiles
->len
;
1054 //g_tree_destroy(tsc->pqueue);
1055 //tsc->pqueue = g_tree_new(compare_tracefile);
1057 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1059 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1060 LttvTracefileContext
*, i
));
1061 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1062 g_assert(type
== LTTV_GOBJECT
);
1063 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1065 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1067 g_assert(type
== LTTV_UINT
);
1068 pid
= *(value
.v_uint
);
1069 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1071 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1073 g_assert(type
== LTTV_POINTER
);
1074 //g_assert(*(value.v_pointer) != NULL);
1075 ep
= *(value
.v_pointer
);
1076 g_assert(tfcs
->parent
.t_context
!= NULL
);
1078 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1079 g_tree_remove(tsc
->pqueue
, tfc
);
1082 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1083 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1084 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1085 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1086 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1088 tfc
->timestamp
= ltt_time_infinite
;
1094 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1096 guint i
, nb_tracefile
, nb_cpus
;
1098 LttvTracefileState
*tfcs
;
1100 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1102 guint
*running_process
;
1104 LttvAttributeType type
;
1106 LttvAttributeValue value
;
1108 LttvAttributeName name
;
1112 LttEventPosition
*ep
;
1114 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1115 LTTV_STATE_TRACEFILES
);
1116 g_object_ref(G_OBJECT(tracefiles_tree
));
1117 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1119 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1121 g_assert(type
== LTTV_POINTER
);
1122 lttv_state_free_process_table(*(value
.v_pointer
));
1123 *(value
.v_pointer
) = NULL
;
1124 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1126 /* Free running processes array */
1127 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1128 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1130 g_assert(type
== LTTV_POINTER
);
1131 running_process
= *(value
.v_pointer
);
1132 g_free(running_process
);
1134 nb_tracefile
= self
->parent
.tracefiles
->len
;
1136 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1138 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1139 LttvTracefileContext
*, i
));
1140 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1141 g_assert(type
== LTTV_GOBJECT
);
1142 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1144 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1146 g_assert(type
== LTTV_POINTER
);
1147 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1149 g_object_unref(G_OBJECT(tracefiles_tree
));
1153 static void free_saved_state(LttvTraceState
*self
)
1157 LttvAttributeType type
;
1159 LttvAttributeValue value
;
1161 LttvAttributeName name
;
1165 LttvAttribute
*saved_states
;
1167 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1168 LTTV_STATE_SAVED_STATES
);
1170 nb
= lttv_attribute_get_number(saved_states
);
1171 for(i
= 0 ; i
< nb
; i
++) {
1172 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1173 g_assert(type
== LTTV_GOBJECT
);
1174 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1177 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1182 create_max_time(LttvTraceState
*tcs
)
1184 LttvAttributeValue v
;
1186 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1188 g_assert(*(v
.v_pointer
) == NULL
);
1189 *(v
.v_pointer
) = g_new(LttTime
,1);
1190 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1195 get_max_time(LttvTraceState
*tcs
)
1197 LttvAttributeValue v
;
1199 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1201 g_assert(*(v
.v_pointer
) != NULL
);
1202 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1207 free_max_time(LttvTraceState
*tcs
)
1209 LttvAttributeValue v
;
1211 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1213 g_free(*(v
.v_pointer
));
1214 *(v
.v_pointer
) = NULL
;
1218 typedef struct _LttvNameTables
{
1219 // FIXME GQuark *eventtype_names;
1220 GQuark
*syscall_names
;
1225 GQuark
*soft_irq_names
;
1230 create_name_tables(LttvTraceState
*tcs
)
1234 GQuark f_name
, e_name
;
1238 LttvTraceHookByFacility
*thf
;
1244 GString
*fe_name
= g_string_new("");
1246 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1248 LttvAttributeValue v
;
1250 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1252 g_assert(*(v
.v_pointer
) == NULL
);
1253 *(v
.v_pointer
) = name_tables
;
1254 #if 0 // Use iteration over the facilities_by_name and then list all event
1255 // types of each facility
1256 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1257 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1258 for(i
= 0 ; i
< nb
; i
++) {
1259 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1260 e_name
= ltt_eventtype_name(et
);
1261 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1262 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1263 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1266 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1267 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1268 LTT_FIELD_SYSCALL_ID
, 0, 0,
1271 thf
= lttv_trace_hook_get_first(&h
);
1273 t
= ltt_field_type(thf
->f1
);
1274 nb
= ltt_type_element_number(t
);
1276 lttv_trace_hook_destroy(&h
);
1278 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1279 name_tables
->nb_syscalls
= nb
;
1281 for(i
= 0 ; i
< nb
; i
++) {
1282 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1285 //name_tables->syscall_names = g_new(GQuark, 256);
1286 //for(i = 0 ; i < 256 ; i++) {
1287 // g_string_printf(fe_name, "syscall %d", i);
1288 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1291 name_tables
->syscall_names
= NULL
;
1292 name_tables
->nb_syscalls
= 0;
1295 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1296 LTT_EVENT_TRAP_ENTRY
,
1297 LTT_FIELD_TRAP_ID
, 0, 0,
1300 thf
= lttv_trace_hook_get_first(&h
);
1302 t
= ltt_field_type(thf
->f1
);
1303 //nb = ltt_type_element_number(t);
1305 lttv_trace_hook_destroy(&h
);
1308 name_tables->trap_names = g_new(GQuark, nb);
1309 for(i = 0 ; i < nb ; i++) {
1310 name_tables->trap_names[i] = g_quark_from_string(
1311 ltt_enum_string_get(t, i));
1314 name_tables
->nb_traps
= 256;
1315 name_tables
->trap_names
= g_new(GQuark
, 256);
1316 for(i
= 0 ; i
< 256 ; i
++) {
1317 g_string_printf(fe_name
, "trap %d", i
);
1318 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1321 name_tables
->trap_names
= NULL
;
1322 name_tables
->nb_traps
= 0;
1325 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1326 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1327 LTT_FIELD_IRQ_ID
, 0, 0,
1330 thf
= lttv_trace_hook_get_first(&h
);
1332 t
= ltt_field_type(thf
->f1
);
1333 //nb = ltt_type_element_number(t);
1335 lttv_trace_hook_destroy(&h
);
1338 name_tables->irq_names = g_new(GQuark, nb);
1339 for(i = 0 ; i < nb ; i++) {
1340 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1344 name_tables
->irq_names
= g_new(GQuark
, 256);
1345 for(i
= 0 ; i
< 256 ; i
++) {
1346 g_string_printf(fe_name
, "irq %d", i
);
1347 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1350 name_tables
->irq_names
= NULL
;
1353 name_tables->soft_irq_names = g_new(GQuark, nb);
1354 for(i = 0 ; i < nb ; i++) {
1355 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1359 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1360 for(i
= 0 ; i
< 256 ; i
++) {
1361 g_string_printf(fe_name
, "softirq %d", i
);
1362 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1366 g_string_free(fe_name
, TRUE
);
1371 get_name_tables(LttvTraceState
*tcs
)
1373 LttvNameTables
*name_tables
;
1375 LttvAttributeValue v
;
1377 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1379 g_assert(*(v
.v_pointer
) != NULL
);
1380 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1381 //tcs->eventtype_names = name_tables->eventtype_names;
1382 tcs
->syscall_names
= name_tables
->syscall_names
;
1383 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1384 tcs
->trap_names
= name_tables
->trap_names
;
1385 tcs
->nb_traps
= name_tables
->nb_traps
;
1386 tcs
->irq_names
= name_tables
->irq_names
;
1387 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1392 free_name_tables(LttvTraceState
*tcs
)
1394 LttvNameTables
*name_tables
;
1396 LttvAttributeValue v
;
1398 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1400 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1401 *(v
.v_pointer
) = NULL
;
1403 // g_free(name_tables->eventtype_names);
1404 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1405 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1406 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1407 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1408 if(name_tables
) g_free(name_tables
);
1411 #ifdef HASH_TABLE_DEBUG
1413 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1415 LttvProcessState
*process
= (LttvProcessState
*)value
;
1417 /* Test for process corruption */
1418 guint stack_len
= process
->execution_stack
->len
;
1421 static void hash_table_check(GHashTable
*table
)
1423 g_hash_table_foreach(table
, test_process
, NULL
);
1430 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1433 LttvExecutionState
*es
;
1435 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1436 guint cpu
= tfs
->cpu
;
1438 #ifdef HASH_TABLE_DEBUG
1439 hash_table_check(ts
->processes
);
1441 LttvProcessState
*process
= ts
->running_process
[cpu
];
1443 guint depth
= process
->execution_stack
->len
;
1445 process
->execution_stack
=
1446 g_array_set_size(process
->execution_stack
, depth
+ 1);
1449 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1451 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1454 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1455 es
->cum_cpu_time
= ltt_time_zero
;
1456 es
->s
= process
->state
->s
;
1457 process
->state
= es
;
1461 * return 1 when empty, else 0 */
1462 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1463 LttvTracefileState
*tfs
)
1465 guint cpu
= tfs
->cpu
;
1466 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1468 guint depth
= process
->execution_stack
->len
;
1474 process
->execution_stack
=
1475 g_array_set_size(process
->execution_stack
, depth
- 1);
1476 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1478 process
->state
->change
= tfs
->parent
.timestamp
;
1483 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1485 guint cpu
= tfs
->cpu
;
1486 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1487 LttvProcessState
*process
= ts
->running_process
[cpu
];
1489 guint depth
= process
->execution_stack
->len
;
1491 if(process
->state
->t
!= t
){
1492 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1493 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1494 g_info("process state has %s when pop_int is %s\n",
1495 g_quark_to_string(process
->state
->t
),
1496 g_quark_to_string(t
));
1497 g_info("{ %u, %u, %s, %s, %s }\n",
1500 g_quark_to_string(process
->name
),
1501 g_quark_to_string(process
->brand
),
1502 g_quark_to_string(process
->state
->s
));
1507 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1508 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1512 process
->execution_stack
=
1513 g_array_set_size(process
->execution_stack
, depth
- 1);
1514 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1516 process
->state
->change
= tfs
->parent
.timestamp
;
1519 struct search_result
{
1520 const LttTime
*time
; /* Requested time */
1521 LttTime
*best
; /* Best result */
1524 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1526 const LttTime
*elem_time
= (const LttTime
*)a
;
1527 /* Explicit non const cast */
1528 struct search_result
*res
= (struct search_result
*)b
;
1530 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1531 /* The usertrace was created before the schedchange */
1532 /* Get larger keys */
1534 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1535 /* The usertrace was created after the schedchange time */
1536 /* Get smaller keys */
1538 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1539 res
->best
= elem_time
;
1542 res
->best
= elem_time
;
1549 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1550 guint pid
, const LttTime
*timestamp
)
1552 LttvTracefileState
*tfs
= NULL
;
1553 struct search_result res
;
1554 /* Find the usertrace associated with a pid and time interval.
1555 * Search in the usertraces by PID (within a hash) and then, for each
1556 * corresponding element of the array, find the first one with creation
1557 * timestamp the lowest, but higher or equal to "timestamp". */
1558 res
.time
= timestamp
;
1560 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1561 if(usertrace_tree
) {
1562 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1564 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1572 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1573 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1575 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1577 LttvExecutionState
*es
;
1579 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1584 process
->tgid
= tgid
;
1586 process
->name
= name
;
1587 process
->brand
= LTTV_STATE_UNBRANDED
;
1588 //process->last_cpu = tfs->cpu_name;
1589 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1590 process
->type
= LTTV_STATE_USER_THREAD
;
1591 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1592 process
->current_function
= 0; //function 0x0 by default.
1594 g_info("Process %u, core %p", process
->pid
, process
);
1595 g_hash_table_insert(tcs
->processes
, process
, process
);
1598 process
->ppid
= parent
->pid
;
1599 process
->creation_time
= *timestamp
;
1602 /* No parent. This process exists but we are missing all information about
1603 its creation. The birth time is set to zero but we remember the time of
1608 process
->creation_time
= ltt_time_zero
;
1611 process
->insertion_time
= *timestamp
;
1612 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1613 process
->creation_time
.tv_nsec
);
1614 process
->pid_time
= g_quark_from_string(buffer
);
1616 //process->last_cpu = tfs->cpu_name;
1617 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1618 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1619 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1620 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1621 es
= process
->state
= &g_array_index(process
->execution_stack
,
1622 LttvExecutionState
, 0);
1623 es
->t
= LTTV_STATE_USER_MODE
;
1624 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1625 es
->entry
= *timestamp
;
1626 //g_assert(timestamp->tv_sec != 0);
1627 es
->change
= *timestamp
;
1628 es
->cum_cpu_time
= ltt_time_zero
;
1629 es
->s
= LTTV_STATE_RUN
;
1631 es
= process
->state
= &g_array_index(process
->execution_stack
,
1632 LttvExecutionState
, 1);
1633 es
->t
= LTTV_STATE_SYSCALL
;
1634 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1635 es
->entry
= *timestamp
;
1636 //g_assert(timestamp->tv_sec != 0);
1637 es
->change
= *timestamp
;
1638 es
->cum_cpu_time
= ltt_time_zero
;
1639 es
->s
= LTTV_STATE_WAIT_FORK
;
1641 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1642 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1643 sizeof(guint64
), 0);
1648 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1651 LttvProcessState key
;
1652 LttvProcessState
*process
;
1656 process
= g_hash_table_lookup(ts
->processes
, &key
);
1661 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1664 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1665 LttvExecutionState
*es
;
1667 /* Put ltt_time_zero creation time for unexisting processes */
1668 if(unlikely(process
== NULL
)) {
1669 process
= lttv_state_create_process(ts
,
1670 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1671 /* We are not sure is it's a kernel thread or normal thread, put the
1672 * bottom stack state to unknown */
1673 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1674 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1679 /* FIXME : this function should be called when we receive an event telling that
1680 * release_task has been called in the kernel. In happens generally when
1681 * the parent waits for its child terminaison, but may also happen in special
1682 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1683 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1684 * of a killed thread ground, but isn't the leader.
1686 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1688 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1689 LttvProcessState key
;
1691 key
.pid
= process
->pid
;
1692 key
.cpu
= process
->cpu
;
1693 g_hash_table_remove(ts
->processes
, &key
);
1694 g_array_free(process
->execution_stack
, TRUE
);
1695 g_array_free(process
->user_stack
, TRUE
);
1700 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1702 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1703 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1708 static void lttv_state_free_process_table(GHashTable
*processes
)
1710 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1711 g_hash_table_destroy(processes
);
1715 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1717 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1718 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1719 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1720 LttField
*f
= thf
->f1
;
1722 LttvExecutionSubmode submode
;
1724 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1725 guint syscall
= ltt_event_get_unsigned(e
, f
);
1727 if(syscall
< nb_syscalls
) {
1728 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1731 /* Fixup an incomplete syscall table */
1732 GString
*string
= g_string_new("");
1733 g_string_printf(string
, "syscall %u", syscall
);
1734 submode
= g_quark_from_string(string
->str
);
1735 g_string_free(string
, TRUE
);
1737 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1742 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1744 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1746 pop_state(s
, LTTV_STATE_SYSCALL
);
1751 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1753 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1754 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1755 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1756 LttField
*f
= thf
->f1
;
1758 LttvExecutionSubmode submode
;
1760 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1761 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1763 if(trap
< nb_traps
) {
1764 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1766 /* Fixup an incomplete trap table */
1767 GString
*string
= g_string_new("");
1768 g_string_printf(string
, "trap %llu", trap
);
1769 submode
= g_quark_from_string(string
->str
);
1770 g_string_free(string
, TRUE
);
1773 push_state(s
, LTTV_STATE_TRAP
, submode
);
1778 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1780 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1782 pop_state(s
, LTTV_STATE_TRAP
);
1787 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1789 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1790 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1791 guint8 fac_id
= ltt_event_facility_id(e
);
1792 guint8 ev_id
= ltt_event_eventtype_id(e
);
1793 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1794 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1795 g_assert(thf
->f1
!= NULL
);
1796 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1797 LttField
*f
= thf
->f1
;
1799 LttvExecutionSubmode submode
;
1801 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1802 ltt_event_get_unsigned(e
, f
)];
1804 /* Do something with the info about being in user or system mode when int? */
1805 push_state(s
, LTTV_STATE_IRQ
, submode
);
1809 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1811 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1813 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1819 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1821 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1823 pop_state(s
, LTTV_STATE_IRQ
);
1827 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1829 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1830 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1831 guint8 fac_id
= ltt_event_facility_id(e
);
1832 guint8 ev_id
= ltt_event_eventtype_id(e
);
1833 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1834 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1835 g_assert(thf
->f1
!= NULL
);
1836 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1837 LttField
*f
= thf
->f1
;
1839 LttvExecutionSubmode submode
;
1841 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1842 ltt_event_get_long_unsigned(e
, f
)];
1844 /* Do something with the info about being in user or system mode when int? */
1845 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1849 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1853 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1854 guint cpu
= tfs
->cpu
;
1855 LttvProcessState
*process
= ts
->running_process
[cpu
];
1857 guint depth
= process
->user_stack
->len
;
1859 process
->user_stack
=
1860 g_array_set_size(process
->user_stack
, depth
+ 1);
1862 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1863 *new_func
= funcptr
;
1864 process
->current_function
= funcptr
;
1867 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1869 guint cpu
= tfs
->cpu
;
1870 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1871 LttvProcessState
*process
= ts
->running_process
[cpu
];
1873 if(process
->current_function
!= funcptr
){
1874 g_info("Different functions (%lu.%09lu): ignore it\n",
1875 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1876 g_info("process state has %llu when pop_function is %llu\n",
1877 process
->current_function
, funcptr
);
1878 g_info("{ %u, %u, %s, %s, %s }\n",
1881 g_quark_to_string(process
->name
),
1882 g_quark_to_string(process
->brand
),
1883 g_quark_to_string(process
->state
->s
));
1886 guint depth
= process
->user_stack
->len
;
1889 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1890 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1894 process
->user_stack
=
1895 g_array_set_size(process
->user_stack
, depth
- 1);
1896 process
->current_function
=
1897 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1901 static gboolean
function_entry(void *hook_data
, void *call_data
)
1903 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1904 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1905 guint8 fac_id
= ltt_event_facility_id(e
);
1906 guint8 ev_id
= ltt_event_eventtype_id(e
);
1907 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1908 g_assert(thf
->f1
!= NULL
);
1909 LttField
*f
= thf
->f1
;
1910 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1912 push_function(s
, funcptr
);
1916 static gboolean
function_exit(void *hook_data
, void *call_data
)
1918 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1919 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1920 guint8 fac_id
= ltt_event_facility_id(e
);
1921 guint8 ev_id
= ltt_event_eventtype_id(e
);
1922 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1923 g_assert(thf
->f1
!= NULL
);
1924 LttField
*f
= thf
->f1
;
1925 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1927 LttvExecutionSubmode submode
;
1929 pop_function(s
, funcptr
);
1933 static gboolean
schedchange(void *hook_data
, void *call_data
)
1935 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1937 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1938 LttvProcessState
*process
= ts
->running_process
[cpu
];
1939 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1941 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1942 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1943 guint pid_in
, pid_out
;
1946 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1947 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1948 state_out
= ltt_event_get_int(e
, thf
->f3
);
1950 if(likely(process
!= NULL
)) {
1952 /* We could not know but it was not the idle process executing.
1953 This should only happen at the beginning, before the first schedule
1954 event, and when the initial information (current process for each CPU)
1955 is missing. It is not obvious how we could, after the fact, compensate
1956 the wrongly attributed statistics. */
1958 //This test only makes sense once the state is known and if there is no
1959 //missing events. We need to silently ignore schedchange coming after a
1960 //process_free, or it causes glitches. (FIXME)
1961 //if(unlikely(process->pid != pid_out)) {
1962 // g_assert(process->pid == 0);
1965 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1966 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1967 process
->state
->change
= s
->parent
.timestamp
;
1969 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1970 else process
->state
->s
= LTTV_STATE_WAIT
;
1971 process
->state
->change
= s
->parent
.timestamp
;
1975 exit_process(s
, process
); /* EXIT_DEAD */
1976 /* see sched.h for states */
1978 process
= ts
->running_process
[cpu
] =
1979 lttv_state_find_process_or_create(
1980 (LttvTraceState
*)s
->parent
.t_context
,
1982 &s
->parent
.timestamp
);
1983 process
->state
->s
= LTTV_STATE_RUN
;
1985 if(process
->usertrace
)
1986 process
->usertrace
->cpu
= cpu
;
1987 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1988 process
->state
->change
= s
->parent
.timestamp
;
1992 static gboolean
process_fork(void *hook_data
, void *call_data
)
1994 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1995 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1996 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1998 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
1999 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2000 LttvProcessState
*zombie_process
;
2002 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2003 LttvProcessState
*process
= ts
->running_process
[cpu
];
2004 LttvProcessState
*child_process
;
2007 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2010 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2011 s
->parent
.target_pid
= child_pid
;
2014 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2015 else child_tgid
= 0;
2017 /* Mathieu : it seems like the process might have been scheduled in before the
2018 * fork, and, in a rare case, might be the current process. This might happen
2019 * in a SMP case where we don't have enough precision on the clocks.
2021 * Test reenabled after precision fixes on time. (Mathieu) */
2023 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2025 if(unlikely(zombie_process
!= NULL
)) {
2026 /* Reutilisation of PID. Only now we are sure that the old PID
2027 * has been released. FIXME : should know when release_task happens instead.
2029 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2031 for(i
=0; i
< num_cpus
; i
++) {
2032 g_assert(zombie_process
!= ts
->running_process
[i
]);
2035 exit_process(s
, zombie_process
);
2038 g_assert(process
->pid
!= child_pid
);
2039 // FIXME : Add this test in the "known state" section
2040 // g_assert(process->pid == parent_pid);
2041 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2042 if(child_process
== NULL
) {
2043 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2044 child_pid
, child_tgid
,
2045 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2047 /* The process has already been created : due to time imprecision between
2048 * multiple CPUs : it has been scheduled in before creation. Note that we
2049 * shouldn't have this kind of imprecision.
2051 * Simply put a correct parent.
2053 g_assert(0); /* This is a problematic case : the process has been created
2054 before the fork event */
2055 child_process
->ppid
= process
->pid
;
2056 child_process
->tgid
= child_tgid
;
2058 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2059 child_process
->name
= process
->name
;
2060 child_process
->brand
= process
->brand
;
2065 /* We stamp a newly created process as kernel_thread */
2066 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2068 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2069 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2070 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2073 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2074 LttvProcessState
*process
;
2075 LttvExecutionState
*es
;
2078 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2079 s
->parent
.target_pid
= pid
;
2081 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2082 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2083 es
->t
= LTTV_STATE_SYSCALL
;
2084 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2089 static gboolean
process_exit(void *hook_data
, void *call_data
)
2091 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2092 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2093 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2097 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2098 LttvProcessState
*process
; // = ts->running_process[cpu];
2100 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2101 s
->parent
.target_pid
= pid
;
2103 // FIXME : Add this test in the "known state" section
2104 // g_assert(process->pid == pid);
2106 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2107 if(likely(process
!= NULL
)) {
2108 process
->state
->s
= LTTV_STATE_EXIT
;
2113 static gboolean
process_free(void *hook_data
, void *call_data
)
2115 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2116 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2117 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2118 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2120 LttvProcessState
*process
;
2122 /* PID of the process to release */
2123 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2124 s
->parent
.target_pid
= release_pid
;
2126 g_assert(release_pid
!= 0);
2128 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2130 if(likely(process
!= NULL
)) {
2131 /* release_task is happening at kernel level : we can now safely release
2132 * the data structure of the process */
2133 //This test is fun, though, as it may happen that
2134 //at time t : CPU 0 : process_free
2135 //at time t+150ns : CPU 1 : schedule out
2136 //Clearly due to time imprecision, we disable it. (Mathieu)
2137 //If this weird case happen, we have no choice but to put the
2138 //Currently running process on the cpu to 0.
2139 //I re-enable it following time precision fixes. (Mathieu)
2140 //Well, in the case where an process is freed by a process on another CPU
2141 //and still scheduled, it happens that this is the schedchange that will
2142 //drop the last reference count. Do not free it here!
2143 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2145 for(i
=0; i
< num_cpus
; i
++) {
2146 //g_assert(process != ts->running_process[i]);
2147 if(process
== ts
->running_process
[i
]) {
2148 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2152 if(i
== num_cpus
) /* process is not scheduled */
2153 exit_process(s
, process
);
2160 static gboolean
process_exec(void *hook_data
, void *call_data
)
2162 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2163 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2164 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2165 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2168 LttvProcessState
*process
= ts
->running_process
[cpu
];
2170 /* PID of the process to release */
2171 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2172 //name = ltt_event_get_string(e, thf->f1);
2173 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2175 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2176 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2177 memcpy(null_term_name
, name_begin
, name_len
);
2178 null_term_name
[name_len
] = '\0';
2180 process
->name
= g_quark_from_string(null_term_name
);
2181 process
->brand
= LTTV_STATE_UNBRANDED
;
2182 g_free(null_term_name
);
2186 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2188 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2189 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2190 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2191 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2194 LttvProcessState
*process
= ts
->running_process
[cpu
];
2196 name
= ltt_event_get_string(e
, thf
->f1
);
2197 process
->brand
= g_quark_from_string(name
);
2202 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2204 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2205 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2206 //It's slow : optimise later by doing this before reading trace.
2207 LttEventType
*et
= ltt_event_eventtype(e
);
2209 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2215 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2216 LttvProcessState
*process
= ts
->running_process
[cpu
];
2217 LttvProcessState
*parent_process
;
2218 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2219 GQuark type
, mode
, submode
, status
;
2220 LttvExecutionState
*es
;
2223 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2224 s
->parent
.target_pid
= pid
;
2227 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2230 command
= ltt_event_get_string(e
, thf
->f3
);
2233 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2234 type
= ltt_enum_string_get(ltt_field_type(f4
),
2235 ltt_event_get_unsigned(e
, f4
));
2238 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2239 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2240 ltt_event_get_unsigned(e
, f5
));
2243 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2244 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2245 ltt_event_get_unsigned(e
, f6
));
2248 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2249 status
= ltt_enum_string_get(ltt_field_type(f7
),
2250 ltt_event_get_unsigned(e
, f7
));
2253 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2254 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2257 /* The process might exist if a process was forked while performing the state
2259 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2260 if(process
== NULL
) {
2261 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2262 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2263 pid
, tgid
, g_quark_from_string(command
),
2264 &s
->parent
.timestamp
);
2266 /* Keep the stack bottom : a running user mode */
2267 /* Disabled because of inconsistencies in the current statedump states. */
2268 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2269 /* Only keep the bottom */
2270 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2271 es
= process
->state
= &g_array_index(process
->execution_stack
,
2272 LttvExecutionState
, 0);
2273 es
->t
= LTTV_STATE_SYSCALL
;
2277 /* On top of it : */
2278 es
= process
->state
= &g_array_index(process
->execution_stack
,
2279 LttvExecutionState
, 1);
2280 es
->t
= LTTV_STATE_USER_MODE
;
2287 es
= process
->state
= &g_array_index(process
->execution_stack
,
2288 LttvExecutionState
, 1);
2289 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2290 es
->s
= LTTV_STATE_UNNAMED
;
2291 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2295 /* The process has already been created :
2296 * Probably was forked while dumping the process state or
2297 * was simply scheduled in prior to get the state dump event.
2298 * We know for sure if it is a user space thread.
2300 process
->ppid
= parent_pid
;
2301 process
->tgid
= tgid
;
2302 process
->name
= g_quark_from_string(command
);
2303 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2304 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2305 es
->t
= LTTV_STATE_USER_MODE
;
2306 /* Don't mess around with the stack, it will eventually become
2307 * ok after the end of state dump. */
2313 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2315 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2317 lttv_state_add_event_hooks(tss
);
2322 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2324 LttvTraceset
*traceset
= self
->parent
.ts
;
2326 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2330 LttvTracefileState
*tfs
;
2334 LttvTraceHookByFacility
*thf
;
2336 LttvTraceHook
*hook
;
2338 LttvAttributeValue val
;
2343 nb_trace
= lttv_traceset_number(traceset
);
2344 for(i
= 0 ; i
< nb_trace
; i
++) {
2345 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2347 /* Find the eventtype id for the following events and register the
2348 associated by id hooks. */
2350 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
2351 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
2354 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2355 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2356 LTT_FIELD_SYSCALL_ID
, 0, 0,
2357 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2360 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2361 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2363 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2366 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2367 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2368 LTT_FIELD_TRAP_ID
, 0, 0,
2369 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2372 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2373 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2375 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2378 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2379 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2380 LTT_FIELD_IRQ_ID
, 0, 0,
2381 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2384 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2385 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2387 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2390 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2391 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2392 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2393 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2396 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2397 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2399 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2402 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2403 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2404 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2405 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2408 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2409 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2410 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2411 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2414 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2415 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2416 LTT_FIELD_PID
, 0, 0,
2417 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2421 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2422 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2423 LTT_FIELD_PID
, 0, 0,
2424 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2427 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2428 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2429 LTT_FIELD_PID
, 0, 0,
2430 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2433 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2434 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2435 LTT_FIELD_FILENAME
, 0, 0,
2436 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2439 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2440 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2441 LTT_FIELD_NAME
, 0, 0,
2442 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2445 /* statedump-related hooks */
2446 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2447 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2448 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2449 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2452 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2453 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2454 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2455 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2458 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2459 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2460 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2461 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2464 hooks
= g_array_set_size(hooks
, hn
);
2466 /* Add these hooks to each event_by_id hooks list */
2468 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2470 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2472 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2473 LttvTracefileContext
*, j
));
2475 for(k
= 0 ; k
< hooks
->len
; k
++) {
2476 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2477 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2478 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2480 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2487 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2488 *(val
.v_pointer
) = hooks
;
2492 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2494 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2496 lttv_state_remove_event_hooks(tss
);
2501 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2503 LttvTraceset
*traceset
= self
->parent
.ts
;
2505 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2509 LttvTracefileState
*tfs
;
2513 LttvTraceHook
*hook
;
2515 LttvTraceHookByFacility
*thf
;
2517 LttvAttributeValue val
;
2519 nb_trace
= lttv_traceset_number(traceset
);
2520 for(i
= 0 ; i
< nb_trace
; i
++) {
2521 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2522 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2523 hooks
= *(val
.v_pointer
);
2525 /* Remove these hooks from each event_by_id hooks list */
2527 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2529 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2531 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2532 LttvTracefileContext
*, j
));
2534 for(k
= 0 ; k
< hooks
->len
; k
++) {
2535 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2536 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2537 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2539 lttv_hooks_remove_data(
2540 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2546 for(k
= 0 ; k
< hooks
->len
; k
++)
2547 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2548 g_array_free(hooks
, TRUE
);
2552 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2554 guint
*event_count
= (guint
*)hook_data
;
2556 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2557 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2562 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2564 LttvTracefileState
*tfcs
;
2566 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2568 LttEventPosition
*ep
;
2574 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2576 LttvAttributeValue value
;
2578 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2579 LTTV_STATE_SAVED_STATES
);
2580 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2581 value
= lttv_attribute_add(saved_states_tree
,
2582 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2583 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2584 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2585 *(value
.v_time
) = self
->parent
.timestamp
;
2586 lttv_state_save(tcs
, saved_state_tree
);
2587 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2588 self
->parent
.timestamp
.tv_nsec
);
2590 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2595 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2597 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2599 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2604 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2612 static gboolean
block_start(void *hook_data
, void *call_data
)
2614 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2616 LttvTracefileState
*tfcs
;
2618 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2620 LttEventPosition
*ep
;
2622 guint i
, nb_block
, nb_event
, nb_tracefile
;
2626 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2628 LttvAttributeValue value
;
2630 ep
= ltt_event_position_new();
2632 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2634 /* Count the number of events added since the last block end in any
2637 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2639 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2640 LttvTracefileContext
, i
));
2641 ltt_event_position(tfcs
->parent
.e
, ep
);
2642 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2643 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2644 tfcs
->saved_position
= nb_event
;
2648 if(tcs
->nb_event
>= tcs
->save_interval
) {
2649 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2650 LTTV_STATE_SAVED_STATES
);
2651 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2652 value
= lttv_attribute_add(saved_states_tree
,
2653 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2654 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2655 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2656 *(value
.v_time
) = self
->parent
.timestamp
;
2657 lttv_state_save(tcs
, saved_state_tree
);
2659 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2660 self
->parent
.timestamp
.tv_nsec
);
2662 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2668 static gboolean
block_end(void *hook_data
, void *call_data
)
2670 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2672 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2676 LttEventPosition
*ep
;
2678 guint nb_block
, nb_event
;
2680 ep
= ltt_event_position_new();
2681 ltt_event_position(self
->parent
.e
, ep
);
2682 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2683 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2684 self
->saved_position
= 0;
2685 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2692 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2694 LttvTraceset
*traceset
= self
->parent
.ts
;
2696 guint i
, j
, nb_trace
, nb_tracefile
;
2700 LttvTracefileState
*tfs
;
2702 LttvTraceHook hook_start
, hook_end
;
2704 nb_trace
= lttv_traceset_number(traceset
);
2705 for(i
= 0 ; i
< nb_trace
; i
++) {
2706 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2708 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2709 NULL
, NULL
, block_start
, &hook_start
);
2710 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2711 NULL
, NULL
, block_end
, &hook_end
);
2713 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2715 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2717 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2718 LttvTracefileContext
, j
));
2719 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2720 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2721 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2722 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2728 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2730 LttvTraceset
*traceset
= self
->parent
.ts
;
2732 guint i
, j
, nb_trace
, nb_tracefile
;
2736 LttvTracefileState
*tfs
;
2739 nb_trace
= lttv_traceset_number(traceset
);
2740 for(i
= 0 ; i
< nb_trace
; i
++) {
2742 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2743 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2745 guint
*event_count
= g_new(guint
, 1);
2748 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2750 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2751 LttvTracefileContext
*, j
));
2752 lttv_hooks_add(tfs
->parent
.event
,
2753 state_save_event_hook
,
2760 lttv_process_traceset_begin(&self
->parent
,
2761 NULL
, NULL
, NULL
, NULL
, NULL
);
2765 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2767 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2769 lttv_state_save_add_event_hooks(tss
);
2776 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2778 LttvTraceset
*traceset
= self
->parent
.ts
;
2780 guint i
, j
, nb_trace
, nb_tracefile
;
2784 LttvTracefileState
*tfs
;
2786 LttvTraceHook hook_start
, hook_end
;
2788 nb_trace
= lttv_traceset_number(traceset
);
2789 for(i
= 0 ; i
< nb_trace
; i
++) {
2790 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2792 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2793 NULL
, NULL
, block_start
, &hook_start
);
2795 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2796 NULL
, NULL
, block_end
, &hook_end
);
2798 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2800 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2802 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2803 LttvTracefileContext
, j
));
2804 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2805 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2806 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2807 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2813 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2815 LttvTraceset
*traceset
= self
->parent
.ts
;
2817 guint i
, j
, nb_trace
, nb_tracefile
;
2821 LttvTracefileState
*tfs
;
2823 LttvHooks
*after_trace
= lttv_hooks_new();
2825 lttv_hooks_add(after_trace
,
2826 state_save_after_trace_hook
,
2831 lttv_process_traceset_end(&self
->parent
,
2832 NULL
, after_trace
, NULL
, NULL
, NULL
);
2834 lttv_hooks_destroy(after_trace
);
2836 nb_trace
= lttv_traceset_number(traceset
);
2837 for(i
= 0 ; i
< nb_trace
; i
++) {
2839 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2840 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2842 guint
*event_count
= NULL
;
2844 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2846 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2847 LttvTracefileContext
*, j
));
2848 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2849 state_save_event_hook
);
2851 if(event_count
) g_free(event_count
);
2855 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2857 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2859 lttv_state_save_remove_event_hooks(tss
);
2864 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2866 LttvTraceset
*traceset
= self
->parent
.ts
;
2870 int min_pos
, mid_pos
, max_pos
;
2872 guint call_rest
= 0;
2874 LttvTraceState
*tcs
;
2876 LttvAttributeValue value
;
2878 LttvAttributeType type
;
2880 LttvAttributeName name
;
2884 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2886 //g_tree_destroy(self->parent.pqueue);
2887 //self->parent.pqueue = g_tree_new(compare_tracefile);
2889 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2891 nb_trace
= lttv_traceset_number(traceset
);
2892 for(i
= 0 ; i
< nb_trace
; i
++) {
2893 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2895 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2896 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2897 LTTV_STATE_SAVED_STATES
);
2900 if(saved_states_tree
) {
2901 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2902 mid_pos
= max_pos
/ 2;
2903 while(min_pos
< max_pos
) {
2904 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2906 g_assert(type
== LTTV_GOBJECT
);
2907 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2908 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2910 g_assert(type
== LTTV_TIME
);
2911 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2913 closest_tree
= saved_state_tree
;
2915 else max_pos
= mid_pos
- 1;
2917 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2921 /* restore the closest earlier saved state */
2923 lttv_state_restore(tcs
, closest_tree
);
2927 /* There is no saved state, yet we want to have it. Restart at T0 */
2929 restore_init_state(tcs
);
2930 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2933 /* We want to seek quickly without restoring/updating the state */
2935 restore_init_state(tcs
);
2936 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2939 if(!call_rest
) g_info("NOT Calling restore");
2944 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2950 traceset_state_finalize (LttvTracesetState
*self
)
2952 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2953 finalize(G_OBJECT(self
));
2958 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2960 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2962 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2963 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2964 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2965 klass
->new_traceset_context
= new_traceset_context
;
2966 klass
->new_trace_context
= new_trace_context
;
2967 klass
->new_tracefile_context
= new_tracefile_context
;
2972 lttv_traceset_state_get_type(void)
2974 static GType type
= 0;
2976 static const GTypeInfo info
= {
2977 sizeof (LttvTracesetStateClass
),
2978 NULL
, /* base_init */
2979 NULL
, /* base_finalize */
2980 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2981 NULL
, /* class_finalize */
2982 NULL
, /* class_data */
2983 sizeof (LttvTracesetState
),
2984 0, /* n_preallocs */
2985 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2986 NULL
/* value handling */
2989 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2997 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3003 trace_state_finalize (LttvTraceState
*self
)
3005 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3006 finalize(G_OBJECT(self
));
3011 trace_state_class_init (LttvTraceStateClass
*klass
)
3013 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3015 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3016 klass
->state_save
= state_save
;
3017 klass
->state_restore
= state_restore
;
3018 klass
->state_saved_free
= state_saved_free
;
3023 lttv_trace_state_get_type(void)
3025 static GType type
= 0;
3027 static const GTypeInfo info
= {
3028 sizeof (LttvTraceStateClass
),
3029 NULL
, /* base_init */
3030 NULL
, /* base_finalize */
3031 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3032 NULL
, /* class_finalize */
3033 NULL
, /* class_data */
3034 sizeof (LttvTraceState
),
3035 0, /* n_preallocs */
3036 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3037 NULL
/* value handling */
3040 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3041 "LttvTraceStateType", &info
, 0);
3048 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3054 tracefile_state_finalize (LttvTracefileState
*self
)
3056 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3057 finalize(G_OBJECT(self
));
3062 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3064 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3066 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3071 lttv_tracefile_state_get_type(void)
3073 static GType type
= 0;
3075 static const GTypeInfo info
= {
3076 sizeof (LttvTracefileStateClass
),
3077 NULL
, /* base_init */
3078 NULL
, /* base_finalize */
3079 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3080 NULL
, /* class_finalize */
3081 NULL
, /* class_data */
3082 sizeof (LttvTracefileState
),
3083 0, /* n_preallocs */
3084 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3085 NULL
/* value handling */
3088 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3089 "LttvTracefileStateType", &info
, 0);
3095 static void module_init()
3097 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3098 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3099 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3100 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3101 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3102 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3103 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3104 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3105 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3106 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3107 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3108 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3109 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3110 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3111 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3112 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3113 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3114 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3115 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3116 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3117 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3118 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3119 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3120 LTTV_STATE_EVENT
= g_quark_from_string("event");
3121 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3122 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3123 LTTV_STATE_TIME
= g_quark_from_string("time");
3124 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3125 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3126 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3127 g_quark_from_string("trace_state_use_count");
3130 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3131 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3132 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3133 LTT_FACILITY_FS
= g_quark_from_string("fs");
3134 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3135 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3138 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3139 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3140 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3141 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3142 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3143 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3144 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3145 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3146 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3147 LTT_EVENT_FORK
= g_quark_from_string("fork");
3148 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3149 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3150 LTT_EVENT_FREE
= g_quark_from_string("free");
3151 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3152 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3153 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3154 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3155 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3158 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3159 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3160 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3161 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3162 LTT_FIELD_OUT
= g_quark_from_string("out");
3163 LTT_FIELD_IN
= g_quark_from_string("in");
3164 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3165 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3166 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3167 LTT_FIELD_PID
= g_quark_from_string("pid");
3168 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3169 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3170 LTT_FIELD_NAME
= g_quark_from_string("name");
3171 LTT_FIELD_TYPE
= g_quark_from_string("type");
3172 LTT_FIELD_MODE
= g_quark_from_string("mode");
3173 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3174 LTT_FIELD_STATUS
= g_quark_from_string("status");
3175 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3176 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3180 static void module_destroy()
3185 LTTV_MODULE("state", "State computation", \
3186 "Update the system state, possibly saving it at intervals", \
3187 module_init
, module_destroy
)