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
;
1358 GQuark
*soft_irq_names
;
1363 create_name_tables(LttvTraceState
*tcs
)
1367 GQuark f_name
, e_name
;
1371 LttvTraceHookByFacility
*thf
;
1377 GString
*fe_name
= g_string_new("");
1379 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1381 LttvAttributeValue v
;
1383 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1385 g_assert(*(v
.v_pointer
) == NULL
);
1386 *(v
.v_pointer
) = name_tables
;
1387 #if 0 // Use iteration over the facilities_by_name and then list all event
1388 // types of each facility
1389 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1390 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1391 for(i
= 0 ; i
< nb
; i
++) {
1392 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1393 e_name
= ltt_eventtype_name(et
);
1394 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1395 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1396 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1399 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1400 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1401 LTT_FIELD_SYSCALL_ID
, 0, 0,
1404 thf
= lttv_trace_hook_get_first(&h
);
1406 t
= ltt_field_type(thf
->f1
);
1407 nb
= ltt_type_element_number(t
);
1409 lttv_trace_hook_destroy(&h
);
1411 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1412 name_tables
->nb_syscalls
= nb
;
1414 for(i
= 0 ; i
< nb
; i
++) {
1415 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1418 //name_tables->syscall_names = g_new(GQuark, 256);
1419 //for(i = 0 ; i < 256 ; i++) {
1420 // g_string_printf(fe_name, "syscall %d", i);
1421 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1424 name_tables
->syscall_names
= NULL
;
1425 name_tables
->nb_syscalls
= 0;
1428 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1429 LTT_EVENT_TRAP_ENTRY
,
1430 LTT_FIELD_TRAP_ID
, 0, 0,
1433 thf
= lttv_trace_hook_get_first(&h
);
1435 t
= ltt_field_type(thf
->f1
);
1436 //nb = ltt_type_element_number(t);
1438 lttv_trace_hook_destroy(&h
);
1441 name_tables->trap_names = g_new(GQuark, nb);
1442 for(i = 0 ; i < nb ; i++) {
1443 name_tables->trap_names[i] = g_quark_from_string(
1444 ltt_enum_string_get(t, i));
1447 name_tables
->nb_traps
= 256;
1448 name_tables
->trap_names
= g_new(GQuark
, 256);
1449 for(i
= 0 ; i
< 256 ; i
++) {
1450 g_string_printf(fe_name
, "trap %d", i
);
1451 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1454 name_tables
->trap_names
= NULL
;
1455 name_tables
->nb_traps
= 0;
1458 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1459 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1460 LTT_FIELD_IRQ_ID
, 0, 0,
1463 thf
= lttv_trace_hook_get_first(&h
);
1465 t
= ltt_field_type(thf
->f1
);
1466 //nb = ltt_type_element_number(t);
1468 lttv_trace_hook_destroy(&h
);
1471 name_tables->irq_names = g_new(GQuark, nb);
1472 for(i = 0 ; i < nb ; i++) {
1473 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1477 name_tables
->irq_names
= g_new(GQuark
, 256);
1478 for(i
= 0 ; i
< 256 ; i
++) {
1479 g_string_printf(fe_name
, "irq %d", i
);
1480 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1483 name_tables
->irq_names
= NULL
;
1486 name_tables->soft_irq_names = g_new(GQuark, nb);
1487 for(i = 0 ; i < nb ; i++) {
1488 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1492 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1493 for(i
= 0 ; i
< 256 ; i
++) {
1494 g_string_printf(fe_name
, "softirq %d", i
);
1495 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1499 g_string_free(fe_name
, TRUE
);
1504 get_name_tables(LttvTraceState
*tcs
)
1506 LttvNameTables
*name_tables
;
1508 LttvAttributeValue v
;
1510 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1512 g_assert(*(v
.v_pointer
) != NULL
);
1513 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1514 //tcs->eventtype_names = name_tables->eventtype_names;
1515 tcs
->syscall_names
= name_tables
->syscall_names
;
1516 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1517 tcs
->trap_names
= name_tables
->trap_names
;
1518 tcs
->nb_traps
= name_tables
->nb_traps
;
1519 tcs
->irq_names
= name_tables
->irq_names
;
1520 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1525 free_name_tables(LttvTraceState
*tcs
)
1527 LttvNameTables
*name_tables
;
1529 LttvAttributeValue v
;
1531 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1533 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1534 *(v
.v_pointer
) = NULL
;
1536 // g_free(name_tables->eventtype_names);
1537 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1538 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1539 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1540 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1541 if(name_tables
) g_free(name_tables
);
1544 #ifdef HASH_TABLE_DEBUG
1546 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1548 LttvProcessState
*process
= (LttvProcessState
*)value
;
1550 /* Test for process corruption */
1551 guint stack_len
= process
->execution_stack
->len
;
1554 static void hash_table_check(GHashTable
*table
)
1556 g_hash_table_foreach(table
, test_process
, NULL
);
1563 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1566 LttvExecutionState
*es
;
1568 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1569 guint cpu
= tfs
->cpu
;
1571 #ifdef HASH_TABLE_DEBUG
1572 hash_table_check(ts
->processes
);
1574 LttvProcessState
*process
= ts
->running_process
[cpu
];
1576 guint depth
= process
->execution_stack
->len
;
1578 process
->execution_stack
=
1579 g_array_set_size(process
->execution_stack
, depth
+ 1);
1582 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1584 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1587 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1588 es
->cum_cpu_time
= ltt_time_zero
;
1589 es
->s
= process
->state
->s
;
1590 process
->state
= es
;
1594 * return 1 when empty, else 0 */
1595 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1596 LttvTracefileState
*tfs
)
1598 guint cpu
= tfs
->cpu
;
1599 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1601 guint depth
= process
->execution_stack
->len
;
1607 process
->execution_stack
=
1608 g_array_set_size(process
->execution_stack
, depth
- 1);
1609 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1611 process
->state
->change
= tfs
->parent
.timestamp
;
1616 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1618 guint cpu
= tfs
->cpu
;
1619 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1620 LttvProcessState
*process
= ts
->running_process
[cpu
];
1622 guint depth
= process
->execution_stack
->len
;
1624 if(process
->state
->t
!= t
){
1625 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1626 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1627 g_info("process state has %s when pop_int is %s\n",
1628 g_quark_to_string(process
->state
->t
),
1629 g_quark_to_string(t
));
1630 g_info("{ %u, %u, %s, %s, %s }\n",
1633 g_quark_to_string(process
->name
),
1634 g_quark_to_string(process
->brand
),
1635 g_quark_to_string(process
->state
->s
));
1640 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1641 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1645 process
->execution_stack
=
1646 g_array_set_size(process
->execution_stack
, depth
- 1);
1647 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1649 process
->state
->change
= tfs
->parent
.timestamp
;
1652 struct search_result
{
1653 const LttTime
*time
; /* Requested time */
1654 LttTime
*best
; /* Best result */
1657 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1659 const LttTime
*elem_time
= (const LttTime
*)a
;
1660 /* Explicit non const cast */
1661 struct search_result
*res
= (struct search_result
*)b
;
1663 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1664 /* The usertrace was created before the schedchange */
1665 /* Get larger keys */
1667 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1668 /* The usertrace was created after the schedchange time */
1669 /* Get smaller keys */
1671 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1672 res
->best
= elem_time
;
1675 res
->best
= elem_time
;
1682 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1683 guint pid
, const LttTime
*timestamp
)
1685 LttvTracefileState
*tfs
= NULL
;
1686 struct search_result res
;
1687 /* Find the usertrace associated with a pid and time interval.
1688 * Search in the usertraces by PID (within a hash) and then, for each
1689 * corresponding element of the array, find the first one with creation
1690 * timestamp the lowest, but higher or equal to "timestamp". */
1691 res
.time
= timestamp
;
1693 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1694 if(usertrace_tree
) {
1695 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1697 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1705 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1706 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1708 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1710 LttvExecutionState
*es
;
1712 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1717 process
->tgid
= tgid
;
1719 process
->name
= name
;
1720 process
->brand
= LTTV_STATE_UNBRANDED
;
1721 //process->last_cpu = tfs->cpu_name;
1722 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1723 process
->type
= LTTV_STATE_USER_THREAD
;
1724 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1725 process
->current_function
= 0; //function 0x0 by default.
1727 g_info("Process %u, core %p", process
->pid
, process
);
1728 g_hash_table_insert(tcs
->processes
, process
, process
);
1731 process
->ppid
= parent
->pid
;
1732 process
->creation_time
= *timestamp
;
1735 /* No parent. This process exists but we are missing all information about
1736 its creation. The birth time is set to zero but we remember the time of
1741 process
->creation_time
= ltt_time_zero
;
1744 process
->insertion_time
= *timestamp
;
1745 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1746 process
->creation_time
.tv_nsec
);
1747 process
->pid_time
= g_quark_from_string(buffer
);
1749 //process->last_cpu = tfs->cpu_name;
1750 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1751 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1752 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1753 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1754 es
= process
->state
= &g_array_index(process
->execution_stack
,
1755 LttvExecutionState
, 0);
1756 es
->t
= LTTV_STATE_USER_MODE
;
1757 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1758 es
->entry
= *timestamp
;
1759 //g_assert(timestamp->tv_sec != 0);
1760 es
->change
= *timestamp
;
1761 es
->cum_cpu_time
= ltt_time_zero
;
1762 es
->s
= LTTV_STATE_RUN
;
1764 es
= process
->state
= &g_array_index(process
->execution_stack
,
1765 LttvExecutionState
, 1);
1766 es
->t
= LTTV_STATE_SYSCALL
;
1767 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1768 es
->entry
= *timestamp
;
1769 //g_assert(timestamp->tv_sec != 0);
1770 es
->change
= *timestamp
;
1771 es
->cum_cpu_time
= ltt_time_zero
;
1772 es
->s
= LTTV_STATE_WAIT_FORK
;
1774 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1775 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1776 sizeof(guint64
), 0);
1781 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1784 LttvProcessState key
;
1785 LttvProcessState
*process
;
1789 process
= g_hash_table_lookup(ts
->processes
, &key
);
1794 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1795 const LttTime
*timestamp
)
1797 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1798 LttvExecutionState
*es
;
1800 /* Put ltt_time_zero creation time for unexisting processes */
1801 if(unlikely(process
== NULL
)) {
1802 process
= lttv_state_create_process(ts
,
1803 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1804 /* We are not sure is it's a kernel thread or normal thread, put the
1805 * bottom stack state to unknown */
1806 process
->execution_stack
=
1807 g_array_set_size(process
->execution_stack
, 1);
1808 process
->state
= es
=
1809 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1810 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1815 /* FIXME : this function should be called when we receive an event telling that
1816 * release_task has been called in the kernel. In happens generally when
1817 * the parent waits for its child terminaison, but may also happen in special
1818 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1819 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1820 * of a killed thread ground, but isn't the leader.
1822 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1824 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1825 LttvProcessState key
;
1827 key
.pid
= process
->pid
;
1828 key
.cpu
= process
->cpu
;
1829 g_hash_table_remove(ts
->processes
, &key
);
1830 g_array_free(process
->execution_stack
, TRUE
);
1831 g_array_free(process
->user_stack
, TRUE
);
1836 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1838 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1839 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1844 static void lttv_state_free_process_table(GHashTable
*processes
)
1846 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1847 g_hash_table_destroy(processes
);
1851 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1853 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1855 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1856 LttvProcessState
*process
= ts
->running_process
[cpu
];
1857 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1858 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1859 LttField
*f
= thf
->f1
;
1861 LttvExecutionSubmode submode
;
1863 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1864 guint syscall
= ltt_event_get_unsigned(e
, f
);
1866 if(syscall
< nb_syscalls
) {
1867 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1870 /* Fixup an incomplete syscall table */
1871 GString
*string
= g_string_new("");
1872 g_string_printf(string
, "syscall %u", syscall
);
1873 submode
= g_quark_from_string(string
->str
);
1874 g_string_free(string
, TRUE
);
1876 /* There can be no system call from PID 0 : unknown state */
1877 if(process
->pid
!= 0)
1878 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1883 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1885 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1887 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1888 LttvProcessState
*process
= ts
->running_process
[cpu
];
1890 /* There can be no system call from PID 0 : unknown state */
1891 if(process
->pid
!= 0)
1892 pop_state(s
, LTTV_STATE_SYSCALL
);
1897 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1899 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1900 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1901 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1902 LttField
*f
= thf
->f1
;
1904 LttvExecutionSubmode submode
;
1906 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1907 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1909 if(trap
< nb_traps
) {
1910 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1912 /* Fixup an incomplete trap table */
1913 GString
*string
= g_string_new("");
1914 g_string_printf(string
, "trap %llu", trap
);
1915 submode
= g_quark_from_string(string
->str
);
1916 g_string_free(string
, TRUE
);
1919 push_state(s
, LTTV_STATE_TRAP
, submode
);
1924 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1926 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1928 pop_state(s
, LTTV_STATE_TRAP
);
1933 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1935 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1936 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1937 guint8 fac_id
= ltt_event_facility_id(e
);
1938 guint8 ev_id
= ltt_event_eventtype_id(e
);
1939 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1940 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1941 g_assert(thf
->f1
!= NULL
);
1942 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1943 LttField
*f
= thf
->f1
;
1945 LttvExecutionSubmode submode
;
1947 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1948 ltt_event_get_unsigned(e
, f
)];
1950 /* Do something with the info about being in user or system mode when int? */
1951 push_state(s
, LTTV_STATE_IRQ
, submode
);
1955 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1957 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1959 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1965 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1967 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1969 pop_state(s
, LTTV_STATE_IRQ
);
1973 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1975 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1976 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1977 guint8 fac_id
= ltt_event_facility_id(e
);
1978 guint8 ev_id
= ltt_event_eventtype_id(e
);
1979 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1980 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1981 g_assert(thf
->f1
!= NULL
);
1982 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1983 LttField
*f
= thf
->f1
;
1985 LttvExecutionSubmode submode
;
1987 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1988 ltt_event_get_long_unsigned(e
, f
)];
1990 /* Do something with the info about being in user or system mode when int? */
1991 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1995 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1999 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2000 guint cpu
= tfs
->cpu
;
2001 LttvProcessState
*process
= ts
->running_process
[cpu
];
2003 guint depth
= process
->user_stack
->len
;
2005 process
->user_stack
=
2006 g_array_set_size(process
->user_stack
, depth
+ 1);
2008 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2009 *new_func
= funcptr
;
2010 process
->current_function
= funcptr
;
2013 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2015 guint cpu
= tfs
->cpu
;
2016 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2017 LttvProcessState
*process
= ts
->running_process
[cpu
];
2019 if(process
->current_function
!= funcptr
){
2020 g_info("Different functions (%lu.%09lu): ignore it\n",
2021 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2022 g_info("process state has %llu when pop_function is %llu\n",
2023 process
->current_function
, funcptr
);
2024 g_info("{ %u, %u, %s, %s, %s }\n",
2027 g_quark_to_string(process
->name
),
2028 g_quark_to_string(process
->brand
),
2029 g_quark_to_string(process
->state
->s
));
2032 guint depth
= process
->user_stack
->len
;
2035 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2036 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2040 process
->user_stack
=
2041 g_array_set_size(process
->user_stack
, depth
- 1);
2042 process
->current_function
=
2043 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2047 static gboolean
function_entry(void *hook_data
, void *call_data
)
2049 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2050 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2051 guint8 fac_id
= ltt_event_facility_id(e
);
2052 guint8 ev_id
= ltt_event_eventtype_id(e
);
2053 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2054 g_assert(thf
->f1
!= NULL
);
2055 LttField
*f
= thf
->f1
;
2056 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2058 push_function(s
, funcptr
);
2062 static gboolean
function_exit(void *hook_data
, void *call_data
)
2064 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2065 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2066 guint8 fac_id
= ltt_event_facility_id(e
);
2067 guint8 ev_id
= ltt_event_eventtype_id(e
);
2068 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2069 g_assert(thf
->f1
!= NULL
);
2070 LttField
*f
= thf
->f1
;
2071 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2073 LttvExecutionSubmode submode
;
2075 pop_function(s
, funcptr
);
2079 static gboolean
schedchange(void *hook_data
, void *call_data
)
2081 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2083 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2084 LttvProcessState
*process
= ts
->running_process
[cpu
];
2085 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2087 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2088 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2089 guint pid_in
, pid_out
;
2092 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2093 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2094 state_out
= ltt_event_get_int(e
, thf
->f3
);
2096 if(likely(process
!= NULL
)) {
2098 /* We could not know but it was not the idle process executing.
2099 This should only happen at the beginning, before the first schedule
2100 event, and when the initial information (current process for each CPU)
2101 is missing. It is not obvious how we could, after the fact, compensate
2102 the wrongly attributed statistics. */
2104 //This test only makes sense once the state is known and if there is no
2105 //missing events. We need to silently ignore schedchange coming after a
2106 //process_free, or it causes glitches. (FIXME)
2107 //if(unlikely(process->pid != pid_out)) {
2108 // g_assert(process->pid == 0);
2110 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2111 /* Scheduling out of pid 0 at beginning of the trace :
2112 * we know for sure it is in syscall mode at this point. */
2113 g_assert(process
->execution_stack
->len
== 1);
2114 process
->state
->t
= LTTV_STATE_SYSCALL
;
2116 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2117 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2118 process
->state
->change
= s
->parent
.timestamp
;
2120 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2121 else process
->state
->s
= LTTV_STATE_WAIT
;
2122 process
->state
->change
= s
->parent
.timestamp
;
2126 exit_process(s
, process
); /* EXIT_DEAD */
2127 /* see sched.h for states */
2129 process
= ts
->running_process
[cpu
] =
2130 lttv_state_find_process_or_create(
2131 (LttvTraceState
*)s
->parent
.t_context
,
2133 &s
->parent
.timestamp
);
2134 process
->state
->s
= LTTV_STATE_RUN
;
2136 if(process
->usertrace
)
2137 process
->usertrace
->cpu
= cpu
;
2138 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2139 process
->state
->change
= s
->parent
.timestamp
;
2143 static gboolean
process_fork(void *hook_data
, void *call_data
)
2145 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2146 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2147 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2149 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2150 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2151 LttvProcessState
*zombie_process
;
2153 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2154 LttvProcessState
*process
= ts
->running_process
[cpu
];
2155 LttvProcessState
*child_process
;
2158 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2161 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2162 s
->parent
.target_pid
= child_pid
;
2165 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2166 else child_tgid
= 0;
2168 /* Mathieu : it seems like the process might have been scheduled in before the
2169 * fork, and, in a rare case, might be the current process. This might happen
2170 * in a SMP case where we don't have enough precision on the clocks.
2172 * Test reenabled after precision fixes on time. (Mathieu) */
2174 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2176 if(unlikely(zombie_process
!= NULL
)) {
2177 /* Reutilisation of PID. Only now we are sure that the old PID
2178 * has been released. FIXME : should know when release_task happens instead.
2180 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2182 for(i
=0; i
< num_cpus
; i
++) {
2183 g_assert(zombie_process
!= ts
->running_process
[i
]);
2186 exit_process(s
, zombie_process
);
2189 g_assert(process
->pid
!= child_pid
);
2190 // FIXME : Add this test in the "known state" section
2191 // g_assert(process->pid == parent_pid);
2192 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2193 if(child_process
== NULL
) {
2194 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2195 child_pid
, child_tgid
,
2196 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2198 /* The process has already been created : due to time imprecision between
2199 * multiple CPUs : it has been scheduled in before creation. Note that we
2200 * shouldn't have this kind of imprecision.
2202 * Simply put a correct parent.
2204 g_assert(0); /* This is a problematic case : the process has been created
2205 before the fork event */
2206 child_process
->ppid
= process
->pid
;
2207 child_process
->tgid
= child_tgid
;
2209 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2210 child_process
->name
= process
->name
;
2211 child_process
->brand
= process
->brand
;
2216 /* We stamp a newly created process as kernel_thread */
2217 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2219 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2220 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2221 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2224 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2225 LttvProcessState
*process
;
2226 LttvExecutionState
*es
;
2229 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2230 s
->parent
.target_pid
= pid
;
2232 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2233 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2234 es
->t
= LTTV_STATE_SYSCALL
;
2235 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2240 static gboolean
process_exit(void *hook_data
, void *call_data
)
2242 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2243 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2244 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2248 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2249 LttvProcessState
*process
; // = ts->running_process[cpu];
2251 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2252 s
->parent
.target_pid
= pid
;
2254 // FIXME : Add this test in the "known state" section
2255 // g_assert(process->pid == pid);
2257 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2258 if(likely(process
!= NULL
)) {
2259 process
->state
->s
= LTTV_STATE_EXIT
;
2264 static gboolean
process_free(void *hook_data
, void *call_data
)
2266 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2267 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2268 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2269 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2271 LttvProcessState
*process
;
2273 /* PID of the process to release */
2274 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2275 s
->parent
.target_pid
= release_pid
;
2277 g_assert(release_pid
!= 0);
2279 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2281 if(likely(process
!= NULL
)) {
2282 /* release_task is happening at kernel level : we can now safely release
2283 * the data structure of the process */
2284 //This test is fun, though, as it may happen that
2285 //at time t : CPU 0 : process_free
2286 //at time t+150ns : CPU 1 : schedule out
2287 //Clearly due to time imprecision, we disable it. (Mathieu)
2288 //If this weird case happen, we have no choice but to put the
2289 //Currently running process on the cpu to 0.
2290 //I re-enable it following time precision fixes. (Mathieu)
2291 //Well, in the case where an process is freed by a process on another CPU
2292 //and still scheduled, it happens that this is the schedchange that will
2293 //drop the last reference count. Do not free it here!
2294 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2296 for(i
=0; i
< num_cpus
; i
++) {
2297 //g_assert(process != ts->running_process[i]);
2298 if(process
== ts
->running_process
[i
]) {
2299 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2303 if(i
== num_cpus
) /* process is not scheduled */
2304 exit_process(s
, process
);
2311 static gboolean
process_exec(void *hook_data
, void *call_data
)
2313 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2314 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2315 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2316 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2319 LttvProcessState
*process
= ts
->running_process
[cpu
];
2321 /* PID of the process to release */
2322 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2323 //name = ltt_event_get_string(e, thf->f1);
2324 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2326 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2327 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2328 memcpy(null_term_name
, name_begin
, name_len
);
2329 null_term_name
[name_len
] = '\0';
2331 process
->name
= g_quark_from_string(null_term_name
);
2332 process
->brand
= LTTV_STATE_UNBRANDED
;
2333 g_free(null_term_name
);
2337 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2339 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2340 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2341 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2342 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2345 LttvProcessState
*process
= ts
->running_process
[cpu
];
2347 name
= ltt_event_get_string(e
, thf
->f1
);
2348 process
->brand
= g_quark_from_string(name
);
2353 static void fix_process(gpointer key
, gpointer value
,
2356 LttvProcessState
*process
;
2357 LttvExecutionState
*es
;
2358 process
= (LttvProcessState
*)value
;
2359 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2360 LttTime
*timestamp
= (LttTime
*)user_data
;
2362 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2363 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2364 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2365 es
->t
= LTTV_STATE_SYSCALL
;
2366 es
->s
= LTTV_STATE_WAIT
;
2367 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2368 es
->entry
= *timestamp
;
2369 es
->change
= *timestamp
;
2370 es
->cum_cpu_time
= ltt_time_zero
;
2373 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2374 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2375 es
->t
= LTTV_STATE_USER_MODE
;
2376 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2377 es
->entry
= *timestamp
;
2378 //g_assert(timestamp->tv_sec != 0);
2379 es
->change
= *timestamp
;
2380 es
->cum_cpu_time
= ltt_time_zero
;
2381 es
->s
= LTTV_STATE_RUN
;
2383 if(process
->execution_stack
->len
== 1) {
2384 /* Still in user mode, means never scheduled */
2385 process
->execution_stack
=
2386 g_array_set_size(process
->execution_stack
, 2);
2387 es
= process
->state
= &g_array_index(process
->execution_stack
,
2388 LttvExecutionState
, 1);
2389 es
->t
= LTTV_STATE_SYSCALL
;
2390 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2391 es
->entry
= *timestamp
;
2392 //g_assert(timestamp->tv_sec != 0);
2393 es
->change
= *timestamp
;
2394 es
->cum_cpu_time
= ltt_time_zero
;
2395 es
->s
= LTTV_STATE_WAIT
;
2401 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2403 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2404 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2405 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2406 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2407 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2409 /* For all processes */
2410 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2411 /* else, if stack[0] is unknown, set to user mode, running */
2413 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2416 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2418 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2419 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2420 //It's slow : optimise later by doing this before reading trace.
2421 LttEventType
*et
= ltt_event_eventtype(e
);
2423 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2429 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2430 LttvProcessState
*process
= ts
->running_process
[cpu
];
2431 LttvProcessState
*parent_process
;
2432 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2433 GQuark type
, mode
, submode
, status
;
2434 LttvExecutionState
*es
;
2437 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2438 s
->parent
.target_pid
= pid
;
2441 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2444 command
= ltt_event_get_string(e
, thf
->f3
);
2447 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2448 type
= ltt_enum_string_get(ltt_field_type(f4
),
2449 ltt_event_get_unsigned(e
, f4
));
2452 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2453 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2454 ltt_event_get_unsigned(e
, f5
));
2457 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2458 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2459 ltt_event_get_unsigned(e
, f6
));
2462 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2463 status
= ltt_enum_string_get(ltt_field_type(f7
),
2464 ltt_event_get_unsigned(e
, f7
));
2467 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2468 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2471 /* The process might exist if a process was forked while performing the state
2473 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2474 if(process
== NULL
) {
2475 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2476 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2477 pid
, tgid
, g_quark_from_string(command
),
2478 &s
->parent
.timestamp
);
2480 /* Keep the stack bottom : a running user mode */
2481 /* Disabled because of inconsistencies in the current statedump states. */
2482 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2483 /* Only keep the bottom
2484 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2485 /* Will cause expected trap when in fact being syscall (even after end of
2487 * Will cause expected interrupt when being syscall. (only before end of
2488 * statedump event) */
2489 // This will cause a "popping last state on stack, ignoring it."
2490 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2491 es
= process
->state
= &g_array_index(process
->execution_stack
,
2492 LttvExecutionState
, 0);
2493 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2494 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2495 es
->s
= LTTV_STATE_UNNAMED
;
2496 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2498 es
->t
= LTTV_STATE_SYSCALL
;
2503 /* User space process :
2504 * bottom : user mode
2505 * either currently running or scheduled out.
2506 * can be scheduled out because interrupted in (user mode or in syscall)
2507 * or because of an explicit call to the scheduler in syscall. Note that
2508 * the scheduler call comes after the irq_exit, so never in interrupt
2510 // temp workaround : set size to 1 : only have user mode bottom of stack.
2511 // will cause g_info message of expected syscall mode when in fact being
2512 // in user mode. Can also cause expected trap when in fact being user
2513 // mode in the event of a page fault reenabling interrupts in the handler.
2514 // Expected syscall and trap can also happen after the end of statedump
2515 // This will cause a "popping last state on stack, ignoring it."
2516 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2517 es
= process
->state
= &g_array_index(process
->execution_stack
,
2518 LttvExecutionState
, 0);
2519 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2520 es
->s
= LTTV_STATE_UNNAMED
;
2521 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2523 es
->t
= LTTV_STATE_USER_MODE
;
2531 es
= process
->state
= &g_array_index(process
->execution_stack
,
2532 LttvExecutionState
, 1);
2533 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2534 es
->s
= LTTV_STATE_UNNAMED
;
2535 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2539 /* The process has already been created :
2540 * Probably was forked while dumping the process state or
2541 * was simply scheduled in prior to get the state dump event.
2542 * We know for sure if it is a user space thread.
2544 process
->ppid
= parent_pid
;
2545 process
->tgid
= tgid
;
2546 process
->name
= g_quark_from_string(command
);
2548 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2549 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2550 es
->t
= LTTV_STATE_USER_MODE
;
2551 /* Don't mess around with the stack, it will eventually become
2552 * ok after the end of state dump. */
2558 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2560 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2562 lttv_state_add_event_hooks(tss
);
2567 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2569 LttvTraceset
*traceset
= self
->parent
.ts
;
2571 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2575 LttvTracefileState
*tfs
;
2579 LttvTraceHookByFacility
*thf
;
2581 LttvTraceHook
*hook
;
2583 LttvAttributeValue val
;
2588 nb_trace
= lttv_traceset_number(traceset
);
2589 for(i
= 0 ; i
< nb_trace
; i
++) {
2590 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2592 /* Find the eventtype id for the following events and register the
2593 associated by id hooks. */
2595 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2596 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2599 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2600 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2601 LTT_FIELD_SYSCALL_ID
, 0, 0,
2602 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2605 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2606 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2608 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2611 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2612 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2613 LTT_FIELD_TRAP_ID
, 0, 0,
2614 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2617 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2618 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2620 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2623 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2624 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2625 LTT_FIELD_IRQ_ID
, 0, 0,
2626 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2629 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2630 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2632 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2635 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2636 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2637 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2638 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2641 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2642 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2644 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2647 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2648 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2649 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2650 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2653 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2654 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2655 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2656 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2659 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2660 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2661 LTT_FIELD_PID
, 0, 0,
2662 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2666 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2667 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2668 LTT_FIELD_PID
, 0, 0,
2669 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2672 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2673 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2674 LTT_FIELD_PID
, 0, 0,
2675 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2678 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2679 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2680 LTT_FIELD_FILENAME
, 0, 0,
2681 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2684 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2685 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2686 LTT_FIELD_NAME
, 0, 0,
2687 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2690 /* statedump-related hooks */
2691 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2692 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2693 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2694 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2697 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2698 LTT_FACILITY_STATEDUMP
, LTT_EVENT_STATEDUMP_END
,
2700 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2703 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2704 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2705 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2706 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2709 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2710 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2711 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2712 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2715 hooks
= g_array_set_size(hooks
, hn
);
2717 /* Add these hooks to each event_by_id hooks list */
2719 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2721 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2723 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2724 LttvTracefileContext
*, j
));
2726 for(k
= 0 ; k
< hooks
->len
; k
++) {
2727 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2728 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2729 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2731 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2738 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2739 *(val
.v_pointer
) = hooks
;
2743 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2745 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2747 lttv_state_remove_event_hooks(tss
);
2752 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2754 LttvTraceset
*traceset
= self
->parent
.ts
;
2756 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2760 LttvTracefileState
*tfs
;
2764 LttvTraceHook
*hook
;
2766 LttvTraceHookByFacility
*thf
;
2768 LttvAttributeValue val
;
2770 nb_trace
= lttv_traceset_number(traceset
);
2771 for(i
= 0 ; i
< nb_trace
; i
++) {
2772 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2774 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2775 hooks
= *(val
.v_pointer
);
2777 /* Remove these hooks from each event_by_id hooks list */
2779 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2781 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2783 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2784 LttvTracefileContext
*, j
));
2786 for(k
= 0 ; k
< hooks
->len
; k
++) {
2787 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2788 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2789 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2791 lttv_hooks_remove_data(
2792 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2798 for(k
= 0 ; k
< hooks
->len
; k
++)
2799 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2800 g_array_free(hooks
, TRUE
);
2804 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2806 guint
*event_count
= (guint
*)hook_data
;
2808 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2809 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2814 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2816 LttvTracefileState
*tfcs
;
2818 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2820 LttEventPosition
*ep
;
2826 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2828 LttvAttributeValue value
;
2830 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2831 LTTV_STATE_SAVED_STATES
);
2832 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2833 value
= lttv_attribute_add(saved_states_tree
,
2834 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2835 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2836 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2837 *(value
.v_time
) = self
->parent
.timestamp
;
2838 lttv_state_save(tcs
, saved_state_tree
);
2839 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2840 self
->parent
.timestamp
.tv_nsec
);
2842 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2847 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2849 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2851 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2856 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2864 static gboolean
block_start(void *hook_data
, void *call_data
)
2866 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2868 LttvTracefileState
*tfcs
;
2870 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2872 LttEventPosition
*ep
;
2874 guint i
, nb_block
, nb_event
, nb_tracefile
;
2878 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2880 LttvAttributeValue value
;
2882 ep
= ltt_event_position_new();
2884 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2886 /* Count the number of events added since the last block end in any
2889 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2891 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2892 LttvTracefileContext
, i
));
2893 ltt_event_position(tfcs
->parent
.e
, ep
);
2894 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2895 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2896 tfcs
->saved_position
= nb_event
;
2900 if(tcs
->nb_event
>= tcs
->save_interval
) {
2901 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2902 LTTV_STATE_SAVED_STATES
);
2903 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2904 value
= lttv_attribute_add(saved_states_tree
,
2905 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2906 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2907 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2908 *(value
.v_time
) = self
->parent
.timestamp
;
2909 lttv_state_save(tcs
, saved_state_tree
);
2911 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2912 self
->parent
.timestamp
.tv_nsec
);
2914 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2920 static gboolean
block_end(void *hook_data
, void *call_data
)
2922 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2924 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2928 LttEventPosition
*ep
;
2930 guint nb_block
, nb_event
;
2932 ep
= ltt_event_position_new();
2933 ltt_event_position(self
->parent
.e
, ep
);
2934 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2935 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2936 self
->saved_position
= 0;
2937 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2944 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2946 LttvTraceset
*traceset
= self
->parent
.ts
;
2948 guint i
, j
, nb_trace
, nb_tracefile
;
2952 LttvTracefileState
*tfs
;
2954 LttvTraceHook hook_start
, hook_end
;
2956 nb_trace
= lttv_traceset_number(traceset
);
2957 for(i
= 0 ; i
< nb_trace
; i
++) {
2958 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2960 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2961 NULL
, NULL
, block_start
, &hook_start
);
2962 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2963 NULL
, NULL
, block_end
, &hook_end
);
2965 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2967 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2969 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2970 LttvTracefileContext
, j
));
2971 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2972 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2973 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2974 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2980 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2982 LttvTraceset
*traceset
= self
->parent
.ts
;
2984 guint i
, j
, nb_trace
, nb_tracefile
;
2988 LttvTracefileState
*tfs
;
2991 nb_trace
= lttv_traceset_number(traceset
);
2992 for(i
= 0 ; i
< nb_trace
; i
++) {
2994 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2995 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2997 if(ts
->has_precomputed_states
) continue;
2999 guint
*event_count
= g_new(guint
, 1);
3002 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3004 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3005 LttvTracefileContext
*, j
));
3006 lttv_hooks_add(tfs
->parent
.event
,
3007 state_save_event_hook
,
3014 lttv_process_traceset_begin(&self
->parent
,
3015 NULL
, NULL
, NULL
, NULL
, NULL
);
3019 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3021 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3023 lttv_state_save_add_event_hooks(tss
);
3030 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3032 LttvTraceset
*traceset
= self
->parent
.ts
;
3034 guint i
, j
, nb_trace
, nb_tracefile
;
3038 LttvTracefileState
*tfs
;
3040 LttvTraceHook hook_start
, hook_end
;
3042 nb_trace
= lttv_traceset_number(traceset
);
3043 for(i
= 0 ; i
< nb_trace
; i
++) {
3044 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3046 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3047 NULL
, NULL
, block_start
, &hook_start
);
3049 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3050 NULL
, NULL
, block_end
, &hook_end
);
3052 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3054 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3056 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3057 LttvTracefileContext
, j
));
3058 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3059 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3060 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3061 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3067 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3069 LttvTraceset
*traceset
= self
->parent
.ts
;
3071 guint i
, j
, nb_trace
, nb_tracefile
;
3075 LttvTracefileState
*tfs
;
3077 LttvHooks
*after_trace
= lttv_hooks_new();
3079 lttv_hooks_add(after_trace
,
3080 state_save_after_trace_hook
,
3085 lttv_process_traceset_end(&self
->parent
,
3086 NULL
, after_trace
, NULL
, NULL
, NULL
);
3088 lttv_hooks_destroy(after_trace
);
3090 nb_trace
= lttv_traceset_number(traceset
);
3091 for(i
= 0 ; i
< nb_trace
; i
++) {
3093 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3094 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3096 if(ts
->has_precomputed_states
) continue;
3098 guint
*event_count
= NULL
;
3100 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3102 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3103 LttvTracefileContext
*, j
));
3104 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3105 state_save_event_hook
);
3107 if(event_count
) g_free(event_count
);
3111 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3113 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3115 lttv_state_save_remove_event_hooks(tss
);
3120 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3122 LttvTraceset
*traceset
= self
->parent
.ts
;
3126 int min_pos
, mid_pos
, max_pos
;
3128 guint call_rest
= 0;
3130 LttvTraceState
*tcs
;
3132 LttvAttributeValue value
;
3134 LttvAttributeType type
;
3136 LttvAttributeName name
;
3140 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3142 //g_tree_destroy(self->parent.pqueue);
3143 //self->parent.pqueue = g_tree_new(compare_tracefile);
3145 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3147 nb_trace
= lttv_traceset_number(traceset
);
3148 for(i
= 0 ; i
< nb_trace
; i
++) {
3149 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3151 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3152 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3153 LTTV_STATE_SAVED_STATES
);
3156 if(saved_states_tree
) {
3157 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3158 mid_pos
= max_pos
/ 2;
3159 while(min_pos
< max_pos
) {
3160 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3162 g_assert(type
== LTTV_GOBJECT
);
3163 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3164 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3166 g_assert(type
== LTTV_TIME
);
3167 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3169 closest_tree
= saved_state_tree
;
3171 else max_pos
= mid_pos
- 1;
3173 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3177 /* restore the closest earlier saved state */
3179 lttv_state_restore(tcs
, closest_tree
);
3183 /* There is no saved state, yet we want to have it. Restart at T0 */
3185 restore_init_state(tcs
);
3186 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3189 /* We want to seek quickly without restoring/updating the state */
3191 restore_init_state(tcs
);
3192 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3195 if(!call_rest
) g_info("NOT Calling restore");
3200 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3206 traceset_state_finalize (LttvTracesetState
*self
)
3208 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3209 finalize(G_OBJECT(self
));
3214 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3216 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3218 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3219 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3220 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3221 klass
->new_traceset_context
= new_traceset_context
;
3222 klass
->new_trace_context
= new_trace_context
;
3223 klass
->new_tracefile_context
= new_tracefile_context
;
3228 lttv_traceset_state_get_type(void)
3230 static GType type
= 0;
3232 static const GTypeInfo info
= {
3233 sizeof (LttvTracesetStateClass
),
3234 NULL
, /* base_init */
3235 NULL
, /* base_finalize */
3236 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3237 NULL
, /* class_finalize */
3238 NULL
, /* class_data */
3239 sizeof (LttvTracesetState
),
3240 0, /* n_preallocs */
3241 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3242 NULL
/* value handling */
3245 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3253 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3259 trace_state_finalize (LttvTraceState
*self
)
3261 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3262 finalize(G_OBJECT(self
));
3267 trace_state_class_init (LttvTraceStateClass
*klass
)
3269 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3271 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3272 klass
->state_save
= state_save
;
3273 klass
->state_restore
= state_restore
;
3274 klass
->state_saved_free
= state_saved_free
;
3279 lttv_trace_state_get_type(void)
3281 static GType type
= 0;
3283 static const GTypeInfo info
= {
3284 sizeof (LttvTraceStateClass
),
3285 NULL
, /* base_init */
3286 NULL
, /* base_finalize */
3287 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3288 NULL
, /* class_finalize */
3289 NULL
, /* class_data */
3290 sizeof (LttvTraceState
),
3291 0, /* n_preallocs */
3292 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3293 NULL
/* value handling */
3296 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3297 "LttvTraceStateType", &info
, 0);
3304 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3310 tracefile_state_finalize (LttvTracefileState
*self
)
3312 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3313 finalize(G_OBJECT(self
));
3318 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3320 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3322 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3327 lttv_tracefile_state_get_type(void)
3329 static GType type
= 0;
3331 static const GTypeInfo info
= {
3332 sizeof (LttvTracefileStateClass
),
3333 NULL
, /* base_init */
3334 NULL
, /* base_finalize */
3335 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3336 NULL
, /* class_finalize */
3337 NULL
, /* class_data */
3338 sizeof (LttvTracefileState
),
3339 0, /* n_preallocs */
3340 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3341 NULL
/* value handling */
3344 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3345 "LttvTracefileStateType", &info
, 0);
3351 static void module_init()
3353 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3354 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3355 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3356 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3357 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3358 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3359 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3360 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3361 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3362 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3363 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3364 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3365 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3366 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3367 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3368 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3369 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3370 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3371 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3372 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3373 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3374 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3375 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3376 LTTV_STATE_EVENT
= g_quark_from_string("event");
3377 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3378 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3379 LTTV_STATE_TIME
= g_quark_from_string("time");
3380 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3381 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3382 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3383 g_quark_from_string("trace_state_use_count");
3386 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3387 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3388 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3389 LTT_FACILITY_FS
= g_quark_from_string("fs");
3390 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3391 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3394 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3395 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3396 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3397 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3398 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3399 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3400 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3401 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3402 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3403 LTT_EVENT_FORK
= g_quark_from_string("fork");
3404 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3405 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3406 LTT_EVENT_FREE
= g_quark_from_string("free");
3407 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3408 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3409 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3410 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3411 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3412 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3415 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3416 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3417 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3418 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3419 LTT_FIELD_OUT
= g_quark_from_string("out");
3420 LTT_FIELD_IN
= g_quark_from_string("in");
3421 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3422 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3423 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3424 LTT_FIELD_PID
= g_quark_from_string("pid");
3425 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3426 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3427 LTT_FIELD_NAME
= g_quark_from_string("name");
3428 LTT_FIELD_TYPE
= g_quark_from_string("type");
3429 LTT_FIELD_MODE
= g_quark_from_string("mode");
3430 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3431 LTT_FIELD_STATUS
= g_quark_from_string("status");
3432 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3433 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3437 static void module_destroy()
3442 LTTV_MODULE("state", "State computation", \
3443 "Update the system state, possibly saving it at intervals", \
3444 module_init
, module_destroy
)