1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_USER_GENERIC
;
57 LTT_EVENT_SYSCALL_ENTRY
,
58 LTT_EVENT_SYSCALL_EXIT
,
63 LTT_EVENT_SOFT_IRQ_ENTRY
,
64 LTT_EVENT_SOFT_IRQ_EXIT
,
65 LTT_EVENT_SCHED_SCHEDULE
,
66 LTT_EVENT_PROCESS_FORK
,
67 LTT_EVENT_KTHREAD_CREATE
,
68 LTT_EVENT_PROCESS_EXIT
,
69 LTT_EVENT_PROCESS_FREE
,
71 LTT_EVENT_PROCESS_STATE
,
72 LTT_EVENT_STATEDUMP_END
,
73 LTT_EVENT_FUNCTION_ENTRY
,
74 LTT_EVENT_FUNCTION_EXIT
,
75 LTT_EVENT_THREAD_BRAND
;
83 LTT_FIELD_SOFT_IRQ_ID
,
102 LTTV_STATE_MODE_UNKNOWN
,
103 LTTV_STATE_USER_MODE
,
110 LTTV_STATE_SUBMODE_UNKNOWN
,
111 LTTV_STATE_SUBMODE_NONE
;
115 LTTV_STATE_WAIT_FORK
,
124 LTTV_STATE_UNBRANDED
;
127 LTTV_STATE_USER_THREAD
,
128 LTTV_STATE_KERNEL_THREAD
;
143 LTTV_STATE_TRACEFILES
,
144 LTTV_STATE_PROCESSES
,
146 LTTV_STATE_RUNNING_PROCESS
,
148 LTTV_STATE_SAVED_STATES
,
149 LTTV_STATE_SAVED_STATES_TIME
,
152 LTTV_STATE_NAME_TABLES
,
153 LTTV_STATE_TRACE_STATE_USE_COUNT
,
154 LTTV_STATE_RESOURCE_CPUS
;
156 static void create_max_time(LttvTraceState
*tcs
);
158 static void get_max_time(LttvTraceState
*tcs
);
160 static void free_max_time(LttvTraceState
*tcs
);
162 static void create_name_tables(LttvTraceState
*tcs
);
164 static void get_name_tables(LttvTraceState
*tcs
);
166 static void free_name_tables(LttvTraceState
*tcs
);
168 static void free_saved_state(LttvTraceState
*tcs
);
170 static void lttv_state_free_process_table(GHashTable
*processes
);
172 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
173 GPtrArray
*quarktable
);
175 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
177 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
181 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
183 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
187 void lttv_state_state_saved_free(LttvTraceState
*self
,
188 LttvAttribute
*container
)
190 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
194 guint
process_hash(gconstpointer key
)
196 guint pid
= ((const LttvProcessState
*)key
)->pid
;
197 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
201 /* If the hash table hash function is well distributed,
202 * the process_equal should compare different pid */
203 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
205 const LttvProcessState
*process_a
, *process_b
;
208 process_a
= (const LttvProcessState
*)a
;
209 process_b
= (const LttvProcessState
*)b
;
211 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
212 else if(likely(process_a
->pid
== 0 &&
213 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
218 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
220 g_tree_destroy((GTree
*)value
);
223 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
225 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
226 g_hash_table_destroy(usertraces
);
232 restore_init_state(LttvTraceState
*self
)
236 LttvTracefileState
*tfcs
;
238 LttTime start_time
, end_time
;
240 /* Free the process tables */
241 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
242 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
243 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
244 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
247 /* Seek time to beginning */
248 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
249 // closest. It's the tracecontext job to seek the trace to the beginning
250 // anyway : the init state might be used at the middle of the trace as well...
251 //g_tree_destroy(self->parent.ts_context->pqueue);
252 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
254 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
256 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
258 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
260 /* Put the per cpu running_process to beginning state : process 0. */
261 for(i
=0; i
< nb_cpus
; i
++) {
262 LttvExecutionState
*es
;
263 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
264 LTTV_STATE_UNNAMED
, &start_time
);
265 /* We are not sure is it's a kernel thread or normal thread, put the
266 * bottom stack state to unknown */
267 self
->running_process
[i
]->execution_stack
=
268 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
269 es
= self
->running_process
[i
]->state
=
270 &g_array_index(self
->running_process
[i
]->execution_stack
,
271 LttvExecutionState
, 0);
272 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
273 es
->s
= LTTV_STATE_UNNAMED
;
275 //self->running_process[i]->state->s = LTTV_STATE_RUN;
276 self
->running_process
[i
]->cpu
= i
;
280 nb_tracefile
= self
->parent
.tracefiles
->len
;
282 for(i
= 0 ; i
< nb_tracefile
; i
++) {
284 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
285 LttvTracefileContext
*, i
));
286 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
287 // tfcs->saved_position = 0;
288 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
289 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
290 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
291 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
296 //static LttTime time_zero = {0,0};
298 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
301 const LttTime
*t1
= (const LttTime
*)a
;
302 const LttTime
*t2
= (const LttTime
*)b
;
304 return ltt_time_compare(*t1
, *t2
);
307 static void free_usertrace_key(gpointer data
)
312 #define MAX_STRING_LEN 4096
315 state_load_saved_states(LttvTraceState
*tcs
)
318 GPtrArray
*quarktable
;
323 tcs
->has_precomputed_states
= FALSE
;
327 gchar buf
[MAX_STRING_LEN
];
330 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
331 strncpy(path
, trace_path
, PATH_MAX
-1);
332 count
= strnlen(trace_path
, PATH_MAX
-1);
333 // quarktable : open, test
334 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
335 fp
= fopen(path
, "r");
337 quarktable
= g_ptr_array_sized_new(4096);
339 /* Index 0 is null */
341 if(hdr
== EOF
) return;
342 g_assert(hdr
== HDR_QUARKS
);
346 if(hdr
== EOF
) break;
347 g_assert(hdr
== HDR_QUARK
);
348 g_ptr_array_set_size(quarktable
, q
+1);
351 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
352 if(buf
[i
] == '\0' || feof(fp
)) break;
355 len
= strnlen(buf
, MAX_STRING_LEN
-1);
356 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
357 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
363 // saved_states : open, test
364 strncpy(path
, trace_path
, PATH_MAX
-1);
365 count
= strnlen(trace_path
, PATH_MAX
-1);
366 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
367 fp
= fopen(path
, "r");
371 if(hdr
!= HDR_TRACE
) goto end
;
373 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
375 tcs
->has_precomputed_states
= TRUE
;
380 /* Free the quarktable */
381 for(i
=0; i
<quarktable
->len
; i
++) {
382 string
= g_ptr_array_index (quarktable
, i
);
385 g_ptr_array_free(quarktable
, TRUE
);
390 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
392 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
395 LttvTraceContext
*tc
;
399 LttvTracefileState
*tfcs
;
401 LttvAttributeValue v
;
403 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
404 init((LttvTracesetContext
*)self
, ts
);
406 nb_trace
= lttv_traceset_number(ts
);
407 for(i
= 0 ; i
< nb_trace
; i
++) {
408 tc
= self
->parent
.traces
[i
];
409 tcs
= LTTV_TRACE_STATE(tc
);
410 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
411 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
415 if(*(v
.v_uint
) == 1) {
416 create_name_tables(tcs
);
417 create_max_time(tcs
);
419 get_name_tables(tcs
);
422 nb_tracefile
= tc
->tracefiles
->len
;
423 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
424 nb_irq
= tcs
->nb_irqs
;
425 tcs
->processes
= NULL
;
426 tcs
->usertraces
= NULL
;
427 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
429 /* init cpu resource stuff */
430 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
431 for(j
= 0; j
<nb_cpu
; j
++) {
432 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
433 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
436 /* init irq resource stuff */
437 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
438 for(j
= 0; j
<nb_irq
; j
++) {
439 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
440 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
443 restore_init_state(tcs
);
444 for(j
= 0 ; j
< nb_tracefile
; j
++) {
446 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
447 LttvTracefileContext
*, j
));
448 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
449 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
450 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
451 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
452 /* It's a Usertrace */
453 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
454 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
456 if(!usertrace_tree
) {
457 usertrace_tree
= g_tree_new_full(compare_usertraces
,
458 NULL
, free_usertrace_key
, NULL
);
459 g_hash_table_insert(tcs
->usertraces
,
460 (gpointer
)tid
, usertrace_tree
);
462 LttTime
*timestamp
= g_new(LttTime
, 1);
463 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
464 ltt_tracefile_creation(tfcs
->parent
.tf
));
465 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
469 /* See if the trace has saved states */
470 state_load_saved_states(tcs
);
475 fini(LttvTracesetState
*self
)
481 LttvTracefileState
*tfcs
;
483 LttvAttributeValue v
;
485 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
486 for(i
= 0 ; i
< nb_trace
; i
++) {
487 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
488 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
491 g_assert(*(v
.v_uint
) != 0);
494 if(*(v
.v_uint
) == 0) {
495 free_name_tables(tcs
);
497 free_saved_state(tcs
);
499 g_free(tcs
->running_process
);
500 tcs
->running_process
= NULL
;
501 lttv_state_free_process_table(tcs
->processes
);
502 lttv_state_free_usertraces(tcs
->usertraces
);
503 tcs
->processes
= NULL
;
504 tcs
->usertraces
= NULL
;
506 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
507 fini((LttvTracesetContext
*)self
);
511 static LttvTracesetContext
*
512 new_traceset_context(LttvTracesetContext
*self
)
514 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
518 static LttvTraceContext
*
519 new_trace_context(LttvTracesetContext
*self
)
521 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
525 static LttvTracefileContext
*
526 new_tracefile_context(LttvTracesetContext
*self
)
528 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
532 /* Write the process state of the trace */
534 static void write_process_state(gpointer key
, gpointer value
,
537 LttvProcessState
*process
;
539 LttvExecutionState
*es
;
541 FILE *fp
= (FILE *)user_data
;
546 process
= (LttvProcessState
*)value
;
548 " <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",
549 process
, process
->pid
, process
->tgid
, process
->ppid
,
550 g_quark_to_string(process
->type
),
551 process
->creation_time
.tv_sec
,
552 process
->creation_time
.tv_nsec
,
553 process
->insertion_time
.tv_sec
,
554 process
->insertion_time
.tv_nsec
,
555 g_quark_to_string(process
->name
),
556 g_quark_to_string(process
->brand
),
559 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
560 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
561 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
562 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
563 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
564 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
565 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
568 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
569 address
= &g_array_index(process
->user_stack
, guint64
, i
);
570 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
574 if(process
->usertrace
) {
575 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
576 g_quark_to_string(process
->usertrace
->tracefile_name
),
577 process
->usertrace
->cpu
);
581 fprintf(fp
, " </PROCESS>\n");
585 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
587 guint i
, nb_tracefile
, nb_block
, offset
;
590 LttvTracefileState
*tfcs
;
594 LttEventPosition
*ep
;
598 ep
= ltt_event_position_new();
600 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
602 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
604 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
605 for(i
=0;i
<nb_cpus
;i
++) {
606 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
607 i
, self
->running_process
[i
]->pid
);
610 nb_tracefile
= self
->parent
.tracefiles
->len
;
612 for(i
= 0 ; i
< nb_tracefile
; i
++) {
614 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
615 LttvTracefileContext
*, i
));
616 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
617 tfcs
->parent
.timestamp
.tv_sec
,
618 tfcs
->parent
.timestamp
.tv_nsec
);
619 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
620 if(e
== NULL
) fprintf(fp
,"/>\n");
622 ltt_event_position(e
, ep
);
623 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
624 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
629 fprintf(fp
,"</PROCESS_STATE>\n");
633 static void write_process_state_raw(gpointer key
, gpointer value
,
636 LttvProcessState
*process
;
638 LttvExecutionState
*es
;
640 FILE *fp
= (FILE *)user_data
;
645 process
= (LttvProcessState
*)value
;
646 fputc(HDR_PROCESS
, fp
);
647 //fwrite(&header, sizeof(header), 1, fp);
648 //fprintf(fp, "%s", g_quark_to_string(process->type));
650 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
651 //fprintf(fp, "%s", g_quark_to_string(process->name));
653 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
654 //fprintf(fp, "%s", g_quark_to_string(process->brand));
656 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
657 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
658 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
659 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
660 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
661 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
662 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
666 " <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",
667 process
, process
->pid
, process
->tgid
, process
->ppid
,
668 g_quark_to_string(process
->type
),
669 process
->creation_time
.tv_sec
,
670 process
->creation_time
.tv_nsec
,
671 process
->insertion_time
.tv_sec
,
672 process
->insertion_time
.tv_nsec
,
673 g_quark_to_string(process
->name
),
674 g_quark_to_string(process
->brand
),
678 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
679 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
682 //fprintf(fp, "%s", g_quark_to_string(es->t));
684 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
685 //fprintf(fp, "%s", g_quark_to_string(es->n));
687 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
688 //fprintf(fp, "%s", g_quark_to_string(es->s));
690 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
691 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
692 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
693 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
695 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
696 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
697 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
698 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
699 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
703 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
704 address
= &g_array_index(process
->user_stack
, guint64
, i
);
705 fputc(HDR_USER_STACK
, fp
);
706 fwrite(&address
, sizeof(address
), 1, fp
);
708 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
713 if(process
->usertrace
) {
714 fputc(HDR_USERTRACE
, fp
);
715 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
717 fwrite(&process
->usertrace
->tracefile_name
,
718 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
719 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
721 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
722 g_quark_to_string(process
->usertrace
->tracefile_name
),
723 process
->usertrace
->cpu
);
730 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
732 guint i
, nb_tracefile
, nb_block
, offset
;
735 LttvTracefileState
*tfcs
;
739 LttEventPosition
*ep
;
743 ep
= ltt_event_position_new();
745 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
746 fputc(HDR_PROCESS_STATE
, fp
);
747 fwrite(&t
, sizeof(t
), 1, fp
);
749 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
751 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
752 for(i
=0;i
<nb_cpus
;i
++) {
754 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
755 fwrite(&self
->running_process
[i
]->pid
,
756 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
757 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
758 // i, self->running_process[i]->pid);
761 nb_tracefile
= self
->parent
.tracefiles
->len
;
763 for(i
= 0 ; i
< nb_tracefile
; i
++) {
765 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
766 LttvTracefileContext
*, i
));
767 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
768 // tfcs->parent.timestamp.tv_sec,
769 // tfcs->parent.timestamp.tv_nsec);
770 fputc(HDR_TRACEFILE
, fp
);
771 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
772 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
773 * position following : end of trace */
774 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
776 ltt_event_position(e
, ep
);
777 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
778 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
780 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
781 fwrite(&offset
, sizeof(offset
), 1, fp
);
782 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
789 /* Read process state from a file */
791 /* Called because a HDR_PROCESS was found */
792 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
793 GPtrArray
*quarktable
)
795 LttvExecutionState
*es
;
796 LttvProcessState
*process
, *parent_process
;
797 LttvProcessState tmp
;
804 /* TODO : check return value */
805 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
806 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
807 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
808 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
809 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
810 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
811 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
812 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
813 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
816 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
818 /* We must link to the parent */
819 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
821 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
822 if(process
== NULL
) {
823 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
825 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
829 process
->insertion_time
= tmp
.insertion_time
;
830 process
->creation_time
= tmp
.creation_time
;
831 process
->type
= g_quark_from_string(
832 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
833 process
->tgid
= tmp
.tgid
;
834 process
->ppid
= tmp
.ppid
;
835 process
->brand
= g_quark_from_string(
836 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
838 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
842 if(feof(fp
) || ferror(fp
)) goto end_loop
;
844 gint hdr
= fgetc(fp
);
845 if(hdr
== EOF
) goto end_loop
;
849 process
->execution_stack
=
850 g_array_set_size(process
->execution_stack
,
851 process
->execution_stack
->len
+ 1);
852 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
853 process
->execution_stack
->len
-1);
856 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
857 es
->t
= g_quark_from_string(
858 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
859 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
860 es
->n
= g_quark_from_string(
861 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
862 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
863 es
->s
= g_quark_from_string(
864 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
865 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
866 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
867 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
870 process
->user_stack
= g_array_set_size(process
->user_stack
,
871 process
->user_stack
->len
+ 1);
872 address
= &g_array_index(process
->user_stack
, guint64
,
873 process
->user_stack
->len
-1);
874 fread(address
, sizeof(address
), 1, fp
);
875 process
->current_function
= *address
;
878 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
879 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
891 /* Called because a HDR_PROCESS_STATE was found */
892 /* Append a saved state to the trace states */
893 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
895 guint i
, nb_tracefile
, nb_block
, offset
;
897 LttvTracefileState
*tfcs
;
899 LttEventPosition
*ep
;
907 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
909 LttvAttributeValue value
;
910 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
911 ep
= ltt_event_position_new();
913 restore_init_state(self
);
915 fread(&t
, sizeof(t
), 1, fp
);
918 if(feof(fp
) || ferror(fp
)) goto end_loop
;
920 if(hdr
== EOF
) goto end_loop
;
924 /* Call read_process_state_raw */
925 read_process_state_raw(self
, fp
, quarktable
);
935 case HDR_PROCESS_STATE
:
941 g_error("Error while parsing saved state file : unknown data header %d",
947 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
948 for(i
=0;i
<nb_cpus
;i
++) {
951 g_assert(hdr
== HDR_CPU
);
952 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
953 g_assert(i
== cpu_num
);
954 fread(&self
->running_process
[i
]->pid
,
955 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
958 nb_tracefile
= self
->parent
.tracefiles
->len
;
960 for(i
= 0 ; i
< nb_tracefile
; i
++) {
962 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
963 LttvTracefileContext
*, i
));
964 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
965 // tfcs->parent.timestamp.tv_sec,
966 // tfcs->parent.timestamp.tv_nsec);
967 g_tree_remove(pqueue
, &tfcs
->parent
);
969 g_assert(hdr
== HDR_TRACEFILE
);
970 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
971 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
972 * position following : end of trace */
973 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
974 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
975 fread(&offset
, sizeof(offset
), 1, fp
);
976 fread(&tsc
, sizeof(tsc
), 1, fp
);
977 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
978 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
980 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
985 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
986 LTTV_STATE_SAVED_STATES
);
987 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
988 value
= lttv_attribute_add(saved_states_tree
,
989 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
990 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
991 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
993 lttv_state_save(self
, saved_state_tree
);
994 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
997 *(self
->max_time_state_recomputed_in_seek
) = t
;
1001 /* Called when a HDR_TRACE is found */
1002 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1003 GPtrArray
*quarktable
)
1008 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1010 if(hdr
== EOF
) goto end_loop
;
1013 case HDR_PROCESS_STATE
:
1014 /* Call read_process_state_raw */
1015 lttv_state_read_raw(tcs
, fp
, quarktable
);
1023 case HDR_USER_STACK
:
1027 g_error("Error while parsing saved state file :"
1028 " unexpected data header %d",
1032 g_error("Error while parsing saved state file : unknown data header %d",
1037 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1038 restore_init_state(tcs
);
1039 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1045 /* Copy each process from an existing hash table to a new one */
1047 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1049 LttvProcessState
*process
, *new_process
;
1051 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1055 process
= (LttvProcessState
*)value
;
1056 new_process
= g_new(LttvProcessState
, 1);
1057 *new_process
= *process
;
1058 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1059 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1060 new_process
->execution_stack
=
1061 g_array_set_size(new_process
->execution_stack
,
1062 process
->execution_stack
->len
);
1063 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1064 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1065 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1067 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1068 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1069 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1070 sizeof(guint64
), 0);
1071 new_process
->user_stack
=
1072 g_array_set_size(new_process
->user_stack
,
1073 process
->user_stack
->len
);
1074 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1075 g_array_index(new_process
->user_stack
, guint64
, i
) =
1076 g_array_index(process
->user_stack
, guint64
, i
);
1078 new_process
->current_function
= process
->current_function
;
1079 g_hash_table_insert(new_processes
, new_process
, new_process
);
1083 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1085 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1087 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1088 return new_processes
;
1091 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1094 LttvCPUState
*retval
;
1096 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1098 for(i
=0; i
<n
; i
++) {
1099 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1100 retval
[i
].last_irq
= states
[i
].last_irq
;
1101 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1102 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1103 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1110 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1114 for(i
=0; i
<n
; i
++) {
1115 g_array_free(states
[i
].mode_stack
, FALSE
);
1121 /* The saved state for each trace contains a member "processes", which
1122 stores a copy of the process table, and a member "tracefiles" with
1123 one entry per tracefile. Each tracefile has a "process" member pointing
1124 to the current process and a "position" member storing the tracefile
1125 position (needed to seek to the current "next" event. */
1127 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1129 guint i
, nb_tracefile
, nb_cpus
;
1131 LttvTracefileState
*tfcs
;
1133 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1135 guint
*running_process
;
1137 LttvAttributeType type
;
1139 LttvAttributeValue value
;
1141 LttvAttributeName name
;
1143 LttEventPosition
*ep
;
1145 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1146 LTTV_STATE_TRACEFILES
);
1148 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1150 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1152 /* Add the currently running processes array */
1153 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1154 running_process
= g_new(guint
, nb_cpus
);
1155 for(i
=0;i
<nb_cpus
;i
++) {
1156 running_process
[i
] = self
->running_process
[i
]->pid
;
1158 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1160 *(value
.v_pointer
) = running_process
;
1162 g_info("State save");
1164 nb_tracefile
= self
->parent
.tracefiles
->len
;
1166 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1168 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1169 LttvTracefileContext
*, i
));
1170 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1171 value
= lttv_attribute_add(tracefiles_tree
, i
,
1173 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1175 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1177 *(value
.v_uint
) = tfcs
->process
->pid
;
1179 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1181 /* Only save the position if the tfs has not infinite time. */
1182 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1183 // && current_tfcs != tfcs) {
1184 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1185 *(value
.v_pointer
) = NULL
;
1187 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1188 ep
= ltt_event_position_new();
1189 ltt_event_position(e
, ep
);
1190 *(value
.v_pointer
) = ep
;
1192 guint nb_block
, offset
;
1195 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1196 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1198 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1202 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1204 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1205 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1209 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1211 guint i
, nb_tracefile
, pid
, nb_cpus
;
1213 LttvTracefileState
*tfcs
;
1215 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1217 guint
*running_process
;
1219 LttvAttributeType type
;
1221 LttvAttributeValue value
;
1223 LttvAttributeName name
;
1227 LttEventPosition
*ep
;
1229 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1231 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1232 LTTV_STATE_TRACEFILES
);
1234 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1236 g_assert(type
== LTTV_POINTER
);
1237 lttv_state_free_process_table(self
->processes
);
1238 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1240 /* Add the currently running processes array */
1241 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1242 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1244 g_assert(type
== LTTV_POINTER
);
1245 running_process
= *(value
.v_pointer
);
1246 for(i
=0;i
<nb_cpus
;i
++) {
1247 pid
= running_process
[i
];
1248 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1249 g_assert(self
->running_process
[i
] != NULL
);
1252 printf("state restore\n");
1254 nb_tracefile
= self
->parent
.tracefiles
->len
;
1256 //g_tree_destroy(tsc->pqueue);
1257 //tsc->pqueue = g_tree_new(compare_tracefile);
1259 /* restore cpu resource states */
1260 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1261 g_assert(type
== LTTV_POINTER
);
1262 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1263 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1265 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1267 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1268 LttvTracefileContext
*, i
));
1269 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1270 g_assert(type
== LTTV_GOBJECT
);
1271 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1273 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1275 g_assert(type
== LTTV_UINT
);
1276 pid
= *(value
.v_uint
);
1277 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1279 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1281 g_assert(type
== LTTV_POINTER
);
1282 //g_assert(*(value.v_pointer) != NULL);
1283 ep
= *(value
.v_pointer
);
1284 g_assert(tfcs
->parent
.t_context
!= NULL
);
1286 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1288 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1289 g_tree_remove(tsc
->pqueue
, tfc
);
1292 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1293 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1294 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1295 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1296 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1298 tfc
->timestamp
= ltt_time_infinite
;
1304 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1306 guint i
, nb_tracefile
, nb_cpus
;
1308 LttvTracefileState
*tfcs
;
1310 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1312 guint
*running_process
;
1314 LttvAttributeType type
;
1316 LttvAttributeValue value
;
1318 LttvAttributeName name
;
1322 LttEventPosition
*ep
;
1324 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1325 LTTV_STATE_TRACEFILES
);
1326 g_object_ref(G_OBJECT(tracefiles_tree
));
1327 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1329 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1331 g_assert(type
== LTTV_POINTER
);
1332 lttv_state_free_process_table(*(value
.v_pointer
));
1333 *(value
.v_pointer
) = NULL
;
1334 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1336 /* Free running processes array */
1337 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1338 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1340 g_assert(type
== LTTV_POINTER
);
1341 running_process
= *(value
.v_pointer
);
1342 g_free(running_process
);
1344 nb_tracefile
= self
->parent
.tracefiles
->len
;
1346 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1348 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1349 LttvTracefileContext
*, i
));
1350 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1351 g_assert(type
== LTTV_GOBJECT
);
1352 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1354 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1356 g_assert(type
== LTTV_POINTER
);
1357 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1359 g_object_unref(G_OBJECT(tracefiles_tree
));
1363 static void free_saved_state(LttvTraceState
*self
)
1367 LttvAttributeType type
;
1369 LttvAttributeValue value
;
1371 LttvAttributeName name
;
1375 LttvAttribute
*saved_states
;
1377 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1378 LTTV_STATE_SAVED_STATES
);
1380 nb
= lttv_attribute_get_number(saved_states
);
1381 for(i
= 0 ; i
< nb
; i
++) {
1382 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1383 g_assert(type
== LTTV_GOBJECT
);
1384 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1387 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1392 create_max_time(LttvTraceState
*tcs
)
1394 LttvAttributeValue v
;
1396 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1398 g_assert(*(v
.v_pointer
) == NULL
);
1399 *(v
.v_pointer
) = g_new(LttTime
,1);
1400 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1405 get_max_time(LttvTraceState
*tcs
)
1407 LttvAttributeValue v
;
1409 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1411 g_assert(*(v
.v_pointer
) != NULL
);
1412 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1417 free_max_time(LttvTraceState
*tcs
)
1419 LttvAttributeValue v
;
1421 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1423 g_free(*(v
.v_pointer
));
1424 *(v
.v_pointer
) = NULL
;
1428 typedef struct _LttvNameTables
{
1429 // FIXME GQuark *eventtype_names;
1430 GQuark
*syscall_names
;
1436 GQuark
*soft_irq_names
;
1442 create_name_tables(LttvTraceState
*tcs
)
1446 GQuark f_name
, e_name
;
1450 LttvTraceHookByFacility
*thf
;
1456 GString
*fe_name
= g_string_new("");
1458 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1460 LttvAttributeValue v
;
1462 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1464 g_assert(*(v
.v_pointer
) == NULL
);
1465 *(v
.v_pointer
) = name_tables
;
1466 #if 0 // Use iteration over the facilities_by_name and then list all event
1467 // types of each facility
1468 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1469 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1470 for(i
= 0 ; i
< nb
; i
++) {
1471 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1472 e_name
= ltt_eventtype_name(et
);
1473 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1474 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1475 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1478 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1479 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1480 LTT_FIELD_SYSCALL_ID
, 0, 0,
1483 thf
= lttv_trace_hook_get_first(&h
);
1485 t
= ltt_field_type(thf
->f1
);
1486 nb
= ltt_type_element_number(t
);
1488 lttv_trace_hook_destroy(&h
);
1490 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1491 name_tables
->nb_syscalls
= nb
;
1493 for(i
= 0 ; i
< nb
; i
++) {
1494 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1495 if(!name_tables
->syscall_names
[i
]) {
1496 GString
*string
= g_string_new("");
1497 g_string_printf(string
, "syscall %u", i
);
1498 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1499 g_string_free(string
, TRUE
);
1503 //name_tables->syscall_names = g_new(GQuark, 256);
1504 //for(i = 0 ; i < 256 ; i++) {
1505 // g_string_printf(fe_name, "syscall %d", i);
1506 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1509 name_tables
->syscall_names
= NULL
;
1510 name_tables
->nb_syscalls
= 0;
1513 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1514 LTT_EVENT_TRAP_ENTRY
,
1515 LTT_FIELD_TRAP_ID
, 0, 0,
1518 thf
= lttv_trace_hook_get_first(&h
);
1520 t
= ltt_field_type(thf
->f1
);
1521 //nb = ltt_type_element_number(t);
1523 lttv_trace_hook_destroy(&h
);
1526 name_tables->trap_names = g_new(GQuark, nb);
1527 for(i = 0 ; i < nb ; i++) {
1528 name_tables->trap_names[i] = g_quark_from_string(
1529 ltt_enum_string_get(t, i));
1532 name_tables
->nb_traps
= 256;
1533 name_tables
->trap_names
= g_new(GQuark
, 256);
1534 for(i
= 0 ; i
< 256 ; i
++) {
1535 g_string_printf(fe_name
, "trap %d", i
);
1536 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1539 name_tables
->trap_names
= NULL
;
1540 name_tables
->nb_traps
= 0;
1543 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1544 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1545 LTT_FIELD_IRQ_ID
, 0, 0,
1548 thf
= lttv_trace_hook_get_first(&h
);
1550 t
= ltt_field_type(thf
->f1
);
1551 //nb = ltt_type_element_number(t);
1553 lttv_trace_hook_destroy(&h
);
1556 name_tables->irq_names = g_new(GQuark, nb);
1557 for(i = 0 ; i < nb ; i++) {
1558 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1562 name_tables
->nb_irqs
= 256;
1563 name_tables
->irq_names
= g_new(GQuark
, 256);
1564 for(i
= 0 ; i
< 256 ; i
++) {
1565 g_string_printf(fe_name
, "irq %d", i
);
1566 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1569 name_tables
->nb_irqs
= 0;
1570 name_tables
->irq_names
= NULL
;
1573 name_tables->soft_irq_names = g_new(GQuark, nb);
1574 for(i = 0 ; i < nb ; i++) {
1575 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1579 name_tables
->nb_softirqs
= 256;
1580 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1581 for(i
= 0 ; i
< 256 ; i
++) {
1582 g_string_printf(fe_name
, "softirq %d", i
);
1583 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1587 g_string_free(fe_name
, TRUE
);
1592 get_name_tables(LttvTraceState
*tcs
)
1594 LttvNameTables
*name_tables
;
1596 LttvAttributeValue v
;
1598 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1600 g_assert(*(v
.v_pointer
) != NULL
);
1601 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1602 //tcs->eventtype_names = name_tables->eventtype_names;
1603 tcs
->syscall_names
= name_tables
->syscall_names
;
1604 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1605 tcs
->trap_names
= name_tables
->trap_names
;
1606 tcs
->nb_traps
= name_tables
->nb_traps
;
1607 tcs
->irq_names
= name_tables
->irq_names
;
1608 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1609 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1610 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1615 free_name_tables(LttvTraceState
*tcs
)
1617 LttvNameTables
*name_tables
;
1619 LttvAttributeValue v
;
1621 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1623 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1624 *(v
.v_pointer
) = NULL
;
1626 // g_free(name_tables->eventtype_names);
1627 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1628 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1629 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1630 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1631 if(name_tables
) g_free(name_tables
);
1634 #ifdef HASH_TABLE_DEBUG
1636 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1638 LttvProcessState
*process
= (LttvProcessState
*)value
;
1640 /* Test for process corruption */
1641 guint stack_len
= process
->execution_stack
->len
;
1644 static void hash_table_check(GHashTable
*table
)
1646 g_hash_table_foreach(table
, test_process
, NULL
);
1652 /* clears the stack and sets the state passed as argument */
1653 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1655 g_array_set_size(cpust
->mode_stack
, 1);
1656 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1659 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1661 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1662 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1665 static void cpu_pop_mode(LttvCPUState
*cpust
)
1667 if(cpust
->mode_stack
->len
== 1)
1668 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1670 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1673 /* clears the stack and sets the state passed as argument */
1674 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1676 g_array_set_size(irqst
->mode_stack
, 1);
1677 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1680 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1682 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1683 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1686 static void irq_pop_mode(LttvIRQState
*irqst
)
1688 if(irqst
->mode_stack
->len
== 1)
1689 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1691 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1694 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1697 LttvExecutionState
*es
;
1699 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1700 guint cpu
= tfs
->cpu
;
1702 #ifdef HASH_TABLE_DEBUG
1703 hash_table_check(ts
->processes
);
1705 LttvProcessState
*process
= ts
->running_process
[cpu
];
1707 guint depth
= process
->execution_stack
->len
;
1709 process
->execution_stack
=
1710 g_array_set_size(process
->execution_stack
, depth
+ 1);
1713 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1715 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1718 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1719 es
->cum_cpu_time
= ltt_time_zero
;
1720 es
->s
= process
->state
->s
;
1721 process
->state
= es
;
1725 * return 1 when empty, else 0 */
1726 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1727 LttvTracefileState
*tfs
)
1729 guint cpu
= tfs
->cpu
;
1730 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1732 guint depth
= process
->execution_stack
->len
;
1738 process
->execution_stack
=
1739 g_array_set_size(process
->execution_stack
, depth
- 1);
1740 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1742 process
->state
->change
= tfs
->parent
.timestamp
;
1747 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1749 guint cpu
= tfs
->cpu
;
1750 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1751 LttvProcessState
*process
= ts
->running_process
[cpu
];
1753 guint depth
= process
->execution_stack
->len
;
1755 if(process
->state
->t
!= t
){
1756 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1757 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1758 g_info("process state has %s when pop_int is %s\n",
1759 g_quark_to_string(process
->state
->t
),
1760 g_quark_to_string(t
));
1761 g_info("{ %u, %u, %s, %s, %s }\n",
1764 g_quark_to_string(process
->name
),
1765 g_quark_to_string(process
->brand
),
1766 g_quark_to_string(process
->state
->s
));
1771 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1772 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1776 process
->execution_stack
=
1777 g_array_set_size(process
->execution_stack
, depth
- 1);
1778 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1780 process
->state
->change
= tfs
->parent
.timestamp
;
1783 struct search_result
{
1784 const LttTime
*time
; /* Requested time */
1785 LttTime
*best
; /* Best result */
1788 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1790 const LttTime
*elem_time
= (const LttTime
*)a
;
1791 /* Explicit non const cast */
1792 struct search_result
*res
= (struct search_result
*)b
;
1794 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1795 /* The usertrace was created before the schedchange */
1796 /* Get larger keys */
1798 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1799 /* The usertrace was created after the schedchange time */
1800 /* Get smaller keys */
1802 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1803 res
->best
= elem_time
;
1806 res
->best
= elem_time
;
1813 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1814 guint pid
, const LttTime
*timestamp
)
1816 LttvTracefileState
*tfs
= NULL
;
1817 struct search_result res
;
1818 /* Find the usertrace associated with a pid and time interval.
1819 * Search in the usertraces by PID (within a hash) and then, for each
1820 * corresponding element of the array, find the first one with creation
1821 * timestamp the lowest, but higher or equal to "timestamp". */
1822 res
.time
= timestamp
;
1824 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1825 if(usertrace_tree
) {
1826 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1828 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1836 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1837 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1839 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1841 LttvExecutionState
*es
;
1843 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1848 process
->tgid
= tgid
;
1850 process
->name
= name
;
1851 process
->brand
= LTTV_STATE_UNBRANDED
;
1852 //process->last_cpu = tfs->cpu_name;
1853 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1854 process
->type
= LTTV_STATE_USER_THREAD
;
1855 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1856 process
->current_function
= 0; //function 0x0 by default.
1858 g_info("Process %u, core %p", process
->pid
, process
);
1859 g_hash_table_insert(tcs
->processes
, process
, process
);
1862 process
->ppid
= parent
->pid
;
1863 process
->creation_time
= *timestamp
;
1866 /* No parent. This process exists but we are missing all information about
1867 its creation. The birth time is set to zero but we remember the time of
1872 process
->creation_time
= ltt_time_zero
;
1875 process
->insertion_time
= *timestamp
;
1876 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1877 process
->creation_time
.tv_nsec
);
1878 process
->pid_time
= g_quark_from_string(buffer
);
1880 //process->last_cpu = tfs->cpu_name;
1881 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1882 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1883 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1884 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1885 es
= process
->state
= &g_array_index(process
->execution_stack
,
1886 LttvExecutionState
, 0);
1887 es
->t
= LTTV_STATE_USER_MODE
;
1888 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1889 es
->entry
= *timestamp
;
1890 //g_assert(timestamp->tv_sec != 0);
1891 es
->change
= *timestamp
;
1892 es
->cum_cpu_time
= ltt_time_zero
;
1893 es
->s
= LTTV_STATE_RUN
;
1895 es
= process
->state
= &g_array_index(process
->execution_stack
,
1896 LttvExecutionState
, 1);
1897 es
->t
= LTTV_STATE_SYSCALL
;
1898 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1899 es
->entry
= *timestamp
;
1900 //g_assert(timestamp->tv_sec != 0);
1901 es
->change
= *timestamp
;
1902 es
->cum_cpu_time
= ltt_time_zero
;
1903 es
->s
= LTTV_STATE_WAIT_FORK
;
1905 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1906 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1907 sizeof(guint64
), 0);
1912 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1915 LttvProcessState key
;
1916 LttvProcessState
*process
;
1920 process
= g_hash_table_lookup(ts
->processes
, &key
);
1925 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1926 const LttTime
*timestamp
)
1928 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1929 LttvExecutionState
*es
;
1931 /* Put ltt_time_zero creation time for unexisting processes */
1932 if(unlikely(process
== NULL
)) {
1933 process
= lttv_state_create_process(ts
,
1934 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1935 /* We are not sure is it's a kernel thread or normal thread, put the
1936 * bottom stack state to unknown */
1937 process
->execution_stack
=
1938 g_array_set_size(process
->execution_stack
, 1);
1939 process
->state
= es
=
1940 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1941 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1942 es
->s
= LTTV_STATE_UNNAMED
;
1947 /* FIXME : this function should be called when we receive an event telling that
1948 * release_task has been called in the kernel. In happens generally when
1949 * the parent waits for its child terminaison, but may also happen in special
1950 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1951 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1952 * of a killed thread ground, but isn't the leader.
1954 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1956 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1957 LttvProcessState key
;
1959 key
.pid
= process
->pid
;
1960 key
.cpu
= process
->cpu
;
1961 g_hash_table_remove(ts
->processes
, &key
);
1962 g_array_free(process
->execution_stack
, TRUE
);
1963 g_array_free(process
->user_stack
, TRUE
);
1968 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1970 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1971 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1976 static void lttv_state_free_process_table(GHashTable
*processes
)
1978 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1979 g_hash_table_destroy(processes
);
1983 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1985 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1987 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1988 LttvProcessState
*process
= ts
->running_process
[cpu
];
1989 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1990 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1991 LttField
*f
= thf
->f1
;
1993 LttvExecutionSubmode submode
;
1995 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1996 guint syscall
= ltt_event_get_unsigned(e
, f
);
1998 if(syscall
< nb_syscalls
) {
1999 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2002 /* Fixup an incomplete syscall table */
2003 GString
*string
= g_string_new("");
2004 g_string_printf(string
, "syscall %u", syscall
);
2005 submode
= g_quark_from_string(string
->str
);
2006 g_string_free(string
, TRUE
);
2008 /* There can be no system call from PID 0 : unknown state */
2009 if(process
->pid
!= 0)
2010 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2015 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2017 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2019 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2020 LttvProcessState
*process
= ts
->running_process
[cpu
];
2022 /* There can be no system call from PID 0 : unknown state */
2023 if(process
->pid
!= 0)
2024 pop_state(s
, LTTV_STATE_SYSCALL
);
2029 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2031 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2032 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2033 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2034 LttField
*f
= thf
->f1
;
2036 LttvExecutionSubmode submode
;
2038 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2039 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2041 if(trap
< nb_traps
) {
2042 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2044 /* Fixup an incomplete trap table */
2045 GString
*string
= g_string_new("");
2046 g_string_printf(string
, "trap %llu", trap
);
2047 submode
= g_quark_from_string(string
->str
);
2048 g_string_free(string
, TRUE
);
2051 push_state(s
, LTTV_STATE_TRAP
, submode
);
2053 /* update cpu status */
2054 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2059 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2061 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2063 pop_state(s
, LTTV_STATE_TRAP
);
2065 /* update cpu status */
2066 cpu_pop_mode(s
->cpu_state
);
2071 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2073 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2074 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2075 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2076 guint8 fac_id
= ltt_event_facility_id(e
);
2077 guint8 ev_id
= ltt_event_eventtype_id(e
);
2078 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2079 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2080 g_assert(thf
->f1
!= NULL
);
2081 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2082 LttField
*f
= thf
->f1
;
2084 LttvExecutionSubmode submode
;
2085 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2086 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2090 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2092 /* Fixup an incomplete irq table */
2093 GString
*string
= g_string_new("");
2094 g_string_printf(string
, "irq %llu", irq
);
2095 submode
= g_quark_from_string(string
->str
);
2096 g_string_free(string
, TRUE
);
2099 /* Do something with the info about being in user or system mode when int? */
2100 push_state(s
, LTTV_STATE_IRQ
, submode
);
2102 /* update cpu status */
2103 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2105 /* update irq status */
2106 s
->cpu_state
->last_irq
= irq
;
2107 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2112 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2114 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2116 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2122 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2124 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2125 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2127 pop_state(s
, LTTV_STATE_IRQ
);
2129 /* update cpu status */
2130 cpu_pop_mode(s
->cpu_state
);
2132 /* update irq status */
2133 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2138 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2140 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2141 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2142 guint8 fac_id
= ltt_event_facility_id(e
);
2143 guint8 ev_id
= ltt_event_eventtype_id(e
);
2144 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2145 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2146 g_assert(thf
->f1
!= NULL
);
2147 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2148 LttField
*f
= thf
->f1
;
2150 LttvExecutionSubmode submode
;
2151 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2152 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2155 if(softirq
< nb_softirqs
) {
2156 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2158 /* Fixup an incomplete irq table */
2159 GString
*string
= g_string_new("");
2160 g_string_printf(string
, "softirq %llu", softirq
);
2161 submode
= g_quark_from_string(string
->str
);
2162 g_string_free(string
, TRUE
);
2165 /* Do something with the info about being in user or system mode when int? */
2166 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2170 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2174 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2175 guint cpu
= tfs
->cpu
;
2176 LttvProcessState
*process
= ts
->running_process
[cpu
];
2178 guint depth
= process
->user_stack
->len
;
2180 process
->user_stack
=
2181 g_array_set_size(process
->user_stack
, depth
+ 1);
2183 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2184 *new_func
= funcptr
;
2185 process
->current_function
= funcptr
;
2188 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2190 guint cpu
= tfs
->cpu
;
2191 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2192 LttvProcessState
*process
= ts
->running_process
[cpu
];
2194 if(process
->current_function
!= funcptr
){
2195 g_info("Different functions (%lu.%09lu): ignore it\n",
2196 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2197 g_info("process state has %llu when pop_function is %llu\n",
2198 process
->current_function
, funcptr
);
2199 g_info("{ %u, %u, %s, %s, %s }\n",
2202 g_quark_to_string(process
->name
),
2203 g_quark_to_string(process
->brand
),
2204 g_quark_to_string(process
->state
->s
));
2207 guint depth
= process
->user_stack
->len
;
2210 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2211 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2215 process
->user_stack
=
2216 g_array_set_size(process
->user_stack
, depth
- 1);
2217 process
->current_function
=
2218 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2222 static gboolean
function_entry(void *hook_data
, void *call_data
)
2224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2225 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2226 guint8 fac_id
= ltt_event_facility_id(e
);
2227 guint8 ev_id
= ltt_event_eventtype_id(e
);
2228 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2229 g_assert(thf
->f1
!= NULL
);
2230 LttField
*f
= thf
->f1
;
2231 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2233 push_function(s
, funcptr
);
2237 static gboolean
function_exit(void *hook_data
, void *call_data
)
2239 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2240 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2241 guint8 fac_id
= ltt_event_facility_id(e
);
2242 guint8 ev_id
= ltt_event_eventtype_id(e
);
2243 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2244 g_assert(thf
->f1
!= NULL
);
2245 LttField
*f
= thf
->f1
;
2246 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2248 LttvExecutionSubmode submode
;
2250 pop_function(s
, funcptr
);
2254 static gboolean
schedchange(void *hook_data
, void *call_data
)
2256 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2258 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2259 LttvProcessState
*process
= ts
->running_process
[cpu
];
2260 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2262 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2263 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2264 guint pid_in
, pid_out
;
2267 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2268 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2269 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2271 if(likely(process
!= NULL
)) {
2273 /* We could not know but it was not the idle process executing.
2274 This should only happen at the beginning, before the first schedule
2275 event, and when the initial information (current process for each CPU)
2276 is missing. It is not obvious how we could, after the fact, compensate
2277 the wrongly attributed statistics. */
2279 //This test only makes sense once the state is known and if there is no
2280 //missing events. We need to silently ignore schedchange coming after a
2281 //process_free, or it causes glitches. (FIXME)
2282 //if(unlikely(process->pid != pid_out)) {
2283 // g_assert(process->pid == 0);
2285 if(process
->pid
== 0
2286 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2288 /* Scheduling out of pid 0 at beginning of the trace :
2289 * we know for sure it is in syscall mode at this point. */
2290 g_assert(process
->execution_stack
->len
== 1);
2291 process
->state
->t
= LTTV_STATE_SYSCALL
;
2292 process
->state
->s
= LTTV_STATE_WAIT
;
2293 process
->state
->change
= s
->parent
.timestamp
;
2294 process
->state
->entry
= s
->parent
.timestamp
;
2297 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2298 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2299 process
->state
->change
= s
->parent
.timestamp
;
2301 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2302 else process
->state
->s
= LTTV_STATE_WAIT
;
2303 process
->state
->change
= s
->parent
.timestamp
;
2306 if(state_out
== 32 || state_out
== 128)
2307 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2308 /* see sched.h for states */
2311 process
= ts
->running_process
[cpu
] =
2312 lttv_state_find_process_or_create(
2313 (LttvTraceState
*)s
->parent
.t_context
,
2315 &s
->parent
.timestamp
);
2316 process
->state
->s
= LTTV_STATE_RUN
;
2318 if(process
->usertrace
)
2319 process
->usertrace
->cpu
= cpu
;
2320 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2321 process
->state
->change
= s
->parent
.timestamp
;
2323 /* update cpu status */
2325 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2327 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2332 static gboolean
process_fork(void *hook_data
, void *call_data
)
2334 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2335 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2336 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2338 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2339 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2340 LttvProcessState
*zombie_process
;
2342 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2343 LttvProcessState
*process
= ts
->running_process
[cpu
];
2344 LttvProcessState
*child_process
;
2347 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2350 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2351 s
->parent
.target_pid
= child_pid
;
2354 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2355 else child_tgid
= 0;
2357 /* Mathieu : it seems like the process might have been scheduled in before the
2358 * fork, and, in a rare case, might be the current process. This might happen
2359 * in a SMP case where we don't have enough precision on the clocks.
2361 * Test reenabled after precision fixes on time. (Mathieu) */
2363 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2365 if(unlikely(zombie_process
!= NULL
)) {
2366 /* Reutilisation of PID. Only now we are sure that the old PID
2367 * has been released. FIXME : should know when release_task happens instead.
2369 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2371 for(i
=0; i
< num_cpus
; i
++) {
2372 g_assert(zombie_process
!= ts
->running_process
[i
]);
2375 exit_process(s
, zombie_process
);
2378 g_assert(process
->pid
!= child_pid
);
2379 // FIXME : Add this test in the "known state" section
2380 // g_assert(process->pid == parent_pid);
2381 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2382 if(child_process
== NULL
) {
2383 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2384 child_pid
, child_tgid
,
2385 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2387 /* The process has already been created : due to time imprecision between
2388 * multiple CPUs : it has been scheduled in before creation. Note that we
2389 * shouldn't have this kind of imprecision.
2391 * Simply put a correct parent.
2393 g_assert(0); /* This is a problematic case : the process has been created
2394 before the fork event */
2395 child_process
->ppid
= process
->pid
;
2396 child_process
->tgid
= child_tgid
;
2398 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2399 child_process
->name
= process
->name
;
2400 child_process
->brand
= process
->brand
;
2405 /* We stamp a newly created process as kernel_thread.
2406 * The thread should not be running yet. */
2407 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2409 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2410 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2411 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2414 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2415 LttvProcessState
*process
;
2416 LttvExecutionState
*es
;
2419 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2420 s
->parent
.target_pid
= pid
;
2422 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2424 process
->execution_stack
=
2425 g_array_set_size(process
->execution_stack
, 1);
2426 es
= process
->state
=
2427 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2428 es
->t
= LTTV_STATE_SYSCALL
;
2429 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2434 static gboolean
process_exit(void *hook_data
, void *call_data
)
2436 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2437 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2438 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2442 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2443 LttvProcessState
*process
; // = ts->running_process[cpu];
2445 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2446 s
->parent
.target_pid
= pid
;
2448 // FIXME : Add this test in the "known state" section
2449 // g_assert(process->pid == pid);
2451 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2452 if(likely(process
!= NULL
)) {
2453 process
->state
->s
= LTTV_STATE_EXIT
;
2458 static gboolean
process_free(void *hook_data
, void *call_data
)
2460 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2461 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2462 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2463 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2465 LttvProcessState
*process
;
2467 /* PID of the process to release */
2468 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2469 s
->parent
.target_pid
= release_pid
;
2471 g_assert(release_pid
!= 0);
2473 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2475 if(likely(process
!= NULL
)) {
2476 /* release_task is happening at kernel level : we can now safely release
2477 * the data structure of the process */
2478 //This test is fun, though, as it may happen that
2479 //at time t : CPU 0 : process_free
2480 //at time t+150ns : CPU 1 : schedule out
2481 //Clearly due to time imprecision, we disable it. (Mathieu)
2482 //If this weird case happen, we have no choice but to put the
2483 //Currently running process on the cpu to 0.
2484 //I re-enable it following time precision fixes. (Mathieu)
2485 //Well, in the case where an process is freed by a process on another CPU
2486 //and still scheduled, it happens that this is the schedchange that will
2487 //drop the last reference count. Do not free it here!
2488 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2490 for(i
=0; i
< num_cpus
; i
++) {
2491 //g_assert(process != ts->running_process[i]);
2492 if(process
== ts
->running_process
[i
]) {
2493 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2497 if(i
== num_cpus
) /* process is not scheduled */
2498 exit_process(s
, process
);
2505 static gboolean
process_exec(void *hook_data
, void *call_data
)
2507 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2508 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2509 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2510 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2513 LttvProcessState
*process
= ts
->running_process
[cpu
];
2515 #if 0//how to use a sequence that must be transformed in a string
2516 /* PID of the process to release */
2517 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2518 //name = ltt_event_get_string(e, thf->f1);
2519 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2521 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2522 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2523 memcpy(null_term_name
, name_begin
, name_len
);
2524 null_term_name
[name_len
] = '\0';
2525 process
->name
= g_quark_from_string(null_term_name
);
2528 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2529 process
->brand
= LTTV_STATE_UNBRANDED
;
2530 //g_free(null_term_name);
2534 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2536 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2537 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2538 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2539 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2542 LttvProcessState
*process
= ts
->running_process
[cpu
];
2544 name
= ltt_event_get_string(e
, thf
->f1
);
2545 process
->brand
= g_quark_from_string(name
);
2550 static void fix_process(gpointer key
, gpointer value
,
2553 LttvProcessState
*process
;
2554 LttvExecutionState
*es
;
2555 process
= (LttvProcessState
*)value
;
2556 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2557 LttTime
*timestamp
= (LttTime
*)user_data
;
2559 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2560 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2561 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2562 es
->t
= LTTV_STATE_SYSCALL
;
2563 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2564 es
->entry
= *timestamp
;
2565 es
->change
= *timestamp
;
2566 es
->cum_cpu_time
= ltt_time_zero
;
2567 if(es
->s
== LTTV_STATE_UNNAMED
)
2568 es
->s
= LTTV_STATE_WAIT
;
2571 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2572 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2573 es
->t
= LTTV_STATE_USER_MODE
;
2574 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2575 es
->entry
= *timestamp
;
2576 //g_assert(timestamp->tv_sec != 0);
2577 es
->change
= *timestamp
;
2578 es
->cum_cpu_time
= ltt_time_zero
;
2579 if(es
->s
== LTTV_STATE_UNNAMED
)
2580 es
->s
= LTTV_STATE_RUN
;
2582 if(process
->execution_stack
->len
== 1) {
2583 /* Still in bottom unknown mode, means never did a system call
2584 * May be either in user mode, syscall mode, running or waiting.*/
2585 /* FIXME : we may be tagging syscall mode when being user mode */
2586 process
->execution_stack
=
2587 g_array_set_size(process
->execution_stack
, 2);
2588 es
= process
->state
= &g_array_index(process
->execution_stack
,
2589 LttvExecutionState
, 1);
2590 es
->t
= LTTV_STATE_SYSCALL
;
2591 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2592 es
->entry
= *timestamp
;
2593 //g_assert(timestamp->tv_sec != 0);
2594 es
->change
= *timestamp
;
2595 es
->cum_cpu_time
= ltt_time_zero
;
2596 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2597 es
->s
= LTTV_STATE_WAIT
;
2603 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2605 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2606 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2607 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2608 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2609 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2611 /* For all processes */
2612 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2613 /* else, if stack[0] is unknown, set to user mode, running */
2615 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2618 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2620 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2621 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2622 //It's slow : optimise later by doing this before reading trace.
2623 LttEventType
*et
= ltt_event_eventtype(e
);
2625 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2631 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2632 LttvProcessState
*process
= ts
->running_process
[cpu
];
2633 LttvProcessState
*parent_process
;
2634 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2635 GQuark type
, mode
, submode
, status
;
2636 LttvExecutionState
*es
;
2640 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2641 s
->parent
.target_pid
= pid
;
2644 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2647 command
= ltt_event_get_string(e
, thf
->f3
);
2650 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2651 type
= ltt_enum_string_get(ltt_field_type(f4
),
2652 ltt_event_get_unsigned(e
, f4
));
2655 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2656 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2657 ltt_event_get_unsigned(e
, f5
));
2660 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2661 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2662 ltt_event_get_unsigned(e
, f6
));
2665 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2666 status
= ltt_enum_string_get(ltt_field_type(f7
),
2667 ltt_event_get_unsigned(e
, f7
));
2670 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2671 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2676 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2677 for(i
=0; i
<nb_cpus
; i
++) {
2678 process
= lttv_state_find_process(ts
, i
, pid
);
2679 g_assert(process
!= NULL
);
2681 process
->ppid
= parent_pid
;
2682 process
->tgid
= tgid
;
2683 process
->name
= g_quark_from_string(command
);
2685 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2686 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2690 /* The process might exist if a process was forked while performing the
2692 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2693 if(process
== NULL
) {
2694 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2695 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2696 pid
, tgid
, g_quark_from_string(command
),
2697 &s
->parent
.timestamp
);
2699 /* Keep the stack bottom : a running user mode */
2700 /* Disabled because of inconsistencies in the current statedump states. */
2701 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2702 /* Only keep the bottom
2703 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2704 /* Will cause expected trap when in fact being syscall (even after end of
2706 * Will cause expected interrupt when being syscall. (only before end of
2707 * statedump event) */
2708 // This will cause a "popping last state on stack, ignoring it."
2709 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2710 es
= process
->state
= &g_array_index(process
->execution_stack
,
2711 LttvExecutionState
, 0);
2712 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2713 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2714 es
->s
= LTTV_STATE_UNNAMED
;
2715 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2717 es
->t
= LTTV_STATE_SYSCALL
;
2722 /* User space process :
2723 * bottom : user mode
2724 * either currently running or scheduled out.
2725 * can be scheduled out because interrupted in (user mode or in syscall)
2726 * or because of an explicit call to the scheduler in syscall. Note that
2727 * the scheduler call comes after the irq_exit, so never in interrupt
2729 // temp workaround : set size to 1 : only have user mode bottom of stack.
2730 // will cause g_info message of expected syscall mode when in fact being
2731 // in user mode. Can also cause expected trap when in fact being user
2732 // mode in the event of a page fault reenabling interrupts in the handler.
2733 // Expected syscall and trap can also happen after the end of statedump
2734 // This will cause a "popping last state on stack, ignoring it."
2735 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2736 es
= process
->state
= &g_array_index(process
->execution_stack
,
2737 LttvExecutionState
, 0);
2738 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2739 es
->s
= LTTV_STATE_UNNAMED
;
2740 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2742 es
->t
= LTTV_STATE_USER_MODE
;
2750 es
= process
->state
= &g_array_index(process
->execution_stack
,
2751 LttvExecutionState
, 1);
2752 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2753 es
->s
= LTTV_STATE_UNNAMED
;
2754 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2758 /* The process has already been created :
2759 * Probably was forked while dumping the process state or
2760 * was simply scheduled in prior to get the state dump event.
2762 process
->ppid
= parent_pid
;
2763 process
->tgid
= tgid
;
2764 process
->name
= g_quark_from_string(command
);
2765 process
->type
= type
;
2767 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2769 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2770 if(type
== LTTV_STATE_KERNEL_THREAD
)
2771 es
->t
= LTTV_STATE_SYSCALL
;
2773 es
->t
= LTTV_STATE_USER_MODE
;
2776 /* Don't mess around with the stack, it will eventually become
2777 * ok after the end of state dump. */
2784 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2786 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2788 lttv_state_add_event_hooks(tss
);
2793 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2795 LttvTraceset
*traceset
= self
->parent
.ts
;
2797 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2801 LttvTracefileState
*tfs
;
2805 LttvTraceHookByFacility
*thf
;
2807 LttvTraceHook
*hook
;
2809 LttvAttributeValue val
;
2814 nb_trace
= lttv_traceset_number(traceset
);
2815 for(i
= 0 ; i
< nb_trace
; i
++) {
2816 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2818 /* Find the eventtype id for the following events and register the
2819 associated by id hooks. */
2821 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2822 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2825 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2826 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2827 LTT_FIELD_SYSCALL_ID
, 0, 0,
2828 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2831 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2832 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2834 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2837 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2838 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2839 LTT_FIELD_TRAP_ID
, 0, 0,
2840 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2843 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2844 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2846 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2849 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2850 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2851 LTT_FIELD_IRQ_ID
, 0, 0,
2852 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2855 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2856 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2858 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2861 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2862 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2863 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2864 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2867 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2868 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2870 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2873 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2874 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2875 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2876 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2879 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2880 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2881 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2882 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2885 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2886 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2887 LTT_FIELD_PID
, 0, 0,
2888 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2892 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2893 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
2894 LTT_FIELD_PID
, 0, 0,
2895 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2898 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2899 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
2900 LTT_FIELD_PID
, 0, 0,
2901 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2904 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2905 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2906 LTT_FIELD_FILENAME
, 0, 0,
2907 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2910 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2911 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2912 LTT_FIELD_NAME
, 0, 0,
2913 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2916 /* statedump-related hooks */
2917 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2918 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
2919 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2920 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2923 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2924 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
2926 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2929 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2930 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2931 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2932 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2935 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2936 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2937 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2938 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2941 hooks
= g_array_set_size(hooks
, hn
);
2943 /* Add these hooks to each event_by_id hooks list */
2945 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2947 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2949 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2950 LttvTracefileContext
*, j
));
2952 for(k
= 0 ; k
< hooks
->len
; k
++) {
2953 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2954 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2955 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2957 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2964 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2965 *(val
.v_pointer
) = hooks
;
2969 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2971 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2973 lttv_state_remove_event_hooks(tss
);
2978 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2980 LttvTraceset
*traceset
= self
->parent
.ts
;
2982 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2986 LttvTracefileState
*tfs
;
2990 LttvTraceHook
*hook
;
2992 LttvTraceHookByFacility
*thf
;
2994 LttvAttributeValue val
;
2996 nb_trace
= lttv_traceset_number(traceset
);
2997 for(i
= 0 ; i
< nb_trace
; i
++) {
2998 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3000 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3001 hooks
= *(val
.v_pointer
);
3003 /* Remove these hooks from each event_by_id hooks list */
3005 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3007 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3009 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3010 LttvTracefileContext
*, j
));
3012 for(k
= 0 ; k
< hooks
->len
; k
++) {
3013 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3014 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3015 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3017 lttv_hooks_remove_data(
3018 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3024 for(k
= 0 ; k
< hooks
->len
; k
++)
3025 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3026 g_array_free(hooks
, TRUE
);
3030 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3032 guint
*event_count
= (guint
*)hook_data
;
3034 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3035 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3040 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3042 LttvTracefileState
*tfcs
;
3044 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3046 LttEventPosition
*ep
;
3052 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3054 LttvAttributeValue value
;
3056 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3057 LTTV_STATE_SAVED_STATES
);
3058 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3059 value
= lttv_attribute_add(saved_states_tree
,
3060 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3061 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3062 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3063 *(value
.v_time
) = self
->parent
.timestamp
;
3064 lttv_state_save(tcs
, saved_state_tree
);
3065 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3066 self
->parent
.timestamp
.tv_nsec
);
3068 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3073 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3075 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3077 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3082 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3090 static gboolean
block_start(void *hook_data
, void *call_data
)
3092 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3094 LttvTracefileState
*tfcs
;
3096 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3098 LttEventPosition
*ep
;
3100 guint i
, nb_block
, nb_event
, nb_tracefile
;
3104 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3106 LttvAttributeValue value
;
3108 ep
= ltt_event_position_new();
3110 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3112 /* Count the number of events added since the last block end in any
3115 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3117 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3118 LttvTracefileContext
, i
));
3119 ltt_event_position(tfcs
->parent
.e
, ep
);
3120 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3121 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3122 tfcs
->saved_position
= nb_event
;
3126 if(tcs
->nb_event
>= tcs
->save_interval
) {
3127 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3128 LTTV_STATE_SAVED_STATES
);
3129 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3130 value
= lttv_attribute_add(saved_states_tree
,
3131 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3132 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3133 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3134 *(value
.v_time
) = self
->parent
.timestamp
;
3135 lttv_state_save(tcs
, saved_state_tree
);
3137 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3138 self
->parent
.timestamp
.tv_nsec
);
3140 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3146 static gboolean
block_end(void *hook_data
, void *call_data
)
3148 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3150 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3154 LttEventPosition
*ep
;
3156 guint nb_block
, nb_event
;
3158 ep
= ltt_event_position_new();
3159 ltt_event_position(self
->parent
.e
, ep
);
3160 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3161 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3162 self
->saved_position
= 0;
3163 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3170 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3172 LttvTraceset
*traceset
= self
->parent
.ts
;
3174 guint i
, j
, nb_trace
, nb_tracefile
;
3178 LttvTracefileState
*tfs
;
3180 LttvTraceHook hook_start
, hook_end
;
3182 nb_trace
= lttv_traceset_number(traceset
);
3183 for(i
= 0 ; i
< nb_trace
; i
++) {
3184 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3186 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3187 NULL
, NULL
, block_start
, &hook_start
);
3188 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3189 NULL
, NULL
, block_end
, &hook_end
);
3191 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3193 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3195 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3196 LttvTracefileContext
, j
));
3197 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3198 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3199 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3200 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3206 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3208 LttvTraceset
*traceset
= self
->parent
.ts
;
3210 guint i
, j
, nb_trace
, nb_tracefile
;
3214 LttvTracefileState
*tfs
;
3217 nb_trace
= lttv_traceset_number(traceset
);
3218 for(i
= 0 ; i
< nb_trace
; i
++) {
3220 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3221 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3223 if(ts
->has_precomputed_states
) continue;
3225 guint
*event_count
= g_new(guint
, 1);
3228 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3230 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3231 LttvTracefileContext
*, j
));
3232 lttv_hooks_add(tfs
->parent
.event
,
3233 state_save_event_hook
,
3240 lttv_process_traceset_begin(&self
->parent
,
3241 NULL
, NULL
, NULL
, NULL
, NULL
);
3245 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3247 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3249 lttv_state_save_add_event_hooks(tss
);
3256 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3258 LttvTraceset
*traceset
= self
->parent
.ts
;
3260 guint i
, j
, nb_trace
, nb_tracefile
;
3264 LttvTracefileState
*tfs
;
3266 LttvTraceHook hook_start
, hook_end
;
3268 nb_trace
= lttv_traceset_number(traceset
);
3269 for(i
= 0 ; i
< nb_trace
; i
++) {
3270 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3272 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3273 NULL
, NULL
, block_start
, &hook_start
);
3275 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3276 NULL
, NULL
, block_end
, &hook_end
);
3278 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3280 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3282 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3283 LttvTracefileContext
, j
));
3284 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3285 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3286 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3287 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3293 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3295 LttvTraceset
*traceset
= self
->parent
.ts
;
3297 guint i
, j
, nb_trace
, nb_tracefile
;
3301 LttvTracefileState
*tfs
;
3303 LttvHooks
*after_trace
= lttv_hooks_new();
3305 lttv_hooks_add(after_trace
,
3306 state_save_after_trace_hook
,
3311 lttv_process_traceset_end(&self
->parent
,
3312 NULL
, after_trace
, NULL
, NULL
, NULL
);
3314 lttv_hooks_destroy(after_trace
);
3316 nb_trace
= lttv_traceset_number(traceset
);
3317 for(i
= 0 ; i
< nb_trace
; i
++) {
3319 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3320 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3322 if(ts
->has_precomputed_states
) continue;
3324 guint
*event_count
= NULL
;
3326 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3328 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3329 LttvTracefileContext
*, j
));
3330 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3331 state_save_event_hook
);
3333 if(event_count
) g_free(event_count
);
3337 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3339 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3341 lttv_state_save_remove_event_hooks(tss
);
3346 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3348 LttvTraceset
*traceset
= self
->parent
.ts
;
3352 int min_pos
, mid_pos
, max_pos
;
3354 guint call_rest
= 0;
3356 LttvTraceState
*tcs
;
3358 LttvAttributeValue value
;
3360 LttvAttributeType type
;
3362 LttvAttributeName name
;
3366 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3368 //g_tree_destroy(self->parent.pqueue);
3369 //self->parent.pqueue = g_tree_new(compare_tracefile);
3371 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3373 nb_trace
= lttv_traceset_number(traceset
);
3374 for(i
= 0 ; i
< nb_trace
; i
++) {
3375 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3377 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3378 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3379 LTTV_STATE_SAVED_STATES
);
3382 if(saved_states_tree
) {
3383 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3384 mid_pos
= max_pos
/ 2;
3385 while(min_pos
< max_pos
) {
3386 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3388 g_assert(type
== LTTV_GOBJECT
);
3389 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3390 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3392 g_assert(type
== LTTV_TIME
);
3393 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3395 closest_tree
= saved_state_tree
;
3397 else max_pos
= mid_pos
- 1;
3399 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3403 /* restore the closest earlier saved state */
3405 lttv_state_restore(tcs
, closest_tree
);
3409 /* There is no saved state, yet we want to have it. Restart at T0 */
3411 restore_init_state(tcs
);
3412 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3415 /* We want to seek quickly without restoring/updating the state */
3417 restore_init_state(tcs
);
3418 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3421 if(!call_rest
) g_info("NOT Calling restore");
3426 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3432 traceset_state_finalize (LttvTracesetState
*self
)
3434 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3435 finalize(G_OBJECT(self
));
3440 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3442 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3444 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3445 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3446 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3447 klass
->new_traceset_context
= new_traceset_context
;
3448 klass
->new_trace_context
= new_trace_context
;
3449 klass
->new_tracefile_context
= new_tracefile_context
;
3454 lttv_traceset_state_get_type(void)
3456 static GType type
= 0;
3458 static const GTypeInfo info
= {
3459 sizeof (LttvTracesetStateClass
),
3460 NULL
, /* base_init */
3461 NULL
, /* base_finalize */
3462 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3463 NULL
, /* class_finalize */
3464 NULL
, /* class_data */
3465 sizeof (LttvTracesetState
),
3466 0, /* n_preallocs */
3467 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3468 NULL
/* value handling */
3471 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3479 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3485 trace_state_finalize (LttvTraceState
*self
)
3487 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3488 finalize(G_OBJECT(self
));
3493 trace_state_class_init (LttvTraceStateClass
*klass
)
3495 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3497 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3498 klass
->state_save
= state_save
;
3499 klass
->state_restore
= state_restore
;
3500 klass
->state_saved_free
= state_saved_free
;
3505 lttv_trace_state_get_type(void)
3507 static GType type
= 0;
3509 static const GTypeInfo info
= {
3510 sizeof (LttvTraceStateClass
),
3511 NULL
, /* base_init */
3512 NULL
, /* base_finalize */
3513 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3514 NULL
, /* class_finalize */
3515 NULL
, /* class_data */
3516 sizeof (LttvTraceState
),
3517 0, /* n_preallocs */
3518 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3519 NULL
/* value handling */
3522 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3523 "LttvTraceStateType", &info
, 0);
3530 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3536 tracefile_state_finalize (LttvTracefileState
*self
)
3538 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3539 finalize(G_OBJECT(self
));
3544 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3546 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3548 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3553 lttv_tracefile_state_get_type(void)
3555 static GType type
= 0;
3557 static const GTypeInfo info
= {
3558 sizeof (LttvTracefileStateClass
),
3559 NULL
, /* base_init */
3560 NULL
, /* base_finalize */
3561 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3562 NULL
, /* class_finalize */
3563 NULL
, /* class_data */
3564 sizeof (LttvTracefileState
),
3565 0, /* n_preallocs */
3566 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3567 NULL
/* value handling */
3570 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3571 "LttvTracefileStateType", &info
, 0);
3577 static void module_init()
3579 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3580 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3581 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3582 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3583 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3584 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3585 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3586 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3587 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3588 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3589 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3590 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3591 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3592 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3593 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3594 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3595 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3596 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3597 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3598 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3599 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3600 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3601 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3602 LTTV_STATE_EVENT
= g_quark_from_string("event");
3603 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3604 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3605 LTTV_STATE_TIME
= g_quark_from_string("time");
3606 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3607 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3608 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3609 g_quark_from_string("trace_state_use_count");
3610 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3613 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3614 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3615 LTT_FACILITY_FS
= g_quark_from_string("fs");
3616 LTT_FACILITY_LIST
= g_quark_from_string("list");
3617 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3620 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3621 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3622 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3623 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3624 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3625 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3626 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3627 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3628 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3629 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3630 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3631 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3632 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3633 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3634 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3635 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3636 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3637 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3638 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3641 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3642 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3643 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3644 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3645 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3646 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3647 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3648 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3649 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3650 LTT_FIELD_PID
= g_quark_from_string("pid");
3651 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3652 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3653 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3654 LTT_FIELD_NAME
= g_quark_from_string("name");
3655 LTT_FIELD_TYPE
= g_quark_from_string("type");
3656 LTT_FIELD_MODE
= g_quark_from_string("mode");
3657 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3658 LTT_FIELD_STATUS
= g_quark_from_string("status");
3659 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3660 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3662 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3663 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3664 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3665 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3666 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3668 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3669 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3670 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3673 static void module_destroy()
3678 LTTV_MODULE("state", "State computation", \
3679 "Update the system state, possibly saving it at intervals", \
3680 module_init
, module_destroy
)