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 LttvExecutionState
*es
;
235 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
236 LTTV_STATE_UNNAMED
, &start_time
);
237 /* We are not sure is it's a kernel thread or normal thread, put the
238 * bottom stack state to unknown */
239 self
->running_process
[i
]->execution_stack
=
240 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
241 es
= self
->running_process
[i
]->state
=
242 &g_array_index(self
->running_process
[i
]->execution_stack
,
243 LttvExecutionState
, 0);
244 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
246 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
247 self
->running_process
[i
]->cpu
= i
;
251 nb_tracefile
= self
->parent
.tracefiles
->len
;
253 for(i
= 0 ; i
< nb_tracefile
; i
++) {
255 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
256 LttvTracefileContext
*, i
));
257 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
258 // tfcs->saved_position = 0;
259 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
260 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
261 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
262 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
267 //static LttTime time_zero = {0,0};
269 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
272 const LttTime
*t1
= (const LttTime
*)a
;
273 const LttTime
*t2
= (const LttTime
*)b
;
275 return ltt_time_compare(*t1
, *t2
);
278 static void free_usertrace_key(gpointer data
)
284 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
286 guint i
, j
, nb_trace
, nb_tracefile
;
288 LttvTraceContext
*tc
;
292 LttvTracefileState
*tfcs
;
294 LttvAttributeValue v
;
296 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
297 init((LttvTracesetContext
*)self
, ts
);
299 nb_trace
= lttv_traceset_number(ts
);
300 for(i
= 0 ; i
< nb_trace
; i
++) {
301 tc
= self
->parent
.traces
[i
];
302 tcs
= LTTV_TRACE_STATE(tc
);
303 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
304 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
308 if(*(v
.v_uint
) == 1) {
309 create_name_tables(tcs
);
310 create_max_time(tcs
);
312 get_name_tables(tcs
);
315 nb_tracefile
= tc
->tracefiles
->len
;
316 tcs
->processes
= NULL
;
317 tcs
->usertraces
= NULL
;
318 tcs
->running_process
= g_new(LttvProcessState
*,
319 ltt_trace_get_num_cpu(tc
->t
));
320 restore_init_state(tcs
);
321 for(j
= 0 ; j
< nb_tracefile
; j
++) {
323 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
324 LttvTracefileContext
*, j
));
325 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
326 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
328 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
329 /* It's a Usertrace */
330 LttvProcessState
*process
;
332 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
333 ltt_tracefile_creation(tfcs
->parent
.tf
));
334 process
= lttv_state_find_process_or_create(
336 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
338 process
->usertrace
= tfcs
;
342 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
343 /* It's a Usertrace */
344 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
345 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
347 if(!usertrace_tree
) {
348 usertrace_tree
= g_tree_new_full(compare_usertraces
,
349 NULL
, free_usertrace_key
, NULL
);
350 g_hash_table_insert(tcs
->usertraces
,
351 (gpointer
)tid
, usertrace_tree
);
353 LttTime
*timestamp
= g_new(LttTime
, 1);
354 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
355 ltt_tracefile_creation(tfcs
->parent
.tf
));
356 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
364 fini(LttvTracesetState
*self
)
370 LttvTracefileState
*tfcs
;
372 LttvAttributeValue v
;
374 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
375 for(i
= 0 ; i
< nb_trace
; i
++) {
376 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
377 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
380 g_assert(*(v
.v_uint
) != 0);
383 if(*(v
.v_uint
) == 0) {
384 free_name_tables(tcs
);
386 free_saved_state(tcs
);
388 g_free(tcs
->running_process
);
389 tcs
->running_process
= NULL
;
390 lttv_state_free_process_table(tcs
->processes
);
391 lttv_state_free_usertraces(tcs
->usertraces
);
392 tcs
->processes
= NULL
;
393 tcs
->usertraces
= NULL
;
395 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
396 fini((LttvTracesetContext
*)self
);
400 static LttvTracesetContext
*
401 new_traceset_context(LttvTracesetContext
*self
)
403 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
407 static LttvTraceContext
*
408 new_trace_context(LttvTracesetContext
*self
)
410 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
414 static LttvTracefileContext
*
415 new_tracefile_context(LttvTracesetContext
*self
)
417 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
421 /* Write the process state of the trace */
423 static void write_process_state(gpointer key
, gpointer value
,
426 LttvProcessState
*process
;
428 LttvExecutionState
*es
;
430 FILE *fp
= (FILE *)user_data
;
435 process
= (LttvProcessState
*)value
;
437 " <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",
438 process
, process
->pid
, process
->tgid
, process
->ppid
,
439 g_quark_to_string(process
->type
),
440 process
->creation_time
.tv_sec
,
441 process
->creation_time
.tv_nsec
,
442 process
->insertion_time
.tv_sec
,
443 process
->insertion_time
.tv_nsec
,
444 g_quark_to_string(process
->name
),
445 g_quark_to_string(process
->brand
),
448 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
449 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
450 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
451 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
452 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
453 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
454 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
457 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
458 address
= &g_array_index(process
->user_stack
, guint64
, i
);
459 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
463 if(process
->usertrace
) {
464 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
465 g_quark_to_string(process
->usertrace
->tracefile_name
),
466 process
->usertrace
->cpu
);
470 fprintf(fp
, " </PROCESS>\n");
474 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
476 guint i
, nb_tracefile
, nb_block
, offset
;
479 LttvTracefileState
*tfcs
;
483 LttEventPosition
*ep
;
487 ep
= ltt_event_position_new();
489 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
491 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
493 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
494 for(i
=0;i
<nb_cpus
;i
++) {
495 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
496 i
, self
->running_process
[i
]->pid
);
499 nb_tracefile
= self
->parent
.tracefiles
->len
;
501 for(i
= 0 ; i
< nb_tracefile
; i
++) {
503 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
504 LttvTracefileContext
*, i
));
505 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
506 tfcs
->parent
.timestamp
.tv_sec
,
507 tfcs
->parent
.timestamp
.tv_nsec
);
508 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
509 if(e
== NULL
) fprintf(fp
,"/>\n");
511 ltt_event_position(e
, ep
);
512 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
513 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
518 fprintf(fp
,"</PROCESS_STATE>\n");
522 static void write_process_state_raw(gpointer key
, gpointer value
,
525 LttvProcessState
*process
;
527 LttvExecutionState
*es
;
529 FILE *fp
= (FILE *)user_data
;
534 process
= (LttvProcessState
*)value
;
535 fputc(HDR_PROCESS
, fp
);
536 //fwrite(&header, sizeof(header), 1, fp);
537 //fprintf(fp, "%s", g_quark_to_string(process->type));
539 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
540 //fprintf(fp, "%s", g_quark_to_string(process->name));
542 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
543 //fprintf(fp, "%s", g_quark_to_string(process->brand));
545 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
546 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
547 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
548 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
549 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
550 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
551 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
555 " <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",
556 process
, process
->pid
, process
->tgid
, process
->ppid
,
557 g_quark_to_string(process
->type
),
558 process
->creation_time
.tv_sec
,
559 process
->creation_time
.tv_nsec
,
560 process
->insertion_time
.tv_sec
,
561 process
->insertion_time
.tv_nsec
,
562 g_quark_to_string(process
->name
),
563 g_quark_to_string(process
->brand
),
567 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
568 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
571 //fprintf(fp, "%s", g_quark_to_string(es->t));
573 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
574 //fprintf(fp, "%s", g_quark_to_string(es->n));
576 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
577 //fprintf(fp, "%s", g_quark_to_string(es->s));
579 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
580 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
581 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
583 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
584 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
585 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
586 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
587 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
591 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
592 address
= &g_array_index(process
->user_stack
, guint64
, i
);
593 fputc(HDR_USER_STACK
, fp
);
594 fwrite(&address
, sizeof(address
), 1, fp
);
596 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
601 if(process
->usertrace
) {
602 fputc(HDR_USERTRACE
, fp
);
603 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
605 fwrite(&process
->usertrace
->tracefile_name
,
606 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
607 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
609 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
610 g_quark_to_string(process
->usertrace
->tracefile_name
),
611 process
->usertrace
->cpu
);
618 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
620 guint i
, nb_tracefile
, nb_block
, offset
;
623 LttvTracefileState
*tfcs
;
627 LttEventPosition
*ep
;
631 ep
= ltt_event_position_new();
633 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
634 fputc(HDR_PROCESS_STATE
, fp
);
635 fwrite(&t
, sizeof(t
), 1, fp
);
637 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
639 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
640 for(i
=0;i
<nb_cpus
;i
++) {
642 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
643 fwrite(&self
->running_process
[i
]->pid
,
644 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
645 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
646 // i, self->running_process[i]->pid);
649 nb_tracefile
= self
->parent
.tracefiles
->len
;
651 for(i
= 0 ; i
< nb_tracefile
; i
++) {
653 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
654 LttvTracefileContext
*, i
));
655 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
656 // tfcs->parent.timestamp.tv_sec,
657 // tfcs->parent.timestamp.tv_nsec);
658 fputc(HDR_TRACEFILE
, fp
);
659 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
660 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
661 * position following : end of trace */
662 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
664 ltt_event_position(e
, ep
);
665 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
666 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
668 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
669 fwrite(&offset
, sizeof(offset
), 1, fp
);
670 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
677 /* Read process state from a file */
679 /* Called because a HDR_PROCESS was found */
680 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
)
682 LttvExecutionState
*es
;
683 LttvProcessState
*process
, *parent_process
;
684 LttvProcessState tmp
;
690 /* TOOD : check return value */
691 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
692 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
693 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
694 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
695 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
696 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
697 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
698 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
699 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
702 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
704 /* We must link to the parent */
705 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
707 process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.pid
,
708 &tmp
.insertion_time
);
710 process
->creation_time
= tmp
.creation_time
;
711 process
->type
= tmp
.type
;
712 process
->brand
= tmp
.brand
;
713 process
->tgid
= tmp
.tgid
;
714 process
->cpu
= tmp
.cpu
;
717 if(feof(fp
) || ferror(fp
)) goto end_loop
;
719 gint hdr
= fgetc(fp
);
728 case HDR_PROCESS_STATE
:
740 /* Called because a HDR_PROCESS_STATE was found */
741 /* Append a saved state to the trace states */
742 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
)
744 guint i
, nb_tracefile
, nb_block
, offset
;
747 LttvTracefileState
*tfcs
;
749 LttEventPosition
*ep
;
757 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
759 LttvAttributeValue value
;
760 ep
= ltt_event_position_new();
762 restore_init_state(self
);
764 fread(&t
, sizeof(t
), 1, fp
);
767 if(feof(fp
) || ferror(fp
)) goto end_loop
;
772 /* Call read_process_state_raw */
773 read_process_state_raw(self
, fp
);
783 case HDR_PROCESS_STATE
:
785 g_error("Error while parsing saved state file :"
786 " unexpected data header %d",
790 g_error("Error while parsing saved state file : unknown data header %d",
796 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
797 for(i
=0;i
<nb_cpus
;i
++) {
800 g_assert(hdr
== HDR_CPU
);
801 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
802 g_assert(i
== cpu_num
);
803 fread(&self
->running_process
[i
]->pid
,
804 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
807 nb_tracefile
= self
->parent
.tracefiles
->len
;
809 for(i
= 0 ; i
< nb_tracefile
; i
++) {
811 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
812 LttvTracefileContext
*, i
));
813 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
814 // tfcs->parent.timestamp.tv_sec,
815 // tfcs->parent.timestamp.tv_nsec);
817 g_assert(hdr
== HDR_TRACEFILE
);
818 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
819 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
820 * position following : end of trace */
821 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
822 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
823 fread(&offset
, sizeof(offset
), 1, fp
);
824 fread(&tsc
, sizeof(tsc
), 1, fp
);
825 ltt_event_position_set(ep
, tf
, nb_block
, offset
, tsc
);
826 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
832 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
833 LTTV_STATE_SAVED_STATES
);
834 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
835 value
= lttv_attribute_add(saved_states_tree
,
836 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
837 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
838 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
840 lttv_state_save(self
, saved_state_tree
);
841 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
844 *(self
->max_time_state_recomputed_in_seek
) = t
;
847 /* Called when a HDR_TRACE is found */
848 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
)
853 if(feof(fp
) || ferror(fp
)) goto end_loop
;
857 case HDR_PROCESS_STATE
:
858 /* Call read_process_state_raw */
859 lttv_state_read_raw(tcs
, fp
);
871 g_error("Error while parsing saved state file :"
872 " unexpected data header %d",
876 g_error("Error while parsing saved state file : unknown data header %d",
882 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
887 /* Copy each process from an existing hash table to a new one */
889 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
891 LttvProcessState
*process
, *new_process
;
893 GHashTable
*new_processes
= (GHashTable
*)user_data
;
897 process
= (LttvProcessState
*)value
;
898 new_process
= g_new(LttvProcessState
, 1);
899 *new_process
= *process
;
900 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
901 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
902 new_process
->execution_stack
=
903 g_array_set_size(new_process
->execution_stack
,
904 process
->execution_stack
->len
);
905 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
906 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
907 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
909 new_process
->state
= &g_array_index(new_process
->execution_stack
,
910 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
911 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
913 new_process
->user_stack
=
914 g_array_set_size(new_process
->user_stack
,
915 process
->user_stack
->len
);
916 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
917 g_array_index(new_process
->user_stack
, guint64
, i
) =
918 g_array_index(process
->user_stack
, guint64
, i
);
920 new_process
->current_function
= process
->current_function
;
921 g_hash_table_insert(new_processes
, new_process
, new_process
);
925 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
927 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
929 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
930 return new_processes
;
934 /* The saved state for each trace contains a member "processes", which
935 stores a copy of the process table, and a member "tracefiles" with
936 one entry per tracefile. Each tracefile has a "process" member pointing
937 to the current process and a "position" member storing the tracefile
938 position (needed to seek to the current "next" event. */
940 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
942 guint i
, nb_tracefile
, nb_cpus
;
944 LttvTracefileState
*tfcs
;
946 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
948 guint
*running_process
;
950 LttvAttributeType type
;
952 LttvAttributeValue value
;
954 LttvAttributeName name
;
956 LttEventPosition
*ep
;
958 tracefiles_tree
= lttv_attribute_find_subdir(container
,
959 LTTV_STATE_TRACEFILES
);
961 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
963 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
965 /* Add the currently running processes array */
966 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
967 running_process
= g_new(guint
, nb_cpus
);
968 for(i
=0;i
<nb_cpus
;i
++) {
969 running_process
[i
] = self
->running_process
[i
]->pid
;
971 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
973 *(value
.v_pointer
) = running_process
;
975 g_info("State save");
977 nb_tracefile
= self
->parent
.tracefiles
->len
;
979 for(i
= 0 ; i
< nb_tracefile
; i
++) {
981 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
982 LttvTracefileContext
*, i
));
983 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
984 value
= lttv_attribute_add(tracefiles_tree
, i
,
986 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
988 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
990 *(value
.v_uint
) = tfcs
->process
->pid
;
992 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
994 /* Only save the position if the tfs has not infinite time. */
995 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
996 // && current_tfcs != tfcs) {
997 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
998 *(value
.v_pointer
) = NULL
;
1000 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1001 ep
= ltt_event_position_new();
1002 ltt_event_position(e
, ep
);
1003 *(value
.v_pointer
) = ep
;
1005 guint nb_block
, offset
;
1008 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1009 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1011 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1017 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1019 guint i
, nb_tracefile
, pid
, nb_cpus
;
1021 LttvTracefileState
*tfcs
;
1023 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1025 guint
*running_process
;
1027 LttvAttributeType type
;
1029 LttvAttributeValue value
;
1031 LttvAttributeName name
;
1035 LttEventPosition
*ep
;
1037 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1039 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1040 LTTV_STATE_TRACEFILES
);
1042 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1044 g_assert(type
== LTTV_POINTER
);
1045 lttv_state_free_process_table(self
->processes
);
1046 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1048 /* Add the currently running processes array */
1049 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1050 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1052 g_assert(type
== LTTV_POINTER
);
1053 running_process
= *(value
.v_pointer
);
1054 for(i
=0;i
<nb_cpus
;i
++) {
1055 pid
= running_process
[i
];
1056 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1057 g_assert(self
->running_process
[i
] != NULL
);
1061 nb_tracefile
= self
->parent
.tracefiles
->len
;
1063 //g_tree_destroy(tsc->pqueue);
1064 //tsc->pqueue = g_tree_new(compare_tracefile);
1066 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1068 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1069 LttvTracefileContext
*, i
));
1070 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1071 g_assert(type
== LTTV_GOBJECT
);
1072 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1074 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1076 g_assert(type
== LTTV_UINT
);
1077 pid
= *(value
.v_uint
);
1078 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1080 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1082 g_assert(type
== LTTV_POINTER
);
1083 //g_assert(*(value.v_pointer) != NULL);
1084 ep
= *(value
.v_pointer
);
1085 g_assert(tfcs
->parent
.t_context
!= NULL
);
1087 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1088 g_tree_remove(tsc
->pqueue
, tfc
);
1091 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1092 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1093 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1094 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1095 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1097 tfc
->timestamp
= ltt_time_infinite
;
1103 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1105 guint i
, nb_tracefile
, nb_cpus
;
1107 LttvTracefileState
*tfcs
;
1109 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1111 guint
*running_process
;
1113 LttvAttributeType type
;
1115 LttvAttributeValue value
;
1117 LttvAttributeName name
;
1121 LttEventPosition
*ep
;
1123 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1124 LTTV_STATE_TRACEFILES
);
1125 g_object_ref(G_OBJECT(tracefiles_tree
));
1126 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1128 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1130 g_assert(type
== LTTV_POINTER
);
1131 lttv_state_free_process_table(*(value
.v_pointer
));
1132 *(value
.v_pointer
) = NULL
;
1133 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1135 /* Free running processes array */
1136 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1137 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1139 g_assert(type
== LTTV_POINTER
);
1140 running_process
= *(value
.v_pointer
);
1141 g_free(running_process
);
1143 nb_tracefile
= self
->parent
.tracefiles
->len
;
1145 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1147 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1148 LttvTracefileContext
*, i
));
1149 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1150 g_assert(type
== LTTV_GOBJECT
);
1151 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1153 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1155 g_assert(type
== LTTV_POINTER
);
1156 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1158 g_object_unref(G_OBJECT(tracefiles_tree
));
1162 static void free_saved_state(LttvTraceState
*self
)
1166 LttvAttributeType type
;
1168 LttvAttributeValue value
;
1170 LttvAttributeName name
;
1174 LttvAttribute
*saved_states
;
1176 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1177 LTTV_STATE_SAVED_STATES
);
1179 nb
= lttv_attribute_get_number(saved_states
);
1180 for(i
= 0 ; i
< nb
; i
++) {
1181 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1182 g_assert(type
== LTTV_GOBJECT
);
1183 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1186 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1191 create_max_time(LttvTraceState
*tcs
)
1193 LttvAttributeValue v
;
1195 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1197 g_assert(*(v
.v_pointer
) == NULL
);
1198 *(v
.v_pointer
) = g_new(LttTime
,1);
1199 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1204 get_max_time(LttvTraceState
*tcs
)
1206 LttvAttributeValue v
;
1208 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1210 g_assert(*(v
.v_pointer
) != NULL
);
1211 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1216 free_max_time(LttvTraceState
*tcs
)
1218 LttvAttributeValue v
;
1220 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1222 g_free(*(v
.v_pointer
));
1223 *(v
.v_pointer
) = NULL
;
1227 typedef struct _LttvNameTables
{
1228 // FIXME GQuark *eventtype_names;
1229 GQuark
*syscall_names
;
1234 GQuark
*soft_irq_names
;
1239 create_name_tables(LttvTraceState
*tcs
)
1243 GQuark f_name
, e_name
;
1247 LttvTraceHookByFacility
*thf
;
1253 GString
*fe_name
= g_string_new("");
1255 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1257 LttvAttributeValue v
;
1259 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1261 g_assert(*(v
.v_pointer
) == NULL
);
1262 *(v
.v_pointer
) = name_tables
;
1263 #if 0 // Use iteration over the facilities_by_name and then list all event
1264 // types of each facility
1265 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1266 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1267 for(i
= 0 ; i
< nb
; i
++) {
1268 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1269 e_name
= ltt_eventtype_name(et
);
1270 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1271 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1272 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1275 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1276 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1277 LTT_FIELD_SYSCALL_ID
, 0, 0,
1280 thf
= lttv_trace_hook_get_first(&h
);
1282 t
= ltt_field_type(thf
->f1
);
1283 nb
= ltt_type_element_number(t
);
1285 lttv_trace_hook_destroy(&h
);
1287 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1288 name_tables
->nb_syscalls
= nb
;
1290 for(i
= 0 ; i
< nb
; i
++) {
1291 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1294 //name_tables->syscall_names = g_new(GQuark, 256);
1295 //for(i = 0 ; i < 256 ; i++) {
1296 // g_string_printf(fe_name, "syscall %d", i);
1297 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1300 name_tables
->syscall_names
= NULL
;
1301 name_tables
->nb_syscalls
= 0;
1304 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1305 LTT_EVENT_TRAP_ENTRY
,
1306 LTT_FIELD_TRAP_ID
, 0, 0,
1309 thf
= lttv_trace_hook_get_first(&h
);
1311 t
= ltt_field_type(thf
->f1
);
1312 //nb = ltt_type_element_number(t);
1314 lttv_trace_hook_destroy(&h
);
1317 name_tables->trap_names = g_new(GQuark, nb);
1318 for(i = 0 ; i < nb ; i++) {
1319 name_tables->trap_names[i] = g_quark_from_string(
1320 ltt_enum_string_get(t, i));
1323 name_tables
->nb_traps
= 256;
1324 name_tables
->trap_names
= g_new(GQuark
, 256);
1325 for(i
= 0 ; i
< 256 ; i
++) {
1326 g_string_printf(fe_name
, "trap %d", i
);
1327 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1330 name_tables
->trap_names
= NULL
;
1331 name_tables
->nb_traps
= 0;
1334 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1335 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1336 LTT_FIELD_IRQ_ID
, 0, 0,
1339 thf
= lttv_trace_hook_get_first(&h
);
1341 t
= ltt_field_type(thf
->f1
);
1342 //nb = ltt_type_element_number(t);
1344 lttv_trace_hook_destroy(&h
);
1347 name_tables->irq_names = g_new(GQuark, nb);
1348 for(i = 0 ; i < nb ; i++) {
1349 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1353 name_tables
->irq_names
= g_new(GQuark
, 256);
1354 for(i
= 0 ; i
< 256 ; i
++) {
1355 g_string_printf(fe_name
, "irq %d", i
);
1356 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1359 name_tables
->irq_names
= NULL
;
1362 name_tables->soft_irq_names = g_new(GQuark, nb);
1363 for(i = 0 ; i < nb ; i++) {
1364 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1368 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1369 for(i
= 0 ; i
< 256 ; i
++) {
1370 g_string_printf(fe_name
, "softirq %d", i
);
1371 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1375 g_string_free(fe_name
, TRUE
);
1380 get_name_tables(LttvTraceState
*tcs
)
1382 LttvNameTables
*name_tables
;
1384 LttvAttributeValue v
;
1386 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1388 g_assert(*(v
.v_pointer
) != NULL
);
1389 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1390 //tcs->eventtype_names = name_tables->eventtype_names;
1391 tcs
->syscall_names
= name_tables
->syscall_names
;
1392 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1393 tcs
->trap_names
= name_tables
->trap_names
;
1394 tcs
->nb_traps
= name_tables
->nb_traps
;
1395 tcs
->irq_names
= name_tables
->irq_names
;
1396 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1401 free_name_tables(LttvTraceState
*tcs
)
1403 LttvNameTables
*name_tables
;
1405 LttvAttributeValue v
;
1407 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1409 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1410 *(v
.v_pointer
) = NULL
;
1412 // g_free(name_tables->eventtype_names);
1413 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1414 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1415 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1416 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1417 if(name_tables
) g_free(name_tables
);
1420 #ifdef HASH_TABLE_DEBUG
1422 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1424 LttvProcessState
*process
= (LttvProcessState
*)value
;
1426 /* Test for process corruption */
1427 guint stack_len
= process
->execution_stack
->len
;
1430 static void hash_table_check(GHashTable
*table
)
1432 g_hash_table_foreach(table
, test_process
, NULL
);
1439 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1442 LttvExecutionState
*es
;
1444 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1445 guint cpu
= tfs
->cpu
;
1447 #ifdef HASH_TABLE_DEBUG
1448 hash_table_check(ts
->processes
);
1450 LttvProcessState
*process
= ts
->running_process
[cpu
];
1452 guint depth
= process
->execution_stack
->len
;
1454 process
->execution_stack
=
1455 g_array_set_size(process
->execution_stack
, depth
+ 1);
1458 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1460 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1463 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1464 es
->cum_cpu_time
= ltt_time_zero
;
1465 es
->s
= process
->state
->s
;
1466 process
->state
= es
;
1470 * return 1 when empty, else 0 */
1471 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1472 LttvTracefileState
*tfs
)
1474 guint cpu
= tfs
->cpu
;
1475 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1477 guint depth
= process
->execution_stack
->len
;
1483 process
->execution_stack
=
1484 g_array_set_size(process
->execution_stack
, depth
- 1);
1485 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1487 process
->state
->change
= tfs
->parent
.timestamp
;
1492 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1494 guint cpu
= tfs
->cpu
;
1495 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1496 LttvProcessState
*process
= ts
->running_process
[cpu
];
1498 guint depth
= process
->execution_stack
->len
;
1500 if(process
->state
->t
!= t
){
1501 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1502 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1503 g_info("process state has %s when pop_int is %s\n",
1504 g_quark_to_string(process
->state
->t
),
1505 g_quark_to_string(t
));
1506 g_info("{ %u, %u, %s, %s, %s }\n",
1509 g_quark_to_string(process
->name
),
1510 g_quark_to_string(process
->brand
),
1511 g_quark_to_string(process
->state
->s
));
1516 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1517 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1521 process
->execution_stack
=
1522 g_array_set_size(process
->execution_stack
, depth
- 1);
1523 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1525 process
->state
->change
= tfs
->parent
.timestamp
;
1528 struct search_result
{
1529 const LttTime
*time
; /* Requested time */
1530 LttTime
*best
; /* Best result */
1533 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1535 const LttTime
*elem_time
= (const LttTime
*)a
;
1536 /* Explicit non const cast */
1537 struct search_result
*res
= (struct search_result
*)b
;
1539 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1540 /* The usertrace was created before the schedchange */
1541 /* Get larger keys */
1543 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1544 /* The usertrace was created after the schedchange time */
1545 /* Get smaller keys */
1547 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1548 res
->best
= elem_time
;
1551 res
->best
= elem_time
;
1558 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1559 guint pid
, const LttTime
*timestamp
)
1561 LttvTracefileState
*tfs
= NULL
;
1562 struct search_result res
;
1563 /* Find the usertrace associated with a pid and time interval.
1564 * Search in the usertraces by PID (within a hash) and then, for each
1565 * corresponding element of the array, find the first one with creation
1566 * timestamp the lowest, but higher or equal to "timestamp". */
1567 res
.time
= timestamp
;
1569 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1570 if(usertrace_tree
) {
1571 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1573 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1581 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1582 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1584 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1586 LttvExecutionState
*es
;
1588 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1593 process
->tgid
= tgid
;
1595 process
->name
= name
;
1596 process
->brand
= LTTV_STATE_UNBRANDED
;
1597 //process->last_cpu = tfs->cpu_name;
1598 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1599 process
->type
= LTTV_STATE_USER_THREAD
;
1600 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1601 process
->current_function
= 0; //function 0x0 by default.
1603 g_info("Process %u, core %p", process
->pid
, process
);
1604 g_hash_table_insert(tcs
->processes
, process
, process
);
1607 process
->ppid
= parent
->pid
;
1608 process
->creation_time
= *timestamp
;
1611 /* No parent. This process exists but we are missing all information about
1612 its creation. The birth time is set to zero but we remember the time of
1617 process
->creation_time
= ltt_time_zero
;
1620 process
->insertion_time
= *timestamp
;
1621 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1622 process
->creation_time
.tv_nsec
);
1623 process
->pid_time
= g_quark_from_string(buffer
);
1625 //process->last_cpu = tfs->cpu_name;
1626 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1627 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1628 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1629 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1630 es
= process
->state
= &g_array_index(process
->execution_stack
,
1631 LttvExecutionState
, 0);
1632 es
->t
= LTTV_STATE_USER_MODE
;
1633 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1634 es
->entry
= *timestamp
;
1635 //g_assert(timestamp->tv_sec != 0);
1636 es
->change
= *timestamp
;
1637 es
->cum_cpu_time
= ltt_time_zero
;
1638 es
->s
= LTTV_STATE_RUN
;
1640 es
= process
->state
= &g_array_index(process
->execution_stack
,
1641 LttvExecutionState
, 1);
1642 es
->t
= LTTV_STATE_SYSCALL
;
1643 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1644 es
->entry
= *timestamp
;
1645 //g_assert(timestamp->tv_sec != 0);
1646 es
->change
= *timestamp
;
1647 es
->cum_cpu_time
= ltt_time_zero
;
1648 es
->s
= LTTV_STATE_WAIT_FORK
;
1650 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1651 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1652 sizeof(guint64
), 0);
1657 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1660 LttvProcessState key
;
1661 LttvProcessState
*process
;
1665 process
= g_hash_table_lookup(ts
->processes
, &key
);
1670 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1671 const LttTime
*timestamp
)
1673 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1674 LttvExecutionState
*es
;
1676 /* Put ltt_time_zero creation time for unexisting processes */
1677 if(unlikely(process
== NULL
)) {
1678 process
= lttv_state_create_process(ts
,
1679 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1680 /* We are not sure is it's a kernel thread or normal thread, put the
1681 * bottom stack state to unknown */
1682 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1683 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1688 /* FIXME : this function should be called when we receive an event telling that
1689 * release_task has been called in the kernel. In happens generally when
1690 * the parent waits for its child terminaison, but may also happen in special
1691 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1692 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1693 * of a killed thread ground, but isn't the leader.
1695 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1697 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1698 LttvProcessState key
;
1700 key
.pid
= process
->pid
;
1701 key
.cpu
= process
->cpu
;
1702 g_hash_table_remove(ts
->processes
, &key
);
1703 g_array_free(process
->execution_stack
, TRUE
);
1704 g_array_free(process
->user_stack
, TRUE
);
1709 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1711 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1712 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1717 static void lttv_state_free_process_table(GHashTable
*processes
)
1719 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1720 g_hash_table_destroy(processes
);
1724 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1726 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1728 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1729 LttvProcessState
*process
= ts
->running_process
[cpu
];
1730 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1731 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1732 LttField
*f
= thf
->f1
;
1734 LttvExecutionSubmode submode
;
1736 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1737 guint syscall
= ltt_event_get_unsigned(e
, f
);
1739 if(syscall
< nb_syscalls
) {
1740 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1743 /* Fixup an incomplete syscall table */
1744 GString
*string
= g_string_new("");
1745 g_string_printf(string
, "syscall %u", syscall
);
1746 submode
= g_quark_from_string(string
->str
);
1747 g_string_free(string
, TRUE
);
1749 /* There can be no system call from PID 0 : unknown state */
1750 if(process
->pid
!= 0)
1751 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1756 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1758 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1760 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1761 LttvProcessState
*process
= ts
->running_process
[cpu
];
1763 /* There can be no system call from PID 0 : unknown state */
1764 if(process
->pid
!= 0)
1765 pop_state(s
, LTTV_STATE_SYSCALL
);
1770 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1772 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1773 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1774 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1775 LttField
*f
= thf
->f1
;
1777 LttvExecutionSubmode submode
;
1779 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1780 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1782 if(trap
< nb_traps
) {
1783 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1785 /* Fixup an incomplete trap table */
1786 GString
*string
= g_string_new("");
1787 g_string_printf(string
, "trap %llu", trap
);
1788 submode
= g_quark_from_string(string
->str
);
1789 g_string_free(string
, TRUE
);
1792 push_state(s
, LTTV_STATE_TRAP
, submode
);
1797 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1799 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1801 pop_state(s
, LTTV_STATE_TRAP
);
1806 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1808 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1809 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1810 guint8 fac_id
= ltt_event_facility_id(e
);
1811 guint8 ev_id
= ltt_event_eventtype_id(e
);
1812 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1813 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1814 g_assert(thf
->f1
!= NULL
);
1815 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1816 LttField
*f
= thf
->f1
;
1818 LttvExecutionSubmode submode
;
1820 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1821 ltt_event_get_unsigned(e
, f
)];
1823 /* Do something with the info about being in user or system mode when int? */
1824 push_state(s
, LTTV_STATE_IRQ
, submode
);
1828 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1830 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1832 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1838 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1840 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1842 pop_state(s
, LTTV_STATE_IRQ
);
1846 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1848 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1849 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1850 guint8 fac_id
= ltt_event_facility_id(e
);
1851 guint8 ev_id
= ltt_event_eventtype_id(e
);
1852 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1853 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1854 g_assert(thf
->f1
!= NULL
);
1855 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1856 LttField
*f
= thf
->f1
;
1858 LttvExecutionSubmode submode
;
1860 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1861 ltt_event_get_long_unsigned(e
, f
)];
1863 /* Do something with the info about being in user or system mode when int? */
1864 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1868 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1872 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1873 guint cpu
= tfs
->cpu
;
1874 LttvProcessState
*process
= ts
->running_process
[cpu
];
1876 guint depth
= process
->user_stack
->len
;
1878 process
->user_stack
=
1879 g_array_set_size(process
->user_stack
, depth
+ 1);
1881 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1882 *new_func
= funcptr
;
1883 process
->current_function
= funcptr
;
1886 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1888 guint cpu
= tfs
->cpu
;
1889 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1890 LttvProcessState
*process
= ts
->running_process
[cpu
];
1892 if(process
->current_function
!= funcptr
){
1893 g_info("Different functions (%lu.%09lu): ignore it\n",
1894 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1895 g_info("process state has %llu when pop_function is %llu\n",
1896 process
->current_function
, funcptr
);
1897 g_info("{ %u, %u, %s, %s, %s }\n",
1900 g_quark_to_string(process
->name
),
1901 g_quark_to_string(process
->brand
),
1902 g_quark_to_string(process
->state
->s
));
1905 guint depth
= process
->user_stack
->len
;
1908 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1909 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1913 process
->user_stack
=
1914 g_array_set_size(process
->user_stack
, depth
- 1);
1915 process
->current_function
=
1916 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1920 static gboolean
function_entry(void *hook_data
, void *call_data
)
1922 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1923 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1924 guint8 fac_id
= ltt_event_facility_id(e
);
1925 guint8 ev_id
= ltt_event_eventtype_id(e
);
1926 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1927 g_assert(thf
->f1
!= NULL
);
1928 LttField
*f
= thf
->f1
;
1929 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1931 push_function(s
, funcptr
);
1935 static gboolean
function_exit(void *hook_data
, void *call_data
)
1937 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1938 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1939 guint8 fac_id
= ltt_event_facility_id(e
);
1940 guint8 ev_id
= ltt_event_eventtype_id(e
);
1941 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1942 g_assert(thf
->f1
!= NULL
);
1943 LttField
*f
= thf
->f1
;
1944 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1946 LttvExecutionSubmode submode
;
1948 pop_function(s
, funcptr
);
1952 static gboolean
schedchange(void *hook_data
, void *call_data
)
1954 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1956 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1957 LttvProcessState
*process
= ts
->running_process
[cpu
];
1958 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1960 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1961 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1962 guint pid_in
, pid_out
;
1965 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1966 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1967 state_out
= ltt_event_get_int(e
, thf
->f3
);
1969 if(likely(process
!= NULL
)) {
1971 /* We could not know but it was not the idle process executing.
1972 This should only happen at the beginning, before the first schedule
1973 event, and when the initial information (current process for each CPU)
1974 is missing. It is not obvious how we could, after the fact, compensate
1975 the wrongly attributed statistics. */
1977 //This test only makes sense once the state is known and if there is no
1978 //missing events. We need to silently ignore schedchange coming after a
1979 //process_free, or it causes glitches. (FIXME)
1980 //if(unlikely(process->pid != pid_out)) {
1981 // g_assert(process->pid == 0);
1983 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
1984 /* Scheduling out of pid 0 at beginning of the trace :
1985 * we know for sure it is in syscall mode at this point. */
1986 g_assert(process
->execution_stack
->len
== 1);
1987 process
->state
->t
= LTTV_STATE_SYSCALL
;
1989 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1990 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1991 process
->state
->change
= s
->parent
.timestamp
;
1993 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1994 else process
->state
->s
= LTTV_STATE_WAIT
;
1995 process
->state
->change
= s
->parent
.timestamp
;
1999 exit_process(s
, process
); /* EXIT_DEAD */
2000 /* see sched.h for states */
2002 process
= ts
->running_process
[cpu
] =
2003 lttv_state_find_process_or_create(
2004 (LttvTraceState
*)s
->parent
.t_context
,
2006 &s
->parent
.timestamp
);
2007 process
->state
->s
= LTTV_STATE_RUN
;
2009 if(process
->usertrace
)
2010 process
->usertrace
->cpu
= cpu
;
2011 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2012 process
->state
->change
= s
->parent
.timestamp
;
2016 static gboolean
process_fork(void *hook_data
, void *call_data
)
2018 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2019 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2020 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2022 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2023 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2024 LttvProcessState
*zombie_process
;
2026 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2027 LttvProcessState
*process
= ts
->running_process
[cpu
];
2028 LttvProcessState
*child_process
;
2031 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2034 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2035 s
->parent
.target_pid
= child_pid
;
2038 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2039 else child_tgid
= 0;
2041 /* Mathieu : it seems like the process might have been scheduled in before the
2042 * fork, and, in a rare case, might be the current process. This might happen
2043 * in a SMP case where we don't have enough precision on the clocks.
2045 * Test reenabled after precision fixes on time. (Mathieu) */
2047 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2049 if(unlikely(zombie_process
!= NULL
)) {
2050 /* Reutilisation of PID. Only now we are sure that the old PID
2051 * has been released. FIXME : should know when release_task happens instead.
2053 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2055 for(i
=0; i
< num_cpus
; i
++) {
2056 g_assert(zombie_process
!= ts
->running_process
[i
]);
2059 exit_process(s
, zombie_process
);
2062 g_assert(process
->pid
!= child_pid
);
2063 // FIXME : Add this test in the "known state" section
2064 // g_assert(process->pid == parent_pid);
2065 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2066 if(child_process
== NULL
) {
2067 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2068 child_pid
, child_tgid
,
2069 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2071 /* The process has already been created : due to time imprecision between
2072 * multiple CPUs : it has been scheduled in before creation. Note that we
2073 * shouldn't have this kind of imprecision.
2075 * Simply put a correct parent.
2077 g_assert(0); /* This is a problematic case : the process has been created
2078 before the fork event */
2079 child_process
->ppid
= process
->pid
;
2080 child_process
->tgid
= child_tgid
;
2082 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2083 child_process
->name
= process
->name
;
2084 child_process
->brand
= process
->brand
;
2089 /* We stamp a newly created process as kernel_thread */
2090 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2092 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2093 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2094 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2097 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2098 LttvProcessState
*process
;
2099 LttvExecutionState
*es
;
2102 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2103 s
->parent
.target_pid
= pid
;
2105 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2106 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2107 es
->t
= LTTV_STATE_SYSCALL
;
2108 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2113 static gboolean
process_exit(void *hook_data
, void *call_data
)
2115 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2116 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2117 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2121 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2122 LttvProcessState
*process
; // = ts->running_process[cpu];
2124 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2125 s
->parent
.target_pid
= pid
;
2127 // FIXME : Add this test in the "known state" section
2128 // g_assert(process->pid == pid);
2130 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2131 if(likely(process
!= NULL
)) {
2132 process
->state
->s
= LTTV_STATE_EXIT
;
2137 static gboolean
process_free(void *hook_data
, void *call_data
)
2139 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2140 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2141 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2142 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2144 LttvProcessState
*process
;
2146 /* PID of the process to release */
2147 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2148 s
->parent
.target_pid
= release_pid
;
2150 g_assert(release_pid
!= 0);
2152 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2154 if(likely(process
!= NULL
)) {
2155 /* release_task is happening at kernel level : we can now safely release
2156 * the data structure of the process */
2157 //This test is fun, though, as it may happen that
2158 //at time t : CPU 0 : process_free
2159 //at time t+150ns : CPU 1 : schedule out
2160 //Clearly due to time imprecision, we disable it. (Mathieu)
2161 //If this weird case happen, we have no choice but to put the
2162 //Currently running process on the cpu to 0.
2163 //I re-enable it following time precision fixes. (Mathieu)
2164 //Well, in the case where an process is freed by a process on another CPU
2165 //and still scheduled, it happens that this is the schedchange that will
2166 //drop the last reference count. Do not free it here!
2167 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2169 for(i
=0; i
< num_cpus
; i
++) {
2170 //g_assert(process != ts->running_process[i]);
2171 if(process
== ts
->running_process
[i
]) {
2172 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2176 if(i
== num_cpus
) /* process is not scheduled */
2177 exit_process(s
, process
);
2184 static gboolean
process_exec(void *hook_data
, void *call_data
)
2186 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2187 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2188 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2189 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2192 LttvProcessState
*process
= ts
->running_process
[cpu
];
2194 /* PID of the process to release */
2195 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2196 //name = ltt_event_get_string(e, thf->f1);
2197 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2199 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2200 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2201 memcpy(null_term_name
, name_begin
, name_len
);
2202 null_term_name
[name_len
] = '\0';
2204 process
->name
= g_quark_from_string(null_term_name
);
2205 process
->brand
= LTTV_STATE_UNBRANDED
;
2206 g_free(null_term_name
);
2210 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2212 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2213 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2214 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2215 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2218 LttvProcessState
*process
= ts
->running_process
[cpu
];
2220 name
= ltt_event_get_string(e
, thf
->f1
);
2221 process
->brand
= g_quark_from_string(name
);
2226 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2228 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2229 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2230 //It's slow : optimise later by doing this before reading trace.
2231 LttEventType
*et
= ltt_event_eventtype(e
);
2233 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2239 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2240 LttvProcessState
*process
= ts
->running_process
[cpu
];
2241 LttvProcessState
*parent_process
;
2242 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2243 GQuark type
, mode
, submode
, status
;
2244 LttvExecutionState
*es
;
2247 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2248 s
->parent
.target_pid
= pid
;
2251 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2254 command
= ltt_event_get_string(e
, thf
->f3
);
2257 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2258 type
= ltt_enum_string_get(ltt_field_type(f4
),
2259 ltt_event_get_unsigned(e
, f4
));
2262 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2263 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2264 ltt_event_get_unsigned(e
, f5
));
2267 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2268 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2269 ltt_event_get_unsigned(e
, f6
));
2272 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2273 status
= ltt_enum_string_get(ltt_field_type(f7
),
2274 ltt_event_get_unsigned(e
, f7
));
2277 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2278 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2281 /* The process might exist if a process was forked while performing the state
2283 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2284 if(process
== NULL
) {
2285 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2286 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2287 pid
, tgid
, g_quark_from_string(command
),
2288 &s
->parent
.timestamp
);
2290 /* Keep the stack bottom : a running user mode */
2291 /* Disabled because of inconsistencies in the current statedump states. */
2292 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2293 /* Only keep the bottom */
2294 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2295 es
= process
->state
= &g_array_index(process
->execution_stack
,
2296 LttvExecutionState
, 0);
2297 es
->t
= LTTV_STATE_SYSCALL
;
2301 /* On top of it : */
2302 es
= process
->state
= &g_array_index(process
->execution_stack
,
2303 LttvExecutionState
, 1);
2304 es
->t
= LTTV_STATE_USER_MODE
;
2311 es
= process
->state
= &g_array_index(process
->execution_stack
,
2312 LttvExecutionState
, 1);
2313 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2314 es
->s
= LTTV_STATE_UNNAMED
;
2315 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2319 /* The process has already been created :
2320 * Probably was forked while dumping the process state or
2321 * was simply scheduled in prior to get the state dump event.
2322 * We know for sure if it is a user space thread.
2324 process
->ppid
= parent_pid
;
2325 process
->tgid
= tgid
;
2326 process
->name
= g_quark_from_string(command
);
2327 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2328 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2329 es
->t
= LTTV_STATE_USER_MODE
;
2330 /* Don't mess around with the stack, it will eventually become
2331 * ok after the end of state dump. */
2337 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2339 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2341 lttv_state_add_event_hooks(tss
);
2346 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2348 LttvTraceset
*traceset
= self
->parent
.ts
;
2350 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2354 LttvTracefileState
*tfs
;
2358 LttvTraceHookByFacility
*thf
;
2360 LttvTraceHook
*hook
;
2362 LttvAttributeValue val
;
2367 nb_trace
= lttv_traceset_number(traceset
);
2368 for(i
= 0 ; i
< nb_trace
; i
++) {
2369 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2371 /* Find the eventtype id for the following events and register the
2372 associated by id hooks. */
2374 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
2375 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
2378 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2379 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2380 LTT_FIELD_SYSCALL_ID
, 0, 0,
2381 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2384 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2385 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2387 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2390 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2391 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2392 LTT_FIELD_TRAP_ID
, 0, 0,
2393 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2396 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2397 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2399 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2402 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2403 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2404 LTT_FIELD_IRQ_ID
, 0, 0,
2405 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2408 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2409 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2411 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2414 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2415 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2416 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2417 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2420 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2421 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2423 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2426 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2427 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2428 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2429 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2432 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2433 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2434 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2435 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2438 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2439 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2440 LTT_FIELD_PID
, 0, 0,
2441 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2445 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2446 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2447 LTT_FIELD_PID
, 0, 0,
2448 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2451 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2452 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2453 LTT_FIELD_PID
, 0, 0,
2454 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2457 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2458 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2459 LTT_FIELD_FILENAME
, 0, 0,
2460 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2463 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2464 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2465 LTT_FIELD_NAME
, 0, 0,
2466 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2469 /* statedump-related hooks */
2470 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2471 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2472 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2473 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2476 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2477 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2478 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2479 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2482 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2483 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2484 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2485 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2488 hooks
= g_array_set_size(hooks
, hn
);
2490 /* Add these hooks to each event_by_id hooks list */
2492 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2494 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2496 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2497 LttvTracefileContext
*, j
));
2499 for(k
= 0 ; k
< hooks
->len
; k
++) {
2500 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2501 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2502 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2504 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2511 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2512 *(val
.v_pointer
) = hooks
;
2516 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2518 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2520 lttv_state_remove_event_hooks(tss
);
2525 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2527 LttvTraceset
*traceset
= self
->parent
.ts
;
2529 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2533 LttvTracefileState
*tfs
;
2537 LttvTraceHook
*hook
;
2539 LttvTraceHookByFacility
*thf
;
2541 LttvAttributeValue val
;
2543 nb_trace
= lttv_traceset_number(traceset
);
2544 for(i
= 0 ; i
< nb_trace
; i
++) {
2545 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2546 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2547 hooks
= *(val
.v_pointer
);
2549 /* Remove these hooks from each event_by_id hooks list */
2551 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2553 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2555 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2556 LttvTracefileContext
*, j
));
2558 for(k
= 0 ; k
< hooks
->len
; k
++) {
2559 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2560 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2561 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2563 lttv_hooks_remove_data(
2564 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2570 for(k
= 0 ; k
< hooks
->len
; k
++)
2571 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2572 g_array_free(hooks
, TRUE
);
2576 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2578 guint
*event_count
= (guint
*)hook_data
;
2580 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2581 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2586 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2588 LttvTracefileState
*tfcs
;
2590 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2592 LttEventPosition
*ep
;
2598 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2600 LttvAttributeValue value
;
2602 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2603 LTTV_STATE_SAVED_STATES
);
2604 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2605 value
= lttv_attribute_add(saved_states_tree
,
2606 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2607 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2608 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2609 *(value
.v_time
) = self
->parent
.timestamp
;
2610 lttv_state_save(tcs
, saved_state_tree
);
2611 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2612 self
->parent
.timestamp
.tv_nsec
);
2614 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2619 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2621 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2623 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2628 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2636 static gboolean
block_start(void *hook_data
, void *call_data
)
2638 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2640 LttvTracefileState
*tfcs
;
2642 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2644 LttEventPosition
*ep
;
2646 guint i
, nb_block
, nb_event
, nb_tracefile
;
2650 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2652 LttvAttributeValue value
;
2654 ep
= ltt_event_position_new();
2656 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2658 /* Count the number of events added since the last block end in any
2661 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2663 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2664 LttvTracefileContext
, i
));
2665 ltt_event_position(tfcs
->parent
.e
, ep
);
2666 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2667 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2668 tfcs
->saved_position
= nb_event
;
2672 if(tcs
->nb_event
>= tcs
->save_interval
) {
2673 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2674 LTTV_STATE_SAVED_STATES
);
2675 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2676 value
= lttv_attribute_add(saved_states_tree
,
2677 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2678 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2679 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2680 *(value
.v_time
) = self
->parent
.timestamp
;
2681 lttv_state_save(tcs
, saved_state_tree
);
2683 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2684 self
->parent
.timestamp
.tv_nsec
);
2686 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2692 static gboolean
block_end(void *hook_data
, void *call_data
)
2694 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2696 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2700 LttEventPosition
*ep
;
2702 guint nb_block
, nb_event
;
2704 ep
= ltt_event_position_new();
2705 ltt_event_position(self
->parent
.e
, ep
);
2706 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2707 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2708 self
->saved_position
= 0;
2709 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2716 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2718 LttvTraceset
*traceset
= self
->parent
.ts
;
2720 guint i
, j
, nb_trace
, nb_tracefile
;
2724 LttvTracefileState
*tfs
;
2726 LttvTraceHook hook_start
, hook_end
;
2728 nb_trace
= lttv_traceset_number(traceset
);
2729 for(i
= 0 ; i
< nb_trace
; i
++) {
2730 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2732 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2733 NULL
, NULL
, block_start
, &hook_start
);
2734 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2735 NULL
, NULL
, block_end
, &hook_end
);
2737 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2739 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2741 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2742 LttvTracefileContext
, j
));
2743 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2744 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2745 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2746 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2752 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2754 LttvTraceset
*traceset
= self
->parent
.ts
;
2756 guint i
, j
, nb_trace
, nb_tracefile
;
2760 LttvTracefileState
*tfs
;
2763 nb_trace
= lttv_traceset_number(traceset
);
2764 for(i
= 0 ; i
< nb_trace
; i
++) {
2766 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2767 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2769 guint
*event_count
= g_new(guint
, 1);
2772 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2774 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2775 LttvTracefileContext
*, j
));
2776 lttv_hooks_add(tfs
->parent
.event
,
2777 state_save_event_hook
,
2784 lttv_process_traceset_begin(&self
->parent
,
2785 NULL
, NULL
, NULL
, NULL
, NULL
);
2789 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2791 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2793 lttv_state_save_add_event_hooks(tss
);
2800 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2802 LttvTraceset
*traceset
= self
->parent
.ts
;
2804 guint i
, j
, nb_trace
, nb_tracefile
;
2808 LttvTracefileState
*tfs
;
2810 LttvTraceHook hook_start
, hook_end
;
2812 nb_trace
= lttv_traceset_number(traceset
);
2813 for(i
= 0 ; i
< nb_trace
; i
++) {
2814 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2816 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2817 NULL
, NULL
, block_start
, &hook_start
);
2819 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2820 NULL
, NULL
, block_end
, &hook_end
);
2822 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2824 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2826 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2827 LttvTracefileContext
, j
));
2828 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2829 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2830 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2831 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2837 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2839 LttvTraceset
*traceset
= self
->parent
.ts
;
2841 guint i
, j
, nb_trace
, nb_tracefile
;
2845 LttvTracefileState
*tfs
;
2847 LttvHooks
*after_trace
= lttv_hooks_new();
2849 lttv_hooks_add(after_trace
,
2850 state_save_after_trace_hook
,
2855 lttv_process_traceset_end(&self
->parent
,
2856 NULL
, after_trace
, NULL
, NULL
, NULL
);
2858 lttv_hooks_destroy(after_trace
);
2860 nb_trace
= lttv_traceset_number(traceset
);
2861 for(i
= 0 ; i
< nb_trace
; i
++) {
2863 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2864 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2866 guint
*event_count
= NULL
;
2868 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2870 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2871 LttvTracefileContext
*, j
));
2872 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2873 state_save_event_hook
);
2875 if(event_count
) g_free(event_count
);
2879 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2881 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2883 lttv_state_save_remove_event_hooks(tss
);
2888 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2890 LttvTraceset
*traceset
= self
->parent
.ts
;
2894 int min_pos
, mid_pos
, max_pos
;
2896 guint call_rest
= 0;
2898 LttvTraceState
*tcs
;
2900 LttvAttributeValue value
;
2902 LttvAttributeType type
;
2904 LttvAttributeName name
;
2908 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2910 //g_tree_destroy(self->parent.pqueue);
2911 //self->parent.pqueue = g_tree_new(compare_tracefile);
2913 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2915 nb_trace
= lttv_traceset_number(traceset
);
2916 for(i
= 0 ; i
< nb_trace
; i
++) {
2917 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2919 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2920 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2921 LTTV_STATE_SAVED_STATES
);
2924 if(saved_states_tree
) {
2925 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2926 mid_pos
= max_pos
/ 2;
2927 while(min_pos
< max_pos
) {
2928 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2930 g_assert(type
== LTTV_GOBJECT
);
2931 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2932 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2934 g_assert(type
== LTTV_TIME
);
2935 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2937 closest_tree
= saved_state_tree
;
2939 else max_pos
= mid_pos
- 1;
2941 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2945 /* restore the closest earlier saved state */
2947 lttv_state_restore(tcs
, closest_tree
);
2951 /* There is no saved state, yet we want to have it. Restart at T0 */
2953 restore_init_state(tcs
);
2954 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2957 /* We want to seek quickly without restoring/updating the state */
2959 restore_init_state(tcs
);
2960 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2963 if(!call_rest
) g_info("NOT Calling restore");
2968 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2974 traceset_state_finalize (LttvTracesetState
*self
)
2976 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2977 finalize(G_OBJECT(self
));
2982 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2984 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2986 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2987 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2988 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2989 klass
->new_traceset_context
= new_traceset_context
;
2990 klass
->new_trace_context
= new_trace_context
;
2991 klass
->new_tracefile_context
= new_tracefile_context
;
2996 lttv_traceset_state_get_type(void)
2998 static GType type
= 0;
3000 static const GTypeInfo info
= {
3001 sizeof (LttvTracesetStateClass
),
3002 NULL
, /* base_init */
3003 NULL
, /* base_finalize */
3004 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3005 NULL
, /* class_finalize */
3006 NULL
, /* class_data */
3007 sizeof (LttvTracesetState
),
3008 0, /* n_preallocs */
3009 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3010 NULL
/* value handling */
3013 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3021 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3027 trace_state_finalize (LttvTraceState
*self
)
3029 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3030 finalize(G_OBJECT(self
));
3035 trace_state_class_init (LttvTraceStateClass
*klass
)
3037 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3039 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3040 klass
->state_save
= state_save
;
3041 klass
->state_restore
= state_restore
;
3042 klass
->state_saved_free
= state_saved_free
;
3047 lttv_trace_state_get_type(void)
3049 static GType type
= 0;
3051 static const GTypeInfo info
= {
3052 sizeof (LttvTraceStateClass
),
3053 NULL
, /* base_init */
3054 NULL
, /* base_finalize */
3055 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3056 NULL
, /* class_finalize */
3057 NULL
, /* class_data */
3058 sizeof (LttvTraceState
),
3059 0, /* n_preallocs */
3060 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3061 NULL
/* value handling */
3064 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3065 "LttvTraceStateType", &info
, 0);
3072 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3078 tracefile_state_finalize (LttvTracefileState
*self
)
3080 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3081 finalize(G_OBJECT(self
));
3086 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3088 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3090 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3095 lttv_tracefile_state_get_type(void)
3097 static GType type
= 0;
3099 static const GTypeInfo info
= {
3100 sizeof (LttvTracefileStateClass
),
3101 NULL
, /* base_init */
3102 NULL
, /* base_finalize */
3103 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3104 NULL
, /* class_finalize */
3105 NULL
, /* class_data */
3106 sizeof (LttvTracefileState
),
3107 0, /* n_preallocs */
3108 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3109 NULL
/* value handling */
3112 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3113 "LttvTracefileStateType", &info
, 0);
3119 static void module_init()
3121 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3122 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3123 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3124 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3125 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3126 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3127 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3128 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3129 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3130 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3131 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3132 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3133 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3134 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3135 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3136 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3137 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3138 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3139 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3140 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3141 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3142 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3143 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3144 LTTV_STATE_EVENT
= g_quark_from_string("event");
3145 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3146 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3147 LTTV_STATE_TIME
= g_quark_from_string("time");
3148 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3149 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3150 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3151 g_quark_from_string("trace_state_use_count");
3154 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3155 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3156 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3157 LTT_FACILITY_FS
= g_quark_from_string("fs");
3158 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3159 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3162 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3163 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3164 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3165 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3166 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3167 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3168 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3169 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3170 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3171 LTT_EVENT_FORK
= g_quark_from_string("fork");
3172 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3173 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3174 LTT_EVENT_FREE
= g_quark_from_string("free");
3175 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3176 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3177 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3178 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3179 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3182 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3183 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3184 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3185 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3186 LTT_FIELD_OUT
= g_quark_from_string("out");
3187 LTT_FIELD_IN
= g_quark_from_string("in");
3188 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3189 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3190 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3191 LTT_FIELD_PID
= g_quark_from_string("pid");
3192 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3193 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3194 LTT_FIELD_NAME
= g_quark_from_string("name");
3195 LTT_FIELD_TYPE
= g_quark_from_string("type");
3196 LTT_FIELD_MODE
= g_quark_from_string("mode");
3197 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3198 LTT_FIELD_STATUS
= g_quark_from_string("status");
3199 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3200 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3204 static void module_destroy()
3209 LTTV_MODULE("state", "State computation", \
3210 "Update the system state, possibly saving it at intervals", \
3211 module_init
, module_destroy
)