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);
346 // saved_states : open, test
347 strncpy(path
, trace_path
, PATH_MAX
-1);
348 count
= strnlen(trace_path
, PATH_MAX
-1);
349 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
350 fp
= fopen(path
, "r");
354 if(hdr
!= HDR_TRACE
) goto end
;
356 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
358 tcs
->has_precomputed_states
= TRUE
;
363 /* Free the quarktable */
364 for(i
=0; i
<quarktable
->len
; i
++) {
365 string
= g_ptr_array_index (quarktable
, i
);
368 g_ptr_array_free(quarktable
, TRUE
);
373 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
375 guint i
, j
, nb_trace
, nb_tracefile
;
377 LttvTraceContext
*tc
;
381 LttvTracefileState
*tfcs
;
383 LttvAttributeValue v
;
385 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
386 init((LttvTracesetContext
*)self
, ts
);
388 nb_trace
= lttv_traceset_number(ts
);
389 for(i
= 0 ; i
< nb_trace
; i
++) {
390 tc
= self
->parent
.traces
[i
];
391 tcs
= LTTV_TRACE_STATE(tc
);
392 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
393 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
397 if(*(v
.v_uint
) == 1) {
398 create_name_tables(tcs
);
399 create_max_time(tcs
);
401 get_name_tables(tcs
);
404 nb_tracefile
= tc
->tracefiles
->len
;
405 tcs
->processes
= NULL
;
406 tcs
->usertraces
= NULL
;
407 tcs
->running_process
= g_new(LttvProcessState
*,
408 ltt_trace_get_num_cpu(tc
->t
));
409 restore_init_state(tcs
);
410 for(j
= 0 ; j
< nb_tracefile
; j
++) {
412 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
413 LttvTracefileContext
*, j
));
414 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
415 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
416 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
417 /* It's a Usertrace */
418 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
419 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
421 if(!usertrace_tree
) {
422 usertrace_tree
= g_tree_new_full(compare_usertraces
,
423 NULL
, free_usertrace_key
, NULL
);
424 g_hash_table_insert(tcs
->usertraces
,
425 (gpointer
)tid
, usertrace_tree
);
427 LttTime
*timestamp
= g_new(LttTime
, 1);
428 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
429 ltt_tracefile_creation(tfcs
->parent
.tf
));
430 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
434 /* See if the trace has saved states */
435 state_load_saved_states(tcs
);
440 fini(LttvTracesetState
*self
)
446 LttvTracefileState
*tfcs
;
448 LttvAttributeValue v
;
450 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
451 for(i
= 0 ; i
< nb_trace
; i
++) {
452 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
453 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
456 g_assert(*(v
.v_uint
) != 0);
459 if(*(v
.v_uint
) == 0) {
460 free_name_tables(tcs
);
462 free_saved_state(tcs
);
464 g_free(tcs
->running_process
);
465 tcs
->running_process
= NULL
;
466 lttv_state_free_process_table(tcs
->processes
);
467 lttv_state_free_usertraces(tcs
->usertraces
);
468 tcs
->processes
= NULL
;
469 tcs
->usertraces
= NULL
;
471 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
472 fini((LttvTracesetContext
*)self
);
476 static LttvTracesetContext
*
477 new_traceset_context(LttvTracesetContext
*self
)
479 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
483 static LttvTraceContext
*
484 new_trace_context(LttvTracesetContext
*self
)
486 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
490 static LttvTracefileContext
*
491 new_tracefile_context(LttvTracesetContext
*self
)
493 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
497 /* Write the process state of the trace */
499 static void write_process_state(gpointer key
, gpointer value
,
502 LttvProcessState
*process
;
504 LttvExecutionState
*es
;
506 FILE *fp
= (FILE *)user_data
;
511 process
= (LttvProcessState
*)value
;
513 " <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",
514 process
, process
->pid
, process
->tgid
, process
->ppid
,
515 g_quark_to_string(process
->type
),
516 process
->creation_time
.tv_sec
,
517 process
->creation_time
.tv_nsec
,
518 process
->insertion_time
.tv_sec
,
519 process
->insertion_time
.tv_nsec
,
520 g_quark_to_string(process
->name
),
521 g_quark_to_string(process
->brand
),
524 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
525 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
526 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
527 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
528 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
529 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
530 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
533 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
534 address
= &g_array_index(process
->user_stack
, guint64
, i
);
535 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
539 if(process
->usertrace
) {
540 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
541 g_quark_to_string(process
->usertrace
->tracefile_name
),
542 process
->usertrace
->cpu
);
546 fprintf(fp
, " </PROCESS>\n");
550 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
552 guint i
, nb_tracefile
, nb_block
, offset
;
555 LttvTracefileState
*tfcs
;
559 LttEventPosition
*ep
;
563 ep
= ltt_event_position_new();
565 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
567 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
569 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
570 for(i
=0;i
<nb_cpus
;i
++) {
571 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
572 i
, self
->running_process
[i
]->pid
);
575 nb_tracefile
= self
->parent
.tracefiles
->len
;
577 for(i
= 0 ; i
< nb_tracefile
; i
++) {
579 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
580 LttvTracefileContext
*, i
));
581 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
582 tfcs
->parent
.timestamp
.tv_sec
,
583 tfcs
->parent
.timestamp
.tv_nsec
);
584 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
585 if(e
== NULL
) fprintf(fp
,"/>\n");
587 ltt_event_position(e
, ep
);
588 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
589 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
594 fprintf(fp
,"</PROCESS_STATE>\n");
598 static void write_process_state_raw(gpointer key
, gpointer value
,
601 LttvProcessState
*process
;
603 LttvExecutionState
*es
;
605 FILE *fp
= (FILE *)user_data
;
610 process
= (LttvProcessState
*)value
;
611 fputc(HDR_PROCESS
, fp
);
612 //fwrite(&header, sizeof(header), 1, fp);
613 //fprintf(fp, "%s", g_quark_to_string(process->type));
615 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
616 //fprintf(fp, "%s", g_quark_to_string(process->name));
618 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
619 //fprintf(fp, "%s", g_quark_to_string(process->brand));
621 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
622 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
623 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
624 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
625 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
626 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
627 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
631 " <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",
632 process
, process
->pid
, process
->tgid
, process
->ppid
,
633 g_quark_to_string(process
->type
),
634 process
->creation_time
.tv_sec
,
635 process
->creation_time
.tv_nsec
,
636 process
->insertion_time
.tv_sec
,
637 process
->insertion_time
.tv_nsec
,
638 g_quark_to_string(process
->name
),
639 g_quark_to_string(process
->brand
),
643 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
644 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
647 //fprintf(fp, "%s", g_quark_to_string(es->t));
649 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
650 //fprintf(fp, "%s", g_quark_to_string(es->n));
652 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
653 //fprintf(fp, "%s", g_quark_to_string(es->s));
655 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
656 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
657 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
658 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
660 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
661 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
662 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
663 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
664 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
668 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
669 address
= &g_array_index(process
->user_stack
, guint64
, i
);
670 fputc(HDR_USER_STACK
, fp
);
671 fwrite(&address
, sizeof(address
), 1, fp
);
673 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
678 if(process
->usertrace
) {
679 fputc(HDR_USERTRACE
, fp
);
680 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
682 fwrite(&process
->usertrace
->tracefile_name
,
683 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
684 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
686 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
687 g_quark_to_string(process
->usertrace
->tracefile_name
),
688 process
->usertrace
->cpu
);
695 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
697 guint i
, nb_tracefile
, nb_block
, offset
;
700 LttvTracefileState
*tfcs
;
704 LttEventPosition
*ep
;
708 ep
= ltt_event_position_new();
710 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
711 fputc(HDR_PROCESS_STATE
, fp
);
712 fwrite(&t
, sizeof(t
), 1, fp
);
714 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
716 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
717 for(i
=0;i
<nb_cpus
;i
++) {
719 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
720 fwrite(&self
->running_process
[i
]->pid
,
721 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
722 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
723 // i, self->running_process[i]->pid);
726 nb_tracefile
= self
->parent
.tracefiles
->len
;
728 for(i
= 0 ; i
< nb_tracefile
; i
++) {
730 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
731 LttvTracefileContext
*, i
));
732 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
733 // tfcs->parent.timestamp.tv_sec,
734 // tfcs->parent.timestamp.tv_nsec);
735 fputc(HDR_TRACEFILE
, fp
);
736 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
737 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
738 * position following : end of trace */
739 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
741 ltt_event_position(e
, ep
);
742 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
743 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
745 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
746 fwrite(&offset
, sizeof(offset
), 1, fp
);
747 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
754 /* Read process state from a file */
756 /* Called because a HDR_PROCESS was found */
757 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
758 GPtrArray
*quarktable
)
760 LttvExecutionState
*es
;
761 LttvProcessState
*process
, *parent_process
;
762 LttvProcessState tmp
;
769 /* TODO : check return value */
770 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
771 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
772 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
773 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
774 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
775 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
776 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
777 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
778 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
781 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
783 /* We must link to the parent */
784 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
786 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
787 if(process
== NULL
) {
788 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
790 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
794 process
->insertion_time
= tmp
.insertion_time
;
795 process
->creation_time
= tmp
.creation_time
;
796 process
->type
= g_quark_from_string(
797 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
798 process
->tgid
= tmp
.tgid
;
799 process
->ppid
= tmp
.ppid
;
800 process
->brand
= g_quark_from_string(
801 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
803 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
807 if(feof(fp
) || ferror(fp
)) goto end_loop
;
809 gint hdr
= fgetc(fp
);
810 if(hdr
== EOF
) goto end_loop
;
814 process
->execution_stack
=
815 g_array_set_size(process
->execution_stack
,
816 process
->execution_stack
->len
+ 1);
817 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
818 process
->execution_stack
->len
-1);
821 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
822 es
->t
= g_quark_from_string(
823 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
824 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
825 es
->n
= g_quark_from_string(
826 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
827 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
828 es
->s
= g_quark_from_string(
829 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
830 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
831 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
832 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
835 process
->user_stack
= g_array_set_size(process
->user_stack
,
836 process
->user_stack
->len
+ 1);
837 address
= &g_array_index(process
->user_stack
, guint64
,
838 process
->user_stack
->len
-1);
839 fread(address
, sizeof(address
), 1, fp
);
840 process
->current_function
= *address
;
843 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
844 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
856 /* Called because a HDR_PROCESS_STATE was found */
857 /* Append a saved state to the trace states */
858 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
860 guint i
, nb_tracefile
, nb_block
, offset
;
862 LttvTracefileState
*tfcs
;
864 LttEventPosition
*ep
;
872 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
874 LttvAttributeValue value
;
875 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
876 ep
= ltt_event_position_new();
878 restore_init_state(self
);
880 fread(&t
, sizeof(t
), 1, fp
);
883 if(feof(fp
) || ferror(fp
)) goto end_loop
;
885 if(hdr
== EOF
) goto end_loop
;
889 /* Call read_process_state_raw */
890 read_process_state_raw(self
, fp
, quarktable
);
900 case HDR_PROCESS_STATE
:
906 g_error("Error while parsing saved state file : unknown data header %d",
912 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
913 for(i
=0;i
<nb_cpus
;i
++) {
916 g_assert(hdr
== HDR_CPU
);
917 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
918 g_assert(i
== cpu_num
);
919 fread(&self
->running_process
[i
]->pid
,
920 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
923 nb_tracefile
= self
->parent
.tracefiles
->len
;
925 for(i
= 0 ; i
< nb_tracefile
; i
++) {
927 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
928 LttvTracefileContext
*, i
));
929 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
930 // tfcs->parent.timestamp.tv_sec,
931 // tfcs->parent.timestamp.tv_nsec);
932 g_tree_remove(pqueue
, &tfcs
->parent
);
934 g_assert(hdr
== HDR_TRACEFILE
);
935 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
936 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
937 * position following : end of trace */
938 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
939 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
940 fread(&offset
, sizeof(offset
), 1, fp
);
941 fread(&tsc
, sizeof(tsc
), 1, fp
);
942 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
943 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
945 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
950 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
951 LTTV_STATE_SAVED_STATES
);
952 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
953 value
= lttv_attribute_add(saved_states_tree
,
954 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
955 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
956 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
958 lttv_state_save(self
, saved_state_tree
);
959 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
962 *(self
->max_time_state_recomputed_in_seek
) = t
;
966 /* Called when a HDR_TRACE is found */
967 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
968 GPtrArray
*quarktable
)
973 if(feof(fp
) || ferror(fp
)) goto end_loop
;
975 if(hdr
== EOF
) goto end_loop
;
978 case HDR_PROCESS_STATE
:
979 /* Call read_process_state_raw */
980 lttv_state_read_raw(tcs
, fp
, quarktable
);
992 g_error("Error while parsing saved state file :"
993 " unexpected data header %d",
997 g_error("Error while parsing saved state file : unknown data header %d",
1002 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1003 restore_init_state(tcs
);
1004 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1010 /* Copy each process from an existing hash table to a new one */
1012 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1014 LttvProcessState
*process
, *new_process
;
1016 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1020 process
= (LttvProcessState
*)value
;
1021 new_process
= g_new(LttvProcessState
, 1);
1022 *new_process
= *process
;
1023 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1024 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1025 new_process
->execution_stack
=
1026 g_array_set_size(new_process
->execution_stack
,
1027 process
->execution_stack
->len
);
1028 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1029 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1030 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1032 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1033 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1034 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1035 sizeof(guint64
), 0);
1036 new_process
->user_stack
=
1037 g_array_set_size(new_process
->user_stack
,
1038 process
->user_stack
->len
);
1039 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1040 g_array_index(new_process
->user_stack
, guint64
, i
) =
1041 g_array_index(process
->user_stack
, guint64
, i
);
1043 new_process
->current_function
= process
->current_function
;
1044 g_hash_table_insert(new_processes
, new_process
, new_process
);
1048 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1050 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1052 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1053 return new_processes
;
1057 /* The saved state for each trace contains a member "processes", which
1058 stores a copy of the process table, and a member "tracefiles" with
1059 one entry per tracefile. Each tracefile has a "process" member pointing
1060 to the current process and a "position" member storing the tracefile
1061 position (needed to seek to the current "next" event. */
1063 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1065 guint i
, nb_tracefile
, nb_cpus
;
1067 LttvTracefileState
*tfcs
;
1069 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1071 guint
*running_process
;
1073 LttvAttributeType type
;
1075 LttvAttributeValue value
;
1077 LttvAttributeName name
;
1079 LttEventPosition
*ep
;
1081 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1082 LTTV_STATE_TRACEFILES
);
1084 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1086 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1088 /* Add the currently running processes array */
1089 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1090 running_process
= g_new(guint
, nb_cpus
);
1091 for(i
=0;i
<nb_cpus
;i
++) {
1092 running_process
[i
] = self
->running_process
[i
]->pid
;
1094 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1096 *(value
.v_pointer
) = running_process
;
1098 g_info("State save");
1100 nb_tracefile
= self
->parent
.tracefiles
->len
;
1102 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1104 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1105 LttvTracefileContext
*, i
));
1106 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1107 value
= lttv_attribute_add(tracefiles_tree
, i
,
1109 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1111 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1113 *(value
.v_uint
) = tfcs
->process
->pid
;
1115 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1117 /* Only save the position if the tfs has not infinite time. */
1118 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1119 // && current_tfcs != tfcs) {
1120 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1121 *(value
.v_pointer
) = NULL
;
1123 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1124 ep
= ltt_event_position_new();
1125 ltt_event_position(e
, ep
);
1126 *(value
.v_pointer
) = ep
;
1128 guint nb_block
, offset
;
1131 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1132 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1134 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1140 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1142 guint i
, nb_tracefile
, pid
, nb_cpus
;
1144 LttvTracefileState
*tfcs
;
1146 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1148 guint
*running_process
;
1150 LttvAttributeType type
;
1152 LttvAttributeValue value
;
1154 LttvAttributeName name
;
1158 LttEventPosition
*ep
;
1160 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1162 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1163 LTTV_STATE_TRACEFILES
);
1165 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1167 g_assert(type
== LTTV_POINTER
);
1168 lttv_state_free_process_table(self
->processes
);
1169 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1171 /* Add the currently running processes array */
1172 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1173 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1175 g_assert(type
== LTTV_POINTER
);
1176 running_process
= *(value
.v_pointer
);
1177 for(i
=0;i
<nb_cpus
;i
++) {
1178 pid
= running_process
[i
];
1179 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1180 g_assert(self
->running_process
[i
] != NULL
);
1184 nb_tracefile
= self
->parent
.tracefiles
->len
;
1186 //g_tree_destroy(tsc->pqueue);
1187 //tsc->pqueue = g_tree_new(compare_tracefile);
1189 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1191 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1192 LttvTracefileContext
*, i
));
1193 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1194 g_assert(type
== LTTV_GOBJECT
);
1195 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1197 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1199 g_assert(type
== LTTV_UINT
);
1200 pid
= *(value
.v_uint
);
1201 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1203 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1205 g_assert(type
== LTTV_POINTER
);
1206 //g_assert(*(value.v_pointer) != NULL);
1207 ep
= *(value
.v_pointer
);
1208 g_assert(tfcs
->parent
.t_context
!= NULL
);
1210 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1211 g_tree_remove(tsc
->pqueue
, tfc
);
1214 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1215 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1216 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1217 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1218 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1220 tfc
->timestamp
= ltt_time_infinite
;
1226 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1228 guint i
, nb_tracefile
, nb_cpus
;
1230 LttvTracefileState
*tfcs
;
1232 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1234 guint
*running_process
;
1236 LttvAttributeType type
;
1238 LttvAttributeValue value
;
1240 LttvAttributeName name
;
1244 LttEventPosition
*ep
;
1246 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1247 LTTV_STATE_TRACEFILES
);
1248 g_object_ref(G_OBJECT(tracefiles_tree
));
1249 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1251 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1253 g_assert(type
== LTTV_POINTER
);
1254 lttv_state_free_process_table(*(value
.v_pointer
));
1255 *(value
.v_pointer
) = NULL
;
1256 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1258 /* Free running processes array */
1259 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1260 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1262 g_assert(type
== LTTV_POINTER
);
1263 running_process
= *(value
.v_pointer
);
1264 g_free(running_process
);
1266 nb_tracefile
= self
->parent
.tracefiles
->len
;
1268 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1270 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1271 LttvTracefileContext
*, i
));
1272 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1273 g_assert(type
== LTTV_GOBJECT
);
1274 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1276 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1278 g_assert(type
== LTTV_POINTER
);
1279 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1281 g_object_unref(G_OBJECT(tracefiles_tree
));
1285 static void free_saved_state(LttvTraceState
*self
)
1289 LttvAttributeType type
;
1291 LttvAttributeValue value
;
1293 LttvAttributeName name
;
1297 LttvAttribute
*saved_states
;
1299 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1300 LTTV_STATE_SAVED_STATES
);
1302 nb
= lttv_attribute_get_number(saved_states
);
1303 for(i
= 0 ; i
< nb
; i
++) {
1304 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1305 g_assert(type
== LTTV_GOBJECT
);
1306 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1309 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1314 create_max_time(LttvTraceState
*tcs
)
1316 LttvAttributeValue v
;
1318 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1320 g_assert(*(v
.v_pointer
) == NULL
);
1321 *(v
.v_pointer
) = g_new(LttTime
,1);
1322 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1327 get_max_time(LttvTraceState
*tcs
)
1329 LttvAttributeValue v
;
1331 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1333 g_assert(*(v
.v_pointer
) != NULL
);
1334 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1339 free_max_time(LttvTraceState
*tcs
)
1341 LttvAttributeValue v
;
1343 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1345 g_free(*(v
.v_pointer
));
1346 *(v
.v_pointer
) = NULL
;
1350 typedef struct _LttvNameTables
{
1351 // FIXME GQuark *eventtype_names;
1352 GQuark
*syscall_names
;
1357 GQuark
*soft_irq_names
;
1362 create_name_tables(LttvTraceState
*tcs
)
1366 GQuark f_name
, e_name
;
1370 LttvTraceHookByFacility
*thf
;
1376 GString
*fe_name
= g_string_new("");
1378 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1380 LttvAttributeValue v
;
1382 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1384 g_assert(*(v
.v_pointer
) == NULL
);
1385 *(v
.v_pointer
) = name_tables
;
1386 #if 0 // Use iteration over the facilities_by_name and then list all event
1387 // types of each facility
1388 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1389 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1390 for(i
= 0 ; i
< nb
; i
++) {
1391 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1392 e_name
= ltt_eventtype_name(et
);
1393 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1394 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1395 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1398 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1399 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1400 LTT_FIELD_SYSCALL_ID
, 0, 0,
1403 thf
= lttv_trace_hook_get_first(&h
);
1405 t
= ltt_field_type(thf
->f1
);
1406 nb
= ltt_type_element_number(t
);
1408 lttv_trace_hook_destroy(&h
);
1410 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1411 name_tables
->nb_syscalls
= nb
;
1413 for(i
= 0 ; i
< nb
; i
++) {
1414 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1417 //name_tables->syscall_names = g_new(GQuark, 256);
1418 //for(i = 0 ; i < 256 ; i++) {
1419 // g_string_printf(fe_name, "syscall %d", i);
1420 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1423 name_tables
->syscall_names
= NULL
;
1424 name_tables
->nb_syscalls
= 0;
1427 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1428 LTT_EVENT_TRAP_ENTRY
,
1429 LTT_FIELD_TRAP_ID
, 0, 0,
1432 thf
= lttv_trace_hook_get_first(&h
);
1434 t
= ltt_field_type(thf
->f1
);
1435 //nb = ltt_type_element_number(t);
1437 lttv_trace_hook_destroy(&h
);
1440 name_tables->trap_names = g_new(GQuark, nb);
1441 for(i = 0 ; i < nb ; i++) {
1442 name_tables->trap_names[i] = g_quark_from_string(
1443 ltt_enum_string_get(t, i));
1446 name_tables
->nb_traps
= 256;
1447 name_tables
->trap_names
= g_new(GQuark
, 256);
1448 for(i
= 0 ; i
< 256 ; i
++) {
1449 g_string_printf(fe_name
, "trap %d", i
);
1450 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1453 name_tables
->trap_names
= NULL
;
1454 name_tables
->nb_traps
= 0;
1457 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1458 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1459 LTT_FIELD_IRQ_ID
, 0, 0,
1462 thf
= lttv_trace_hook_get_first(&h
);
1464 t
= ltt_field_type(thf
->f1
);
1465 //nb = ltt_type_element_number(t);
1467 lttv_trace_hook_destroy(&h
);
1470 name_tables->irq_names = g_new(GQuark, nb);
1471 for(i = 0 ; i < nb ; i++) {
1472 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1476 name_tables
->irq_names
= g_new(GQuark
, 256);
1477 for(i
= 0 ; i
< 256 ; i
++) {
1478 g_string_printf(fe_name
, "irq %d", i
);
1479 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1482 name_tables
->irq_names
= NULL
;
1485 name_tables->soft_irq_names = g_new(GQuark, nb);
1486 for(i = 0 ; i < nb ; i++) {
1487 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1491 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1492 for(i
= 0 ; i
< 256 ; i
++) {
1493 g_string_printf(fe_name
, "softirq %d", i
);
1494 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1498 g_string_free(fe_name
, TRUE
);
1503 get_name_tables(LttvTraceState
*tcs
)
1505 LttvNameTables
*name_tables
;
1507 LttvAttributeValue v
;
1509 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1511 g_assert(*(v
.v_pointer
) != NULL
);
1512 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1513 //tcs->eventtype_names = name_tables->eventtype_names;
1514 tcs
->syscall_names
= name_tables
->syscall_names
;
1515 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1516 tcs
->trap_names
= name_tables
->trap_names
;
1517 tcs
->nb_traps
= name_tables
->nb_traps
;
1518 tcs
->irq_names
= name_tables
->irq_names
;
1519 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1524 free_name_tables(LttvTraceState
*tcs
)
1526 LttvNameTables
*name_tables
;
1528 LttvAttributeValue v
;
1530 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1532 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1533 *(v
.v_pointer
) = NULL
;
1535 // g_free(name_tables->eventtype_names);
1536 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1537 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1538 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1539 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1540 if(name_tables
) g_free(name_tables
);
1543 #ifdef HASH_TABLE_DEBUG
1545 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1547 LttvProcessState
*process
= (LttvProcessState
*)value
;
1549 /* Test for process corruption */
1550 guint stack_len
= process
->execution_stack
->len
;
1553 static void hash_table_check(GHashTable
*table
)
1555 g_hash_table_foreach(table
, test_process
, NULL
);
1562 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1565 LttvExecutionState
*es
;
1567 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1568 guint cpu
= tfs
->cpu
;
1570 #ifdef HASH_TABLE_DEBUG
1571 hash_table_check(ts
->processes
);
1573 LttvProcessState
*process
= ts
->running_process
[cpu
];
1575 guint depth
= process
->execution_stack
->len
;
1577 process
->execution_stack
=
1578 g_array_set_size(process
->execution_stack
, depth
+ 1);
1581 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1583 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1586 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1587 es
->cum_cpu_time
= ltt_time_zero
;
1588 es
->s
= process
->state
->s
;
1589 process
->state
= es
;
1593 * return 1 when empty, else 0 */
1594 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1595 LttvTracefileState
*tfs
)
1597 guint cpu
= tfs
->cpu
;
1598 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1600 guint depth
= process
->execution_stack
->len
;
1606 process
->execution_stack
=
1607 g_array_set_size(process
->execution_stack
, depth
- 1);
1608 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1610 process
->state
->change
= tfs
->parent
.timestamp
;
1615 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1617 guint cpu
= tfs
->cpu
;
1618 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1619 LttvProcessState
*process
= ts
->running_process
[cpu
];
1621 guint depth
= process
->execution_stack
->len
;
1623 if(process
->state
->t
!= t
){
1624 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1625 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1626 g_info("process state has %s when pop_int is %s\n",
1627 g_quark_to_string(process
->state
->t
),
1628 g_quark_to_string(t
));
1629 g_info("{ %u, %u, %s, %s, %s }\n",
1632 g_quark_to_string(process
->name
),
1633 g_quark_to_string(process
->brand
),
1634 g_quark_to_string(process
->state
->s
));
1639 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1640 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1644 process
->execution_stack
=
1645 g_array_set_size(process
->execution_stack
, depth
- 1);
1646 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1648 process
->state
->change
= tfs
->parent
.timestamp
;
1651 struct search_result
{
1652 const LttTime
*time
; /* Requested time */
1653 LttTime
*best
; /* Best result */
1656 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1658 const LttTime
*elem_time
= (const LttTime
*)a
;
1659 /* Explicit non const cast */
1660 struct search_result
*res
= (struct search_result
*)b
;
1662 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1663 /* The usertrace was created before the schedchange */
1664 /* Get larger keys */
1666 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1667 /* The usertrace was created after the schedchange time */
1668 /* Get smaller keys */
1670 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1671 res
->best
= elem_time
;
1674 res
->best
= elem_time
;
1681 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1682 guint pid
, const LttTime
*timestamp
)
1684 LttvTracefileState
*tfs
= NULL
;
1685 struct search_result res
;
1686 /* Find the usertrace associated with a pid and time interval.
1687 * Search in the usertraces by PID (within a hash) and then, for each
1688 * corresponding element of the array, find the first one with creation
1689 * timestamp the lowest, but higher or equal to "timestamp". */
1690 res
.time
= timestamp
;
1692 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1693 if(usertrace_tree
) {
1694 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1696 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1704 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1705 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1707 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1709 LttvExecutionState
*es
;
1711 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1716 process
->tgid
= tgid
;
1718 process
->name
= name
;
1719 process
->brand
= LTTV_STATE_UNBRANDED
;
1720 //process->last_cpu = tfs->cpu_name;
1721 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1722 process
->type
= LTTV_STATE_USER_THREAD
;
1723 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1724 process
->current_function
= 0; //function 0x0 by default.
1726 g_info("Process %u, core %p", process
->pid
, process
);
1727 g_hash_table_insert(tcs
->processes
, process
, process
);
1730 process
->ppid
= parent
->pid
;
1731 process
->creation_time
= *timestamp
;
1734 /* No parent. This process exists but we are missing all information about
1735 its creation. The birth time is set to zero but we remember the time of
1740 process
->creation_time
= ltt_time_zero
;
1743 process
->insertion_time
= *timestamp
;
1744 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1745 process
->creation_time
.tv_nsec
);
1746 process
->pid_time
= g_quark_from_string(buffer
);
1748 //process->last_cpu = tfs->cpu_name;
1749 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1750 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1751 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1752 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1753 es
= process
->state
= &g_array_index(process
->execution_stack
,
1754 LttvExecutionState
, 0);
1755 es
->t
= LTTV_STATE_USER_MODE
;
1756 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1757 es
->entry
= *timestamp
;
1758 //g_assert(timestamp->tv_sec != 0);
1759 es
->change
= *timestamp
;
1760 es
->cum_cpu_time
= ltt_time_zero
;
1761 es
->s
= LTTV_STATE_RUN
;
1763 es
= process
->state
= &g_array_index(process
->execution_stack
,
1764 LttvExecutionState
, 1);
1765 es
->t
= LTTV_STATE_SYSCALL
;
1766 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1767 es
->entry
= *timestamp
;
1768 //g_assert(timestamp->tv_sec != 0);
1769 es
->change
= *timestamp
;
1770 es
->cum_cpu_time
= ltt_time_zero
;
1771 es
->s
= LTTV_STATE_WAIT_FORK
;
1773 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1774 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1775 sizeof(guint64
), 0);
1780 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1783 LttvProcessState key
;
1784 LttvProcessState
*process
;
1788 process
= g_hash_table_lookup(ts
->processes
, &key
);
1793 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1794 const LttTime
*timestamp
)
1796 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1797 LttvExecutionState
*es
;
1799 /* Put ltt_time_zero creation time for unexisting processes */
1800 if(unlikely(process
== NULL
)) {
1801 process
= lttv_state_create_process(ts
,
1802 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1803 /* We are not sure is it's a kernel thread or normal thread, put the
1804 * bottom stack state to unknown */
1805 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1806 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1811 /* FIXME : this function should be called when we receive an event telling that
1812 * release_task has been called in the kernel. In happens generally when
1813 * the parent waits for its child terminaison, but may also happen in special
1814 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1815 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1816 * of a killed thread ground, but isn't the leader.
1818 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1820 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1821 LttvProcessState key
;
1823 key
.pid
= process
->pid
;
1824 key
.cpu
= process
->cpu
;
1825 g_hash_table_remove(ts
->processes
, &key
);
1826 g_array_free(process
->execution_stack
, TRUE
);
1827 g_array_free(process
->user_stack
, TRUE
);
1832 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1834 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1835 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1840 static void lttv_state_free_process_table(GHashTable
*processes
)
1842 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1843 g_hash_table_destroy(processes
);
1847 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1849 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1851 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1852 LttvProcessState
*process
= ts
->running_process
[cpu
];
1853 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1854 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1855 LttField
*f
= thf
->f1
;
1857 LttvExecutionSubmode submode
;
1859 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1860 guint syscall
= ltt_event_get_unsigned(e
, f
);
1862 if(syscall
< nb_syscalls
) {
1863 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1866 /* Fixup an incomplete syscall table */
1867 GString
*string
= g_string_new("");
1868 g_string_printf(string
, "syscall %u", syscall
);
1869 submode
= g_quark_from_string(string
->str
);
1870 g_string_free(string
, TRUE
);
1872 /* There can be no system call from PID 0 : unknown state */
1873 if(process
->pid
!= 0)
1874 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1879 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1881 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1883 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1884 LttvProcessState
*process
= ts
->running_process
[cpu
];
1886 /* There can be no system call from PID 0 : unknown state */
1887 if(process
->pid
!= 0)
1888 pop_state(s
, LTTV_STATE_SYSCALL
);
1893 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1895 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1896 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1897 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1898 LttField
*f
= thf
->f1
;
1900 LttvExecutionSubmode submode
;
1902 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1903 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1905 if(trap
< nb_traps
) {
1906 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1908 /* Fixup an incomplete trap table */
1909 GString
*string
= g_string_new("");
1910 g_string_printf(string
, "trap %llu", trap
);
1911 submode
= g_quark_from_string(string
->str
);
1912 g_string_free(string
, TRUE
);
1915 push_state(s
, LTTV_STATE_TRAP
, submode
);
1920 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1922 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1924 pop_state(s
, LTTV_STATE_TRAP
);
1929 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1931 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1932 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1933 guint8 fac_id
= ltt_event_facility_id(e
);
1934 guint8 ev_id
= ltt_event_eventtype_id(e
);
1935 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1936 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1937 g_assert(thf
->f1
!= NULL
);
1938 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1939 LttField
*f
= thf
->f1
;
1941 LttvExecutionSubmode submode
;
1943 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1944 ltt_event_get_unsigned(e
, f
)];
1946 /* Do something with the info about being in user or system mode when int? */
1947 push_state(s
, LTTV_STATE_IRQ
, submode
);
1951 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1953 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1955 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1961 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1963 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1965 pop_state(s
, LTTV_STATE_IRQ
);
1969 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1971 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1972 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1973 guint8 fac_id
= ltt_event_facility_id(e
);
1974 guint8 ev_id
= ltt_event_eventtype_id(e
);
1975 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1976 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1977 g_assert(thf
->f1
!= NULL
);
1978 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1979 LttField
*f
= thf
->f1
;
1981 LttvExecutionSubmode submode
;
1983 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1984 ltt_event_get_long_unsigned(e
, f
)];
1986 /* Do something with the info about being in user or system mode when int? */
1987 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1991 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1995 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1996 guint cpu
= tfs
->cpu
;
1997 LttvProcessState
*process
= ts
->running_process
[cpu
];
1999 guint depth
= process
->user_stack
->len
;
2001 process
->user_stack
=
2002 g_array_set_size(process
->user_stack
, depth
+ 1);
2004 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2005 *new_func
= funcptr
;
2006 process
->current_function
= funcptr
;
2009 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2011 guint cpu
= tfs
->cpu
;
2012 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2013 LttvProcessState
*process
= ts
->running_process
[cpu
];
2015 if(process
->current_function
!= funcptr
){
2016 g_info("Different functions (%lu.%09lu): ignore it\n",
2017 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2018 g_info("process state has %llu when pop_function is %llu\n",
2019 process
->current_function
, funcptr
);
2020 g_info("{ %u, %u, %s, %s, %s }\n",
2023 g_quark_to_string(process
->name
),
2024 g_quark_to_string(process
->brand
),
2025 g_quark_to_string(process
->state
->s
));
2028 guint depth
= process
->user_stack
->len
;
2031 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2032 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2036 process
->user_stack
=
2037 g_array_set_size(process
->user_stack
, depth
- 1);
2038 process
->current_function
=
2039 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2043 static gboolean
function_entry(void *hook_data
, void *call_data
)
2045 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2046 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2047 guint8 fac_id
= ltt_event_facility_id(e
);
2048 guint8 ev_id
= ltt_event_eventtype_id(e
);
2049 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2050 g_assert(thf
->f1
!= NULL
);
2051 LttField
*f
= thf
->f1
;
2052 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2054 push_function(s
, funcptr
);
2058 static gboolean
function_exit(void *hook_data
, void *call_data
)
2060 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2061 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2062 guint8 fac_id
= ltt_event_facility_id(e
);
2063 guint8 ev_id
= ltt_event_eventtype_id(e
);
2064 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2065 g_assert(thf
->f1
!= NULL
);
2066 LttField
*f
= thf
->f1
;
2067 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2069 LttvExecutionSubmode submode
;
2071 pop_function(s
, funcptr
);
2075 static gboolean
schedchange(void *hook_data
, void *call_data
)
2077 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2079 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2080 LttvProcessState
*process
= ts
->running_process
[cpu
];
2081 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2083 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2084 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2085 guint pid_in
, pid_out
;
2088 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2089 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2090 state_out
= ltt_event_get_int(e
, thf
->f3
);
2092 if(likely(process
!= NULL
)) {
2094 /* We could not know but it was not the idle process executing.
2095 This should only happen at the beginning, before the first schedule
2096 event, and when the initial information (current process for each CPU)
2097 is missing. It is not obvious how we could, after the fact, compensate
2098 the wrongly attributed statistics. */
2100 //This test only makes sense once the state is known and if there is no
2101 //missing events. We need to silently ignore schedchange coming after a
2102 //process_free, or it causes glitches. (FIXME)
2103 //if(unlikely(process->pid != pid_out)) {
2104 // g_assert(process->pid == 0);
2106 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2107 /* Scheduling out of pid 0 at beginning of the trace :
2108 * we know for sure it is in syscall mode at this point. */
2109 g_assert(process
->execution_stack
->len
== 1);
2110 process
->state
->t
= LTTV_STATE_SYSCALL
;
2112 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2113 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2114 process
->state
->change
= s
->parent
.timestamp
;
2116 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2117 else process
->state
->s
= LTTV_STATE_WAIT
;
2118 process
->state
->change
= s
->parent
.timestamp
;
2122 exit_process(s
, process
); /* EXIT_DEAD */
2123 /* see sched.h for states */
2125 process
= ts
->running_process
[cpu
] =
2126 lttv_state_find_process_or_create(
2127 (LttvTraceState
*)s
->parent
.t_context
,
2129 &s
->parent
.timestamp
);
2130 process
->state
->s
= LTTV_STATE_RUN
;
2132 if(process
->usertrace
)
2133 process
->usertrace
->cpu
= cpu
;
2134 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2135 process
->state
->change
= s
->parent
.timestamp
;
2139 static gboolean
process_fork(void *hook_data
, void *call_data
)
2141 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2142 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2143 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2145 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2146 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2147 LttvProcessState
*zombie_process
;
2149 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2150 LttvProcessState
*process
= ts
->running_process
[cpu
];
2151 LttvProcessState
*child_process
;
2154 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2157 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2158 s
->parent
.target_pid
= child_pid
;
2161 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2162 else child_tgid
= 0;
2164 /* Mathieu : it seems like the process might have been scheduled in before the
2165 * fork, and, in a rare case, might be the current process. This might happen
2166 * in a SMP case where we don't have enough precision on the clocks.
2168 * Test reenabled after precision fixes on time. (Mathieu) */
2170 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2172 if(unlikely(zombie_process
!= NULL
)) {
2173 /* Reutilisation of PID. Only now we are sure that the old PID
2174 * has been released. FIXME : should know when release_task happens instead.
2176 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2178 for(i
=0; i
< num_cpus
; i
++) {
2179 g_assert(zombie_process
!= ts
->running_process
[i
]);
2182 exit_process(s
, zombie_process
);
2185 g_assert(process
->pid
!= child_pid
);
2186 // FIXME : Add this test in the "known state" section
2187 // g_assert(process->pid == parent_pid);
2188 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2189 if(child_process
== NULL
) {
2190 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2191 child_pid
, child_tgid
,
2192 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2194 /* The process has already been created : due to time imprecision between
2195 * multiple CPUs : it has been scheduled in before creation. Note that we
2196 * shouldn't have this kind of imprecision.
2198 * Simply put a correct parent.
2200 g_assert(0); /* This is a problematic case : the process has been created
2201 before the fork event */
2202 child_process
->ppid
= process
->pid
;
2203 child_process
->tgid
= child_tgid
;
2205 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2206 child_process
->name
= process
->name
;
2207 child_process
->brand
= process
->brand
;
2212 /* We stamp a newly created process as kernel_thread */
2213 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2215 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2216 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2217 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2220 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2221 LttvProcessState
*process
;
2222 LttvExecutionState
*es
;
2225 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2226 s
->parent
.target_pid
= pid
;
2228 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2229 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2230 es
->t
= LTTV_STATE_SYSCALL
;
2231 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2236 static gboolean
process_exit(void *hook_data
, void *call_data
)
2238 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2239 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2240 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2244 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2245 LttvProcessState
*process
; // = ts->running_process[cpu];
2247 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2248 s
->parent
.target_pid
= pid
;
2250 // FIXME : Add this test in the "known state" section
2251 // g_assert(process->pid == pid);
2253 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2254 if(likely(process
!= NULL
)) {
2255 process
->state
->s
= LTTV_STATE_EXIT
;
2260 static gboolean
process_free(void *hook_data
, void *call_data
)
2262 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2263 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2264 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2265 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2267 LttvProcessState
*process
;
2269 /* PID of the process to release */
2270 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2271 s
->parent
.target_pid
= release_pid
;
2273 g_assert(release_pid
!= 0);
2275 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2277 if(likely(process
!= NULL
)) {
2278 /* release_task is happening at kernel level : we can now safely release
2279 * the data structure of the process */
2280 //This test is fun, though, as it may happen that
2281 //at time t : CPU 0 : process_free
2282 //at time t+150ns : CPU 1 : schedule out
2283 //Clearly due to time imprecision, we disable it. (Mathieu)
2284 //If this weird case happen, we have no choice but to put the
2285 //Currently running process on the cpu to 0.
2286 //I re-enable it following time precision fixes. (Mathieu)
2287 //Well, in the case where an process is freed by a process on another CPU
2288 //and still scheduled, it happens that this is the schedchange that will
2289 //drop the last reference count. Do not free it here!
2290 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2292 for(i
=0; i
< num_cpus
; i
++) {
2293 //g_assert(process != ts->running_process[i]);
2294 if(process
== ts
->running_process
[i
]) {
2295 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2299 if(i
== num_cpus
) /* process is not scheduled */
2300 exit_process(s
, process
);
2307 static gboolean
process_exec(void *hook_data
, void *call_data
)
2309 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2310 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2311 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2312 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2315 LttvProcessState
*process
= ts
->running_process
[cpu
];
2317 /* PID of the process to release */
2318 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2319 //name = ltt_event_get_string(e, thf->f1);
2320 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2322 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2323 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2324 memcpy(null_term_name
, name_begin
, name_len
);
2325 null_term_name
[name_len
] = '\0';
2327 process
->name
= g_quark_from_string(null_term_name
);
2328 process
->brand
= LTTV_STATE_UNBRANDED
;
2329 g_free(null_term_name
);
2333 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2335 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2336 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2337 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2338 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2341 LttvProcessState
*process
= ts
->running_process
[cpu
];
2343 name
= ltt_event_get_string(e
, thf
->f1
);
2344 process
->brand
= g_quark_from_string(name
);
2349 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2351 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2352 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2353 //It's slow : optimise later by doing this before reading trace.
2354 LttEventType
*et
= ltt_event_eventtype(e
);
2356 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2362 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2363 LttvProcessState
*process
= ts
->running_process
[cpu
];
2364 LttvProcessState
*parent_process
;
2365 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2366 GQuark type
, mode
, submode
, status
;
2367 LttvExecutionState
*es
;
2370 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2371 s
->parent
.target_pid
= pid
;
2374 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2377 command
= ltt_event_get_string(e
, thf
->f3
);
2380 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2381 type
= ltt_enum_string_get(ltt_field_type(f4
),
2382 ltt_event_get_unsigned(e
, f4
));
2385 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2386 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2387 ltt_event_get_unsigned(e
, f5
));
2390 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2391 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2392 ltt_event_get_unsigned(e
, f6
));
2395 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2396 status
= ltt_enum_string_get(ltt_field_type(f7
),
2397 ltt_event_get_unsigned(e
, f7
));
2400 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2401 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2404 /* The process might exist if a process was forked while performing the state
2406 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2407 if(process
== NULL
) {
2408 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2409 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2410 pid
, tgid
, g_quark_from_string(command
),
2411 &s
->parent
.timestamp
);
2413 /* Keep the stack bottom : a running user mode */
2414 /* Disabled because of inconsistencies in the current statedump states. */
2415 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2416 /* Only keep the bottom
2417 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2418 /* Will cause expected trap when in fact being syscall (even after end of
2420 * Will cause expected interrupt when being syscall. (only before end of
2421 * statedump event) */
2422 // This will cause a "popping last state on stack, ignoring it."
2423 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2424 es
= process
->state
= &g_array_index(process
->execution_stack
,
2425 LttvExecutionState
, 0);
2426 es
->t
= LTTV_STATE_SYSCALL
;
2430 /* User space process :
2431 * bottom : user mode
2432 * either currently running or scheduled out.
2433 * can be scheduled out because interrupted in (user mode or in syscall)
2434 * or because of an explicit call to the scheduler in syscall. Note that
2435 * the scheduler call comes after the irq_exit, so never in interrupt
2437 // temp workaround : set size to 1 : only have user mode bottom of stack.
2438 // will cause g_info message of expected syscall mode when in fact being
2439 // in user mode. Can also cause expected trap when in fact being user
2440 // mode in the event of a page fault reenabling interrupts in the handler.
2441 // Expected syscall and trap can also happen after the end of statedump
2442 // This will cause a "popping last state on stack, ignoring it."
2443 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2445 es
= process
->state
= &g_array_index(process
->execution_stack
,
2446 LttvExecutionState
, 1);
2447 es
->t
= LTTV_STATE_USER_MODE
;
2455 es
= process
->state
= &g_array_index(process
->execution_stack
,
2456 LttvExecutionState
, 1);
2457 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2458 es
->s
= LTTV_STATE_UNNAMED
;
2459 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2463 /* The process has already been created :
2464 * Probably was forked while dumping the process state or
2465 * was simply scheduled in prior to get the state dump event.
2466 * We know for sure if it is a user space thread.
2468 process
->ppid
= parent_pid
;
2469 process
->tgid
= tgid
;
2470 process
->name
= g_quark_from_string(command
);
2471 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2472 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2473 es
->t
= LTTV_STATE_USER_MODE
;
2474 /* Don't mess around with the stack, it will eventually become
2475 * ok after the end of state dump. */
2481 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2483 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2485 lttv_state_add_event_hooks(tss
);
2490 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2492 LttvTraceset
*traceset
= self
->parent
.ts
;
2494 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2498 LttvTracefileState
*tfs
;
2502 LttvTraceHookByFacility
*thf
;
2504 LttvTraceHook
*hook
;
2506 LttvAttributeValue val
;
2511 nb_trace
= lttv_traceset_number(traceset
);
2512 for(i
= 0 ; i
< nb_trace
; i
++) {
2513 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2515 /* Find the eventtype id for the following events and register the
2516 associated by id hooks. */
2518 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 18);
2519 hooks
= g_array_set_size(hooks
, 18); // Max possible number of hooks.
2522 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2523 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2524 LTT_FIELD_SYSCALL_ID
, 0, 0,
2525 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2528 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2529 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2531 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2534 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2535 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
2536 LTT_FIELD_TRAP_ID
, 0, 0,
2537 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2540 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2541 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
2543 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2546 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2547 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2548 LTT_FIELD_IRQ_ID
, 0, 0,
2549 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2552 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2553 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2555 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2558 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2559 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2560 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2561 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2564 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2565 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2567 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2570 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2571 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
2572 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
2573 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2576 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2577 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
2578 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
2579 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2582 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2583 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
2584 LTT_FIELD_PID
, 0, 0,
2585 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
2589 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2590 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
2591 LTT_FIELD_PID
, 0, 0,
2592 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2595 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2596 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
2597 LTT_FIELD_PID
, 0, 0,
2598 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2601 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2602 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2603 LTT_FIELD_FILENAME
, 0, 0,
2604 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2607 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2608 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
2609 LTT_FIELD_NAME
, 0, 0,
2610 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2613 /* statedump-related hooks */
2614 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2615 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2616 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2617 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2620 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2621 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2622 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2623 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2626 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2627 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2628 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2629 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2632 hooks
= g_array_set_size(hooks
, hn
);
2634 /* Add these hooks to each event_by_id hooks list */
2636 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2638 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2640 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2641 LttvTracefileContext
*, j
));
2643 for(k
= 0 ; k
< hooks
->len
; k
++) {
2644 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2645 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2646 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2648 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2655 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2656 *(val
.v_pointer
) = hooks
;
2660 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2662 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2664 lttv_state_remove_event_hooks(tss
);
2669 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2671 LttvTraceset
*traceset
= self
->parent
.ts
;
2673 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2677 LttvTracefileState
*tfs
;
2681 LttvTraceHook
*hook
;
2683 LttvTraceHookByFacility
*thf
;
2685 LttvAttributeValue val
;
2687 nb_trace
= lttv_traceset_number(traceset
);
2688 for(i
= 0 ; i
< nb_trace
; i
++) {
2689 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2691 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2692 hooks
= *(val
.v_pointer
);
2694 /* Remove these hooks from each event_by_id hooks list */
2696 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2698 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2700 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2701 LttvTracefileContext
*, j
));
2703 for(k
= 0 ; k
< hooks
->len
; k
++) {
2704 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2705 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2706 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2708 lttv_hooks_remove_data(
2709 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2715 for(k
= 0 ; k
< hooks
->len
; k
++)
2716 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2717 g_array_free(hooks
, TRUE
);
2721 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2723 guint
*event_count
= (guint
*)hook_data
;
2725 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2726 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2731 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2733 LttvTracefileState
*tfcs
;
2735 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2737 LttEventPosition
*ep
;
2743 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2745 LttvAttributeValue value
;
2747 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2748 LTTV_STATE_SAVED_STATES
);
2749 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2750 value
= lttv_attribute_add(saved_states_tree
,
2751 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2752 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2753 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2754 *(value
.v_time
) = self
->parent
.timestamp
;
2755 lttv_state_save(tcs
, saved_state_tree
);
2756 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2757 self
->parent
.timestamp
.tv_nsec
);
2759 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2764 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2766 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2768 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2773 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2781 static gboolean
block_start(void *hook_data
, void *call_data
)
2783 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2785 LttvTracefileState
*tfcs
;
2787 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2789 LttEventPosition
*ep
;
2791 guint i
, nb_block
, nb_event
, nb_tracefile
;
2795 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2797 LttvAttributeValue value
;
2799 ep
= ltt_event_position_new();
2801 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2803 /* Count the number of events added since the last block end in any
2806 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2808 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2809 LttvTracefileContext
, i
));
2810 ltt_event_position(tfcs
->parent
.e
, ep
);
2811 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2812 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2813 tfcs
->saved_position
= nb_event
;
2817 if(tcs
->nb_event
>= tcs
->save_interval
) {
2818 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2819 LTTV_STATE_SAVED_STATES
);
2820 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2821 value
= lttv_attribute_add(saved_states_tree
,
2822 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2823 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2824 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2825 *(value
.v_time
) = self
->parent
.timestamp
;
2826 lttv_state_save(tcs
, saved_state_tree
);
2828 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2829 self
->parent
.timestamp
.tv_nsec
);
2831 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2837 static gboolean
block_end(void *hook_data
, void *call_data
)
2839 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2841 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2845 LttEventPosition
*ep
;
2847 guint nb_block
, nb_event
;
2849 ep
= ltt_event_position_new();
2850 ltt_event_position(self
->parent
.e
, ep
);
2851 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2852 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2853 self
->saved_position
= 0;
2854 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2861 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2863 LttvTraceset
*traceset
= self
->parent
.ts
;
2865 guint i
, j
, nb_trace
, nb_tracefile
;
2869 LttvTracefileState
*tfs
;
2871 LttvTraceHook hook_start
, hook_end
;
2873 nb_trace
= lttv_traceset_number(traceset
);
2874 for(i
= 0 ; i
< nb_trace
; i
++) {
2875 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2877 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2878 NULL
, NULL
, block_start
, &hook_start
);
2879 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2880 NULL
, NULL
, block_end
, &hook_end
);
2882 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2884 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2886 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2887 LttvTracefileContext
, j
));
2888 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2889 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2890 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2891 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2897 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2899 LttvTraceset
*traceset
= self
->parent
.ts
;
2901 guint i
, j
, nb_trace
, nb_tracefile
;
2905 LttvTracefileState
*tfs
;
2908 nb_trace
= lttv_traceset_number(traceset
);
2909 for(i
= 0 ; i
< nb_trace
; i
++) {
2911 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2912 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2914 if(ts
->has_precomputed_states
) continue;
2916 guint
*event_count
= g_new(guint
, 1);
2919 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2921 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2922 LttvTracefileContext
*, j
));
2923 lttv_hooks_add(tfs
->parent
.event
,
2924 state_save_event_hook
,
2931 lttv_process_traceset_begin(&self
->parent
,
2932 NULL
, NULL
, NULL
, NULL
, NULL
);
2936 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2938 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2940 lttv_state_save_add_event_hooks(tss
);
2947 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2949 LttvTraceset
*traceset
= self
->parent
.ts
;
2951 guint i
, j
, nb_trace
, nb_tracefile
;
2955 LttvTracefileState
*tfs
;
2957 LttvTraceHook hook_start
, hook_end
;
2959 nb_trace
= lttv_traceset_number(traceset
);
2960 for(i
= 0 ; i
< nb_trace
; i
++) {
2961 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2963 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2964 NULL
, NULL
, block_start
, &hook_start
);
2966 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2967 NULL
, NULL
, block_end
, &hook_end
);
2969 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2971 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2973 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2974 LttvTracefileContext
, j
));
2975 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2976 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2977 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2978 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2984 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2986 LttvTraceset
*traceset
= self
->parent
.ts
;
2988 guint i
, j
, nb_trace
, nb_tracefile
;
2992 LttvTracefileState
*tfs
;
2994 LttvHooks
*after_trace
= lttv_hooks_new();
2996 lttv_hooks_add(after_trace
,
2997 state_save_after_trace_hook
,
3002 lttv_process_traceset_end(&self
->parent
,
3003 NULL
, after_trace
, NULL
, NULL
, NULL
);
3005 lttv_hooks_destroy(after_trace
);
3007 nb_trace
= lttv_traceset_number(traceset
);
3008 for(i
= 0 ; i
< nb_trace
; i
++) {
3010 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3011 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3013 if(ts
->has_precomputed_states
) continue;
3015 guint
*event_count
= NULL
;
3017 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3019 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3020 LttvTracefileContext
*, j
));
3021 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3022 state_save_event_hook
);
3024 if(event_count
) g_free(event_count
);
3028 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3030 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3032 lttv_state_save_remove_event_hooks(tss
);
3037 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3039 LttvTraceset
*traceset
= self
->parent
.ts
;
3043 int min_pos
, mid_pos
, max_pos
;
3045 guint call_rest
= 0;
3047 LttvTraceState
*tcs
;
3049 LttvAttributeValue value
;
3051 LttvAttributeType type
;
3053 LttvAttributeName name
;
3057 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3059 //g_tree_destroy(self->parent.pqueue);
3060 //self->parent.pqueue = g_tree_new(compare_tracefile);
3062 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3064 nb_trace
= lttv_traceset_number(traceset
);
3065 for(i
= 0 ; i
< nb_trace
; i
++) {
3066 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3068 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3069 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3070 LTTV_STATE_SAVED_STATES
);
3073 if(saved_states_tree
) {
3074 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3075 mid_pos
= max_pos
/ 2;
3076 while(min_pos
< max_pos
) {
3077 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3079 g_assert(type
== LTTV_GOBJECT
);
3080 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3081 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3083 g_assert(type
== LTTV_TIME
);
3084 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3086 closest_tree
= saved_state_tree
;
3088 else max_pos
= mid_pos
- 1;
3090 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3094 /* restore the closest earlier saved state */
3096 lttv_state_restore(tcs
, closest_tree
);
3100 /* There is no saved state, yet we want to have it. Restart at T0 */
3102 restore_init_state(tcs
);
3103 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3106 /* We want to seek quickly without restoring/updating the state */
3108 restore_init_state(tcs
);
3109 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3112 if(!call_rest
) g_info("NOT Calling restore");
3117 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3123 traceset_state_finalize (LttvTracesetState
*self
)
3125 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3126 finalize(G_OBJECT(self
));
3131 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3133 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3135 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3136 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3137 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3138 klass
->new_traceset_context
= new_traceset_context
;
3139 klass
->new_trace_context
= new_trace_context
;
3140 klass
->new_tracefile_context
= new_tracefile_context
;
3145 lttv_traceset_state_get_type(void)
3147 static GType type
= 0;
3149 static const GTypeInfo info
= {
3150 sizeof (LttvTracesetStateClass
),
3151 NULL
, /* base_init */
3152 NULL
, /* base_finalize */
3153 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3154 NULL
, /* class_finalize */
3155 NULL
, /* class_data */
3156 sizeof (LttvTracesetState
),
3157 0, /* n_preallocs */
3158 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3159 NULL
/* value handling */
3162 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3170 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3176 trace_state_finalize (LttvTraceState
*self
)
3178 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3179 finalize(G_OBJECT(self
));
3184 trace_state_class_init (LttvTraceStateClass
*klass
)
3186 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3188 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3189 klass
->state_save
= state_save
;
3190 klass
->state_restore
= state_restore
;
3191 klass
->state_saved_free
= state_saved_free
;
3196 lttv_trace_state_get_type(void)
3198 static GType type
= 0;
3200 static const GTypeInfo info
= {
3201 sizeof (LttvTraceStateClass
),
3202 NULL
, /* base_init */
3203 NULL
, /* base_finalize */
3204 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3205 NULL
, /* class_finalize */
3206 NULL
, /* class_data */
3207 sizeof (LttvTraceState
),
3208 0, /* n_preallocs */
3209 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3210 NULL
/* value handling */
3213 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3214 "LttvTraceStateType", &info
, 0);
3221 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3227 tracefile_state_finalize (LttvTracefileState
*self
)
3229 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3230 finalize(G_OBJECT(self
));
3235 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3237 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3239 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3244 lttv_tracefile_state_get_type(void)
3246 static GType type
= 0;
3248 static const GTypeInfo info
= {
3249 sizeof (LttvTracefileStateClass
),
3250 NULL
, /* base_init */
3251 NULL
, /* base_finalize */
3252 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3253 NULL
, /* class_finalize */
3254 NULL
, /* class_data */
3255 sizeof (LttvTracefileState
),
3256 0, /* n_preallocs */
3257 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3258 NULL
/* value handling */
3261 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3262 "LttvTracefileStateType", &info
, 0);
3268 static void module_init()
3270 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3271 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3272 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3273 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3274 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3275 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3276 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3277 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3278 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3279 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3280 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3281 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3282 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3283 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3284 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3285 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3286 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3287 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3288 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3289 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3290 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3291 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3292 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3293 LTTV_STATE_EVENT
= g_quark_from_string("event");
3294 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3295 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3296 LTTV_STATE_TIME
= g_quark_from_string("time");
3297 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3298 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3299 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3300 g_quark_from_string("trace_state_use_count");
3303 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3304 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3305 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
3306 LTT_FACILITY_FS
= g_quark_from_string("fs");
3307 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
3308 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3311 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3312 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3313 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3314 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3315 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3316 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3317 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3318 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3319 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
3320 LTT_EVENT_FORK
= g_quark_from_string("fork");
3321 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
3322 LTT_EVENT_EXIT
= g_quark_from_string("exit");
3323 LTT_EVENT_FREE
= g_quark_from_string("free");
3324 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3325 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
3326 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3327 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3328 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3331 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3332 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3333 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3334 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3335 LTT_FIELD_OUT
= g_quark_from_string("out");
3336 LTT_FIELD_IN
= g_quark_from_string("in");
3337 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
3338 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3339 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3340 LTT_FIELD_PID
= g_quark_from_string("pid");
3341 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3342 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3343 LTT_FIELD_NAME
= g_quark_from_string("name");
3344 LTT_FIELD_TYPE
= g_quark_from_string("type");
3345 LTT_FIELD_MODE
= g_quark_from_string("mode");
3346 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3347 LTT_FIELD_STATUS
= g_quark_from_string("status");
3348 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3349 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3353 static void module_destroy()
3358 LTTV_MODULE("state", "State computation", \
3359 "Update the system state, possibly saving it at intervals", \
3360 module_init
, module_destroy
)