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_FUNCTION_ENTRY
,
74 LTT_EVENT_FUNCTION_EXIT
,
75 LTT_EVENT_THREAD_BRAND
;
83 LTT_FIELD_SOFT_IRQ_ID
,
101 LTTV_STATE_MODE_UNKNOWN
,
102 LTTV_STATE_USER_MODE
,
109 LTTV_STATE_SUBMODE_UNKNOWN
,
110 LTTV_STATE_SUBMODE_NONE
;
114 LTTV_STATE_UNBRANDED
,
115 LTTV_STATE_WAIT_FORK
,
124 LTTV_STATE_USER_THREAD
,
125 LTTV_STATE_KERNEL_THREAD
;
128 LTTV_STATE_TRACEFILES
,
129 LTTV_STATE_PROCESSES
,
131 LTTV_STATE_RUNNING_PROCESS
,
133 LTTV_STATE_SAVED_STATES
,
134 LTTV_STATE_SAVED_STATES_TIME
,
137 LTTV_STATE_NAME_TABLES
,
138 LTTV_STATE_TRACE_STATE_USE_COUNT
;
140 static void create_max_time(LttvTraceState
*tcs
);
142 static void get_max_time(LttvTraceState
*tcs
);
144 static void free_max_time(LttvTraceState
*tcs
);
146 static void create_name_tables(LttvTraceState
*tcs
);
148 static void get_name_tables(LttvTraceState
*tcs
);
150 static void free_name_tables(LttvTraceState
*tcs
);
152 static void free_saved_state(LttvTraceState
*tcs
);
154 static void lttv_state_free_process_table(GHashTable
*processes
);
156 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
157 GPtrArray
*quarktable
);
159 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
161 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
165 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
167 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
171 void lttv_state_state_saved_free(LttvTraceState
*self
,
172 LttvAttribute
*container
)
174 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
178 guint
process_hash(gconstpointer key
)
180 guint pid
= ((const LttvProcessState
*)key
)->pid
;
181 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
185 /* If the hash table hash function is well distributed,
186 * the process_equal should compare different pid */
187 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
189 const LttvProcessState
*process_a
, *process_b
;
192 process_a
= (const LttvProcessState
*)a
;
193 process_b
= (const LttvProcessState
*)b
;
195 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
196 else if(likely(process_a
->pid
== 0 &&
197 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
202 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
204 g_tree_destroy((GTree
*)value
);
207 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
209 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
210 g_hash_table_destroy(usertraces
);
216 restore_init_state(LttvTraceState
*self
)
220 LttvTracefileState
*tfcs
;
222 LttTime start_time
, end_time
;
224 /* Free the process tables */
225 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
226 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
227 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
228 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
231 /* Seek time to beginning */
232 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
233 // closest. It's the tracecontext job to seek the trace to the beginning
234 // anyway : the init state might be used at the middle of the trace as well...
235 //g_tree_destroy(self->parent.ts_context->pqueue);
236 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
238 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
240 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
242 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
244 /* Put the per cpu running_process to beginning state : process 0. */
245 for(i
=0; i
< nb_cpus
; i
++) {
246 LttvExecutionState
*es
;
247 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
248 LTTV_STATE_UNNAMED
, &start_time
);
249 /* We are not sure is it's a kernel thread or normal thread, put the
250 * bottom stack state to unknown */
251 self
->running_process
[i
]->execution_stack
=
252 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
253 es
= self
->running_process
[i
]->state
=
254 &g_array_index(self
->running_process
[i
]->execution_stack
,
255 LttvExecutionState
, 0);
256 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
258 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
259 self
->running_process
[i
]->cpu
= i
;
263 nb_tracefile
= self
->parent
.tracefiles
->len
;
265 for(i
= 0 ; i
< nb_tracefile
; i
++) {
267 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
268 LttvTracefileContext
*, i
));
269 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
270 // tfcs->saved_position = 0;
271 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
272 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
273 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
274 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
279 //static LttTime time_zero = {0,0};
281 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
284 const LttTime
*t1
= (const LttTime
*)a
;
285 const LttTime
*t2
= (const LttTime
*)b
;
287 return ltt_time_compare(*t1
, *t2
);
290 static void free_usertrace_key(gpointer data
)
295 #define MAX_STRING_LEN 4096
298 state_load_saved_states(LttvTraceState
*tcs
)
301 GPtrArray
*quarktable
;
306 tcs
->has_precomputed_states
= FALSE
;
310 gchar buf
[MAX_STRING_LEN
];
313 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
314 strncpy(path
, trace_path
, PATH_MAX
-1);
315 count
= strnlen(trace_path
, PATH_MAX
-1);
316 // quarktable : open, test
317 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
318 fp
= fopen(path
, "r");
320 quarktable
= g_ptr_array_sized_new(4096);
322 /* Index 0 is null */
324 if(hdr
== EOF
) return;
325 g_assert(hdr
== HDR_QUARKS
);
329 if(hdr
== EOF
) break;
330 g_assert(hdr
== HDR_QUARK
);
331 g_ptr_array_set_size(quarktable
, q
+1);
334 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
335 if(buf
[i
] == '\0' || feof(fp
)) break;
338 len
= strnlen(buf
, MAX_STRING_LEN
-1);
339 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
340 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
345 // saved_states : open, test
346 strncpy(path
, trace_path
, PATH_MAX
-1);
347 count
= strnlen(trace_path
, PATH_MAX
-1);
348 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
349 fp
= fopen(path
, "r");
353 if(hdr
!= HDR_TRACE
) goto end
;
355 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
357 tcs
->has_precomputed_states
= TRUE
;
362 /* Free the quarktable */
363 for(i
=0; i
<quarktable
->len
; i
++) {
364 string
= g_ptr_array_index (quarktable
, i
);
367 g_ptr_array_free(quarktable
, TRUE
);
372 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
374 guint i
, j
, nb_trace
, nb_tracefile
;
376 LttvTraceContext
*tc
;
380 LttvTracefileState
*tfcs
;
382 LttvAttributeValue v
;
384 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
385 init((LttvTracesetContext
*)self
, ts
);
387 nb_trace
= lttv_traceset_number(ts
);
388 for(i
= 0 ; i
< nb_trace
; i
++) {
389 tc
= self
->parent
.traces
[i
];
390 tcs
= LTTV_TRACE_STATE(tc
);
391 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
392 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
396 if(*(v
.v_uint
) == 1) {
397 create_name_tables(tcs
);
398 create_max_time(tcs
);
400 get_name_tables(tcs
);
403 nb_tracefile
= tc
->tracefiles
->len
;
404 tcs
->processes
= NULL
;
405 tcs
->usertraces
= NULL
;
406 tcs
->running_process
= g_new(LttvProcessState
*,
407 ltt_trace_get_num_cpu(tc
->t
));
408 restore_init_state(tcs
);
409 for(j
= 0 ; j
< nb_tracefile
; j
++) {
411 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
412 LttvTracefileContext
*, j
));
413 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
414 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
415 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
416 /* It's a Usertrace */
417 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
418 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
420 if(!usertrace_tree
) {
421 usertrace_tree
= g_tree_new_full(compare_usertraces
,
422 NULL
, free_usertrace_key
, NULL
);
423 g_hash_table_insert(tcs
->usertraces
,
424 (gpointer
)tid
, usertrace_tree
);
426 LttTime
*timestamp
= g_new(LttTime
, 1);
427 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
428 ltt_tracefile_creation(tfcs
->parent
.tf
));
429 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
433 /* See if the trace has saved states */
434 state_load_saved_states(tcs
);
439 fini(LttvTracesetState
*self
)
445 LttvTracefileState
*tfcs
;
447 LttvAttributeValue v
;
449 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
450 for(i
= 0 ; i
< nb_trace
; i
++) {
451 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
452 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
455 g_assert(*(v
.v_uint
) != 0);
458 if(*(v
.v_uint
) == 0) {
459 free_name_tables(tcs
);
461 free_saved_state(tcs
);
463 g_free(tcs
->running_process
);
464 tcs
->running_process
= NULL
;
465 lttv_state_free_process_table(tcs
->processes
);
466 lttv_state_free_usertraces(tcs
->usertraces
);
467 tcs
->processes
= NULL
;
468 tcs
->usertraces
= NULL
;
470 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
471 fini((LttvTracesetContext
*)self
);
475 static LttvTracesetContext
*
476 new_traceset_context(LttvTracesetContext
*self
)
478 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
482 static LttvTraceContext
*
483 new_trace_context(LttvTracesetContext
*self
)
485 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
489 static LttvTracefileContext
*
490 new_tracefile_context(LttvTracesetContext
*self
)
492 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
496 /* Write the process state of the trace */
498 static void write_process_state(gpointer key
, gpointer value
,
501 LttvProcessState
*process
;
503 LttvExecutionState
*es
;
505 FILE *fp
= (FILE *)user_data
;
510 process
= (LttvProcessState
*)value
;
512 " <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",
513 process
, process
->pid
, process
->tgid
, process
->ppid
,
514 g_quark_to_string(process
->type
),
515 process
->creation_time
.tv_sec
,
516 process
->creation_time
.tv_nsec
,
517 process
->insertion_time
.tv_sec
,
518 process
->insertion_time
.tv_nsec
,
519 g_quark_to_string(process
->name
),
520 g_quark_to_string(process
->brand
),
523 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
524 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
525 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
526 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
527 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
528 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
529 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
532 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
533 address
= &g_array_index(process
->user_stack
, guint64
, i
);
534 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
538 if(process
->usertrace
) {
539 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
540 g_quark_to_string(process
->usertrace
->tracefile_name
),
541 process
->usertrace
->cpu
);
545 fprintf(fp
, " </PROCESS>\n");
549 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
551 guint i
, nb_tracefile
, nb_block
, offset
;
554 LttvTracefileState
*tfcs
;
558 LttEventPosition
*ep
;
562 ep
= ltt_event_position_new();
564 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
566 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
568 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
569 for(i
=0;i
<nb_cpus
;i
++) {
570 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
571 i
, self
->running_process
[i
]->pid
);
574 nb_tracefile
= self
->parent
.tracefiles
->len
;
576 for(i
= 0 ; i
< nb_tracefile
; i
++) {
578 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
579 LttvTracefileContext
*, i
));
580 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
581 tfcs
->parent
.timestamp
.tv_sec
,
582 tfcs
->parent
.timestamp
.tv_nsec
);
583 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
584 if(e
== NULL
) fprintf(fp
,"/>\n");
586 ltt_event_position(e
, ep
);
587 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
588 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
593 fprintf(fp
,"</PROCESS_STATE>\n");
597 static void write_process_state_raw(gpointer key
, gpointer value
,
600 LttvProcessState
*process
;
602 LttvExecutionState
*es
;
604 FILE *fp
= (FILE *)user_data
;
609 process
= (LttvProcessState
*)value
;
610 fputc(HDR_PROCESS
, fp
);
611 //fwrite(&header, sizeof(header), 1, fp);
612 //fprintf(fp, "%s", g_quark_to_string(process->type));
614 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
615 //fprintf(fp, "%s", g_quark_to_string(process->name));
617 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
618 //fprintf(fp, "%s", g_quark_to_string(process->brand));
620 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
621 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
622 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
623 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
624 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
625 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
626 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
630 " <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",
631 process
, process
->pid
, process
->tgid
, process
->ppid
,
632 g_quark_to_string(process
->type
),
633 process
->creation_time
.tv_sec
,
634 process
->creation_time
.tv_nsec
,
635 process
->insertion_time
.tv_sec
,
636 process
->insertion_time
.tv_nsec
,
637 g_quark_to_string(process
->name
),
638 g_quark_to_string(process
->brand
),
642 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
643 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
646 //fprintf(fp, "%s", g_quark_to_string(es->t));
648 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
649 //fprintf(fp, "%s", g_quark_to_string(es->n));
651 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
652 //fprintf(fp, "%s", g_quark_to_string(es->s));
654 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
655 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
656 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
657 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
659 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
660 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
661 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
662 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
663 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
667 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
668 address
= &g_array_index(process
->user_stack
, guint64
, i
);
669 fputc(HDR_USER_STACK
, fp
);
670 fwrite(&address
, sizeof(address
), 1, fp
);
672 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
677 if(process
->usertrace
) {
678 fputc(HDR_USERTRACE
, fp
);
679 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
681 fwrite(&process
->usertrace
->tracefile_name
,
682 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
683 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
685 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
686 g_quark_to_string(process
->usertrace
->tracefile_name
),
687 process
->usertrace
->cpu
);
694 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
696 guint i
, nb_tracefile
, nb_block
, offset
;
699 LttvTracefileState
*tfcs
;
703 LttEventPosition
*ep
;
707 ep
= ltt_event_position_new();
709 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
710 fputc(HDR_PROCESS_STATE
, fp
);
711 fwrite(&t
, sizeof(t
), 1, fp
);
713 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
715 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
716 for(i
=0;i
<nb_cpus
;i
++) {
718 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
719 fwrite(&self
->running_process
[i
]->pid
,
720 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
721 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
722 // i, self->running_process[i]->pid);
725 nb_tracefile
= self
->parent
.tracefiles
->len
;
727 for(i
= 0 ; i
< nb_tracefile
; i
++) {
729 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
730 LttvTracefileContext
*, i
));
731 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
732 // tfcs->parent.timestamp.tv_sec,
733 // tfcs->parent.timestamp.tv_nsec);
734 fputc(HDR_TRACEFILE
, fp
);
735 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
736 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
737 * position following : end of trace */
738 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
740 ltt_event_position(e
, ep
);
741 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
742 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
744 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
745 fwrite(&offset
, sizeof(offset
), 1, fp
);
746 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
753 /* Read process state from a file */
755 /* Called because a HDR_PROCESS was found */
756 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
757 GPtrArray
*quarktable
)
759 LttvExecutionState
*es
;
760 LttvProcessState
*process
, *parent_process
;
761 LttvProcessState tmp
;
768 /* TODO : check return value */
769 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
770 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
771 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
772 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
773 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
774 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
775 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
776 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
777 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
780 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
782 /* We must link to the parent */
783 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
785 process
= lttv_state_find_process_or_create(self
, tmp
.cpu
, tmp
.pid
,
788 process
->insertion_time
= tmp
.insertion_time
;
789 process
->creation_time
= tmp
.creation_time
;
790 process
->type
= g_quark_from_string(
791 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
792 process
->tgid
= tmp
.tgid
;
793 process
->ppid
= tmp
.ppid
;
794 process
->brand
= g_quark_from_string(
795 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
797 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
800 if(feof(fp
) || ferror(fp
)) goto end_loop
;
802 gint hdr
= fgetc(fp
);
803 if(hdr
== EOF
) goto end_loop
;
807 process
->execution_stack
=
808 g_array_set_size(process
->execution_stack
,
809 process
->execution_stack
->len
+ 1);
810 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
811 process
->execution_stack
->len
-1);
813 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
814 es
->t
= g_quark_from_string(
815 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
816 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
817 es
->n
= g_quark_from_string(
818 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
819 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
820 es
->s
= g_quark_from_string(
821 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
822 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
823 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
824 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
827 process
->user_stack
= g_array_set_size(process
->user_stack
,
828 process
->user_stack
->len
+ 1);
829 address
= &g_array_index(process
->user_stack
, guint64
,
830 process
->user_stack
->len
-1);
831 fread(address
, sizeof(address
), 1, fp
);
832 process
->current_function
= *address
;
835 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
836 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
848 /* Called because a HDR_PROCESS_STATE was found */
849 /* Append a saved state to the trace states */
850 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
852 guint i
, nb_tracefile
, nb_block
, offset
;
854 LttvTracefileState
*tfcs
;
856 LttEventPosition
*ep
;
864 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
866 LttvAttributeValue value
;
867 ep
= ltt_event_position_new();
869 restore_init_state(self
);
871 fread(&t
, sizeof(t
), 1, fp
);
874 if(feof(fp
) || ferror(fp
)) goto end_loop
;
876 if(hdr
== EOF
) goto end_loop
;
880 /* Call read_process_state_raw */
881 read_process_state_raw(self
, fp
, quarktable
);
891 case HDR_PROCESS_STATE
:
897 g_error("Error while parsing saved state file : unknown data header %d",
903 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
904 for(i
=0;i
<nb_cpus
;i
++) {
907 g_assert(hdr
== HDR_CPU
);
908 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
909 g_assert(i
== cpu_num
);
910 fread(&self
->running_process
[i
]->pid
,
911 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
914 nb_tracefile
= self
->parent
.tracefiles
->len
;
916 for(i
= 0 ; i
< nb_tracefile
; i
++) {
918 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
919 LttvTracefileContext
*, i
));
920 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
921 // tfcs->parent.timestamp.tv_sec,
922 // tfcs->parent.timestamp.tv_nsec);
924 g_assert(hdr
== HDR_TRACEFILE
);
925 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
926 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
927 * position following : end of trace */
928 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
929 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
930 fread(&offset
, sizeof(offset
), 1, fp
);
931 fread(&tsc
, sizeof(tsc
), 1, fp
);
932 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
933 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
939 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
940 LTTV_STATE_SAVED_STATES
);
941 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
942 value
= lttv_attribute_add(saved_states_tree
,
943 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
944 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
945 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
947 lttv_state_save(self
, saved_state_tree
);
948 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
951 *(self
->max_time_state_recomputed_in_seek
) = t
;
954 /* Called when a HDR_TRACE is found */
955 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
956 GPtrArray
*quarktable
)
961 if(feof(fp
) || ferror(fp
)) goto end_loop
;
963 if(hdr
== EOF
) goto end_loop
;
966 case HDR_PROCESS_STATE
:
967 /* Call read_process_state_raw */
968 lttv_state_read_raw(tcs
, fp
, quarktable
);
980 g_error("Error while parsing saved state file :"
981 " unexpected data header %d",
985 g_error("Error while parsing saved state file : unknown data header %d",
991 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
996 /* Copy each process from an existing hash table to a new one */
998 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1000 LttvProcessState
*process
, *new_process
;
1002 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1006 process
= (LttvProcessState
*)value
;
1007 new_process
= g_new(LttvProcessState
, 1);
1008 *new_process
= *process
;
1009 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1010 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1011 new_process
->execution_stack
=
1012 g_array_set_size(new_process
->execution_stack
,
1013 process
->execution_stack
->len
);
1014 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1015 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1016 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1018 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1019 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1020 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1021 sizeof(guint64
), 0);
1022 new_process
->user_stack
=
1023 g_array_set_size(new_process
->user_stack
,
1024 process
->user_stack
->len
);
1025 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1026 g_array_index(new_process
->user_stack
, guint64
, i
) =
1027 g_array_index(process
->user_stack
, guint64
, i
);
1029 new_process
->current_function
= process
->current_function
;
1030 g_hash_table_insert(new_processes
, new_process
, new_process
);
1034 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1036 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1038 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1039 return new_processes
;
1043 /* The saved state for each trace contains a member "processes", which
1044 stores a copy of the process table, and a member "tracefiles" with
1045 one entry per tracefile. Each tracefile has a "process" member pointing
1046 to the current process and a "position" member storing the tracefile
1047 position (needed to seek to the current "next" event. */
1049 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1051 guint i
, nb_tracefile
, nb_cpus
;
1053 LttvTracefileState
*tfcs
;
1055 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1057 guint
*running_process
;
1059 LttvAttributeType type
;
1061 LttvAttributeValue value
;
1063 LttvAttributeName name
;
1065 LttEventPosition
*ep
;
1067 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1068 LTTV_STATE_TRACEFILES
);
1070 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1072 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1074 /* Add the currently running processes array */
1075 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1076 running_process
= g_new(guint
, nb_cpus
);
1077 for(i
=0;i
<nb_cpus
;i
++) {
1078 running_process
[i
] = self
->running_process
[i
]->pid
;
1080 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1082 *(value
.v_pointer
) = running_process
;
1084 g_info("State save");
1086 nb_tracefile
= self
->parent
.tracefiles
->len
;
1088 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1090 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1091 LttvTracefileContext
*, i
));
1092 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1093 value
= lttv_attribute_add(tracefiles_tree
, i
,
1095 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1097 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1099 *(value
.v_uint
) = tfcs
->process
->pid
;
1101 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1103 /* Only save the position if the tfs has not infinite time. */
1104 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1105 // && current_tfcs != tfcs) {
1106 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1107 *(value
.v_pointer
) = NULL
;
1109 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1110 ep
= ltt_event_position_new();
1111 ltt_event_position(e
, ep
);
1112 *(value
.v_pointer
) = ep
;
1114 guint nb_block
, offset
;
1117 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1118 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1120 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1126 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1128 guint i
, nb_tracefile
, pid
, nb_cpus
;
1130 LttvTracefileState
*tfcs
;
1132 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1134 guint
*running_process
;
1136 LttvAttributeType type
;
1138 LttvAttributeValue value
;
1140 LttvAttributeName name
;
1144 LttEventPosition
*ep
;
1146 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1148 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1149 LTTV_STATE_TRACEFILES
);
1151 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1153 g_assert(type
== LTTV_POINTER
);
1154 lttv_state_free_process_table(self
->processes
);
1155 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1157 /* Add the currently running processes array */
1158 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1159 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1161 g_assert(type
== LTTV_POINTER
);
1162 running_process
= *(value
.v_pointer
);
1163 for(i
=0;i
<nb_cpus
;i
++) {
1164 pid
= running_process
[i
];
1165 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1166 g_assert(self
->running_process
[i
] != NULL
);
1170 nb_tracefile
= self
->parent
.tracefiles
->len
;
1172 //g_tree_destroy(tsc->pqueue);
1173 //tsc->pqueue = g_tree_new(compare_tracefile);
1175 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1177 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1178 LttvTracefileContext
*, i
));
1179 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1180 g_assert(type
== LTTV_GOBJECT
);
1181 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1183 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1185 g_assert(type
== LTTV_UINT
);
1186 pid
= *(value
.v_uint
);
1187 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1189 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1191 g_assert(type
== LTTV_POINTER
);
1192 //g_assert(*(value.v_pointer) != NULL);
1193 ep
= *(value
.v_pointer
);
1194 g_assert(tfcs
->parent
.t_context
!= NULL
);
1196 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1197 g_tree_remove(tsc
->pqueue
, tfc
);
1200 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1201 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1202 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1203 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1204 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1206 tfc
->timestamp
= ltt_time_infinite
;
1212 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1214 guint i
, nb_tracefile
, nb_cpus
;
1216 LttvTracefileState
*tfcs
;
1218 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1220 guint
*running_process
;
1222 LttvAttributeType type
;
1224 LttvAttributeValue value
;
1226 LttvAttributeName name
;
1230 LttEventPosition
*ep
;
1232 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1233 LTTV_STATE_TRACEFILES
);
1234 g_object_ref(G_OBJECT(tracefiles_tree
));
1235 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1237 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1239 g_assert(type
== LTTV_POINTER
);
1240 lttv_state_free_process_table(*(value
.v_pointer
));
1241 *(value
.v_pointer
) = NULL
;
1242 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1244 /* Free running processes array */
1245 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1246 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1248 g_assert(type
== LTTV_POINTER
);
1249 running_process
= *(value
.v_pointer
);
1250 g_free(running_process
);
1252 nb_tracefile
= self
->parent
.tracefiles
->len
;
1254 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1256 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1257 LttvTracefileContext
*, i
));
1258 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1259 g_assert(type
== LTTV_GOBJECT
);
1260 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1262 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1264 g_assert(type
== LTTV_POINTER
);
1265 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1267 g_object_unref(G_OBJECT(tracefiles_tree
));
1271 static void free_saved_state(LttvTraceState
*self
)
1275 LttvAttributeType type
;
1277 LttvAttributeValue value
;
1279 LttvAttributeName name
;
1283 LttvAttribute
*saved_states
;
1285 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1286 LTTV_STATE_SAVED_STATES
);
1288 nb
= lttv_attribute_get_number(saved_states
);
1289 for(i
= 0 ; i
< nb
; i
++) {
1290 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1291 g_assert(type
== LTTV_GOBJECT
);
1292 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1295 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1300 create_max_time(LttvTraceState
*tcs
)
1302 LttvAttributeValue v
;
1304 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1306 g_assert(*(v
.v_pointer
) == NULL
);
1307 *(v
.v_pointer
) = g_new(LttTime
,1);
1308 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1313 get_max_time(LttvTraceState
*tcs
)
1315 LttvAttributeValue v
;
1317 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1319 g_assert(*(v
.v_pointer
) != NULL
);
1320 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1325 free_max_time(LttvTraceState
*tcs
)
1327 LttvAttributeValue v
;
1329 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1331 g_free(*(v
.v_pointer
));
1332 *(v
.v_pointer
) = NULL
;
1336 typedef struct _LttvNameTables
{
1337 // FIXME GQuark *eventtype_names;
1338 GQuark
*syscall_names
;
1343 GQuark
*soft_irq_names
;
1348 create_name_tables(LttvTraceState
*tcs
)
1352 GQuark f_name
, e_name
;
1356 LttvTraceHookByFacility
*thf
;
1362 GString
*fe_name
= g_string_new("");
1364 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1366 LttvAttributeValue v
;
1368 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1370 g_assert(*(v
.v_pointer
) == NULL
);
1371 *(v
.v_pointer
) = name_tables
;
1372 #if 0 // Use iteration over the facilities_by_name and then list all event
1373 // types of each facility
1374 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1375 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1376 for(i
= 0 ; i
< nb
; i
++) {
1377 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1378 e_name
= ltt_eventtype_name(et
);
1379 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1380 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1381 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1384 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1385 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1386 LTT_FIELD_SYSCALL_ID
, 0, 0,
1389 thf
= lttv_trace_hook_get_first(&h
);
1391 t
= ltt_field_type(thf
->f1
);
1392 nb
= ltt_type_element_number(t
);
1394 lttv_trace_hook_destroy(&h
);
1396 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1397 name_tables
->nb_syscalls
= nb
;
1399 for(i
= 0 ; i
< nb
; i
++) {
1400 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1403 //name_tables->syscall_names = g_new(GQuark, 256);
1404 //for(i = 0 ; i < 256 ; i++) {
1405 // g_string_printf(fe_name, "syscall %d", i);
1406 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1409 name_tables
->syscall_names
= NULL
;
1410 name_tables
->nb_syscalls
= 0;
1413 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1414 LTT_EVENT_TRAP_ENTRY
,
1415 LTT_FIELD_TRAP_ID
, 0, 0,
1418 thf
= lttv_trace_hook_get_first(&h
);
1420 t
= ltt_field_type(thf
->f1
);
1421 //nb = ltt_type_element_number(t);
1423 lttv_trace_hook_destroy(&h
);
1426 name_tables->trap_names = g_new(GQuark, nb);
1427 for(i = 0 ; i < nb ; i++) {
1428 name_tables->trap_names[i] = g_quark_from_string(
1429 ltt_enum_string_get(t, i));
1432 name_tables
->nb_traps
= 256;
1433 name_tables
->trap_names
= g_new(GQuark
, 256);
1434 for(i
= 0 ; i
< 256 ; i
++) {
1435 g_string_printf(fe_name
, "trap %d", i
);
1436 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1439 name_tables
->trap_names
= NULL
;
1440 name_tables
->nb_traps
= 0;
1443 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1444 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1445 LTT_FIELD_IRQ_ID
, 0, 0,
1448 thf
= lttv_trace_hook_get_first(&h
);
1450 t
= ltt_field_type(thf
->f1
);
1451 //nb = ltt_type_element_number(t);
1453 lttv_trace_hook_destroy(&h
);
1456 name_tables->irq_names = g_new(GQuark, nb);
1457 for(i = 0 ; i < nb ; i++) {
1458 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1462 name_tables
->irq_names
= g_new(GQuark
, 256);
1463 for(i
= 0 ; i
< 256 ; i
++) {
1464 g_string_printf(fe_name
, "irq %d", i
);
1465 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1468 name_tables
->irq_names
= NULL
;
1471 name_tables->soft_irq_names = g_new(GQuark, nb);
1472 for(i = 0 ; i < nb ; i++) {
1473 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1477 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1478 for(i
= 0 ; i
< 256 ; i
++) {
1479 g_string_printf(fe_name
, "softirq %d", i
);
1480 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1484 g_string_free(fe_name
, TRUE
);
1489 get_name_tables(LttvTraceState
*tcs
)
1491 LttvNameTables
*name_tables
;
1493 LttvAttributeValue v
;
1495 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1497 g_assert(*(v
.v_pointer
) != NULL
);
1498 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1499 //tcs->eventtype_names = name_tables->eventtype_names;
1500 tcs
->syscall_names
= name_tables
->syscall_names
;
1501 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1502 tcs
->trap_names
= name_tables
->trap_names
;
1503 tcs
->nb_traps
= name_tables
->nb_traps
;
1504 tcs
->irq_names
= name_tables
->irq_names
;
1505 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1510 free_name_tables(LttvTraceState
*tcs
)
1512 LttvNameTables
*name_tables
;
1514 LttvAttributeValue v
;
1516 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1518 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1519 *(v
.v_pointer
) = NULL
;
1521 // g_free(name_tables->eventtype_names);
1522 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1523 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1524 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1525 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1526 if(name_tables
) g_free(name_tables
);
1529 #ifdef HASH_TABLE_DEBUG
1531 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1533 LttvProcessState
*process
= (LttvProcessState
*)value
;
1535 /* Test for process corruption */
1536 guint stack_len
= process
->execution_stack
->len
;
1539 static void hash_table_check(GHashTable
*table
)
1541 g_hash_table_foreach(table
, test_process
, NULL
);
1548 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1551 LttvExecutionState
*es
;
1553 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1554 guint cpu
= tfs
->cpu
;
1556 #ifdef HASH_TABLE_DEBUG
1557 hash_table_check(ts
->processes
);
1559 LttvProcessState
*process
= ts
->running_process
[cpu
];
1561 guint depth
= process
->execution_stack
->len
;
1563 process
->execution_stack
=
1564 g_array_set_size(process
->execution_stack
, depth
+ 1);
1567 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1569 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1572 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1573 es
->cum_cpu_time
= ltt_time_zero
;
1574 es
->s
= process
->state
->s
;
1575 process
->state
= es
;
1579 * return 1 when empty, else 0 */
1580 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1581 LttvTracefileState
*tfs
)
1583 guint cpu
= tfs
->cpu
;
1584 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1586 guint depth
= process
->execution_stack
->len
;
1592 process
->execution_stack
=
1593 g_array_set_size(process
->execution_stack
, depth
- 1);
1594 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1596 process
->state
->change
= tfs
->parent
.timestamp
;
1601 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1603 guint cpu
= tfs
->cpu
;
1604 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1605 LttvProcessState
*process
= ts
->running_process
[cpu
];
1607 guint depth
= process
->execution_stack
->len
;
1609 if(process
->state
->t
!= t
){
1610 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1611 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1612 g_info("process state has %s when pop_int is %s\n",
1613 g_quark_to_string(process
->state
->t
),
1614 g_quark_to_string(t
));
1615 g_info("{ %u, %u, %s, %s, %s }\n",
1618 g_quark_to_string(process
->name
),
1619 g_quark_to_string(process
->brand
),
1620 g_quark_to_string(process
->state
->s
));
1625 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1626 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1630 process
->execution_stack
=
1631 g_array_set_size(process
->execution_stack
, depth
- 1);
1632 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1634 process
->state
->change
= tfs
->parent
.timestamp
;
1637 struct search_result
{
1638 const LttTime
*time
; /* Requested time */
1639 LttTime
*best
; /* Best result */
1642 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1644 const LttTime
*elem_time
= (const LttTime
*)a
;
1645 /* Explicit non const cast */
1646 struct search_result
*res
= (struct search_result
*)b
;
1648 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1649 /* The usertrace was created before the schedchange */
1650 /* Get larger keys */
1652 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1653 /* The usertrace was created after the schedchange time */
1654 /* Get smaller keys */
1656 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1657 res
->best
= elem_time
;
1660 res
->best
= elem_time
;
1667 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1668 guint pid
, const LttTime
*timestamp
)
1670 LttvTracefileState
*tfs
= NULL
;
1671 struct search_result res
;
1672 /* Find the usertrace associated with a pid and time interval.
1673 * Search in the usertraces by PID (within a hash) and then, for each
1674 * corresponding element of the array, find the first one with creation
1675 * timestamp the lowest, but higher or equal to "timestamp". */
1676 res
.time
= timestamp
;
1678 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1679 if(usertrace_tree
) {
1680 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1682 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1690 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1691 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1693 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1695 LttvExecutionState
*es
;
1697 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1702 process
->tgid
= tgid
;
1704 process
->name
= name
;
1705 process
->brand
= LTTV_STATE_UNBRANDED
;
1706 //process->last_cpu = tfs->cpu_name;
1707 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1708 process
->type
= LTTV_STATE_USER_THREAD
;
1709 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1710 process
->current_function
= 0; //function 0x0 by default.
1712 g_info("Process %u, core %p", process
->pid
, process
);
1713 g_hash_table_insert(tcs
->processes
, process
, process
);
1716 process
->ppid
= parent
->pid
;
1717 process
->creation_time
= *timestamp
;
1720 /* No parent. This process exists but we are missing all information about
1721 its creation. The birth time is set to zero but we remember the time of
1726 process
->creation_time
= ltt_time_zero
;
1729 process
->insertion_time
= *timestamp
;
1730 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1731 process
->creation_time
.tv_nsec
);
1732 process
->pid_time
= g_quark_from_string(buffer
);
1734 //process->last_cpu = tfs->cpu_name;
1735 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1736 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1737 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1738 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1739 es
= process
->state
= &g_array_index(process
->execution_stack
,
1740 LttvExecutionState
, 0);
1741 es
->t
= LTTV_STATE_USER_MODE
;
1742 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1743 es
->entry
= *timestamp
;
1744 //g_assert(timestamp->tv_sec != 0);
1745 es
->change
= *timestamp
;
1746 es
->cum_cpu_time
= ltt_time_zero
;
1747 es
->s
= LTTV_STATE_RUN
;
1749 es
= process
->state
= &g_array_index(process
->execution_stack
,
1750 LttvExecutionState
, 1);
1751 es
->t
= LTTV_STATE_SYSCALL
;
1752 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1753 es
->entry
= *timestamp
;
1754 //g_assert(timestamp->tv_sec != 0);
1755 es
->change
= *timestamp
;
1756 es
->cum_cpu_time
= ltt_time_zero
;
1757 es
->s
= LTTV_STATE_WAIT_FORK
;
1759 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1760 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1761 sizeof(guint64
), 0);
1766 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1769 LttvProcessState key
;
1770 LttvProcessState
*process
;
1774 process
= g_hash_table_lookup(ts
->processes
, &key
);
1779 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1780 const LttTime
*timestamp
)
1782 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1783 LttvExecutionState
*es
;
1785 /* Put ltt_time_zero creation time for unexisting processes */
1786 if(unlikely(process
== NULL
)) {
1787 process
= lttv_state_create_process(ts
,
1788 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1789 /* We are not sure is it's a kernel thread or normal thread, put the
1790 * bottom stack state to unknown */
1791 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1792 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1797 /* FIXME : this function should be called when we receive an event telling that
1798 * release_task has been called in the kernel. In happens generally when
1799 * the parent waits for its child terminaison, but may also happen in special
1800 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1801 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1802 * of a killed thread ground, but isn't the leader.
1804 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1806 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1807 LttvProcessState key
;
1809 key
.pid
= process
->pid
;
1810 key
.cpu
= process
->cpu
;
1811 g_hash_table_remove(ts
->processes
, &key
);
1812 g_array_free(process
->execution_stack
, TRUE
);
1813 g_array_free(process
->user_stack
, TRUE
);
1818 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1820 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1821 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1826 static void lttv_state_free_process_table(GHashTable
*processes
)
1828 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1829 g_hash_table_destroy(processes
);
1833 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1835 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1837 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1838 LttvProcessState
*process
= ts
->running_process
[cpu
];
1839 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1840 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1841 LttField
*f
= thf
->f1
;
1843 LttvExecutionSubmode submode
;
1845 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1846 guint syscall
= ltt_event_get_unsigned(e
, f
);
1848 if(syscall
< nb_syscalls
) {
1849 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1852 /* Fixup an incomplete syscall table */
1853 GString
*string
= g_string_new("");
1854 g_string_printf(string
, "syscall %u", syscall
);
1855 submode
= g_quark_from_string(string
->str
);
1856 g_string_free(string
, TRUE
);
1858 /* There can be no system call from PID 0 : unknown state */
1859 if(process
->pid
!= 0)
1860 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1865 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1867 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1869 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1870 LttvProcessState
*process
= ts
->running_process
[cpu
];
1872 /* There can be no system call from PID 0 : unknown state */
1873 if(process
->pid
!= 0)
1874 pop_state(s
, LTTV_STATE_SYSCALL
);
1879 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1881 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1882 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1883 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1884 LttField
*f
= thf
->f1
;
1886 LttvExecutionSubmode submode
;
1888 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1889 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1891 if(trap
< nb_traps
) {
1892 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1894 /* Fixup an incomplete trap table */
1895 GString
*string
= g_string_new("");
1896 g_string_printf(string
, "trap %llu", trap
);
1897 submode
= g_quark_from_string(string
->str
);
1898 g_string_free(string
, TRUE
);
1901 push_state(s
, LTTV_STATE_TRAP
, submode
);
1906 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1908 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1910 pop_state(s
, LTTV_STATE_TRAP
);
1915 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1917 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1918 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1919 guint8 fac_id
= ltt_event_facility_id(e
);
1920 guint8 ev_id
= ltt_event_eventtype_id(e
);
1921 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1922 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1923 g_assert(thf
->f1
!= NULL
);
1924 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1925 LttField
*f
= thf
->f1
;
1927 LttvExecutionSubmode submode
;
1929 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1930 ltt_event_get_unsigned(e
, f
)];
1932 /* Do something with the info about being in user or system mode when int? */
1933 push_state(s
, LTTV_STATE_IRQ
, submode
);
1937 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1939 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1941 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1947 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1949 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1951 pop_state(s
, LTTV_STATE_IRQ
);
1955 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1957 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1958 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1959 guint8 fac_id
= ltt_event_facility_id(e
);
1960 guint8 ev_id
= ltt_event_eventtype_id(e
);
1961 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1962 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1963 g_assert(thf
->f1
!= NULL
);
1964 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1965 LttField
*f
= thf
->f1
;
1967 LttvExecutionSubmode submode
;
1969 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1970 ltt_event_get_long_unsigned(e
, f
)];
1972 /* Do something with the info about being in user or system mode when int? */
1973 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1977 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1981 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1982 guint cpu
= tfs
->cpu
;
1983 LttvProcessState
*process
= ts
->running_process
[cpu
];
1985 guint depth
= process
->user_stack
->len
;
1987 process
->user_stack
=
1988 g_array_set_size(process
->user_stack
, depth
+ 1);
1990 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1991 *new_func
= funcptr
;
1992 process
->current_function
= funcptr
;
1995 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1997 guint cpu
= tfs
->cpu
;
1998 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1999 LttvProcessState
*process
= ts
->running_process
[cpu
];
2001 if(process
->current_function
!= funcptr
){
2002 g_info("Different functions (%lu.%09lu): ignore it\n",
2003 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2004 g_info("process state has %llu when pop_function is %llu\n",
2005 process
->current_function
, funcptr
);
2006 g_info("{ %u, %u, %s, %s, %s }\n",
2009 g_quark_to_string(process
->name
),
2010 g_quark_to_string(process
->brand
),
2011 g_quark_to_string(process
->state
->s
));
2014 guint depth
= process
->user_stack
->len
;
2017 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2018 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2022 process
->user_stack
=
2023 g_array_set_size(process
->user_stack
, depth
- 1);
2024 process
->current_function
=
2025 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2029 static gboolean
function_entry(void *hook_data
, void *call_data
)
2031 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2032 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2033 guint8 fac_id
= ltt_event_facility_id(e
);
2034 guint8 ev_id
= ltt_event_eventtype_id(e
);
2035 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2036 g_assert(thf
->f1
!= NULL
);
2037 LttField
*f
= thf
->f1
;
2038 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2040 push_function(s
, funcptr
);
2044 static gboolean
function_exit(void *hook_data
, void *call_data
)
2046 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2047 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2048 guint8 fac_id
= ltt_event_facility_id(e
);
2049 guint8 ev_id
= ltt_event_eventtype_id(e
);
2050 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2051 g_assert(thf
->f1
!= NULL
);
2052 LttField
*f
= thf
->f1
;
2053 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2055 LttvExecutionSubmode submode
;
2057 pop_function(s
, funcptr
);
2061 static gboolean
schedchange(void *hook_data
, void *call_data
)
2063 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2065 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2066 LttvProcessState
*process
= ts
->running_process
[cpu
];
2067 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2069 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2070 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2071 guint pid_in
, pid_out
;
2074 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2075 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2076 state_out
= ltt_event_get_int(e
, thf
->f3
);
2078 if(likely(process
!= NULL
)) {
2080 /* We could not know but it was not the idle process executing.
2081 This should only happen at the beginning, before the first schedule
2082 event, and when the initial information (current process for each CPU)
2083 is missing. It is not obvious how we could, after the fact, compensate
2084 the wrongly attributed statistics. */
2086 //This test only makes sense once the state is known and if there is no
2087 //missing events. We need to silently ignore schedchange coming after a
2088 //process_free, or it causes glitches. (FIXME)
2089 //if(unlikely(process->pid != pid_out)) {
2090 // g_assert(process->pid == 0);
2092 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2093 /* Scheduling out of pid 0 at beginning of the trace :
2094 * we know for sure it is in syscall mode at this point. */
2095 g_assert(process
->execution_stack
->len
== 1);
2096 process
->state
->t
= LTTV_STATE_SYSCALL
;
2098 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2099 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2100 process
->state
->change
= s
->parent
.timestamp
;
2102 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2103 else process
->state
->s
= LTTV_STATE_WAIT
;
2104 process
->state
->change
= s
->parent
.timestamp
;
2108 exit_process(s
, process
); /* EXIT_DEAD */
2109 /* see sched.h for states */
2111 process
= ts
->running_process
[cpu
] =
2112 lttv_state_find_process_or_create(
2113 (LttvTraceState
*)s
->parent
.t_context
,
2115 &s
->parent
.timestamp
);
2116 process
->state
->s
= LTTV_STATE_RUN
;
2118 if(process
->usertrace
)
2119 process
->usertrace
->cpu
= cpu
;
2120 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2121 process
->state
->change
= s
->parent
.timestamp
;
2125 static gboolean
process_fork(void *hook_data
, void *call_data
)
2127 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2128 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2129 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2131 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2132 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2133 LttvProcessState
*zombie_process
;
2135 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2136 LttvProcessState
*process
= ts
->running_process
[cpu
];
2137 LttvProcessState
*child_process
;
2140 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2143 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2144 s
->parent
.target_pid
= child_pid
;
2147 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2148 else child_tgid
= 0;
2150 /* Mathieu : it seems like the process might have been scheduled in before the
2151 * fork, and, in a rare case, might be the current process. This might happen
2152 * in a SMP case where we don't have enough precision on the clocks.
2154 * Test reenabled after precision fixes on time. (Mathieu) */
2156 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2158 if(unlikely(zombie_process
!= NULL
)) {
2159 /* Reutilisation of PID. Only now we are sure that the old PID
2160 * has been released. FIXME : should know when release_task happens instead.
2162 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2164 for(i
=0; i
< num_cpus
; i
++) {
2165 g_assert(zombie_process
!= ts
->running_process
[i
]);
2168 exit_process(s
, zombie_process
);
2171 g_assert(process
->pid
!= child_pid
);
2172 // FIXME : Add this test in the "known state" section
2173 // g_assert(process->pid == parent_pid);
2174 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2175 if(child_process
== NULL
) {
2176 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2177 child_pid
, child_tgid
,
2178 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2180 /* The process has already been created : due to time imprecision between
2181 * multiple CPUs : it has been scheduled in before creation. Note that we
2182 * shouldn't have this kind of imprecision.
2184 * Simply put a correct parent.
2186 g_assert(0); /* This is a problematic case : the process has been created
2187 before the fork event */
2188 child_process
->ppid
= process
->pid
;
2189 child_process
->tgid
= child_tgid
;
2191 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2192 child_process
->name
= process
->name
;
2193 child_process
->brand
= process
->brand
;
2198 /* We stamp a newly created process as kernel_thread */
2199 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2201 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2202 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2203 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2206 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2207 LttvProcessState
*process
;
2208 LttvExecutionState
*es
;
2211 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2212 s
->parent
.target_pid
= pid
;
2214 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2215 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2216 es
->t
= LTTV_STATE_SYSCALL
;
2217 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2222 static gboolean
process_exit(void *hook_data
, void *call_data
)
2224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2225 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2226 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2230 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2231 LttvProcessState
*process
; // = ts->running_process[cpu];
2233 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2234 s
->parent
.target_pid
= pid
;
2236 // FIXME : Add this test in the "known state" section
2237 // g_assert(process->pid == pid);
2239 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2240 if(likely(process
!= NULL
)) {
2241 process
->state
->s
= LTTV_STATE_EXIT
;
2246 static gboolean
process_free(void *hook_data
, void *call_data
)
2248 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2249 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2250 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2251 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2253 LttvProcessState
*process
;
2255 /* PID of the process to release */
2256 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2257 s
->parent
.target_pid
= release_pid
;
2259 g_assert(release_pid
!= 0);
2261 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2263 if(likely(process
!= NULL
)) {
2264 /* release_task is happening at kernel level : we can now safely release
2265 * the data structure of the process */
2266 //This test is fun, though, as it may happen that
2267 //at time t : CPU 0 : process_free
2268 //at time t+150ns : CPU 1 : schedule out
2269 //Clearly due to time imprecision, we disable it. (Mathieu)
2270 //If this weird case happen, we have no choice but to put the
2271 //Currently running process on the cpu to 0.
2272 //I re-enable it following time precision fixes. (Mathieu)
2273 //Well, in the case where an process is freed by a process on another CPU
2274 //and still scheduled, it happens that this is the schedchange that will
2275 //drop the last reference count. Do not free it here!
2276 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2278 for(i
=0; i
< num_cpus
; i
++) {
2279 //g_assert(process != ts->running_process[i]);
2280 if(process
== ts
->running_process
[i
]) {
2281 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2285 if(i
== num_cpus
) /* process is not scheduled */
2286 exit_process(s
, process
);
2293 static gboolean
process_exec(void *hook_data
, void *call_data
)
2295 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2296 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2297 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2298 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2301 LttvProcessState
*process
= ts
->running_process
[cpu
];
2303 /* PID of the process to release */
2304 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2305 //name = ltt_event_get_string(e, thf->f1);
2306 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2308 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2309 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2310 memcpy(null_term_name
, name_begin
, name_len
);
2311 null_term_name
[name_len
] = '\0';
2313 process
->name
= g_quark_from_string(null_term_name
);
2314 process
->brand
= LTTV_STATE_UNBRANDED
;
2315 g_free(null_term_name
);
2319 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2321 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2322 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2323 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2324 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2327 LttvProcessState
*process
= ts
->running_process
[cpu
];
2329 name
= ltt_event_get_string(e
, thf
->f1
);
2330 process
->brand
= g_quark_from_string(name
);
2335 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2337 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2338 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2339 //It's slow : optimise later by doing this before reading trace.
2340 LttEventType
*et
= ltt_event_eventtype(e
);
2342 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2348 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2349 LttvProcessState
*process
= ts
->running_process
[cpu
];
2350 LttvProcessState
*parent_process
;
2351 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2352 GQuark type
, mode
, submode
, status
;
2353 LttvExecutionState
*es
;
2356 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2357 s
->parent
.target_pid
= pid
;
2360 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2363 command
= ltt_event_get_string(e
, thf
->f3
);
2366 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2367 type
= ltt_enum_string_get(ltt_field_type(f4
),
2368 ltt_event_get_unsigned(e
, f4
));
2371 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2372 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2373 ltt_event_get_unsigned(e
, f5
));
2376 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2377 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2378 ltt_event_get_unsigned(e
, f6
));
2381 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2382 status
= ltt_enum_string_get(ltt_field_type(f7
),
2383 ltt_event_get_unsigned(e
, f7
));
2386 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2387 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2390 /* The process might exist if a process was forked while performing the state
2392 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2393 if(process
== NULL
) {
2394 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2395 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2396 pid
, tgid
, g_quark_from_string(command
),
2397 &s
->parent
.timestamp
);
2399 /* Keep the stack bottom : a running user mode */
2400 /* Disabled because of inconsistencies in the current statedump states. */
2401 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2402 /* Only keep the bottom */
2403 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2404 es
= process
->state
= &g_array_index(process
->execution_stack
,
2405 LttvExecutionState
, 0);
2406 es
->t
= LTTV_STATE_SYSCALL
;
2410 /* On top of it : */
2411 es
= process
->state
= &g_array_index(process
->execution_stack
,
2412 LttvExecutionState
, 1);
2413 es
->t
= LTTV_STATE_USER_MODE
;
2420 es
= process
->state
= &g_array_index(process
->execution_stack
,
2421 LttvExecutionState
, 1);
2422 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2423 es
->s
= LTTV_STATE_UNNAMED
;
2424 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2428 /* The process has already been created :
2429 * Probably was forked while dumping the process state or
2430 * was simply scheduled in prior to get the state dump event.
2431 * We know for sure if it is a user space thread.
2433 process
->ppid
= parent_pid
;
2434 process
->tgid
= tgid
;
2435 process
->name
= g_quark_from_string(command
);
2436 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2437 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2438 es
->t
= LTTV_STATE_USER_MODE
;
2439 /* Don't mess around with the stack, it will eventually become
2440 * ok after the end of state dump. */
2446 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2448 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2450 lttv_state_add_event_hooks(tss
);
2455 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2457 LttvTraceset
*traceset
= self
->parent
.ts
;
2459 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2463 LttvTracefileState
*tfs
;
2467 LttvTraceHookByFacility
*thf
;
2469 LttvTraceHook
*hook
;
2471 LttvAttributeValue val
;
2476 nb_trace
= lttv_traceset_number(traceset
);
2477 for(i
= 0 ; i
< nb_trace
; i
++) {
2478 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2480 if(ts
->has_precomputed_states
) continue;
2482 /* Find the eventtype id for the following events and register the
2483 associated by id hooks. */
2485 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
2486 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
2489 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2490 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2491 LTT_FIELD_SYSCALL_ID
, 0, 0,
2492 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2495 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2496 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2498 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2501 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2502 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2503 LTT_FIELD_TRAP_ID
, 0, 0,
2504 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2507 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2508 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2510 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2513 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2514 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2515 LTT_FIELD_IRQ_ID
, 0, 0,
2516 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2519 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2520 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2522 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2525 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2526 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2527 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2528 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2531 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2532 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2534 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2537 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2538 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2539 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2540 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2543 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2544 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2545 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2546 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2549 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2550 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2551 LTT_FIELD_PID
, 0, 0,
2552 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2556 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2557 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2558 LTT_FIELD_PID
, 0, 0,
2559 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2562 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2563 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2564 LTT_FIELD_PID
, 0, 0,
2565 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2568 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2569 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2570 LTT_FIELD_FILENAME
, 0, 0,
2571 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2574 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2575 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2576 LTT_FIELD_NAME
, 0, 0,
2577 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2580 /* statedump-related hooks */
2581 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2582 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2583 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2584 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2587 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2588 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2589 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2590 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2593 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2594 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2595 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2596 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2599 hooks
= g_array_set_size(hooks
, hn
);
2601 /* Add these hooks to each event_by_id hooks list */
2603 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2605 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2607 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2608 LttvTracefileContext
*, j
));
2610 for(k
= 0 ; k
< hooks
->len
; k
++) {
2611 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2612 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2613 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2615 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2622 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2623 *(val
.v_pointer
) = hooks
;
2627 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2629 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2631 lttv_state_remove_event_hooks(tss
);
2636 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2638 LttvTraceset
*traceset
= self
->parent
.ts
;
2640 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2644 LttvTracefileState
*tfs
;
2648 LttvTraceHook
*hook
;
2650 LttvTraceHookByFacility
*thf
;
2652 LttvAttributeValue val
;
2654 nb_trace
= lttv_traceset_number(traceset
);
2655 for(i
= 0 ; i
< nb_trace
; i
++) {
2656 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2658 if(ts
->has_precomputed_states
) continue;
2660 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2661 hooks
= *(val
.v_pointer
);
2663 /* Remove these hooks from each event_by_id hooks list */
2665 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2667 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2669 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2670 LttvTracefileContext
*, j
));
2672 for(k
= 0 ; k
< hooks
->len
; k
++) {
2673 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2674 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2675 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2677 lttv_hooks_remove_data(
2678 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2684 for(k
= 0 ; k
< hooks
->len
; k
++)
2685 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2686 g_array_free(hooks
, TRUE
);
2690 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2692 guint
*event_count
= (guint
*)hook_data
;
2694 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2695 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2700 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2702 LttvTracefileState
*tfcs
;
2704 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2706 LttEventPosition
*ep
;
2712 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2714 LttvAttributeValue value
;
2716 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2717 LTTV_STATE_SAVED_STATES
);
2718 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2719 value
= lttv_attribute_add(saved_states_tree
,
2720 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2721 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2722 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2723 *(value
.v_time
) = self
->parent
.timestamp
;
2724 lttv_state_save(tcs
, saved_state_tree
);
2725 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2726 self
->parent
.timestamp
.tv_nsec
);
2728 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2733 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2735 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2737 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2742 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2750 static gboolean
block_start(void *hook_data
, void *call_data
)
2752 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2754 LttvTracefileState
*tfcs
;
2756 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2758 LttEventPosition
*ep
;
2760 guint i
, nb_block
, nb_event
, nb_tracefile
;
2764 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2766 LttvAttributeValue value
;
2768 ep
= ltt_event_position_new();
2770 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2772 /* Count the number of events added since the last block end in any
2775 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2777 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2778 LttvTracefileContext
, i
));
2779 ltt_event_position(tfcs
->parent
.e
, ep
);
2780 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2781 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2782 tfcs
->saved_position
= nb_event
;
2786 if(tcs
->nb_event
>= tcs
->save_interval
) {
2787 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2788 LTTV_STATE_SAVED_STATES
);
2789 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2790 value
= lttv_attribute_add(saved_states_tree
,
2791 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2792 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2793 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2794 *(value
.v_time
) = self
->parent
.timestamp
;
2795 lttv_state_save(tcs
, saved_state_tree
);
2797 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2798 self
->parent
.timestamp
.tv_nsec
);
2800 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2806 static gboolean
block_end(void *hook_data
, void *call_data
)
2808 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2810 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2814 LttEventPosition
*ep
;
2816 guint nb_block
, nb_event
;
2818 ep
= ltt_event_position_new();
2819 ltt_event_position(self
->parent
.e
, ep
);
2820 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2821 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2822 self
->saved_position
= 0;
2823 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2830 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2832 LttvTraceset
*traceset
= self
->parent
.ts
;
2834 guint i
, j
, nb_trace
, nb_tracefile
;
2838 LttvTracefileState
*tfs
;
2840 LttvTraceHook hook_start
, hook_end
;
2842 nb_trace
= lttv_traceset_number(traceset
);
2843 for(i
= 0 ; i
< nb_trace
; i
++) {
2844 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2846 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2847 NULL
, NULL
, block_start
, &hook_start
);
2848 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2849 NULL
, NULL
, block_end
, &hook_end
);
2851 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2853 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2855 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2856 LttvTracefileContext
, j
));
2857 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2858 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2859 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2860 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2866 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2868 LttvTraceset
*traceset
= self
->parent
.ts
;
2870 guint i
, j
, nb_trace
, nb_tracefile
;
2874 LttvTracefileState
*tfs
;
2877 nb_trace
= lttv_traceset_number(traceset
);
2878 for(i
= 0 ; i
< nb_trace
; i
++) {
2880 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2881 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2883 guint
*event_count
= g_new(guint
, 1);
2886 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2888 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2889 LttvTracefileContext
*, j
));
2890 lttv_hooks_add(tfs
->parent
.event
,
2891 state_save_event_hook
,
2898 lttv_process_traceset_begin(&self
->parent
,
2899 NULL
, NULL
, NULL
, NULL
, NULL
);
2903 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2905 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2907 lttv_state_save_add_event_hooks(tss
);
2914 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2916 LttvTraceset
*traceset
= self
->parent
.ts
;
2918 guint i
, j
, nb_trace
, nb_tracefile
;
2922 LttvTracefileState
*tfs
;
2924 LttvTraceHook hook_start
, hook_end
;
2926 nb_trace
= lttv_traceset_number(traceset
);
2927 for(i
= 0 ; i
< nb_trace
; i
++) {
2928 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2930 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2931 NULL
, NULL
, block_start
, &hook_start
);
2933 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2934 NULL
, NULL
, block_end
, &hook_end
);
2936 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2938 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2940 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2941 LttvTracefileContext
, j
));
2942 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2943 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2944 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2945 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2951 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2953 LttvTraceset
*traceset
= self
->parent
.ts
;
2955 guint i
, j
, nb_trace
, nb_tracefile
;
2959 LttvTracefileState
*tfs
;
2961 LttvHooks
*after_trace
= lttv_hooks_new();
2963 lttv_hooks_add(after_trace
,
2964 state_save_after_trace_hook
,
2969 lttv_process_traceset_end(&self
->parent
,
2970 NULL
, after_trace
, NULL
, NULL
, NULL
);
2972 lttv_hooks_destroy(after_trace
);
2974 nb_trace
= lttv_traceset_number(traceset
);
2975 for(i
= 0 ; i
< nb_trace
; i
++) {
2977 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2978 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2980 guint
*event_count
= NULL
;
2982 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2984 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2985 LttvTracefileContext
*, j
));
2986 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2987 state_save_event_hook
);
2989 if(event_count
) g_free(event_count
);
2993 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2995 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2997 lttv_state_save_remove_event_hooks(tss
);
3002 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3004 LttvTraceset
*traceset
= self
->parent
.ts
;
3008 int min_pos
, mid_pos
, max_pos
;
3010 guint call_rest
= 0;
3012 LttvTraceState
*tcs
;
3014 LttvAttributeValue value
;
3016 LttvAttributeType type
;
3018 LttvAttributeName name
;
3022 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3024 //g_tree_destroy(self->parent.pqueue);
3025 //self->parent.pqueue = g_tree_new(compare_tracefile);
3027 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3029 nb_trace
= lttv_traceset_number(traceset
);
3030 for(i
= 0 ; i
< nb_trace
; i
++) {
3031 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3033 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3034 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3035 LTTV_STATE_SAVED_STATES
);
3038 if(saved_states_tree
) {
3039 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3040 mid_pos
= max_pos
/ 2;
3041 while(min_pos
< max_pos
) {
3042 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3044 g_assert(type
== LTTV_GOBJECT
);
3045 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3046 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3048 g_assert(type
== LTTV_TIME
);
3049 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3051 closest_tree
= saved_state_tree
;
3053 else max_pos
= mid_pos
- 1;
3055 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3059 /* restore the closest earlier saved state */
3061 lttv_state_restore(tcs
, closest_tree
);
3065 /* There is no saved state, yet we want to have it. Restart at T0 */
3067 restore_init_state(tcs
);
3068 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3071 /* We want to seek quickly without restoring/updating the state */
3073 restore_init_state(tcs
);
3074 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3077 if(!call_rest
) g_info("NOT Calling restore");
3082 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3088 traceset_state_finalize (LttvTracesetState
*self
)
3090 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3091 finalize(G_OBJECT(self
));
3096 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3098 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3100 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3101 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3102 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3103 klass
->new_traceset_context
= new_traceset_context
;
3104 klass
->new_trace_context
= new_trace_context
;
3105 klass
->new_tracefile_context
= new_tracefile_context
;
3110 lttv_traceset_state_get_type(void)
3112 static GType type
= 0;
3114 static const GTypeInfo info
= {
3115 sizeof (LttvTracesetStateClass
),
3116 NULL
, /* base_init */
3117 NULL
, /* base_finalize */
3118 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3119 NULL
, /* class_finalize */
3120 NULL
, /* class_data */
3121 sizeof (LttvTracesetState
),
3122 0, /* n_preallocs */
3123 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3124 NULL
/* value handling */
3127 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3135 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3141 trace_state_finalize (LttvTraceState
*self
)
3143 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3144 finalize(G_OBJECT(self
));
3149 trace_state_class_init (LttvTraceStateClass
*klass
)
3151 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3153 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3154 klass
->state_save
= state_save
;
3155 klass
->state_restore
= state_restore
;
3156 klass
->state_saved_free
= state_saved_free
;
3161 lttv_trace_state_get_type(void)
3163 static GType type
= 0;
3165 static const GTypeInfo info
= {
3166 sizeof (LttvTraceStateClass
),
3167 NULL
, /* base_init */
3168 NULL
, /* base_finalize */
3169 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3170 NULL
, /* class_finalize */
3171 NULL
, /* class_data */
3172 sizeof (LttvTraceState
),
3173 0, /* n_preallocs */
3174 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3175 NULL
/* value handling */
3178 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3179 "LttvTraceStateType", &info
, 0);
3186 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3192 tracefile_state_finalize (LttvTracefileState
*self
)
3194 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3195 finalize(G_OBJECT(self
));
3200 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3202 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3204 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3209 lttv_tracefile_state_get_type(void)
3211 static GType type
= 0;
3213 static const GTypeInfo info
= {
3214 sizeof (LttvTracefileStateClass
),
3215 NULL
, /* base_init */
3216 NULL
, /* base_finalize */
3217 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3218 NULL
, /* class_finalize */
3219 NULL
, /* class_data */
3220 sizeof (LttvTracefileState
),
3221 0, /* n_preallocs */
3222 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3223 NULL
/* value handling */
3226 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3227 "LttvTracefileStateType", &info
, 0);
3233 static void module_init()
3235 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3236 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3237 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3238 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3239 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3240 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3241 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3242 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3243 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3244 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3245 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3246 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3247 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3248 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3249 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3250 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3251 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3252 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3253 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3254 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3255 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3256 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3257 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3258 LTTV_STATE_EVENT
= g_quark_from_string("event");
3259 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3260 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3261 LTTV_STATE_TIME
= g_quark_from_string("time");
3262 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3263 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3264 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3265 g_quark_from_string("trace_state_use_count");
3268 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3269 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3270 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3271 LTT_FACILITY_FS
= g_quark_from_string("fs");
3272 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3273 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3276 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3277 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3278 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3279 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3280 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3281 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3282 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3283 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3284 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3285 LTT_EVENT_FORK
= g_quark_from_string("fork");
3286 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3287 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3288 LTT_EVENT_FREE
= g_quark_from_string("free");
3289 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3290 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3291 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3292 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3293 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3296 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3297 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3298 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3299 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3300 LTT_FIELD_OUT
= g_quark_from_string("out");
3301 LTT_FIELD_IN
= g_quark_from_string("in");
3302 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3303 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3304 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3305 LTT_FIELD_PID
= g_quark_from_string("pid");
3306 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3307 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3308 LTT_FIELD_NAME
= g_quark_from_string("name");
3309 LTT_FIELD_TYPE
= g_quark_from_string("type");
3310 LTT_FIELD_MODE
= g_quark_from_string("mode");
3311 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3312 LTT_FIELD_STATUS
= g_quark_from_string("status");
3313 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3314 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3318 static void module_destroy()
3323 LTTV_MODULE("state", "State computation", \
3324 "Update the system state, possibly saving it at intervals", \
3325 module_init
, module_destroy
)