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_UNBRANDED
,
116 LTTV_STATE_WAIT_FORK
,
125 LTTV_STATE_USER_THREAD
,
126 LTTV_STATE_KERNEL_THREAD
;
129 LTTV_STATE_TRACEFILES
,
130 LTTV_STATE_PROCESSES
,
132 LTTV_STATE_RUNNING_PROCESS
,
134 LTTV_STATE_SAVED_STATES
,
135 LTTV_STATE_SAVED_STATES_TIME
,
138 LTTV_STATE_NAME_TABLES
,
139 LTTV_STATE_TRACE_STATE_USE_COUNT
;
141 static void create_max_time(LttvTraceState
*tcs
);
143 static void get_max_time(LttvTraceState
*tcs
);
145 static void free_max_time(LttvTraceState
*tcs
);
147 static void create_name_tables(LttvTraceState
*tcs
);
149 static void get_name_tables(LttvTraceState
*tcs
);
151 static void free_name_tables(LttvTraceState
*tcs
);
153 static void free_saved_state(LttvTraceState
*tcs
);
155 static void lttv_state_free_process_table(GHashTable
*processes
);
157 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
158 GPtrArray
*quarktable
);
160 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
162 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
166 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
168 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
172 void lttv_state_state_saved_free(LttvTraceState
*self
,
173 LttvAttribute
*container
)
175 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
179 guint
process_hash(gconstpointer key
)
181 guint pid
= ((const LttvProcessState
*)key
)->pid
;
182 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
186 /* If the hash table hash function is well distributed,
187 * the process_equal should compare different pid */
188 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
190 const LttvProcessState
*process_a
, *process_b
;
193 process_a
= (const LttvProcessState
*)a
;
194 process_b
= (const LttvProcessState
*)b
;
196 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
197 else if(likely(process_a
->pid
== 0 &&
198 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
203 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
205 g_tree_destroy((GTree
*)value
);
208 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
210 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
211 g_hash_table_destroy(usertraces
);
217 restore_init_state(LttvTraceState
*self
)
221 LttvTracefileState
*tfcs
;
223 LttTime start_time
, end_time
;
225 /* Free the process tables */
226 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
227 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
228 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
229 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
232 /* Seek time to beginning */
233 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
234 // closest. It's the tracecontext job to seek the trace to the beginning
235 // anyway : the init state might be used at the middle of the trace as well...
236 //g_tree_destroy(self->parent.ts_context->pqueue);
237 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
239 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
241 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
243 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
245 /* Put the per cpu running_process to beginning state : process 0. */
246 for(i
=0; i
< nb_cpus
; i
++) {
247 LttvExecutionState
*es
;
248 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
249 LTTV_STATE_UNNAMED
, &start_time
);
250 /* We are not sure is it's a kernel thread or normal thread, put the
251 * bottom stack state to unknown */
252 self
->running_process
[i
]->execution_stack
=
253 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
254 es
= self
->running_process
[i
]->state
=
255 &g_array_index(self
->running_process
[i
]->execution_stack
,
256 LttvExecutionState
, 0);
257 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
259 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
260 self
->running_process
[i
]->cpu
= i
;
264 nb_tracefile
= self
->parent
.tracefiles
->len
;
266 for(i
= 0 ; i
< nb_tracefile
; i
++) {
268 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
269 LttvTracefileContext
*, i
));
270 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
271 // tfcs->saved_position = 0;
272 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
273 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
274 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
275 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
280 //static LttTime time_zero = {0,0};
282 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
285 const LttTime
*t1
= (const LttTime
*)a
;
286 const LttTime
*t2
= (const LttTime
*)b
;
288 return ltt_time_compare(*t1
, *t2
);
291 static void free_usertrace_key(gpointer data
)
296 #define MAX_STRING_LEN 4096
299 state_load_saved_states(LttvTraceState
*tcs
)
302 GPtrArray
*quarktable
;
307 tcs
->has_precomputed_states
= FALSE
;
311 gchar buf
[MAX_STRING_LEN
];
314 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
315 strncpy(path
, trace_path
, PATH_MAX
-1);
316 count
= strnlen(trace_path
, PATH_MAX
-1);
317 // quarktable : open, test
318 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
319 fp
= fopen(path
, "r");
321 quarktable
= g_ptr_array_sized_new(4096);
323 /* Index 0 is null */
325 if(hdr
== EOF
) return;
326 g_assert(hdr
== HDR_QUARKS
);
330 if(hdr
== EOF
) break;
331 g_assert(hdr
== HDR_QUARK
);
332 g_ptr_array_set_size(quarktable
, q
+1);
335 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
336 if(buf
[i
] == '\0' || feof(fp
)) break;
339 len
= strnlen(buf
, MAX_STRING_LEN
-1);
340 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
341 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
347 // saved_states : open, test
348 strncpy(path
, trace_path
, PATH_MAX
-1);
349 count
= strnlen(trace_path
, PATH_MAX
-1);
350 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
351 fp
= fopen(path
, "r");
355 if(hdr
!= HDR_TRACE
) goto end
;
357 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
359 tcs
->has_precomputed_states
= TRUE
;
364 /* Free the quarktable */
365 for(i
=0; i
<quarktable
->len
; i
++) {
366 string
= g_ptr_array_index (quarktable
, i
);
369 g_ptr_array_free(quarktable
, TRUE
);
374 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
376 guint i
, j
, nb_trace
, nb_tracefile
;
378 LttvTraceContext
*tc
;
382 LttvTracefileState
*tfcs
;
384 LttvAttributeValue v
;
386 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
387 init((LttvTracesetContext
*)self
, ts
);
389 nb_trace
= lttv_traceset_number(ts
);
390 for(i
= 0 ; i
< nb_trace
; i
++) {
391 tc
= self
->parent
.traces
[i
];
392 tcs
= LTTV_TRACE_STATE(tc
);
393 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
394 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
398 if(*(v
.v_uint
) == 1) {
399 create_name_tables(tcs
);
400 create_max_time(tcs
);
402 get_name_tables(tcs
);
405 nb_tracefile
= tc
->tracefiles
->len
;
406 tcs
->processes
= NULL
;
407 tcs
->usertraces
= NULL
;
408 tcs
->running_process
= g_new(LttvProcessState
*,
409 ltt_trace_get_num_cpu(tc
->t
));
410 restore_init_state(tcs
);
411 for(j
= 0 ; j
< nb_tracefile
; j
++) {
413 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
414 LttvTracefileContext
*, j
));
415 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
416 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
417 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
418 /* It's a Usertrace */
419 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
420 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
422 if(!usertrace_tree
) {
423 usertrace_tree
= g_tree_new_full(compare_usertraces
,
424 NULL
, free_usertrace_key
, NULL
);
425 g_hash_table_insert(tcs
->usertraces
,
426 (gpointer
)tid
, usertrace_tree
);
428 LttTime
*timestamp
= g_new(LttTime
, 1);
429 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
430 ltt_tracefile_creation(tfcs
->parent
.tf
));
431 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
435 /* See if the trace has saved states */
436 state_load_saved_states(tcs
);
441 fini(LttvTracesetState
*self
)
447 LttvTracefileState
*tfcs
;
449 LttvAttributeValue v
;
451 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
452 for(i
= 0 ; i
< nb_trace
; i
++) {
453 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
454 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
457 g_assert(*(v
.v_uint
) != 0);
460 if(*(v
.v_uint
) == 0) {
461 free_name_tables(tcs
);
463 free_saved_state(tcs
);
465 g_free(tcs
->running_process
);
466 tcs
->running_process
= NULL
;
467 lttv_state_free_process_table(tcs
->processes
);
468 lttv_state_free_usertraces(tcs
->usertraces
);
469 tcs
->processes
= NULL
;
470 tcs
->usertraces
= NULL
;
472 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
473 fini((LttvTracesetContext
*)self
);
477 static LttvTracesetContext
*
478 new_traceset_context(LttvTracesetContext
*self
)
480 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
484 static LttvTraceContext
*
485 new_trace_context(LttvTracesetContext
*self
)
487 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
491 static LttvTracefileContext
*
492 new_tracefile_context(LttvTracesetContext
*self
)
494 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
498 /* Write the process state of the trace */
500 static void write_process_state(gpointer key
, gpointer value
,
503 LttvProcessState
*process
;
505 LttvExecutionState
*es
;
507 FILE *fp
= (FILE *)user_data
;
512 process
= (LttvProcessState
*)value
;
514 " <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",
515 process
, process
->pid
, process
->tgid
, process
->ppid
,
516 g_quark_to_string(process
->type
),
517 process
->creation_time
.tv_sec
,
518 process
->creation_time
.tv_nsec
,
519 process
->insertion_time
.tv_sec
,
520 process
->insertion_time
.tv_nsec
,
521 g_quark_to_string(process
->name
),
522 g_quark_to_string(process
->brand
),
525 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
526 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
527 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
528 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
529 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
530 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
531 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
534 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
535 address
= &g_array_index(process
->user_stack
, guint64
, i
);
536 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
540 if(process
->usertrace
) {
541 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
542 g_quark_to_string(process
->usertrace
->tracefile_name
),
543 process
->usertrace
->cpu
);
547 fprintf(fp
, " </PROCESS>\n");
551 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
553 guint i
, nb_tracefile
, nb_block
, offset
;
556 LttvTracefileState
*tfcs
;
560 LttEventPosition
*ep
;
564 ep
= ltt_event_position_new();
566 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
568 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
570 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
571 for(i
=0;i
<nb_cpus
;i
++) {
572 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
573 i
, self
->running_process
[i
]->pid
);
576 nb_tracefile
= self
->parent
.tracefiles
->len
;
578 for(i
= 0 ; i
< nb_tracefile
; i
++) {
580 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
581 LttvTracefileContext
*, i
));
582 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
583 tfcs
->parent
.timestamp
.tv_sec
,
584 tfcs
->parent
.timestamp
.tv_nsec
);
585 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
586 if(e
== NULL
) fprintf(fp
,"/>\n");
588 ltt_event_position(e
, ep
);
589 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
590 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
595 fprintf(fp
,"</PROCESS_STATE>\n");
599 static void write_process_state_raw(gpointer key
, gpointer value
,
602 LttvProcessState
*process
;
604 LttvExecutionState
*es
;
606 FILE *fp
= (FILE *)user_data
;
611 process
= (LttvProcessState
*)value
;
612 fputc(HDR_PROCESS
, fp
);
613 //fwrite(&header, sizeof(header), 1, fp);
614 //fprintf(fp, "%s", g_quark_to_string(process->type));
616 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
617 //fprintf(fp, "%s", g_quark_to_string(process->name));
619 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
620 //fprintf(fp, "%s", g_quark_to_string(process->brand));
622 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
623 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
624 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
625 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
626 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
627 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
628 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
632 " <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",
633 process
, process
->pid
, process
->tgid
, process
->ppid
,
634 g_quark_to_string(process
->type
),
635 process
->creation_time
.tv_sec
,
636 process
->creation_time
.tv_nsec
,
637 process
->insertion_time
.tv_sec
,
638 process
->insertion_time
.tv_nsec
,
639 g_quark_to_string(process
->name
),
640 g_quark_to_string(process
->brand
),
644 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
645 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
648 //fprintf(fp, "%s", g_quark_to_string(es->t));
650 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
651 //fprintf(fp, "%s", g_quark_to_string(es->n));
653 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
654 //fprintf(fp, "%s", g_quark_to_string(es->s));
656 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
657 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
658 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
659 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
661 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
662 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
663 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
664 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
665 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
669 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
670 address
= &g_array_index(process
->user_stack
, guint64
, i
);
671 fputc(HDR_USER_STACK
, fp
);
672 fwrite(&address
, sizeof(address
), 1, fp
);
674 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
679 if(process
->usertrace
) {
680 fputc(HDR_USERTRACE
, fp
);
681 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
683 fwrite(&process
->usertrace
->tracefile_name
,
684 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
685 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
687 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
688 g_quark_to_string(process
->usertrace
->tracefile_name
),
689 process
->usertrace
->cpu
);
696 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
698 guint i
, nb_tracefile
, nb_block
, offset
;
701 LttvTracefileState
*tfcs
;
705 LttEventPosition
*ep
;
709 ep
= ltt_event_position_new();
711 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
712 fputc(HDR_PROCESS_STATE
, fp
);
713 fwrite(&t
, sizeof(t
), 1, fp
);
715 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
717 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
718 for(i
=0;i
<nb_cpus
;i
++) {
720 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
721 fwrite(&self
->running_process
[i
]->pid
,
722 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
723 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
724 // i, self->running_process[i]->pid);
727 nb_tracefile
= self
->parent
.tracefiles
->len
;
729 for(i
= 0 ; i
< nb_tracefile
; i
++) {
731 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
732 LttvTracefileContext
*, i
));
733 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
734 // tfcs->parent.timestamp.tv_sec,
735 // tfcs->parent.timestamp.tv_nsec);
736 fputc(HDR_TRACEFILE
, fp
);
737 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
738 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
739 * position following : end of trace */
740 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
742 ltt_event_position(e
, ep
);
743 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
744 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
746 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
747 fwrite(&offset
, sizeof(offset
), 1, fp
);
748 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
755 /* Read process state from a file */
757 /* Called because a HDR_PROCESS was found */
758 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
759 GPtrArray
*quarktable
)
761 LttvExecutionState
*es
;
762 LttvProcessState
*process
, *parent_process
;
763 LttvProcessState tmp
;
770 /* TODO : check return value */
771 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
772 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
773 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
774 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
775 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
776 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
777 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
778 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
779 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
782 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
784 /* We must link to the parent */
785 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
787 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
788 if(process
== NULL
) {
789 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
791 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
795 process
->insertion_time
= tmp
.insertion_time
;
796 process
->creation_time
= tmp
.creation_time
;
797 process
->type
= g_quark_from_string(
798 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
799 process
->tgid
= tmp
.tgid
;
800 process
->ppid
= tmp
.ppid
;
801 process
->brand
= g_quark_from_string(
802 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
804 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
808 if(feof(fp
) || ferror(fp
)) goto end_loop
;
810 gint hdr
= fgetc(fp
);
811 if(hdr
== EOF
) goto end_loop
;
815 process
->execution_stack
=
816 g_array_set_size(process
->execution_stack
,
817 process
->execution_stack
->len
+ 1);
818 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
819 process
->execution_stack
->len
-1);
822 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
823 es
->t
= g_quark_from_string(
824 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
825 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
826 es
->n
= g_quark_from_string(
827 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
828 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
829 es
->s
= g_quark_from_string(
830 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
831 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
832 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
833 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
836 process
->user_stack
= g_array_set_size(process
->user_stack
,
837 process
->user_stack
->len
+ 1);
838 address
= &g_array_index(process
->user_stack
, guint64
,
839 process
->user_stack
->len
-1);
840 fread(address
, sizeof(address
), 1, fp
);
841 process
->current_function
= *address
;
844 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
845 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
857 /* Called because a HDR_PROCESS_STATE was found */
858 /* Append a saved state to the trace states */
859 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
861 guint i
, nb_tracefile
, nb_block
, offset
;
863 LttvTracefileState
*tfcs
;
865 LttEventPosition
*ep
;
873 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
875 LttvAttributeValue value
;
876 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
877 ep
= ltt_event_position_new();
879 restore_init_state(self
);
881 fread(&t
, sizeof(t
), 1, fp
);
884 if(feof(fp
) || ferror(fp
)) goto end_loop
;
886 if(hdr
== EOF
) goto end_loop
;
890 /* Call read_process_state_raw */
891 read_process_state_raw(self
, fp
, quarktable
);
901 case HDR_PROCESS_STATE
:
907 g_error("Error while parsing saved state file : unknown data header %d",
913 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
914 for(i
=0;i
<nb_cpus
;i
++) {
917 g_assert(hdr
== HDR_CPU
);
918 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
919 g_assert(i
== cpu_num
);
920 fread(&self
->running_process
[i
]->pid
,
921 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
924 nb_tracefile
= self
->parent
.tracefiles
->len
;
926 for(i
= 0 ; i
< nb_tracefile
; i
++) {
928 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
929 LttvTracefileContext
*, i
));
930 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
931 // tfcs->parent.timestamp.tv_sec,
932 // tfcs->parent.timestamp.tv_nsec);
933 g_tree_remove(pqueue
, &tfcs
->parent
);
935 g_assert(hdr
== HDR_TRACEFILE
);
936 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
937 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
938 * position following : end of trace */
939 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
940 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
941 fread(&offset
, sizeof(offset
), 1, fp
);
942 fread(&tsc
, sizeof(tsc
), 1, fp
);
943 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
944 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
946 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
951 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
952 LTTV_STATE_SAVED_STATES
);
953 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
954 value
= lttv_attribute_add(saved_states_tree
,
955 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
956 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
957 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
959 lttv_state_save(self
, saved_state_tree
);
960 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
963 *(self
->max_time_state_recomputed_in_seek
) = t
;
967 /* Called when a HDR_TRACE is found */
968 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
969 GPtrArray
*quarktable
)
974 if(feof(fp
) || ferror(fp
)) goto end_loop
;
976 if(hdr
== EOF
) goto end_loop
;
979 case HDR_PROCESS_STATE
:
980 /* Call read_process_state_raw */
981 lttv_state_read_raw(tcs
, fp
, quarktable
);
993 g_error("Error while parsing saved state file :"
994 " unexpected data header %d",
998 g_error("Error while parsing saved state file : unknown data header %d",
1003 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1004 restore_init_state(tcs
);
1005 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1011 /* Copy each process from an existing hash table to a new one */
1013 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1015 LttvProcessState
*process
, *new_process
;
1017 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1021 process
= (LttvProcessState
*)value
;
1022 new_process
= g_new(LttvProcessState
, 1);
1023 *new_process
= *process
;
1024 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1025 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1026 new_process
->execution_stack
=
1027 g_array_set_size(new_process
->execution_stack
,
1028 process
->execution_stack
->len
);
1029 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1030 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1031 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1033 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1034 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1035 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1036 sizeof(guint64
), 0);
1037 new_process
->user_stack
=
1038 g_array_set_size(new_process
->user_stack
,
1039 process
->user_stack
->len
);
1040 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1041 g_array_index(new_process
->user_stack
, guint64
, i
) =
1042 g_array_index(process
->user_stack
, guint64
, i
);
1044 new_process
->current_function
= process
->current_function
;
1045 g_hash_table_insert(new_processes
, new_process
, new_process
);
1049 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1051 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1053 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1054 return new_processes
;
1058 /* The saved state for each trace contains a member "processes", which
1059 stores a copy of the process table, and a member "tracefiles" with
1060 one entry per tracefile. Each tracefile has a "process" member pointing
1061 to the current process and a "position" member storing the tracefile
1062 position (needed to seek to the current "next" event. */
1064 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1066 guint i
, nb_tracefile
, nb_cpus
;
1068 LttvTracefileState
*tfcs
;
1070 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1072 guint
*running_process
;
1074 LttvAttributeType type
;
1076 LttvAttributeValue value
;
1078 LttvAttributeName name
;
1080 LttEventPosition
*ep
;
1082 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1083 LTTV_STATE_TRACEFILES
);
1085 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1087 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1089 /* Add the currently running processes array */
1090 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1091 running_process
= g_new(guint
, nb_cpus
);
1092 for(i
=0;i
<nb_cpus
;i
++) {
1093 running_process
[i
] = self
->running_process
[i
]->pid
;
1095 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1097 *(value
.v_pointer
) = running_process
;
1099 g_info("State save");
1101 nb_tracefile
= self
->parent
.tracefiles
->len
;
1103 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1105 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1106 LttvTracefileContext
*, i
));
1107 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1108 value
= lttv_attribute_add(tracefiles_tree
, i
,
1110 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1112 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1114 *(value
.v_uint
) = tfcs
->process
->pid
;
1116 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1118 /* Only save the position if the tfs has not infinite time. */
1119 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1120 // && current_tfcs != tfcs) {
1121 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1122 *(value
.v_pointer
) = NULL
;
1124 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1125 ep
= ltt_event_position_new();
1126 ltt_event_position(e
, ep
);
1127 *(value
.v_pointer
) = ep
;
1129 guint nb_block
, offset
;
1132 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1133 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1135 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1141 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1143 guint i
, nb_tracefile
, pid
, nb_cpus
;
1145 LttvTracefileState
*tfcs
;
1147 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1149 guint
*running_process
;
1151 LttvAttributeType type
;
1153 LttvAttributeValue value
;
1155 LttvAttributeName name
;
1159 LttEventPosition
*ep
;
1161 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1163 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1164 LTTV_STATE_TRACEFILES
);
1166 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1168 g_assert(type
== LTTV_POINTER
);
1169 lttv_state_free_process_table(self
->processes
);
1170 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1172 /* Add the currently running processes array */
1173 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1174 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1176 g_assert(type
== LTTV_POINTER
);
1177 running_process
= *(value
.v_pointer
);
1178 for(i
=0;i
<nb_cpus
;i
++) {
1179 pid
= running_process
[i
];
1180 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1181 g_assert(self
->running_process
[i
] != NULL
);
1185 nb_tracefile
= self
->parent
.tracefiles
->len
;
1187 //g_tree_destroy(tsc->pqueue);
1188 //tsc->pqueue = g_tree_new(compare_tracefile);
1190 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1192 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1193 LttvTracefileContext
*, i
));
1194 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1195 g_assert(type
== LTTV_GOBJECT
);
1196 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1198 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1200 g_assert(type
== LTTV_UINT
);
1201 pid
= *(value
.v_uint
);
1202 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1204 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1206 g_assert(type
== LTTV_POINTER
);
1207 //g_assert(*(value.v_pointer) != NULL);
1208 ep
= *(value
.v_pointer
);
1209 g_assert(tfcs
->parent
.t_context
!= NULL
);
1211 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1212 g_tree_remove(tsc
->pqueue
, tfc
);
1215 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1216 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1217 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1218 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1219 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1221 tfc
->timestamp
= ltt_time_infinite
;
1227 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1229 guint i
, nb_tracefile
, nb_cpus
;
1231 LttvTracefileState
*tfcs
;
1233 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1235 guint
*running_process
;
1237 LttvAttributeType type
;
1239 LttvAttributeValue value
;
1241 LttvAttributeName name
;
1245 LttEventPosition
*ep
;
1247 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1248 LTTV_STATE_TRACEFILES
);
1249 g_object_ref(G_OBJECT(tracefiles_tree
));
1250 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1252 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1254 g_assert(type
== LTTV_POINTER
);
1255 lttv_state_free_process_table(*(value
.v_pointer
));
1256 *(value
.v_pointer
) = NULL
;
1257 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1259 /* Free running processes array */
1260 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1261 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1263 g_assert(type
== LTTV_POINTER
);
1264 running_process
= *(value
.v_pointer
);
1265 g_free(running_process
);
1267 nb_tracefile
= self
->parent
.tracefiles
->len
;
1269 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1271 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1272 LttvTracefileContext
*, i
));
1273 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1274 g_assert(type
== LTTV_GOBJECT
);
1275 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1277 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1279 g_assert(type
== LTTV_POINTER
);
1280 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1282 g_object_unref(G_OBJECT(tracefiles_tree
));
1286 static void free_saved_state(LttvTraceState
*self
)
1290 LttvAttributeType type
;
1292 LttvAttributeValue value
;
1294 LttvAttributeName name
;
1298 LttvAttribute
*saved_states
;
1300 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1301 LTTV_STATE_SAVED_STATES
);
1303 nb
= lttv_attribute_get_number(saved_states
);
1304 for(i
= 0 ; i
< nb
; i
++) {
1305 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1306 g_assert(type
== LTTV_GOBJECT
);
1307 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1310 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1315 create_max_time(LttvTraceState
*tcs
)
1317 LttvAttributeValue v
;
1319 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1321 g_assert(*(v
.v_pointer
) == NULL
);
1322 *(v
.v_pointer
) = g_new(LttTime
,1);
1323 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1328 get_max_time(LttvTraceState
*tcs
)
1330 LttvAttributeValue v
;
1332 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1334 g_assert(*(v
.v_pointer
) != NULL
);
1335 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1340 free_max_time(LttvTraceState
*tcs
)
1342 LttvAttributeValue v
;
1344 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1346 g_free(*(v
.v_pointer
));
1347 *(v
.v_pointer
) = NULL
;
1351 typedef struct _LttvNameTables
{
1352 // FIXME GQuark *eventtype_names;
1353 GQuark
*syscall_names
;
1359 GQuark
*soft_irq_names
;
1365 create_name_tables(LttvTraceState
*tcs
)
1369 GQuark f_name
, e_name
;
1373 LttvTraceHookByFacility
*thf
;
1379 GString
*fe_name
= g_string_new("");
1381 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1383 LttvAttributeValue v
;
1385 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1387 g_assert(*(v
.v_pointer
) == NULL
);
1388 *(v
.v_pointer
) = name_tables
;
1389 #if 0 // Use iteration over the facilities_by_name and then list all event
1390 // types of each facility
1391 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1392 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1393 for(i
= 0 ; i
< nb
; i
++) {
1394 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1395 e_name
= ltt_eventtype_name(et
);
1396 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1397 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1398 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1401 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1402 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1403 LTT_FIELD_SYSCALL_ID
, 0, 0,
1406 thf
= lttv_trace_hook_get_first(&h
);
1408 t
= ltt_field_type(thf
->f1
);
1409 nb
= ltt_type_element_number(t
);
1411 lttv_trace_hook_destroy(&h
);
1413 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1414 name_tables
->nb_syscalls
= nb
;
1416 for(i
= 0 ; i
< nb
; i
++) {
1417 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1418 if(!name_tables
->syscall_names
[i
]) {
1419 GString
*string
= g_string_new("");
1420 g_string_printf(string
, "syscall %u", i
);
1421 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1422 g_string_free(string
, TRUE
);
1426 //name_tables->syscall_names = g_new(GQuark, 256);
1427 //for(i = 0 ; i < 256 ; i++) {
1428 // g_string_printf(fe_name, "syscall %d", i);
1429 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1432 name_tables
->syscall_names
= NULL
;
1433 name_tables
->nb_syscalls
= 0;
1436 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1437 LTT_EVENT_TRAP_ENTRY
,
1438 LTT_FIELD_TRAP_ID
, 0, 0,
1441 thf
= lttv_trace_hook_get_first(&h
);
1443 t
= ltt_field_type(thf
->f1
);
1444 //nb = ltt_type_element_number(t);
1446 lttv_trace_hook_destroy(&h
);
1449 name_tables->trap_names = g_new(GQuark, nb);
1450 for(i = 0 ; i < nb ; i++) {
1451 name_tables->trap_names[i] = g_quark_from_string(
1452 ltt_enum_string_get(t, i));
1455 name_tables
->nb_traps
= 256;
1456 name_tables
->trap_names
= g_new(GQuark
, 256);
1457 for(i
= 0 ; i
< 256 ; i
++) {
1458 g_string_printf(fe_name
, "trap %d", i
);
1459 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1462 name_tables
->trap_names
= NULL
;
1463 name_tables
->nb_traps
= 0;
1466 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1467 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1468 LTT_FIELD_IRQ_ID
, 0, 0,
1471 thf
= lttv_trace_hook_get_first(&h
);
1473 t
= ltt_field_type(thf
->f1
);
1474 //nb = ltt_type_element_number(t);
1476 lttv_trace_hook_destroy(&h
);
1479 name_tables->irq_names = g_new(GQuark, nb);
1480 for(i = 0 ; i < nb ; i++) {
1481 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1485 name_tables
->nb_irqs
= 256;
1486 name_tables
->irq_names
= g_new(GQuark
, 256);
1487 for(i
= 0 ; i
< 256 ; i
++) {
1488 g_string_printf(fe_name
, "irq %d", i
);
1489 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1492 name_tables
->nb_irqs
= 0;
1493 name_tables
->irq_names
= NULL
;
1496 name_tables->soft_irq_names = g_new(GQuark, nb);
1497 for(i = 0 ; i < nb ; i++) {
1498 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1502 name_tables
->nb_softirqs
= 256;
1503 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1504 for(i
= 0 ; i
< 256 ; i
++) {
1505 g_string_printf(fe_name
, "softirq %d", i
);
1506 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1510 g_string_free(fe_name
, TRUE
);
1515 get_name_tables(LttvTraceState
*tcs
)
1517 LttvNameTables
*name_tables
;
1519 LttvAttributeValue v
;
1521 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1523 g_assert(*(v
.v_pointer
) != NULL
);
1524 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1525 //tcs->eventtype_names = name_tables->eventtype_names;
1526 tcs
->syscall_names
= name_tables
->syscall_names
;
1527 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1528 tcs
->trap_names
= name_tables
->trap_names
;
1529 tcs
->nb_traps
= name_tables
->nb_traps
;
1530 tcs
->irq_names
= name_tables
->irq_names
;
1531 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1532 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1533 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1538 free_name_tables(LttvTraceState
*tcs
)
1540 LttvNameTables
*name_tables
;
1542 LttvAttributeValue v
;
1544 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1546 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1547 *(v
.v_pointer
) = NULL
;
1549 // g_free(name_tables->eventtype_names);
1550 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1551 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1552 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1553 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1554 if(name_tables
) g_free(name_tables
);
1557 #ifdef HASH_TABLE_DEBUG
1559 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1561 LttvProcessState
*process
= (LttvProcessState
*)value
;
1563 /* Test for process corruption */
1564 guint stack_len
= process
->execution_stack
->len
;
1567 static void hash_table_check(GHashTable
*table
)
1569 g_hash_table_foreach(table
, test_process
, NULL
);
1576 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1579 LttvExecutionState
*es
;
1581 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1582 guint cpu
= tfs
->cpu
;
1584 #ifdef HASH_TABLE_DEBUG
1585 hash_table_check(ts
->processes
);
1587 LttvProcessState
*process
= ts
->running_process
[cpu
];
1589 guint depth
= process
->execution_stack
->len
;
1591 process
->execution_stack
=
1592 g_array_set_size(process
->execution_stack
, depth
+ 1);
1595 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1597 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1600 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1601 es
->cum_cpu_time
= ltt_time_zero
;
1602 es
->s
= process
->state
->s
;
1603 process
->state
= es
;
1607 * return 1 when empty, else 0 */
1608 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1609 LttvTracefileState
*tfs
)
1611 guint cpu
= tfs
->cpu
;
1612 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1614 guint depth
= process
->execution_stack
->len
;
1620 process
->execution_stack
=
1621 g_array_set_size(process
->execution_stack
, depth
- 1);
1622 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1624 process
->state
->change
= tfs
->parent
.timestamp
;
1629 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1631 guint cpu
= tfs
->cpu
;
1632 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1633 LttvProcessState
*process
= ts
->running_process
[cpu
];
1635 guint depth
= process
->execution_stack
->len
;
1637 if(process
->state
->t
!= t
){
1638 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1639 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1640 g_info("process state has %s when pop_int is %s\n",
1641 g_quark_to_string(process
->state
->t
),
1642 g_quark_to_string(t
));
1643 g_info("{ %u, %u, %s, %s, %s }\n",
1646 g_quark_to_string(process
->name
),
1647 g_quark_to_string(process
->brand
),
1648 g_quark_to_string(process
->state
->s
));
1653 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1654 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1658 process
->execution_stack
=
1659 g_array_set_size(process
->execution_stack
, depth
- 1);
1660 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1662 process
->state
->change
= tfs
->parent
.timestamp
;
1665 struct search_result
{
1666 const LttTime
*time
; /* Requested time */
1667 LttTime
*best
; /* Best result */
1670 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1672 const LttTime
*elem_time
= (const LttTime
*)a
;
1673 /* Explicit non const cast */
1674 struct search_result
*res
= (struct search_result
*)b
;
1676 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1677 /* The usertrace was created before the schedchange */
1678 /* Get larger keys */
1680 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1681 /* The usertrace was created after the schedchange time */
1682 /* Get smaller keys */
1684 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1685 res
->best
= elem_time
;
1688 res
->best
= elem_time
;
1695 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1696 guint pid
, const LttTime
*timestamp
)
1698 LttvTracefileState
*tfs
= NULL
;
1699 struct search_result res
;
1700 /* Find the usertrace associated with a pid and time interval.
1701 * Search in the usertraces by PID (within a hash) and then, for each
1702 * corresponding element of the array, find the first one with creation
1703 * timestamp the lowest, but higher or equal to "timestamp". */
1704 res
.time
= timestamp
;
1706 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1707 if(usertrace_tree
) {
1708 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1710 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1718 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1719 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1721 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1723 LttvExecutionState
*es
;
1725 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1730 process
->tgid
= tgid
;
1732 process
->name
= name
;
1733 process
->brand
= LTTV_STATE_UNBRANDED
;
1734 //process->last_cpu = tfs->cpu_name;
1735 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1736 process
->type
= LTTV_STATE_USER_THREAD
;
1737 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1738 process
->current_function
= 0; //function 0x0 by default.
1740 g_info("Process %u, core %p", process
->pid
, process
);
1741 g_hash_table_insert(tcs
->processes
, process
, process
);
1744 process
->ppid
= parent
->pid
;
1745 process
->creation_time
= *timestamp
;
1748 /* No parent. This process exists but we are missing all information about
1749 its creation. The birth time is set to zero but we remember the time of
1754 process
->creation_time
= ltt_time_zero
;
1757 process
->insertion_time
= *timestamp
;
1758 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1759 process
->creation_time
.tv_nsec
);
1760 process
->pid_time
= g_quark_from_string(buffer
);
1762 //process->last_cpu = tfs->cpu_name;
1763 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1764 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1765 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1766 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1767 es
= process
->state
= &g_array_index(process
->execution_stack
,
1768 LttvExecutionState
, 0);
1769 es
->t
= LTTV_STATE_USER_MODE
;
1770 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1771 es
->entry
= *timestamp
;
1772 //g_assert(timestamp->tv_sec != 0);
1773 es
->change
= *timestamp
;
1774 es
->cum_cpu_time
= ltt_time_zero
;
1775 es
->s
= LTTV_STATE_RUN
;
1777 es
= process
->state
= &g_array_index(process
->execution_stack
,
1778 LttvExecutionState
, 1);
1779 es
->t
= LTTV_STATE_SYSCALL
;
1780 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1781 es
->entry
= *timestamp
;
1782 //g_assert(timestamp->tv_sec != 0);
1783 es
->change
= *timestamp
;
1784 es
->cum_cpu_time
= ltt_time_zero
;
1785 es
->s
= LTTV_STATE_WAIT_FORK
;
1787 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1788 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1789 sizeof(guint64
), 0);
1794 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1797 LttvProcessState key
;
1798 LttvProcessState
*process
;
1802 process
= g_hash_table_lookup(ts
->processes
, &key
);
1807 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1808 const LttTime
*timestamp
)
1810 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1811 LttvExecutionState
*es
;
1813 /* Put ltt_time_zero creation time for unexisting processes */
1814 if(unlikely(process
== NULL
)) {
1815 process
= lttv_state_create_process(ts
,
1816 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1817 /* We are not sure is it's a kernel thread or normal thread, put the
1818 * bottom stack state to unknown */
1819 process
->execution_stack
=
1820 g_array_set_size(process
->execution_stack
, 1);
1821 process
->state
= es
=
1822 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1823 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1828 /* FIXME : this function should be called when we receive an event telling that
1829 * release_task has been called in the kernel. In happens generally when
1830 * the parent waits for its child terminaison, but may also happen in special
1831 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1832 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1833 * of a killed thread ground, but isn't the leader.
1835 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1837 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1838 LttvProcessState key
;
1840 key
.pid
= process
->pid
;
1841 key
.cpu
= process
->cpu
;
1842 g_hash_table_remove(ts
->processes
, &key
);
1843 g_array_free(process
->execution_stack
, TRUE
);
1844 g_array_free(process
->user_stack
, TRUE
);
1849 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1851 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1852 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1857 static void lttv_state_free_process_table(GHashTable
*processes
)
1859 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1860 g_hash_table_destroy(processes
);
1864 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1866 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1868 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1869 LttvProcessState
*process
= ts
->running_process
[cpu
];
1870 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1871 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1872 LttField
*f
= thf
->f1
;
1874 LttvExecutionSubmode submode
;
1876 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1877 guint syscall
= ltt_event_get_unsigned(e
, f
);
1879 if(syscall
< nb_syscalls
) {
1880 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1883 /* Fixup an incomplete syscall table */
1884 GString
*string
= g_string_new("");
1885 g_string_printf(string
, "syscall %u", syscall
);
1886 submode
= g_quark_from_string(string
->str
);
1887 g_string_free(string
, TRUE
);
1889 /* There can be no system call from PID 0 : unknown state */
1890 if(process
->pid
!= 0)
1891 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1896 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1898 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1900 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1901 LttvProcessState
*process
= ts
->running_process
[cpu
];
1903 /* There can be no system call from PID 0 : unknown state */
1904 if(process
->pid
!= 0)
1905 pop_state(s
, LTTV_STATE_SYSCALL
);
1910 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1912 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1913 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1914 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1915 LttField
*f
= thf
->f1
;
1917 LttvExecutionSubmode submode
;
1919 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1920 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1922 if(trap
< nb_traps
) {
1923 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1925 /* Fixup an incomplete trap table */
1926 GString
*string
= g_string_new("");
1927 g_string_printf(string
, "trap %llu", trap
);
1928 submode
= g_quark_from_string(string
->str
);
1929 g_string_free(string
, TRUE
);
1932 push_state(s
, LTTV_STATE_TRAP
, submode
);
1937 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1939 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1941 pop_state(s
, LTTV_STATE_TRAP
);
1946 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1948 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1949 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1950 guint8 fac_id
= ltt_event_facility_id(e
);
1951 guint8 ev_id
= ltt_event_eventtype_id(e
);
1952 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1953 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1954 g_assert(thf
->f1
!= NULL
);
1955 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1956 LttField
*f
= thf
->f1
;
1958 LttvExecutionSubmode submode
;
1959 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
1960 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
1964 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
1966 /* Fixup an incomplete irq table */
1967 GString
*string
= g_string_new("");
1968 g_string_printf(string
, "irq %llu", irq
);
1969 submode
= g_quark_from_string(string
->str
);
1970 g_string_free(string
, TRUE
);
1973 /* Do something with the info about being in user or system mode when int? */
1974 push_state(s
, LTTV_STATE_IRQ
, submode
);
1978 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1980 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1982 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1988 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1990 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1992 pop_state(s
, LTTV_STATE_IRQ
);
1996 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1998 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1999 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2000 guint8 fac_id
= ltt_event_facility_id(e
);
2001 guint8 ev_id
= ltt_event_eventtype_id(e
);
2002 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2003 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2004 g_assert(thf
->f1
!= NULL
);
2005 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2006 LttField
*f
= thf
->f1
;
2008 LttvExecutionSubmode submode
;
2009 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2010 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2013 if(softirq
< nb_softirqs
) {
2014 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2016 /* Fixup an incomplete irq table */
2017 GString
*string
= g_string_new("");
2018 g_string_printf(string
, "softirq %llu", softirq
);
2019 submode
= g_quark_from_string(string
->str
);
2020 g_string_free(string
, TRUE
);
2023 /* Do something with the info about being in user or system mode when int? */
2024 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2028 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2032 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2033 guint cpu
= tfs
->cpu
;
2034 LttvProcessState
*process
= ts
->running_process
[cpu
];
2036 guint depth
= process
->user_stack
->len
;
2038 process
->user_stack
=
2039 g_array_set_size(process
->user_stack
, depth
+ 1);
2041 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2042 *new_func
= funcptr
;
2043 process
->current_function
= funcptr
;
2046 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2048 guint cpu
= tfs
->cpu
;
2049 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2050 LttvProcessState
*process
= ts
->running_process
[cpu
];
2052 if(process
->current_function
!= funcptr
){
2053 g_info("Different functions (%lu.%09lu): ignore it\n",
2054 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2055 g_info("process state has %llu when pop_function is %llu\n",
2056 process
->current_function
, funcptr
);
2057 g_info("{ %u, %u, %s, %s, %s }\n",
2060 g_quark_to_string(process
->name
),
2061 g_quark_to_string(process
->brand
),
2062 g_quark_to_string(process
->state
->s
));
2065 guint depth
= process
->user_stack
->len
;
2068 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2069 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2073 process
->user_stack
=
2074 g_array_set_size(process
->user_stack
, depth
- 1);
2075 process
->current_function
=
2076 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2080 static gboolean
function_entry(void *hook_data
, void *call_data
)
2082 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2083 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2084 guint8 fac_id
= ltt_event_facility_id(e
);
2085 guint8 ev_id
= ltt_event_eventtype_id(e
);
2086 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2087 g_assert(thf
->f1
!= NULL
);
2088 LttField
*f
= thf
->f1
;
2089 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2091 push_function(s
, funcptr
);
2095 static gboolean
function_exit(void *hook_data
, void *call_data
)
2097 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2098 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2099 guint8 fac_id
= ltt_event_facility_id(e
);
2100 guint8 ev_id
= ltt_event_eventtype_id(e
);
2101 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2102 g_assert(thf
->f1
!= NULL
);
2103 LttField
*f
= thf
->f1
;
2104 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2106 LttvExecutionSubmode submode
;
2108 pop_function(s
, funcptr
);
2112 static gboolean
schedchange(void *hook_data
, void *call_data
)
2114 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2116 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2117 LttvProcessState
*process
= ts
->running_process
[cpu
];
2118 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2120 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2121 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2122 guint pid_in
, pid_out
;
2125 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2126 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2127 state_out
= ltt_event_get_int(e
, thf
->f3
);
2129 if(likely(process
!= NULL
)) {
2131 /* We could not know but it was not the idle process executing.
2132 This should only happen at the beginning, before the first schedule
2133 event, and when the initial information (current process for each CPU)
2134 is missing. It is not obvious how we could, after the fact, compensate
2135 the wrongly attributed statistics. */
2137 //This test only makes sense once the state is known and if there is no
2138 //missing events. We need to silently ignore schedchange coming after a
2139 //process_free, or it causes glitches. (FIXME)
2140 //if(unlikely(process->pid != pid_out)) {
2141 // g_assert(process->pid == 0);
2143 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2144 /* Scheduling out of pid 0 at beginning of the trace :
2145 * we know for sure it is in syscall mode at this point. */
2146 g_assert(process
->execution_stack
->len
== 1);
2147 process
->state
->t
= LTTV_STATE_SYSCALL
;
2149 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2150 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2151 process
->state
->change
= s
->parent
.timestamp
;
2153 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2154 else process
->state
->s
= LTTV_STATE_WAIT
;
2155 process
->state
->change
= s
->parent
.timestamp
;
2159 exit_process(s
, process
); /* EXIT_DEAD */
2160 /* see sched.h for states */
2162 process
= ts
->running_process
[cpu
] =
2163 lttv_state_find_process_or_create(
2164 (LttvTraceState
*)s
->parent
.t_context
,
2166 &s
->parent
.timestamp
);
2167 process
->state
->s
= LTTV_STATE_RUN
;
2169 if(process
->usertrace
)
2170 process
->usertrace
->cpu
= cpu
;
2171 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2172 process
->state
->change
= s
->parent
.timestamp
;
2176 static gboolean
process_fork(void *hook_data
, void *call_data
)
2178 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2179 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2180 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2182 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2183 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2184 LttvProcessState
*zombie_process
;
2186 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2187 LttvProcessState
*process
= ts
->running_process
[cpu
];
2188 LttvProcessState
*child_process
;
2191 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2194 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2195 s
->parent
.target_pid
= child_pid
;
2198 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2199 else child_tgid
= 0;
2201 /* Mathieu : it seems like the process might have been scheduled in before the
2202 * fork, and, in a rare case, might be the current process. This might happen
2203 * in a SMP case where we don't have enough precision on the clocks.
2205 * Test reenabled after precision fixes on time. (Mathieu) */
2207 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2209 if(unlikely(zombie_process
!= NULL
)) {
2210 /* Reutilisation of PID. Only now we are sure that the old PID
2211 * has been released. FIXME : should know when release_task happens instead.
2213 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2215 for(i
=0; i
< num_cpus
; i
++) {
2216 g_assert(zombie_process
!= ts
->running_process
[i
]);
2219 exit_process(s
, zombie_process
);
2222 g_assert(process
->pid
!= child_pid
);
2223 // FIXME : Add this test in the "known state" section
2224 // g_assert(process->pid == parent_pid);
2225 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2226 if(child_process
== NULL
) {
2227 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2228 child_pid
, child_tgid
,
2229 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2231 /* The process has already been created : due to time imprecision between
2232 * multiple CPUs : it has been scheduled in before creation. Note that we
2233 * shouldn't have this kind of imprecision.
2235 * Simply put a correct parent.
2237 g_assert(0); /* This is a problematic case : the process has been created
2238 before the fork event */
2239 child_process
->ppid
= process
->pid
;
2240 child_process
->tgid
= child_tgid
;
2242 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2243 child_process
->name
= process
->name
;
2244 child_process
->brand
= process
->brand
;
2249 /* We stamp a newly created process as kernel_thread */
2250 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2252 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2253 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2254 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2257 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2258 LttvProcessState
*process
;
2259 LttvExecutionState
*es
;
2262 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2263 s
->parent
.target_pid
= pid
;
2265 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2266 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2267 es
->t
= LTTV_STATE_SYSCALL
;
2268 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2273 static gboolean
process_exit(void *hook_data
, void *call_data
)
2275 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2276 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2277 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2281 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2282 LttvProcessState
*process
; // = ts->running_process[cpu];
2284 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2285 s
->parent
.target_pid
= pid
;
2287 // FIXME : Add this test in the "known state" section
2288 // g_assert(process->pid == pid);
2290 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2291 if(likely(process
!= NULL
)) {
2292 process
->state
->s
= LTTV_STATE_EXIT
;
2297 static gboolean
process_free(void *hook_data
, void *call_data
)
2299 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2300 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2301 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2302 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2304 LttvProcessState
*process
;
2306 /* PID of the process to release */
2307 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2308 s
->parent
.target_pid
= release_pid
;
2310 g_assert(release_pid
!= 0);
2312 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2314 if(likely(process
!= NULL
)) {
2315 /* release_task is happening at kernel level : we can now safely release
2316 * the data structure of the process */
2317 //This test is fun, though, as it may happen that
2318 //at time t : CPU 0 : process_free
2319 //at time t+150ns : CPU 1 : schedule out
2320 //Clearly due to time imprecision, we disable it. (Mathieu)
2321 //If this weird case happen, we have no choice but to put the
2322 //Currently running process on the cpu to 0.
2323 //I re-enable it following time precision fixes. (Mathieu)
2324 //Well, in the case where an process is freed by a process on another CPU
2325 //and still scheduled, it happens that this is the schedchange that will
2326 //drop the last reference count. Do not free it here!
2327 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2329 for(i
=0; i
< num_cpus
; i
++) {
2330 //g_assert(process != ts->running_process[i]);
2331 if(process
== ts
->running_process
[i
]) {
2332 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2336 if(i
== num_cpus
) /* process is not scheduled */
2337 exit_process(s
, process
);
2344 static gboolean
process_exec(void *hook_data
, void *call_data
)
2346 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2347 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2348 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2349 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2352 LttvProcessState
*process
= ts
->running_process
[cpu
];
2354 /* PID of the process to release */
2355 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2356 //name = ltt_event_get_string(e, thf->f1);
2357 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2359 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2360 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2361 memcpy(null_term_name
, name_begin
, name_len
);
2362 null_term_name
[name_len
] = '\0';
2364 process
->name
= g_quark_from_string(null_term_name
);
2365 process
->brand
= LTTV_STATE_UNBRANDED
;
2366 g_free(null_term_name
);
2370 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2372 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2373 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2374 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2375 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2378 LttvProcessState
*process
= ts
->running_process
[cpu
];
2380 name
= ltt_event_get_string(e
, thf
->f1
);
2381 process
->brand
= g_quark_from_string(name
);
2386 static void fix_process(gpointer key
, gpointer value
,
2389 LttvProcessState
*process
;
2390 LttvExecutionState
*es
;
2391 process
= (LttvProcessState
*)value
;
2392 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2393 LttTime
*timestamp
= (LttTime
*)user_data
;
2395 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2396 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2397 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2398 es
->t
= LTTV_STATE_SYSCALL
;
2399 es
->s
= LTTV_STATE_WAIT
;
2400 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2401 es
->entry
= *timestamp
;
2402 es
->change
= *timestamp
;
2403 es
->cum_cpu_time
= ltt_time_zero
;
2406 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2407 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2408 es
->t
= LTTV_STATE_USER_MODE
;
2409 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2410 es
->entry
= *timestamp
;
2411 //g_assert(timestamp->tv_sec != 0);
2412 es
->change
= *timestamp
;
2413 es
->cum_cpu_time
= ltt_time_zero
;
2414 es
->s
= LTTV_STATE_RUN
;
2416 if(process
->execution_stack
->len
== 1) {
2417 /* Still in user mode, means never scheduled */
2418 process
->execution_stack
=
2419 g_array_set_size(process
->execution_stack
, 2);
2420 es
= process
->state
= &g_array_index(process
->execution_stack
,
2421 LttvExecutionState
, 1);
2422 es
->t
= LTTV_STATE_SYSCALL
;
2423 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2424 es
->entry
= *timestamp
;
2425 //g_assert(timestamp->tv_sec != 0);
2426 es
->change
= *timestamp
;
2427 es
->cum_cpu_time
= ltt_time_zero
;
2428 es
->s
= LTTV_STATE_WAIT
;
2434 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2436 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2437 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2438 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2439 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2440 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2442 /* For all processes */
2443 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2444 /* else, if stack[0] is unknown, set to user mode, running */
2446 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2449 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2451 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2452 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2453 //It's slow : optimise later by doing this before reading trace.
2454 LttEventType
*et
= ltt_event_eventtype(e
);
2456 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2462 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2463 LttvProcessState
*process
= ts
->running_process
[cpu
];
2464 LttvProcessState
*parent_process
;
2465 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2466 GQuark type
, mode
, submode
, status
;
2467 LttvExecutionState
*es
;
2470 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2471 s
->parent
.target_pid
= pid
;
2474 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2477 command
= ltt_event_get_string(e
, thf
->f3
);
2480 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2481 type
= ltt_enum_string_get(ltt_field_type(f4
),
2482 ltt_event_get_unsigned(e
, f4
));
2485 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2486 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2487 ltt_event_get_unsigned(e
, f5
));
2490 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2491 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2492 ltt_event_get_unsigned(e
, f6
));
2495 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2496 status
= ltt_enum_string_get(ltt_field_type(f7
),
2497 ltt_event_get_unsigned(e
, f7
));
2500 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2501 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2504 /* The process might exist if a process was forked while performing the state
2506 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2507 if(process
== NULL
) {
2508 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2509 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2510 pid
, tgid
, g_quark_from_string(command
),
2511 &s
->parent
.timestamp
);
2513 /* Keep the stack bottom : a running user mode */
2514 /* Disabled because of inconsistencies in the current statedump states. */
2515 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2516 /* Only keep the bottom
2517 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2518 /* Will cause expected trap when in fact being syscall (even after end of
2520 * Will cause expected interrupt when being syscall. (only before end of
2521 * statedump event) */
2522 // This will cause a "popping last state on stack, ignoring it."
2523 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2524 es
= process
->state
= &g_array_index(process
->execution_stack
,
2525 LttvExecutionState
, 0);
2526 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2527 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2528 es
->s
= LTTV_STATE_UNNAMED
;
2529 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2531 es
->t
= LTTV_STATE_SYSCALL
;
2536 /* User space process :
2537 * bottom : user mode
2538 * either currently running or scheduled out.
2539 * can be scheduled out because interrupted in (user mode or in syscall)
2540 * or because of an explicit call to the scheduler in syscall. Note that
2541 * the scheduler call comes after the irq_exit, so never in interrupt
2543 // temp workaround : set size to 1 : only have user mode bottom of stack.
2544 // will cause g_info message of expected syscall mode when in fact being
2545 // in user mode. Can also cause expected trap when in fact being user
2546 // mode in the event of a page fault reenabling interrupts in the handler.
2547 // Expected syscall and trap can also happen after the end of statedump
2548 // This will cause a "popping last state on stack, ignoring it."
2549 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2550 es
= process
->state
= &g_array_index(process
->execution_stack
,
2551 LttvExecutionState
, 0);
2552 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2553 es
->s
= LTTV_STATE_UNNAMED
;
2554 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2556 es
->t
= LTTV_STATE_USER_MODE
;
2564 es
= process
->state
= &g_array_index(process
->execution_stack
,
2565 LttvExecutionState
, 1);
2566 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2567 es
->s
= LTTV_STATE_UNNAMED
;
2568 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2572 /* The process has already been created :
2573 * Probably was forked while dumping the process state or
2574 * was simply scheduled in prior to get the state dump event.
2575 * We know for sure if it is a user space thread.
2577 process
->ppid
= parent_pid
;
2578 process
->tgid
= tgid
;
2579 process
->name
= g_quark_from_string(command
);
2581 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2582 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2583 es
->t
= LTTV_STATE_USER_MODE
;
2584 /* Don't mess around with the stack, it will eventually become
2585 * ok after the end of state dump. */
2591 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2593 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2595 lttv_state_add_event_hooks(tss
);
2600 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2602 LttvTraceset
*traceset
= self
->parent
.ts
;
2604 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2608 LttvTracefileState
*tfs
;
2612 LttvTraceHookByFacility
*thf
;
2614 LttvTraceHook
*hook
;
2616 LttvAttributeValue val
;
2621 nb_trace
= lttv_traceset_number(traceset
);
2622 for(i
= 0 ; i
< nb_trace
; i
++) {
2623 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2625 /* Find the eventtype id for the following events and register the
2626 associated by id hooks. */
2628 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2629 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2632 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2633 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2634 LTT_FIELD_SYSCALL_ID
, 0, 0,
2635 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2638 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2639 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2641 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2644 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2645 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2646 LTT_FIELD_TRAP_ID
, 0, 0,
2647 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2650 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2651 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2653 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2656 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2657 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2658 LTT_FIELD_IRQ_ID
, 0, 0,
2659 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2662 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2663 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2665 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2668 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2669 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2670 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2671 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2674 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2675 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2677 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2680 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2681 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2682 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2683 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2686 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2687 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2688 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2689 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2692 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2693 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2694 LTT_FIELD_PID
, 0, 0,
2695 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2699 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2700 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2701 LTT_FIELD_PID
, 0, 0,
2702 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2705 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2706 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2707 LTT_FIELD_PID
, 0, 0,
2708 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2711 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2712 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2713 LTT_FIELD_FILENAME
, 0, 0,
2714 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2717 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2718 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2719 LTT_FIELD_NAME
, 0, 0,
2720 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2723 /* statedump-related hooks */
2724 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2725 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2726 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2727 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2730 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2731 LTT_FACILITY_STATEDUMP
, LTT_EVENT_STATEDUMP_END
,
2733 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2736 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2737 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2738 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2739 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2742 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2743 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2744 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2745 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2748 hooks
= g_array_set_size(hooks
, hn
);
2750 /* Add these hooks to each event_by_id hooks list */
2752 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2754 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2756 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2757 LttvTracefileContext
*, j
));
2759 for(k
= 0 ; k
< hooks
->len
; k
++) {
2760 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2761 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2762 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2764 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2771 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2772 *(val
.v_pointer
) = hooks
;
2776 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2778 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2780 lttv_state_remove_event_hooks(tss
);
2785 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2787 LttvTraceset
*traceset
= self
->parent
.ts
;
2789 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2793 LttvTracefileState
*tfs
;
2797 LttvTraceHook
*hook
;
2799 LttvTraceHookByFacility
*thf
;
2801 LttvAttributeValue val
;
2803 nb_trace
= lttv_traceset_number(traceset
);
2804 for(i
= 0 ; i
< nb_trace
; i
++) {
2805 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2807 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2808 hooks
= *(val
.v_pointer
);
2810 /* Remove these hooks from each event_by_id hooks list */
2812 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2814 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2816 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2817 LttvTracefileContext
*, j
));
2819 for(k
= 0 ; k
< hooks
->len
; k
++) {
2820 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2821 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2822 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2824 lttv_hooks_remove_data(
2825 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2831 for(k
= 0 ; k
< hooks
->len
; k
++)
2832 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2833 g_array_free(hooks
, TRUE
);
2837 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2839 guint
*event_count
= (guint
*)hook_data
;
2841 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2842 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2847 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2849 LttvTracefileState
*tfcs
;
2851 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2853 LttEventPosition
*ep
;
2859 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2861 LttvAttributeValue value
;
2863 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2864 LTTV_STATE_SAVED_STATES
);
2865 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2866 value
= lttv_attribute_add(saved_states_tree
,
2867 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2868 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2869 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2870 *(value
.v_time
) = self
->parent
.timestamp
;
2871 lttv_state_save(tcs
, saved_state_tree
);
2872 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2873 self
->parent
.timestamp
.tv_nsec
);
2875 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2880 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2882 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2884 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2889 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2897 static gboolean
block_start(void *hook_data
, void *call_data
)
2899 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2901 LttvTracefileState
*tfcs
;
2903 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2905 LttEventPosition
*ep
;
2907 guint i
, nb_block
, nb_event
, nb_tracefile
;
2911 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2913 LttvAttributeValue value
;
2915 ep
= ltt_event_position_new();
2917 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2919 /* Count the number of events added since the last block end in any
2922 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2924 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2925 LttvTracefileContext
, i
));
2926 ltt_event_position(tfcs
->parent
.e
, ep
);
2927 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2928 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2929 tfcs
->saved_position
= nb_event
;
2933 if(tcs
->nb_event
>= tcs
->save_interval
) {
2934 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2935 LTTV_STATE_SAVED_STATES
);
2936 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2937 value
= lttv_attribute_add(saved_states_tree
,
2938 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2939 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2940 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2941 *(value
.v_time
) = self
->parent
.timestamp
;
2942 lttv_state_save(tcs
, saved_state_tree
);
2944 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2945 self
->parent
.timestamp
.tv_nsec
);
2947 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2953 static gboolean
block_end(void *hook_data
, void *call_data
)
2955 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2957 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2961 LttEventPosition
*ep
;
2963 guint nb_block
, nb_event
;
2965 ep
= ltt_event_position_new();
2966 ltt_event_position(self
->parent
.e
, ep
);
2967 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2968 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2969 self
->saved_position
= 0;
2970 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2977 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2979 LttvTraceset
*traceset
= self
->parent
.ts
;
2981 guint i
, j
, nb_trace
, nb_tracefile
;
2985 LttvTracefileState
*tfs
;
2987 LttvTraceHook hook_start
, hook_end
;
2989 nb_trace
= lttv_traceset_number(traceset
);
2990 for(i
= 0 ; i
< nb_trace
; i
++) {
2991 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2993 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2994 NULL
, NULL
, block_start
, &hook_start
);
2995 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2996 NULL
, NULL
, block_end
, &hook_end
);
2998 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3000 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3002 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3003 LttvTracefileContext
, j
));
3004 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3005 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3006 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3007 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3013 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3015 LttvTraceset
*traceset
= self
->parent
.ts
;
3017 guint i
, j
, nb_trace
, nb_tracefile
;
3021 LttvTracefileState
*tfs
;
3024 nb_trace
= lttv_traceset_number(traceset
);
3025 for(i
= 0 ; i
< nb_trace
; i
++) {
3027 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3028 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3030 if(ts
->has_precomputed_states
) continue;
3032 guint
*event_count
= g_new(guint
, 1);
3035 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3037 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3038 LttvTracefileContext
*, j
));
3039 lttv_hooks_add(tfs
->parent
.event
,
3040 state_save_event_hook
,
3047 lttv_process_traceset_begin(&self
->parent
,
3048 NULL
, NULL
, NULL
, NULL
, NULL
);
3052 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3054 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3056 lttv_state_save_add_event_hooks(tss
);
3063 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3065 LttvTraceset
*traceset
= self
->parent
.ts
;
3067 guint i
, j
, nb_trace
, nb_tracefile
;
3071 LttvTracefileState
*tfs
;
3073 LttvTraceHook hook_start
, hook_end
;
3075 nb_trace
= lttv_traceset_number(traceset
);
3076 for(i
= 0 ; i
< nb_trace
; i
++) {
3077 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3079 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3080 NULL
, NULL
, block_start
, &hook_start
);
3082 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3083 NULL
, NULL
, block_end
, &hook_end
);
3085 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3087 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3089 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3090 LttvTracefileContext
, j
));
3091 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3092 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3093 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3094 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3100 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3102 LttvTraceset
*traceset
= self
->parent
.ts
;
3104 guint i
, j
, nb_trace
, nb_tracefile
;
3108 LttvTracefileState
*tfs
;
3110 LttvHooks
*after_trace
= lttv_hooks_new();
3112 lttv_hooks_add(after_trace
,
3113 state_save_after_trace_hook
,
3118 lttv_process_traceset_end(&self
->parent
,
3119 NULL
, after_trace
, NULL
, NULL
, NULL
);
3121 lttv_hooks_destroy(after_trace
);
3123 nb_trace
= lttv_traceset_number(traceset
);
3124 for(i
= 0 ; i
< nb_trace
; i
++) {
3126 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3127 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3129 if(ts
->has_precomputed_states
) continue;
3131 guint
*event_count
= NULL
;
3133 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3135 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3136 LttvTracefileContext
*, j
));
3137 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3138 state_save_event_hook
);
3140 if(event_count
) g_free(event_count
);
3144 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3146 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3148 lttv_state_save_remove_event_hooks(tss
);
3153 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3155 LttvTraceset
*traceset
= self
->parent
.ts
;
3159 int min_pos
, mid_pos
, max_pos
;
3161 guint call_rest
= 0;
3163 LttvTraceState
*tcs
;
3165 LttvAttributeValue value
;
3167 LttvAttributeType type
;
3169 LttvAttributeName name
;
3173 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3175 //g_tree_destroy(self->parent.pqueue);
3176 //self->parent.pqueue = g_tree_new(compare_tracefile);
3178 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3180 nb_trace
= lttv_traceset_number(traceset
);
3181 for(i
= 0 ; i
< nb_trace
; i
++) {
3182 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3184 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3185 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3186 LTTV_STATE_SAVED_STATES
);
3189 if(saved_states_tree
) {
3190 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3191 mid_pos
= max_pos
/ 2;
3192 while(min_pos
< max_pos
) {
3193 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3195 g_assert(type
== LTTV_GOBJECT
);
3196 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3197 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3199 g_assert(type
== LTTV_TIME
);
3200 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3202 closest_tree
= saved_state_tree
;
3204 else max_pos
= mid_pos
- 1;
3206 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3210 /* restore the closest earlier saved state */
3212 lttv_state_restore(tcs
, closest_tree
);
3216 /* There is no saved state, yet we want to have it. Restart at T0 */
3218 restore_init_state(tcs
);
3219 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3222 /* We want to seek quickly without restoring/updating the state */
3224 restore_init_state(tcs
);
3225 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3228 if(!call_rest
) g_info("NOT Calling restore");
3233 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3239 traceset_state_finalize (LttvTracesetState
*self
)
3241 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3242 finalize(G_OBJECT(self
));
3247 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3249 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3251 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3252 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3253 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3254 klass
->new_traceset_context
= new_traceset_context
;
3255 klass
->new_trace_context
= new_trace_context
;
3256 klass
->new_tracefile_context
= new_tracefile_context
;
3261 lttv_traceset_state_get_type(void)
3263 static GType type
= 0;
3265 static const GTypeInfo info
= {
3266 sizeof (LttvTracesetStateClass
),
3267 NULL
, /* base_init */
3268 NULL
, /* base_finalize */
3269 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3270 NULL
, /* class_finalize */
3271 NULL
, /* class_data */
3272 sizeof (LttvTracesetState
),
3273 0, /* n_preallocs */
3274 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3275 NULL
/* value handling */
3278 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3286 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3292 trace_state_finalize (LttvTraceState
*self
)
3294 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3295 finalize(G_OBJECT(self
));
3300 trace_state_class_init (LttvTraceStateClass
*klass
)
3302 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3304 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3305 klass
->state_save
= state_save
;
3306 klass
->state_restore
= state_restore
;
3307 klass
->state_saved_free
= state_saved_free
;
3312 lttv_trace_state_get_type(void)
3314 static GType type
= 0;
3316 static const GTypeInfo info
= {
3317 sizeof (LttvTraceStateClass
),
3318 NULL
, /* base_init */
3319 NULL
, /* base_finalize */
3320 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3321 NULL
, /* class_finalize */
3322 NULL
, /* class_data */
3323 sizeof (LttvTraceState
),
3324 0, /* n_preallocs */
3325 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3326 NULL
/* value handling */
3329 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3330 "LttvTraceStateType", &info
, 0);
3337 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3343 tracefile_state_finalize (LttvTracefileState
*self
)
3345 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3346 finalize(G_OBJECT(self
));
3351 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3353 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3355 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3360 lttv_tracefile_state_get_type(void)
3362 static GType type
= 0;
3364 static const GTypeInfo info
= {
3365 sizeof (LttvTracefileStateClass
),
3366 NULL
, /* base_init */
3367 NULL
, /* base_finalize */
3368 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3369 NULL
, /* class_finalize */
3370 NULL
, /* class_data */
3371 sizeof (LttvTracefileState
),
3372 0, /* n_preallocs */
3373 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3374 NULL
/* value handling */
3377 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3378 "LttvTracefileStateType", &info
, 0);
3384 static void module_init()
3386 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3387 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3388 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3389 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3390 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3391 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3392 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3393 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3394 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3395 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3396 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3397 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3398 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3399 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3400 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3401 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3402 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3403 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3404 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3405 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3406 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3407 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3408 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3409 LTTV_STATE_EVENT
= g_quark_from_string("event");
3410 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3411 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3412 LTTV_STATE_TIME
= g_quark_from_string("time");
3413 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3414 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3415 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3416 g_quark_from_string("trace_state_use_count");
3419 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3420 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3421 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3422 LTT_FACILITY_FS
= g_quark_from_string("fs");
3423 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3424 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3427 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3428 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3429 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3430 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3431 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3432 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3433 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3434 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3435 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3436 LTT_EVENT_FORK
= g_quark_from_string("fork");
3437 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3438 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3439 LTT_EVENT_FREE
= g_quark_from_string("free");
3440 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3441 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3442 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3443 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3444 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3445 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3448 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3449 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3450 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3451 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3452 LTT_FIELD_OUT
= g_quark_from_string("out");
3453 LTT_FIELD_IN
= g_quark_from_string("in");
3454 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3455 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3456 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3457 LTT_FIELD_PID
= g_quark_from_string("pid");
3458 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3459 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3460 LTT_FIELD_NAME
= g_quark_from_string("name");
3461 LTT_FIELD_TYPE
= g_quark_from_string("type");
3462 LTT_FIELD_MODE
= g_quark_from_string("mode");
3463 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3464 LTT_FIELD_STATUS
= g_quark_from_string("status");
3465 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3466 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3470 static void module_destroy()
3475 LTTV_MODULE("state", "State computation", \
3476 "Update the system state, possibly saving it at intervals", \
3477 module_init
, module_destroy
)