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_STATEDUMP
,
53 LTT_FACILITY_USER_GENERIC
;
58 LTT_EVENT_SYSCALL_ENTRY
,
59 LTT_EVENT_SYSCALL_EXIT
,
64 LTT_EVENT_SOFT_IRQ_ENTRY
,
65 LTT_EVENT_SOFT_IRQ_EXIT
,
66 LTT_EVENT_SCHEDCHANGE
,
68 LTT_EVENT_KERNEL_THREAD
,
72 LTT_EVENT_ENUM_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
;
84 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
;
131 LTTV_STATE_TRACEFILES
,
132 LTTV_STATE_PROCESSES
,
134 LTTV_STATE_RUNNING_PROCESS
,
136 LTTV_STATE_SAVED_STATES
,
137 LTTV_STATE_SAVED_STATES_TIME
,
140 LTTV_STATE_NAME_TABLES
,
141 LTTV_STATE_TRACE_STATE_USE_COUNT
;
143 static void create_max_time(LttvTraceState
*tcs
);
145 static void get_max_time(LttvTraceState
*tcs
);
147 static void free_max_time(LttvTraceState
*tcs
);
149 static void create_name_tables(LttvTraceState
*tcs
);
151 static void get_name_tables(LttvTraceState
*tcs
);
153 static void free_name_tables(LttvTraceState
*tcs
);
155 static void free_saved_state(LttvTraceState
*tcs
);
157 static void lttv_state_free_process_table(GHashTable
*processes
);
159 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
160 GPtrArray
*quarktable
);
162 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
164 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
168 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
170 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
174 void lttv_state_state_saved_free(LttvTraceState
*self
,
175 LttvAttribute
*container
)
177 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
181 guint
process_hash(gconstpointer key
)
183 guint pid
= ((const LttvProcessState
*)key
)->pid
;
184 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
188 /* If the hash table hash function is well distributed,
189 * the process_equal should compare different pid */
190 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
192 const LttvProcessState
*process_a
, *process_b
;
195 process_a
= (const LttvProcessState
*)a
;
196 process_b
= (const LttvProcessState
*)b
;
198 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
199 else if(likely(process_a
->pid
== 0 &&
200 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
205 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
207 g_tree_destroy((GTree
*)value
);
210 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
212 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
213 g_hash_table_destroy(usertraces
);
219 restore_init_state(LttvTraceState
*self
)
223 LttvTracefileState
*tfcs
;
225 LttTime start_time
, end_time
;
227 /* Free the process tables */
228 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
229 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
230 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
231 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
234 /* Seek time to beginning */
235 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
236 // closest. It's the tracecontext job to seek the trace to the beginning
237 // anyway : the init state might be used at the middle of the trace as well...
238 //g_tree_destroy(self->parent.ts_context->pqueue);
239 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
241 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
243 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
245 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
247 /* Put the per cpu running_process to beginning state : process 0. */
248 for(i
=0; i
< nb_cpus
; i
++) {
249 LttvExecutionState
*es
;
250 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
251 LTTV_STATE_UNNAMED
, &start_time
);
252 /* We are not sure is it's a kernel thread or normal thread, put the
253 * bottom stack state to unknown */
254 self
->running_process
[i
]->execution_stack
=
255 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
256 es
= self
->running_process
[i
]->state
=
257 &g_array_index(self
->running_process
[i
]->execution_stack
,
258 LttvExecutionState
, 0);
259 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
260 es
->s
= LTTV_STATE_UNNAMED
;
262 //self->running_process[i]->state->s = LTTV_STATE_RUN;
263 self
->running_process
[i
]->cpu
= i
;
267 nb_tracefile
= self
->parent
.tracefiles
->len
;
269 for(i
= 0 ; i
< nb_tracefile
; i
++) {
271 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
272 LttvTracefileContext
*, i
));
273 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
274 // tfcs->saved_position = 0;
275 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
276 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
277 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
278 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
283 //static LttTime time_zero = {0,0};
285 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
288 const LttTime
*t1
= (const LttTime
*)a
;
289 const LttTime
*t2
= (const LttTime
*)b
;
291 return ltt_time_compare(*t1
, *t2
);
294 static void free_usertrace_key(gpointer data
)
299 #define MAX_STRING_LEN 4096
302 state_load_saved_states(LttvTraceState
*tcs
)
305 GPtrArray
*quarktable
;
310 tcs
->has_precomputed_states
= FALSE
;
314 gchar buf
[MAX_STRING_LEN
];
317 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
318 strncpy(path
, trace_path
, PATH_MAX
-1);
319 count
= strnlen(trace_path
, PATH_MAX
-1);
320 // quarktable : open, test
321 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
322 fp
= fopen(path
, "r");
324 quarktable
= g_ptr_array_sized_new(4096);
326 /* Index 0 is null */
328 if(hdr
== EOF
) return;
329 g_assert(hdr
== HDR_QUARKS
);
333 if(hdr
== EOF
) break;
334 g_assert(hdr
== HDR_QUARK
);
335 g_ptr_array_set_size(quarktable
, q
+1);
338 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
339 if(buf
[i
] == '\0' || feof(fp
)) break;
342 len
= strnlen(buf
, MAX_STRING_LEN
-1);
343 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
344 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
350 // saved_states : open, test
351 strncpy(path
, trace_path
, PATH_MAX
-1);
352 count
= strnlen(trace_path
, PATH_MAX
-1);
353 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
354 fp
= fopen(path
, "r");
358 if(hdr
!= HDR_TRACE
) goto end
;
360 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
362 tcs
->has_precomputed_states
= TRUE
;
367 /* Free the quarktable */
368 for(i
=0; i
<quarktable
->len
; i
++) {
369 string
= g_ptr_array_index (quarktable
, i
);
372 g_ptr_array_free(quarktable
, TRUE
);
377 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
379 guint i
, j
, nb_trace
, nb_tracefile
;
381 LttvTraceContext
*tc
;
385 LttvTracefileState
*tfcs
;
387 LttvAttributeValue v
;
389 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
390 init((LttvTracesetContext
*)self
, ts
);
392 nb_trace
= lttv_traceset_number(ts
);
393 for(i
= 0 ; i
< nb_trace
; i
++) {
394 tc
= self
->parent
.traces
[i
];
395 tcs
= LTTV_TRACE_STATE(tc
);
396 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
397 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
401 if(*(v
.v_uint
) == 1) {
402 create_name_tables(tcs
);
403 create_max_time(tcs
);
405 get_name_tables(tcs
);
408 nb_tracefile
= tc
->tracefiles
->len
;
409 tcs
->processes
= NULL
;
410 tcs
->usertraces
= NULL
;
411 tcs
->running_process
= g_new(LttvProcessState
*,
412 ltt_trace_get_num_cpu(tc
->t
));
413 restore_init_state(tcs
);
414 for(j
= 0 ; j
< nb_tracefile
; j
++) {
416 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
417 LttvTracefileContext
*, j
));
418 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
419 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
420 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
421 /* It's a Usertrace */
422 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
423 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
425 if(!usertrace_tree
) {
426 usertrace_tree
= g_tree_new_full(compare_usertraces
,
427 NULL
, free_usertrace_key
, NULL
);
428 g_hash_table_insert(tcs
->usertraces
,
429 (gpointer
)tid
, usertrace_tree
);
431 LttTime
*timestamp
= g_new(LttTime
, 1);
432 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
433 ltt_tracefile_creation(tfcs
->parent
.tf
));
434 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
438 /* See if the trace has saved states */
439 state_load_saved_states(tcs
);
444 fini(LttvTracesetState
*self
)
450 LttvTracefileState
*tfcs
;
452 LttvAttributeValue v
;
454 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
455 for(i
= 0 ; i
< nb_trace
; i
++) {
456 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
457 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
460 g_assert(*(v
.v_uint
) != 0);
463 if(*(v
.v_uint
) == 0) {
464 free_name_tables(tcs
);
466 free_saved_state(tcs
);
468 g_free(tcs
->running_process
);
469 tcs
->running_process
= NULL
;
470 lttv_state_free_process_table(tcs
->processes
);
471 lttv_state_free_usertraces(tcs
->usertraces
);
472 tcs
->processes
= NULL
;
473 tcs
->usertraces
= NULL
;
475 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
476 fini((LttvTracesetContext
*)self
);
480 static LttvTracesetContext
*
481 new_traceset_context(LttvTracesetContext
*self
)
483 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
487 static LttvTraceContext
*
488 new_trace_context(LttvTracesetContext
*self
)
490 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
494 static LttvTracefileContext
*
495 new_tracefile_context(LttvTracesetContext
*self
)
497 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
501 /* Write the process state of the trace */
503 static void write_process_state(gpointer key
, gpointer value
,
506 LttvProcessState
*process
;
508 LttvExecutionState
*es
;
510 FILE *fp
= (FILE *)user_data
;
515 process
= (LttvProcessState
*)value
;
517 " <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",
518 process
, process
->pid
, process
->tgid
, process
->ppid
,
519 g_quark_to_string(process
->type
),
520 process
->creation_time
.tv_sec
,
521 process
->creation_time
.tv_nsec
,
522 process
->insertion_time
.tv_sec
,
523 process
->insertion_time
.tv_nsec
,
524 g_quark_to_string(process
->name
),
525 g_quark_to_string(process
->brand
),
528 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
529 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
530 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
531 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
532 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
533 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
534 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
537 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
538 address
= &g_array_index(process
->user_stack
, guint64
, i
);
539 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
543 if(process
->usertrace
) {
544 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
545 g_quark_to_string(process
->usertrace
->tracefile_name
),
546 process
->usertrace
->cpu
);
550 fprintf(fp
, " </PROCESS>\n");
554 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
556 guint i
, nb_tracefile
, nb_block
, offset
;
559 LttvTracefileState
*tfcs
;
563 LttEventPosition
*ep
;
567 ep
= ltt_event_position_new();
569 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
571 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
573 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
574 for(i
=0;i
<nb_cpus
;i
++) {
575 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
576 i
, self
->running_process
[i
]->pid
);
579 nb_tracefile
= self
->parent
.tracefiles
->len
;
581 for(i
= 0 ; i
< nb_tracefile
; i
++) {
583 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
584 LttvTracefileContext
*, i
));
585 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
586 tfcs
->parent
.timestamp
.tv_sec
,
587 tfcs
->parent
.timestamp
.tv_nsec
);
588 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
589 if(e
== NULL
) fprintf(fp
,"/>\n");
591 ltt_event_position(e
, ep
);
592 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
593 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
598 fprintf(fp
,"</PROCESS_STATE>\n");
602 static void write_process_state_raw(gpointer key
, gpointer value
,
605 LttvProcessState
*process
;
607 LttvExecutionState
*es
;
609 FILE *fp
= (FILE *)user_data
;
614 process
= (LttvProcessState
*)value
;
615 fputc(HDR_PROCESS
, fp
);
616 //fwrite(&header, sizeof(header), 1, fp);
617 //fprintf(fp, "%s", g_quark_to_string(process->type));
619 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
620 //fprintf(fp, "%s", g_quark_to_string(process->name));
622 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
623 //fprintf(fp, "%s", g_quark_to_string(process->brand));
625 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
626 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
627 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
628 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
629 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
630 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
631 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
635 " <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",
636 process
, process
->pid
, process
->tgid
, process
->ppid
,
637 g_quark_to_string(process
->type
),
638 process
->creation_time
.tv_sec
,
639 process
->creation_time
.tv_nsec
,
640 process
->insertion_time
.tv_sec
,
641 process
->insertion_time
.tv_nsec
,
642 g_quark_to_string(process
->name
),
643 g_quark_to_string(process
->brand
),
647 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
648 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
651 //fprintf(fp, "%s", g_quark_to_string(es->t));
653 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
654 //fprintf(fp, "%s", g_quark_to_string(es->n));
656 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
657 //fprintf(fp, "%s", g_quark_to_string(es->s));
659 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
660 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
661 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
662 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
664 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
665 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
666 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
667 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
668 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
672 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
673 address
= &g_array_index(process
->user_stack
, guint64
, i
);
674 fputc(HDR_USER_STACK
, fp
);
675 fwrite(&address
, sizeof(address
), 1, fp
);
677 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
682 if(process
->usertrace
) {
683 fputc(HDR_USERTRACE
, fp
);
684 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
686 fwrite(&process
->usertrace
->tracefile_name
,
687 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
688 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
690 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
691 g_quark_to_string(process
->usertrace
->tracefile_name
),
692 process
->usertrace
->cpu
);
699 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
701 guint i
, nb_tracefile
, nb_block
, offset
;
704 LttvTracefileState
*tfcs
;
708 LttEventPosition
*ep
;
712 ep
= ltt_event_position_new();
714 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
715 fputc(HDR_PROCESS_STATE
, fp
);
716 fwrite(&t
, sizeof(t
), 1, fp
);
718 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
720 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
721 for(i
=0;i
<nb_cpus
;i
++) {
723 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
724 fwrite(&self
->running_process
[i
]->pid
,
725 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
726 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
727 // i, self->running_process[i]->pid);
730 nb_tracefile
= self
->parent
.tracefiles
->len
;
732 for(i
= 0 ; i
< nb_tracefile
; i
++) {
734 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
735 LttvTracefileContext
*, i
));
736 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
737 // tfcs->parent.timestamp.tv_sec,
738 // tfcs->parent.timestamp.tv_nsec);
739 fputc(HDR_TRACEFILE
, fp
);
740 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
741 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
742 * position following : end of trace */
743 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
745 ltt_event_position(e
, ep
);
746 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
747 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
749 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
750 fwrite(&offset
, sizeof(offset
), 1, fp
);
751 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
758 /* Read process state from a file */
760 /* Called because a HDR_PROCESS was found */
761 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
762 GPtrArray
*quarktable
)
764 LttvExecutionState
*es
;
765 LttvProcessState
*process
, *parent_process
;
766 LttvProcessState tmp
;
773 /* TODO : check return value */
774 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
775 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
776 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
777 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
778 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
779 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
780 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
781 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
782 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
785 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
787 /* We must link to the parent */
788 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
790 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
791 if(process
== NULL
) {
792 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
794 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
798 process
->insertion_time
= tmp
.insertion_time
;
799 process
->creation_time
= tmp
.creation_time
;
800 process
->type
= g_quark_from_string(
801 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
802 process
->tgid
= tmp
.tgid
;
803 process
->ppid
= tmp
.ppid
;
804 process
->brand
= g_quark_from_string(
805 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
807 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
811 if(feof(fp
) || ferror(fp
)) goto end_loop
;
813 gint hdr
= fgetc(fp
);
814 if(hdr
== EOF
) goto end_loop
;
818 process
->execution_stack
=
819 g_array_set_size(process
->execution_stack
,
820 process
->execution_stack
->len
+ 1);
821 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
822 process
->execution_stack
->len
-1);
825 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
826 es
->t
= g_quark_from_string(
827 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
828 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
829 es
->n
= g_quark_from_string(
830 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
831 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
832 es
->s
= g_quark_from_string(
833 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
834 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
835 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
836 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
839 process
->user_stack
= g_array_set_size(process
->user_stack
,
840 process
->user_stack
->len
+ 1);
841 address
= &g_array_index(process
->user_stack
, guint64
,
842 process
->user_stack
->len
-1);
843 fread(address
, sizeof(address
), 1, fp
);
844 process
->current_function
= *address
;
847 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
848 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
860 /* Called because a HDR_PROCESS_STATE was found */
861 /* Append a saved state to the trace states */
862 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
864 guint i
, nb_tracefile
, nb_block
, offset
;
866 LttvTracefileState
*tfcs
;
868 LttEventPosition
*ep
;
876 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
878 LttvAttributeValue value
;
879 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
880 ep
= ltt_event_position_new();
882 restore_init_state(self
);
884 fread(&t
, sizeof(t
), 1, fp
);
887 if(feof(fp
) || ferror(fp
)) goto end_loop
;
889 if(hdr
== EOF
) goto end_loop
;
893 /* Call read_process_state_raw */
894 read_process_state_raw(self
, fp
, quarktable
);
904 case HDR_PROCESS_STATE
:
910 g_error("Error while parsing saved state file : unknown data header %d",
916 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
917 for(i
=0;i
<nb_cpus
;i
++) {
920 g_assert(hdr
== HDR_CPU
);
921 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
922 g_assert(i
== cpu_num
);
923 fread(&self
->running_process
[i
]->pid
,
924 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
927 nb_tracefile
= self
->parent
.tracefiles
->len
;
929 for(i
= 0 ; i
< nb_tracefile
; i
++) {
931 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
932 LttvTracefileContext
*, i
));
933 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
934 // tfcs->parent.timestamp.tv_sec,
935 // tfcs->parent.timestamp.tv_nsec);
936 g_tree_remove(pqueue
, &tfcs
->parent
);
938 g_assert(hdr
== HDR_TRACEFILE
);
939 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
940 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
941 * position following : end of trace */
942 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
943 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
944 fread(&offset
, sizeof(offset
), 1, fp
);
945 fread(&tsc
, sizeof(tsc
), 1, fp
);
946 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
947 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
949 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
954 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
955 LTTV_STATE_SAVED_STATES
);
956 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
957 value
= lttv_attribute_add(saved_states_tree
,
958 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
959 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
960 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
962 lttv_state_save(self
, saved_state_tree
);
963 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
966 *(self
->max_time_state_recomputed_in_seek
) = t
;
970 /* Called when a HDR_TRACE is found */
971 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
972 GPtrArray
*quarktable
)
977 if(feof(fp
) || ferror(fp
)) goto end_loop
;
979 if(hdr
== EOF
) goto end_loop
;
982 case HDR_PROCESS_STATE
:
983 /* Call read_process_state_raw */
984 lttv_state_read_raw(tcs
, fp
, quarktable
);
996 g_error("Error while parsing saved state file :"
997 " unexpected data header %d",
1001 g_error("Error while parsing saved state file : unknown data header %d",
1006 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1007 restore_init_state(tcs
);
1008 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1014 /* Copy each process from an existing hash table to a new one */
1016 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1018 LttvProcessState
*process
, *new_process
;
1020 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1024 process
= (LttvProcessState
*)value
;
1025 new_process
= g_new(LttvProcessState
, 1);
1026 *new_process
= *process
;
1027 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1028 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1029 new_process
->execution_stack
=
1030 g_array_set_size(new_process
->execution_stack
,
1031 process
->execution_stack
->len
);
1032 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1033 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1034 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1036 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1037 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1038 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1039 sizeof(guint64
), 0);
1040 new_process
->user_stack
=
1041 g_array_set_size(new_process
->user_stack
,
1042 process
->user_stack
->len
);
1043 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1044 g_array_index(new_process
->user_stack
, guint64
, i
) =
1045 g_array_index(process
->user_stack
, guint64
, i
);
1047 new_process
->current_function
= process
->current_function
;
1048 g_hash_table_insert(new_processes
, new_process
, new_process
);
1052 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1054 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1056 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1057 return new_processes
;
1061 /* The saved state for each trace contains a member "processes", which
1062 stores a copy of the process table, and a member "tracefiles" with
1063 one entry per tracefile. Each tracefile has a "process" member pointing
1064 to the current process and a "position" member storing the tracefile
1065 position (needed to seek to the current "next" event. */
1067 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1069 guint i
, nb_tracefile
, nb_cpus
;
1071 LttvTracefileState
*tfcs
;
1073 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1075 guint
*running_process
;
1077 LttvAttributeType type
;
1079 LttvAttributeValue value
;
1081 LttvAttributeName name
;
1083 LttEventPosition
*ep
;
1085 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1086 LTTV_STATE_TRACEFILES
);
1088 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1090 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1092 /* Add the currently running processes array */
1093 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1094 running_process
= g_new(guint
, nb_cpus
);
1095 for(i
=0;i
<nb_cpus
;i
++) {
1096 running_process
[i
] = self
->running_process
[i
]->pid
;
1098 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1100 *(value
.v_pointer
) = running_process
;
1102 g_info("State save");
1104 nb_tracefile
= self
->parent
.tracefiles
->len
;
1106 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1108 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1109 LttvTracefileContext
*, i
));
1110 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1111 value
= lttv_attribute_add(tracefiles_tree
, i
,
1113 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1115 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1117 *(value
.v_uint
) = tfcs
->process
->pid
;
1119 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1121 /* Only save the position if the tfs has not infinite time. */
1122 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1123 // && current_tfcs != tfcs) {
1124 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1125 *(value
.v_pointer
) = NULL
;
1127 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1128 ep
= ltt_event_position_new();
1129 ltt_event_position(e
, ep
);
1130 *(value
.v_pointer
) = ep
;
1132 guint nb_block
, offset
;
1135 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1136 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1138 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1144 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1146 guint i
, nb_tracefile
, pid
, nb_cpus
;
1148 LttvTracefileState
*tfcs
;
1150 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1152 guint
*running_process
;
1154 LttvAttributeType type
;
1156 LttvAttributeValue value
;
1158 LttvAttributeName name
;
1162 LttEventPosition
*ep
;
1164 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1166 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1167 LTTV_STATE_TRACEFILES
);
1169 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1171 g_assert(type
== LTTV_POINTER
);
1172 lttv_state_free_process_table(self
->processes
);
1173 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1175 /* Add the currently running processes array */
1176 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1177 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1179 g_assert(type
== LTTV_POINTER
);
1180 running_process
= *(value
.v_pointer
);
1181 for(i
=0;i
<nb_cpus
;i
++) {
1182 pid
= running_process
[i
];
1183 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1184 g_assert(self
->running_process
[i
] != NULL
);
1188 nb_tracefile
= self
->parent
.tracefiles
->len
;
1190 //g_tree_destroy(tsc->pqueue);
1191 //tsc->pqueue = g_tree_new(compare_tracefile);
1193 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1195 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1196 LttvTracefileContext
*, i
));
1197 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1198 g_assert(type
== LTTV_GOBJECT
);
1199 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1201 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1203 g_assert(type
== LTTV_UINT
);
1204 pid
= *(value
.v_uint
);
1205 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1207 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1209 g_assert(type
== LTTV_POINTER
);
1210 //g_assert(*(value.v_pointer) != NULL);
1211 ep
= *(value
.v_pointer
);
1212 g_assert(tfcs
->parent
.t_context
!= NULL
);
1214 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1215 g_tree_remove(tsc
->pqueue
, tfc
);
1218 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1219 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1220 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1221 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1222 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1224 tfc
->timestamp
= ltt_time_infinite
;
1230 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1232 guint i
, nb_tracefile
, nb_cpus
;
1234 LttvTracefileState
*tfcs
;
1236 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1238 guint
*running_process
;
1240 LttvAttributeType type
;
1242 LttvAttributeValue value
;
1244 LttvAttributeName name
;
1248 LttEventPosition
*ep
;
1250 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1251 LTTV_STATE_TRACEFILES
);
1252 g_object_ref(G_OBJECT(tracefiles_tree
));
1253 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1255 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1257 g_assert(type
== LTTV_POINTER
);
1258 lttv_state_free_process_table(*(value
.v_pointer
));
1259 *(value
.v_pointer
) = NULL
;
1260 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1262 /* Free running processes array */
1263 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1264 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1266 g_assert(type
== LTTV_POINTER
);
1267 running_process
= *(value
.v_pointer
);
1268 g_free(running_process
);
1270 nb_tracefile
= self
->parent
.tracefiles
->len
;
1272 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1274 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1275 LttvTracefileContext
*, i
));
1276 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1277 g_assert(type
== LTTV_GOBJECT
);
1278 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1280 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1282 g_assert(type
== LTTV_POINTER
);
1283 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1285 g_object_unref(G_OBJECT(tracefiles_tree
));
1289 static void free_saved_state(LttvTraceState
*self
)
1293 LttvAttributeType type
;
1295 LttvAttributeValue value
;
1297 LttvAttributeName name
;
1301 LttvAttribute
*saved_states
;
1303 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1304 LTTV_STATE_SAVED_STATES
);
1306 nb
= lttv_attribute_get_number(saved_states
);
1307 for(i
= 0 ; i
< nb
; i
++) {
1308 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1309 g_assert(type
== LTTV_GOBJECT
);
1310 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1313 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1318 create_max_time(LttvTraceState
*tcs
)
1320 LttvAttributeValue v
;
1322 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1324 g_assert(*(v
.v_pointer
) == NULL
);
1325 *(v
.v_pointer
) = g_new(LttTime
,1);
1326 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1331 get_max_time(LttvTraceState
*tcs
)
1333 LttvAttributeValue v
;
1335 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1337 g_assert(*(v
.v_pointer
) != NULL
);
1338 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1343 free_max_time(LttvTraceState
*tcs
)
1345 LttvAttributeValue v
;
1347 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1349 g_free(*(v
.v_pointer
));
1350 *(v
.v_pointer
) = NULL
;
1354 typedef struct _LttvNameTables
{
1355 // FIXME GQuark *eventtype_names;
1356 GQuark
*syscall_names
;
1362 GQuark
*soft_irq_names
;
1368 create_name_tables(LttvTraceState
*tcs
)
1372 GQuark f_name
, e_name
;
1376 LttvTraceHookByFacility
*thf
;
1382 GString
*fe_name
= g_string_new("");
1384 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1386 LttvAttributeValue v
;
1388 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1390 g_assert(*(v
.v_pointer
) == NULL
);
1391 *(v
.v_pointer
) = name_tables
;
1392 #if 0 // Use iteration over the facilities_by_name and then list all event
1393 // types of each facility
1394 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1395 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1396 for(i
= 0 ; i
< nb
; i
++) {
1397 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1398 e_name
= ltt_eventtype_name(et
);
1399 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1400 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1401 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1404 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1405 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1406 LTT_FIELD_SYSCALL_ID
, 0, 0,
1409 thf
= lttv_trace_hook_get_first(&h
);
1411 t
= ltt_field_type(thf
->f1
);
1412 nb
= ltt_type_element_number(t
);
1414 lttv_trace_hook_destroy(&h
);
1416 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1417 name_tables
->nb_syscalls
= nb
;
1419 for(i
= 0 ; i
< nb
; i
++) {
1420 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1421 if(!name_tables
->syscall_names
[i
]) {
1422 GString
*string
= g_string_new("");
1423 g_string_printf(string
, "syscall %u", i
);
1424 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1425 g_string_free(string
, TRUE
);
1429 //name_tables->syscall_names = g_new(GQuark, 256);
1430 //for(i = 0 ; i < 256 ; i++) {
1431 // g_string_printf(fe_name, "syscall %d", i);
1432 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1435 name_tables
->syscall_names
= NULL
;
1436 name_tables
->nb_syscalls
= 0;
1439 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1440 LTT_EVENT_TRAP_ENTRY
,
1441 LTT_FIELD_TRAP_ID
, 0, 0,
1444 thf
= lttv_trace_hook_get_first(&h
);
1446 t
= ltt_field_type(thf
->f1
);
1447 //nb = ltt_type_element_number(t);
1449 lttv_trace_hook_destroy(&h
);
1452 name_tables->trap_names = g_new(GQuark, nb);
1453 for(i = 0 ; i < nb ; i++) {
1454 name_tables->trap_names[i] = g_quark_from_string(
1455 ltt_enum_string_get(t, i));
1458 name_tables
->nb_traps
= 256;
1459 name_tables
->trap_names
= g_new(GQuark
, 256);
1460 for(i
= 0 ; i
< 256 ; i
++) {
1461 g_string_printf(fe_name
, "trap %d", i
);
1462 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1465 name_tables
->trap_names
= NULL
;
1466 name_tables
->nb_traps
= 0;
1469 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1470 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1471 LTT_FIELD_IRQ_ID
, 0, 0,
1474 thf
= lttv_trace_hook_get_first(&h
);
1476 t
= ltt_field_type(thf
->f1
);
1477 //nb = ltt_type_element_number(t);
1479 lttv_trace_hook_destroy(&h
);
1482 name_tables->irq_names = g_new(GQuark, nb);
1483 for(i = 0 ; i < nb ; i++) {
1484 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1488 name_tables
->nb_irqs
= 256;
1489 name_tables
->irq_names
= g_new(GQuark
, 256);
1490 for(i
= 0 ; i
< 256 ; i
++) {
1491 g_string_printf(fe_name
, "irq %d", i
);
1492 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1495 name_tables
->nb_irqs
= 0;
1496 name_tables
->irq_names
= NULL
;
1499 name_tables->soft_irq_names = g_new(GQuark, nb);
1500 for(i = 0 ; i < nb ; i++) {
1501 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1505 name_tables
->nb_softirqs
= 256;
1506 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1507 for(i
= 0 ; i
< 256 ; i
++) {
1508 g_string_printf(fe_name
, "softirq %d", i
);
1509 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1513 g_string_free(fe_name
, TRUE
);
1518 get_name_tables(LttvTraceState
*tcs
)
1520 LttvNameTables
*name_tables
;
1522 LttvAttributeValue v
;
1524 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1526 g_assert(*(v
.v_pointer
) != NULL
);
1527 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1528 //tcs->eventtype_names = name_tables->eventtype_names;
1529 tcs
->syscall_names
= name_tables
->syscall_names
;
1530 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1531 tcs
->trap_names
= name_tables
->trap_names
;
1532 tcs
->nb_traps
= name_tables
->nb_traps
;
1533 tcs
->irq_names
= name_tables
->irq_names
;
1534 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1535 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1536 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1541 free_name_tables(LttvTraceState
*tcs
)
1543 LttvNameTables
*name_tables
;
1545 LttvAttributeValue v
;
1547 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1549 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1550 *(v
.v_pointer
) = NULL
;
1552 // g_free(name_tables->eventtype_names);
1553 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1554 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1555 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1556 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1557 if(name_tables
) g_free(name_tables
);
1560 #ifdef HASH_TABLE_DEBUG
1562 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1564 LttvProcessState
*process
= (LttvProcessState
*)value
;
1566 /* Test for process corruption */
1567 guint stack_len
= process
->execution_stack
->len
;
1570 static void hash_table_check(GHashTable
*table
)
1572 g_hash_table_foreach(table
, test_process
, NULL
);
1579 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1582 LttvExecutionState
*es
;
1584 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1585 guint cpu
= tfs
->cpu
;
1587 #ifdef HASH_TABLE_DEBUG
1588 hash_table_check(ts
->processes
);
1590 LttvProcessState
*process
= ts
->running_process
[cpu
];
1592 guint depth
= process
->execution_stack
->len
;
1594 process
->execution_stack
=
1595 g_array_set_size(process
->execution_stack
, depth
+ 1);
1598 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1600 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1603 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1604 es
->cum_cpu_time
= ltt_time_zero
;
1605 es
->s
= process
->state
->s
;
1606 process
->state
= es
;
1610 * return 1 when empty, else 0 */
1611 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1612 LttvTracefileState
*tfs
)
1614 guint cpu
= tfs
->cpu
;
1615 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1617 guint depth
= process
->execution_stack
->len
;
1623 process
->execution_stack
=
1624 g_array_set_size(process
->execution_stack
, depth
- 1);
1625 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1627 process
->state
->change
= tfs
->parent
.timestamp
;
1632 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1634 guint cpu
= tfs
->cpu
;
1635 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1636 LttvProcessState
*process
= ts
->running_process
[cpu
];
1638 guint depth
= process
->execution_stack
->len
;
1640 if(process
->state
->t
!= t
){
1641 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1642 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1643 g_info("process state has %s when pop_int is %s\n",
1644 g_quark_to_string(process
->state
->t
),
1645 g_quark_to_string(t
));
1646 g_info("{ %u, %u, %s, %s, %s }\n",
1649 g_quark_to_string(process
->name
),
1650 g_quark_to_string(process
->brand
),
1651 g_quark_to_string(process
->state
->s
));
1656 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1657 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1661 process
->execution_stack
=
1662 g_array_set_size(process
->execution_stack
, depth
- 1);
1663 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1665 process
->state
->change
= tfs
->parent
.timestamp
;
1668 struct search_result
{
1669 const LttTime
*time
; /* Requested time */
1670 LttTime
*best
; /* Best result */
1673 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1675 const LttTime
*elem_time
= (const LttTime
*)a
;
1676 /* Explicit non const cast */
1677 struct search_result
*res
= (struct search_result
*)b
;
1679 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1680 /* The usertrace was created before the schedchange */
1681 /* Get larger keys */
1683 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1684 /* The usertrace was created after the schedchange time */
1685 /* Get smaller keys */
1687 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1688 res
->best
= elem_time
;
1691 res
->best
= elem_time
;
1698 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1699 guint pid
, const LttTime
*timestamp
)
1701 LttvTracefileState
*tfs
= NULL
;
1702 struct search_result res
;
1703 /* Find the usertrace associated with a pid and time interval.
1704 * Search in the usertraces by PID (within a hash) and then, for each
1705 * corresponding element of the array, find the first one with creation
1706 * timestamp the lowest, but higher or equal to "timestamp". */
1707 res
.time
= timestamp
;
1709 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1710 if(usertrace_tree
) {
1711 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1713 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1721 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1722 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1724 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1726 LttvExecutionState
*es
;
1728 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1733 process
->tgid
= tgid
;
1735 process
->name
= name
;
1736 process
->brand
= LTTV_STATE_UNBRANDED
;
1737 //process->last_cpu = tfs->cpu_name;
1738 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1739 process
->type
= LTTV_STATE_USER_THREAD
;
1740 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1741 process
->current_function
= 0; //function 0x0 by default.
1743 g_info("Process %u, core %p", process
->pid
, process
);
1744 g_hash_table_insert(tcs
->processes
, process
, process
);
1747 process
->ppid
= parent
->pid
;
1748 process
->creation_time
= *timestamp
;
1751 /* No parent. This process exists but we are missing all information about
1752 its creation. The birth time is set to zero but we remember the time of
1757 process
->creation_time
= ltt_time_zero
;
1760 process
->insertion_time
= *timestamp
;
1761 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1762 process
->creation_time
.tv_nsec
);
1763 process
->pid_time
= g_quark_from_string(buffer
);
1765 //process->last_cpu = tfs->cpu_name;
1766 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1767 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1768 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1769 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1770 es
= process
->state
= &g_array_index(process
->execution_stack
,
1771 LttvExecutionState
, 0);
1772 es
->t
= LTTV_STATE_USER_MODE
;
1773 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1774 es
->entry
= *timestamp
;
1775 //g_assert(timestamp->tv_sec != 0);
1776 es
->change
= *timestamp
;
1777 es
->cum_cpu_time
= ltt_time_zero
;
1778 es
->s
= LTTV_STATE_RUN
;
1780 es
= process
->state
= &g_array_index(process
->execution_stack
,
1781 LttvExecutionState
, 1);
1782 es
->t
= LTTV_STATE_SYSCALL
;
1783 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1784 es
->entry
= *timestamp
;
1785 //g_assert(timestamp->tv_sec != 0);
1786 es
->change
= *timestamp
;
1787 es
->cum_cpu_time
= ltt_time_zero
;
1788 es
->s
= LTTV_STATE_WAIT_FORK
;
1790 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1791 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1792 sizeof(guint64
), 0);
1797 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1800 LttvProcessState key
;
1801 LttvProcessState
*process
;
1805 process
= g_hash_table_lookup(ts
->processes
, &key
);
1810 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1811 const LttTime
*timestamp
)
1813 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1814 LttvExecutionState
*es
;
1816 /* Put ltt_time_zero creation time for unexisting processes */
1817 if(unlikely(process
== NULL
)) {
1818 process
= lttv_state_create_process(ts
,
1819 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1820 /* We are not sure is it's a kernel thread or normal thread, put the
1821 * bottom stack state to unknown */
1822 process
->execution_stack
=
1823 g_array_set_size(process
->execution_stack
, 1);
1824 process
->state
= es
=
1825 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1826 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1827 es
->s
= LTTV_STATE_UNNAMED
;
1832 /* FIXME : this function should be called when we receive an event telling that
1833 * release_task has been called in the kernel. In happens generally when
1834 * the parent waits for its child terminaison, but may also happen in special
1835 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1836 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1837 * of a killed thread ground, but isn't the leader.
1839 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1841 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1842 LttvProcessState key
;
1844 key
.pid
= process
->pid
;
1845 key
.cpu
= process
->cpu
;
1846 g_hash_table_remove(ts
->processes
, &key
);
1847 g_array_free(process
->execution_stack
, TRUE
);
1848 g_array_free(process
->user_stack
, TRUE
);
1853 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1855 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1856 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1861 static void lttv_state_free_process_table(GHashTable
*processes
)
1863 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1864 g_hash_table_destroy(processes
);
1868 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1870 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1872 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1873 LttvProcessState
*process
= ts
->running_process
[cpu
];
1874 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1875 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1876 LttField
*f
= thf
->f1
;
1878 LttvExecutionSubmode submode
;
1880 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1881 guint syscall
= ltt_event_get_unsigned(e
, f
);
1883 if(syscall
< nb_syscalls
) {
1884 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1887 /* Fixup an incomplete syscall table */
1888 GString
*string
= g_string_new("");
1889 g_string_printf(string
, "syscall %u", syscall
);
1890 submode
= g_quark_from_string(string
->str
);
1891 g_string_free(string
, TRUE
);
1893 /* There can be no system call from PID 0 : unknown state */
1894 if(process
->pid
!= 0)
1895 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1900 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1902 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1904 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1905 LttvProcessState
*process
= ts
->running_process
[cpu
];
1907 /* There can be no system call from PID 0 : unknown state */
1908 if(process
->pid
!= 0)
1909 pop_state(s
, LTTV_STATE_SYSCALL
);
1914 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1916 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1917 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1918 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1919 LttField
*f
= thf
->f1
;
1921 LttvExecutionSubmode submode
;
1923 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1924 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1926 if(trap
< nb_traps
) {
1927 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1929 /* Fixup an incomplete trap table */
1930 GString
*string
= g_string_new("");
1931 g_string_printf(string
, "trap %llu", trap
);
1932 submode
= g_quark_from_string(string
->str
);
1933 g_string_free(string
, TRUE
);
1936 push_state(s
, LTTV_STATE_TRAP
, submode
);
1941 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1943 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1945 pop_state(s
, LTTV_STATE_TRAP
);
1950 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1952 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1953 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1954 guint8 fac_id
= ltt_event_facility_id(e
);
1955 guint8 ev_id
= ltt_event_eventtype_id(e
);
1956 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1957 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1958 g_assert(thf
->f1
!= NULL
);
1959 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1960 LttField
*f
= thf
->f1
;
1962 LttvExecutionSubmode submode
;
1963 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
1964 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
1968 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
1970 /* Fixup an incomplete irq table */
1971 GString
*string
= g_string_new("");
1972 g_string_printf(string
, "irq %llu", irq
);
1973 submode
= g_quark_from_string(string
->str
);
1974 g_string_free(string
, TRUE
);
1977 /* Do something with the info about being in user or system mode when int? */
1978 push_state(s
, LTTV_STATE_IRQ
, submode
);
1982 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1984 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1986 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1992 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1994 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1996 pop_state(s
, LTTV_STATE_IRQ
);
2000 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2002 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2003 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2004 guint8 fac_id
= ltt_event_facility_id(e
);
2005 guint8 ev_id
= ltt_event_eventtype_id(e
);
2006 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2007 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2008 g_assert(thf
->f1
!= NULL
);
2009 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2010 LttField
*f
= thf
->f1
;
2012 LttvExecutionSubmode submode
;
2013 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2014 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2017 if(softirq
< nb_softirqs
) {
2018 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2020 /* Fixup an incomplete irq table */
2021 GString
*string
= g_string_new("");
2022 g_string_printf(string
, "softirq %llu", softirq
);
2023 submode
= g_quark_from_string(string
->str
);
2024 g_string_free(string
, TRUE
);
2027 /* Do something with the info about being in user or system mode when int? */
2028 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2032 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2036 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2037 guint cpu
= tfs
->cpu
;
2038 LttvProcessState
*process
= ts
->running_process
[cpu
];
2040 guint depth
= process
->user_stack
->len
;
2042 process
->user_stack
=
2043 g_array_set_size(process
->user_stack
, depth
+ 1);
2045 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2046 *new_func
= funcptr
;
2047 process
->current_function
= funcptr
;
2050 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2052 guint cpu
= tfs
->cpu
;
2053 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2054 LttvProcessState
*process
= ts
->running_process
[cpu
];
2056 if(process
->current_function
!= funcptr
){
2057 g_info("Different functions (%lu.%09lu): ignore it\n",
2058 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2059 g_info("process state has %llu when pop_function is %llu\n",
2060 process
->current_function
, funcptr
);
2061 g_info("{ %u, %u, %s, %s, %s }\n",
2064 g_quark_to_string(process
->name
),
2065 g_quark_to_string(process
->brand
),
2066 g_quark_to_string(process
->state
->s
));
2069 guint depth
= process
->user_stack
->len
;
2072 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2073 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2077 process
->user_stack
=
2078 g_array_set_size(process
->user_stack
, depth
- 1);
2079 process
->current_function
=
2080 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2084 static gboolean
function_entry(void *hook_data
, void *call_data
)
2086 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2087 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2088 guint8 fac_id
= ltt_event_facility_id(e
);
2089 guint8 ev_id
= ltt_event_eventtype_id(e
);
2090 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2091 g_assert(thf
->f1
!= NULL
);
2092 LttField
*f
= thf
->f1
;
2093 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2095 push_function(s
, funcptr
);
2099 static gboolean
function_exit(void *hook_data
, void *call_data
)
2101 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2102 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2103 guint8 fac_id
= ltt_event_facility_id(e
);
2104 guint8 ev_id
= ltt_event_eventtype_id(e
);
2105 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2106 g_assert(thf
->f1
!= NULL
);
2107 LttField
*f
= thf
->f1
;
2108 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2110 LttvExecutionSubmode submode
;
2112 pop_function(s
, funcptr
);
2116 static gboolean
schedchange(void *hook_data
, void *call_data
)
2118 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2120 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2121 LttvProcessState
*process
= ts
->running_process
[cpu
];
2122 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2124 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2125 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2126 guint pid_in
, pid_out
;
2129 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2130 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2131 state_out
= ltt_event_get_int(e
, thf
->f3
);
2133 if(likely(process
!= NULL
)) {
2135 /* We could not know but it was not the idle process executing.
2136 This should only happen at the beginning, before the first schedule
2137 event, and when the initial information (current process for each CPU)
2138 is missing. It is not obvious how we could, after the fact, compensate
2139 the wrongly attributed statistics. */
2141 //This test only makes sense once the state is known and if there is no
2142 //missing events. We need to silently ignore schedchange coming after a
2143 //process_free, or it causes glitches. (FIXME)
2144 //if(unlikely(process->pid != pid_out)) {
2145 // g_assert(process->pid == 0);
2147 if(process
->pid
== 0
2148 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2150 /* Scheduling out of pid 0 at beginning of the trace :
2151 * we know for sure it is in syscall mode at this point. */
2152 g_assert(process
->execution_stack
->len
== 1);
2153 process
->state
->t
= LTTV_STATE_SYSCALL
;
2154 process
->state
->s
= LTTV_STATE_WAIT
;
2155 process
->state
->change
= s
->parent
.timestamp
;
2156 process
->state
->entry
= s
->parent
.timestamp
;
2159 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2160 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2161 process
->state
->change
= s
->parent
.timestamp
;
2163 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2164 else process
->state
->s
= LTTV_STATE_WAIT
;
2165 process
->state
->change
= s
->parent
.timestamp
;
2168 if(state_out
== 32 || state_out
== 128)
2169 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2170 /* see sched.h for states */
2173 process
= ts
->running_process
[cpu
] =
2174 lttv_state_find_process_or_create(
2175 (LttvTraceState
*)s
->parent
.t_context
,
2177 &s
->parent
.timestamp
);
2178 process
->state
->s
= LTTV_STATE_RUN
;
2180 if(process
->usertrace
)
2181 process
->usertrace
->cpu
= cpu
;
2182 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2183 process
->state
->change
= s
->parent
.timestamp
;
2187 static gboolean
process_fork(void *hook_data
, void *call_data
)
2189 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2190 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2191 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2193 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2194 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2195 LttvProcessState
*zombie_process
;
2197 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2198 LttvProcessState
*process
= ts
->running_process
[cpu
];
2199 LttvProcessState
*child_process
;
2202 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2205 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2206 s
->parent
.target_pid
= child_pid
;
2209 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2210 else child_tgid
= 0;
2212 /* Mathieu : it seems like the process might have been scheduled in before the
2213 * fork, and, in a rare case, might be the current process. This might happen
2214 * in a SMP case where we don't have enough precision on the clocks.
2216 * Test reenabled after precision fixes on time. (Mathieu) */
2218 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2220 if(unlikely(zombie_process
!= NULL
)) {
2221 /* Reutilisation of PID. Only now we are sure that the old PID
2222 * has been released. FIXME : should know when release_task happens instead.
2224 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2226 for(i
=0; i
< num_cpus
; i
++) {
2227 g_assert(zombie_process
!= ts
->running_process
[i
]);
2230 exit_process(s
, zombie_process
);
2233 g_assert(process
->pid
!= child_pid
);
2234 // FIXME : Add this test in the "known state" section
2235 // g_assert(process->pid == parent_pid);
2236 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2237 if(child_process
== NULL
) {
2238 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2239 child_pid
, child_tgid
,
2240 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2242 /* The process has already been created : due to time imprecision between
2243 * multiple CPUs : it has been scheduled in before creation. Note that we
2244 * shouldn't have this kind of imprecision.
2246 * Simply put a correct parent.
2248 g_assert(0); /* This is a problematic case : the process has been created
2249 before the fork event */
2250 child_process
->ppid
= process
->pid
;
2251 child_process
->tgid
= child_tgid
;
2253 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2254 child_process
->name
= process
->name
;
2255 child_process
->brand
= process
->brand
;
2260 /* We stamp a newly created process as kernel_thread.
2261 * The thread should not be running yet. */
2262 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2264 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2265 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2266 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2269 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2270 LttvProcessState
*process
;
2271 LttvExecutionState
*es
;
2274 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2275 s
->parent
.target_pid
= pid
;
2277 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2278 process
->execution_stack
=
2279 g_array_set_size(process
->execution_stack
, 1);
2280 es
= process
->state
=
2281 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2282 es
->t
= LTTV_STATE_SYSCALL
;
2283 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2288 static gboolean
process_exit(void *hook_data
, void *call_data
)
2290 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2291 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2292 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2296 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2297 LttvProcessState
*process
; // = ts->running_process[cpu];
2299 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2300 s
->parent
.target_pid
= pid
;
2302 // FIXME : Add this test in the "known state" section
2303 // g_assert(process->pid == pid);
2305 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2306 if(likely(process
!= NULL
)) {
2307 process
->state
->s
= LTTV_STATE_EXIT
;
2312 static gboolean
process_free(void *hook_data
, void *call_data
)
2314 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2315 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2316 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2317 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2319 LttvProcessState
*process
;
2321 /* PID of the process to release */
2322 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2323 s
->parent
.target_pid
= release_pid
;
2325 g_assert(release_pid
!= 0);
2327 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2329 if(likely(process
!= NULL
)) {
2330 /* release_task is happening at kernel level : we can now safely release
2331 * the data structure of the process */
2332 //This test is fun, though, as it may happen that
2333 //at time t : CPU 0 : process_free
2334 //at time t+150ns : CPU 1 : schedule out
2335 //Clearly due to time imprecision, we disable it. (Mathieu)
2336 //If this weird case happen, we have no choice but to put the
2337 //Currently running process on the cpu to 0.
2338 //I re-enable it following time precision fixes. (Mathieu)
2339 //Well, in the case where an process is freed by a process on another CPU
2340 //and still scheduled, it happens that this is the schedchange that will
2341 //drop the last reference count. Do not free it here!
2342 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2344 for(i
=0; i
< num_cpus
; i
++) {
2345 //g_assert(process != ts->running_process[i]);
2346 if(process
== ts
->running_process
[i
]) {
2347 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2351 if(i
== num_cpus
) /* process is not scheduled */
2352 exit_process(s
, process
);
2359 static gboolean
process_exec(void *hook_data
, void *call_data
)
2361 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2362 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2363 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2364 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2367 LttvProcessState
*process
= ts
->running_process
[cpu
];
2369 /* PID of the process to release */
2370 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2371 //name = ltt_event_get_string(e, thf->f1);
2372 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2374 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2375 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2376 memcpy(null_term_name
, name_begin
, name_len
);
2377 null_term_name
[name_len
] = '\0';
2379 process
->name
= g_quark_from_string(null_term_name
);
2380 process
->brand
= LTTV_STATE_UNBRANDED
;
2381 g_free(null_term_name
);
2385 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2387 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2388 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2389 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2390 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2393 LttvProcessState
*process
= ts
->running_process
[cpu
];
2395 name
= ltt_event_get_string(e
, thf
->f1
);
2396 process
->brand
= g_quark_from_string(name
);
2401 static void fix_process(gpointer key
, gpointer value
,
2404 LttvProcessState
*process
;
2405 LttvExecutionState
*es
;
2406 process
= (LttvProcessState
*)value
;
2407 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2408 LttTime
*timestamp
= (LttTime
*)user_data
;
2410 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2411 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2412 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2413 es
->t
= LTTV_STATE_SYSCALL
;
2414 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2415 es
->entry
= *timestamp
;
2416 es
->change
= *timestamp
;
2417 es
->cum_cpu_time
= ltt_time_zero
;
2418 if(es
->s
== LTTV_STATE_UNNAMED
)
2419 es
->s
= LTTV_STATE_WAIT
;
2422 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2423 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2424 es
->t
= LTTV_STATE_USER_MODE
;
2425 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2426 es
->entry
= *timestamp
;
2427 //g_assert(timestamp->tv_sec != 0);
2428 es
->change
= *timestamp
;
2429 es
->cum_cpu_time
= ltt_time_zero
;
2430 if(es
->s
== LTTV_STATE_UNNAMED
)
2431 es
->s
= LTTV_STATE_RUN
;
2433 if(process
->execution_stack
->len
== 1) {
2434 /* Still in bottom unknown mode, means never did a system call
2435 * May be either in user mode, syscall mode, running or waiting.*/
2436 /* FIXME : we may be tagging syscall mode when being user mode */
2437 process
->execution_stack
=
2438 g_array_set_size(process
->execution_stack
, 2);
2439 es
= process
->state
= &g_array_index(process
->execution_stack
,
2440 LttvExecutionState
, 1);
2441 es
->t
= LTTV_STATE_SYSCALL
;
2442 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2443 es
->entry
= *timestamp
;
2444 //g_assert(timestamp->tv_sec != 0);
2445 es
->change
= *timestamp
;
2446 es
->cum_cpu_time
= ltt_time_zero
;
2447 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2448 es
->s
= LTTV_STATE_WAIT
;
2454 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2456 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2457 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2458 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2459 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2460 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2462 /* For all processes */
2463 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2464 /* else, if stack[0] is unknown, set to user mode, running */
2466 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2469 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2471 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2472 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2473 //It's slow : optimise later by doing this before reading trace.
2474 LttEventType
*et
= ltt_event_eventtype(e
);
2476 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2482 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2483 LttvProcessState
*process
= ts
->running_process
[cpu
];
2484 LttvProcessState
*parent_process
;
2485 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2486 GQuark type
, mode
, submode
, status
;
2487 LttvExecutionState
*es
;
2491 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2492 s
->parent
.target_pid
= pid
;
2495 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2498 command
= ltt_event_get_string(e
, thf
->f3
);
2501 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2502 type
= ltt_enum_string_get(ltt_field_type(f4
),
2503 ltt_event_get_unsigned(e
, f4
));
2506 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2507 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2508 ltt_event_get_unsigned(e
, f5
));
2511 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2512 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2513 ltt_event_get_unsigned(e
, f6
));
2516 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2517 status
= ltt_enum_string_get(ltt_field_type(f7
),
2518 ltt_event_get_unsigned(e
, f7
));
2521 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2522 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2527 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2528 for(i
=0; i
<nb_cpus
; i
++) {
2529 process
= lttv_state_find_process(ts
, i
, pid
);
2530 g_assert(process
!= NULL
);
2532 process
->ppid
= parent_pid
;
2533 process
->tgid
= tgid
;
2534 process
->name
= g_quark_from_string(command
);
2536 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2537 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2541 /* The process might exist if a process was forked while performing the
2543 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2544 if(process
== NULL
) {
2545 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2546 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2547 pid
, tgid
, g_quark_from_string(command
),
2548 &s
->parent
.timestamp
);
2550 /* Keep the stack bottom : a running user mode */
2551 /* Disabled because of inconsistencies in the current statedump states. */
2552 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2553 /* Only keep the bottom
2554 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2555 /* Will cause expected trap when in fact being syscall (even after end of
2557 * Will cause expected interrupt when being syscall. (only before end of
2558 * statedump event) */
2559 // This will cause a "popping last state on stack, ignoring it."
2560 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2561 es
= process
->state
= &g_array_index(process
->execution_stack
,
2562 LttvExecutionState
, 0);
2563 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2564 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2565 es
->s
= LTTV_STATE_UNNAMED
;
2566 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2568 es
->t
= LTTV_STATE_SYSCALL
;
2573 /* User space process :
2574 * bottom : user mode
2575 * either currently running or scheduled out.
2576 * can be scheduled out because interrupted in (user mode or in syscall)
2577 * or because of an explicit call to the scheduler in syscall. Note that
2578 * the scheduler call comes after the irq_exit, so never in interrupt
2580 // temp workaround : set size to 1 : only have user mode bottom of stack.
2581 // will cause g_info message of expected syscall mode when in fact being
2582 // in user mode. Can also cause expected trap when in fact being user
2583 // mode in the event of a page fault reenabling interrupts in the handler.
2584 // Expected syscall and trap can also happen after the end of statedump
2585 // This will cause a "popping last state on stack, ignoring it."
2586 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2587 es
= process
->state
= &g_array_index(process
->execution_stack
,
2588 LttvExecutionState
, 0);
2589 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2590 es
->s
= LTTV_STATE_UNNAMED
;
2591 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2593 es
->t
= LTTV_STATE_USER_MODE
;
2601 es
= process
->state
= &g_array_index(process
->execution_stack
,
2602 LttvExecutionState
, 1);
2603 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2604 es
->s
= LTTV_STATE_UNNAMED
;
2605 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2609 /* The process has already been created :
2610 * Probably was forked while dumping the process state or
2611 * was simply scheduled in prior to get the state dump event.
2613 process
->ppid
= parent_pid
;
2614 process
->tgid
= tgid
;
2615 process
->name
= g_quark_from_string(command
);
2616 process
->type
= type
;
2618 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2620 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2621 if(type
== LTTV_STATE_KERNEL_THREAD
)
2622 es
->t
= LTTV_STATE_SYSCALL
;
2624 es
->t
= LTTV_STATE_USER_MODE
;
2627 /* Don't mess around with the stack, it will eventually become
2628 * ok after the end of state dump. */
2635 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2637 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2639 lttv_state_add_event_hooks(tss
);
2644 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2646 LttvTraceset
*traceset
= self
->parent
.ts
;
2648 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2652 LttvTracefileState
*tfs
;
2656 LttvTraceHookByFacility
*thf
;
2658 LttvTraceHook
*hook
;
2660 LttvAttributeValue val
;
2665 nb_trace
= lttv_traceset_number(traceset
);
2666 for(i
= 0 ; i
< nb_trace
; i
++) {
2667 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2669 /* Find the eventtype id for the following events and register the
2670 associated by id hooks. */
2672 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2673 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2676 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2677 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2678 LTT_FIELD_SYSCALL_ID
, 0, 0,
2679 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2682 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2683 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2685 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2688 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2689 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2690 LTT_FIELD_TRAP_ID
, 0, 0,
2691 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2694 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2695 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2697 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2700 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2701 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2702 LTT_FIELD_IRQ_ID
, 0, 0,
2703 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2706 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2707 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2709 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2712 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2713 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2714 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2715 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2718 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2719 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2721 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2724 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2725 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2726 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2727 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2730 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2731 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2732 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2733 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2736 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2737 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2738 LTT_FIELD_PID
, 0, 0,
2739 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2743 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2744 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2745 LTT_FIELD_PID
, 0, 0,
2746 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2749 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2750 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2751 LTT_FIELD_PID
, 0, 0,
2752 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2755 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2756 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2757 LTT_FIELD_FILENAME
, 0, 0,
2758 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2761 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2762 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2763 LTT_FIELD_NAME
, 0, 0,
2764 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2767 /* statedump-related hooks */
2768 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2769 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2770 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2771 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2774 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2775 LTT_FACILITY_STATEDUMP
, LTT_EVENT_STATEDUMP_END
,
2777 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2780 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2781 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2782 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2783 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2786 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2787 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2788 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2789 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2792 hooks
= g_array_set_size(hooks
, hn
);
2794 /* Add these hooks to each event_by_id hooks list */
2796 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2798 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2800 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2801 LttvTracefileContext
*, j
));
2803 for(k
= 0 ; k
< hooks
->len
; k
++) {
2804 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2805 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2806 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2808 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2815 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2816 *(val
.v_pointer
) = hooks
;
2820 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2822 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2824 lttv_state_remove_event_hooks(tss
);
2829 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2831 LttvTraceset
*traceset
= self
->parent
.ts
;
2833 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2837 LttvTracefileState
*tfs
;
2841 LttvTraceHook
*hook
;
2843 LttvTraceHookByFacility
*thf
;
2845 LttvAttributeValue val
;
2847 nb_trace
= lttv_traceset_number(traceset
);
2848 for(i
= 0 ; i
< nb_trace
; i
++) {
2849 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2851 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2852 hooks
= *(val
.v_pointer
);
2854 /* Remove these hooks from each event_by_id hooks list */
2856 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2858 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2860 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2861 LttvTracefileContext
*, j
));
2863 for(k
= 0 ; k
< hooks
->len
; k
++) {
2864 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2865 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2866 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2868 lttv_hooks_remove_data(
2869 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2875 for(k
= 0 ; k
< hooks
->len
; k
++)
2876 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2877 g_array_free(hooks
, TRUE
);
2881 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2883 guint
*event_count
= (guint
*)hook_data
;
2885 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2886 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2891 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2893 LttvTracefileState
*tfcs
;
2895 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2897 LttEventPosition
*ep
;
2903 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2905 LttvAttributeValue value
;
2907 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2908 LTTV_STATE_SAVED_STATES
);
2909 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2910 value
= lttv_attribute_add(saved_states_tree
,
2911 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2912 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2913 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2914 *(value
.v_time
) = self
->parent
.timestamp
;
2915 lttv_state_save(tcs
, saved_state_tree
);
2916 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2917 self
->parent
.timestamp
.tv_nsec
);
2919 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2924 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2926 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2928 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2933 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2941 static gboolean
block_start(void *hook_data
, void *call_data
)
2943 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2945 LttvTracefileState
*tfcs
;
2947 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2949 LttEventPosition
*ep
;
2951 guint i
, nb_block
, nb_event
, nb_tracefile
;
2955 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2957 LttvAttributeValue value
;
2959 ep
= ltt_event_position_new();
2961 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2963 /* Count the number of events added since the last block end in any
2966 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2968 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2969 LttvTracefileContext
, i
));
2970 ltt_event_position(tfcs
->parent
.e
, ep
);
2971 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2972 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2973 tfcs
->saved_position
= nb_event
;
2977 if(tcs
->nb_event
>= tcs
->save_interval
) {
2978 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2979 LTTV_STATE_SAVED_STATES
);
2980 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2981 value
= lttv_attribute_add(saved_states_tree
,
2982 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2983 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2984 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2985 *(value
.v_time
) = self
->parent
.timestamp
;
2986 lttv_state_save(tcs
, saved_state_tree
);
2988 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2989 self
->parent
.timestamp
.tv_nsec
);
2991 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2997 static gboolean
block_end(void *hook_data
, void *call_data
)
2999 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3001 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3005 LttEventPosition
*ep
;
3007 guint nb_block
, nb_event
;
3009 ep
= ltt_event_position_new();
3010 ltt_event_position(self
->parent
.e
, ep
);
3011 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3012 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3013 self
->saved_position
= 0;
3014 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3021 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3023 LttvTraceset
*traceset
= self
->parent
.ts
;
3025 guint i
, j
, nb_trace
, nb_tracefile
;
3029 LttvTracefileState
*tfs
;
3031 LttvTraceHook hook_start
, hook_end
;
3033 nb_trace
= lttv_traceset_number(traceset
);
3034 for(i
= 0 ; i
< nb_trace
; i
++) {
3035 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3037 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3038 NULL
, NULL
, block_start
, &hook_start
);
3039 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3040 NULL
, NULL
, block_end
, &hook_end
);
3042 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3044 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3046 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3047 LttvTracefileContext
, j
));
3048 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3049 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3050 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3051 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3057 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3059 LttvTraceset
*traceset
= self
->parent
.ts
;
3061 guint i
, j
, nb_trace
, nb_tracefile
;
3065 LttvTracefileState
*tfs
;
3068 nb_trace
= lttv_traceset_number(traceset
);
3069 for(i
= 0 ; i
< nb_trace
; i
++) {
3071 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3072 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3074 if(ts
->has_precomputed_states
) continue;
3076 guint
*event_count
= g_new(guint
, 1);
3079 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3081 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3082 LttvTracefileContext
*, j
));
3083 lttv_hooks_add(tfs
->parent
.event
,
3084 state_save_event_hook
,
3091 lttv_process_traceset_begin(&self
->parent
,
3092 NULL
, NULL
, NULL
, NULL
, NULL
);
3096 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3098 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3100 lttv_state_save_add_event_hooks(tss
);
3107 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3109 LttvTraceset
*traceset
= self
->parent
.ts
;
3111 guint i
, j
, nb_trace
, nb_tracefile
;
3115 LttvTracefileState
*tfs
;
3117 LttvTraceHook hook_start
, hook_end
;
3119 nb_trace
= lttv_traceset_number(traceset
);
3120 for(i
= 0 ; i
< nb_trace
; i
++) {
3121 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3123 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3124 NULL
, NULL
, block_start
, &hook_start
);
3126 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3127 NULL
, NULL
, block_end
, &hook_end
);
3129 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3131 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3133 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3134 LttvTracefileContext
, j
));
3135 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3136 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3137 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3138 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3144 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3146 LttvTraceset
*traceset
= self
->parent
.ts
;
3148 guint i
, j
, nb_trace
, nb_tracefile
;
3152 LttvTracefileState
*tfs
;
3154 LttvHooks
*after_trace
= lttv_hooks_new();
3156 lttv_hooks_add(after_trace
,
3157 state_save_after_trace_hook
,
3162 lttv_process_traceset_end(&self
->parent
,
3163 NULL
, after_trace
, NULL
, NULL
, NULL
);
3165 lttv_hooks_destroy(after_trace
);
3167 nb_trace
= lttv_traceset_number(traceset
);
3168 for(i
= 0 ; i
< nb_trace
; i
++) {
3170 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3171 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3173 if(ts
->has_precomputed_states
) continue;
3175 guint
*event_count
= NULL
;
3177 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3179 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3180 LttvTracefileContext
*, j
));
3181 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3182 state_save_event_hook
);
3184 if(event_count
) g_free(event_count
);
3188 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3190 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3192 lttv_state_save_remove_event_hooks(tss
);
3197 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3199 LttvTraceset
*traceset
= self
->parent
.ts
;
3203 int min_pos
, mid_pos
, max_pos
;
3205 guint call_rest
= 0;
3207 LttvTraceState
*tcs
;
3209 LttvAttributeValue value
;
3211 LttvAttributeType type
;
3213 LttvAttributeName name
;
3217 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3219 //g_tree_destroy(self->parent.pqueue);
3220 //self->parent.pqueue = g_tree_new(compare_tracefile);
3222 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3224 nb_trace
= lttv_traceset_number(traceset
);
3225 for(i
= 0 ; i
< nb_trace
; i
++) {
3226 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3228 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3229 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3230 LTTV_STATE_SAVED_STATES
);
3233 if(saved_states_tree
) {
3234 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3235 mid_pos
= max_pos
/ 2;
3236 while(min_pos
< max_pos
) {
3237 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3239 g_assert(type
== LTTV_GOBJECT
);
3240 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3241 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3243 g_assert(type
== LTTV_TIME
);
3244 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3246 closest_tree
= saved_state_tree
;
3248 else max_pos
= mid_pos
- 1;
3250 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3254 /* restore the closest earlier saved state */
3256 lttv_state_restore(tcs
, closest_tree
);
3260 /* There is no saved state, yet we want to have it. Restart at T0 */
3262 restore_init_state(tcs
);
3263 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3266 /* We want to seek quickly without restoring/updating the state */
3268 restore_init_state(tcs
);
3269 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3272 if(!call_rest
) g_info("NOT Calling restore");
3277 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3283 traceset_state_finalize (LttvTracesetState
*self
)
3285 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3286 finalize(G_OBJECT(self
));
3291 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3293 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3295 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3296 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3297 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3298 klass
->new_traceset_context
= new_traceset_context
;
3299 klass
->new_trace_context
= new_trace_context
;
3300 klass
->new_tracefile_context
= new_tracefile_context
;
3305 lttv_traceset_state_get_type(void)
3307 static GType type
= 0;
3309 static const GTypeInfo info
= {
3310 sizeof (LttvTracesetStateClass
),
3311 NULL
, /* base_init */
3312 NULL
, /* base_finalize */
3313 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3314 NULL
, /* class_finalize */
3315 NULL
, /* class_data */
3316 sizeof (LttvTracesetState
),
3317 0, /* n_preallocs */
3318 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3319 NULL
/* value handling */
3322 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3330 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3336 trace_state_finalize (LttvTraceState
*self
)
3338 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3339 finalize(G_OBJECT(self
));
3344 trace_state_class_init (LttvTraceStateClass
*klass
)
3346 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3348 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3349 klass
->state_save
= state_save
;
3350 klass
->state_restore
= state_restore
;
3351 klass
->state_saved_free
= state_saved_free
;
3356 lttv_trace_state_get_type(void)
3358 static GType type
= 0;
3360 static const GTypeInfo info
= {
3361 sizeof (LttvTraceStateClass
),
3362 NULL
, /* base_init */
3363 NULL
, /* base_finalize */
3364 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3365 NULL
, /* class_finalize */
3366 NULL
, /* class_data */
3367 sizeof (LttvTraceState
),
3368 0, /* n_preallocs */
3369 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3370 NULL
/* value handling */
3373 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3374 "LttvTraceStateType", &info
, 0);
3381 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3387 tracefile_state_finalize (LttvTracefileState
*self
)
3389 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3390 finalize(G_OBJECT(self
));
3395 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3397 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3399 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3404 lttv_tracefile_state_get_type(void)
3406 static GType type
= 0;
3408 static const GTypeInfo info
= {
3409 sizeof (LttvTracefileStateClass
),
3410 NULL
, /* base_init */
3411 NULL
, /* base_finalize */
3412 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3413 NULL
, /* class_finalize */
3414 NULL
, /* class_data */
3415 sizeof (LttvTracefileState
),
3416 0, /* n_preallocs */
3417 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3418 NULL
/* value handling */
3421 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3422 "LttvTracefileStateType", &info
, 0);
3428 static void module_init()
3430 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3431 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3432 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3433 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3434 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3435 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3436 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3437 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3438 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3439 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3440 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3441 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3442 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3443 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3444 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3445 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3446 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3447 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3448 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3449 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3450 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3451 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3452 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3453 LTTV_STATE_EVENT
= g_quark_from_string("event");
3454 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3455 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3456 LTTV_STATE_TIME
= g_quark_from_string("time");
3457 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3458 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3459 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3460 g_quark_from_string("trace_state_use_count");
3463 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3464 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3465 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3466 LTT_FACILITY_FS
= g_quark_from_string("fs");
3467 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3468 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3471 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3472 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3473 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3474 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3475 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3476 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3477 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3478 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3479 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3480 LTT_EVENT_FORK
= g_quark_from_string("fork");
3481 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3482 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3483 LTT_EVENT_FREE
= g_quark_from_string("free");
3484 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3485 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3486 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3487 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3488 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3489 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3492 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3493 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3494 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3495 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3496 LTT_FIELD_OUT
= g_quark_from_string("out");
3497 LTT_FIELD_IN
= g_quark_from_string("in");
3498 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3499 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3500 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3501 LTT_FIELD_PID
= g_quark_from_string("pid");
3502 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3503 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3504 LTT_FIELD_NAME
= g_quark_from_string("name");
3505 LTT_FIELD_TYPE
= g_quark_from_string("type");
3506 LTT_FIELD_MODE
= g_quark_from_string("mode");
3507 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3508 LTT_FIELD_STATUS
= g_quark_from_string("status");
3509 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3510 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3514 static void module_destroy()
3519 LTTV_MODULE("state", "State computation", \
3520 "Update the system state, possibly saving it at intervals", \
3521 module_init
, module_destroy
)