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_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_SCHED_SCHEDULE
,
67 LTT_EVENT_PROCESS_FORK
,
68 LTT_EVENT_KTHREAD_CREATE
,
69 LTT_EVENT_PROCESS_EXIT
,
70 LTT_EVENT_PROCESS_FREE
,
72 LTT_EVENT_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
,
77 LTT_EVENT_REQUEST_ISSUE
,
78 LTT_EVENT_REQUEST_COMPLETE
;
86 LTT_FIELD_SOFT_IRQ_ID
,
108 LTTV_STATE_MODE_UNKNOWN
,
109 LTTV_STATE_USER_MODE
,
116 LTTV_STATE_SUBMODE_UNKNOWN
,
117 LTTV_STATE_SUBMODE_NONE
;
121 LTTV_STATE_WAIT_FORK
,
130 LTTV_STATE_UNBRANDED
;
133 LTTV_STATE_USER_THREAD
,
134 LTTV_STATE_KERNEL_THREAD
;
151 LTTV_BDEV_BUSY_READING
,
152 LTTV_BDEV_BUSY_WRITING
;
155 LTTV_STATE_TRACEFILES
,
156 LTTV_STATE_PROCESSES
,
158 LTTV_STATE_RUNNING_PROCESS
,
160 LTTV_STATE_SAVED_STATES
,
161 LTTV_STATE_SAVED_STATES_TIME
,
164 LTTV_STATE_NAME_TABLES
,
165 LTTV_STATE_TRACE_STATE_USE_COUNT
,
166 LTTV_STATE_RESOURCE_CPUS
,
167 LTTV_STATE_RESOURCE_IRQS
;
169 static void create_max_time(LttvTraceState
*tcs
);
171 static void get_max_time(LttvTraceState
*tcs
);
173 static void free_max_time(LttvTraceState
*tcs
);
175 static void create_name_tables(LttvTraceState
*tcs
);
177 static void get_name_tables(LttvTraceState
*tcs
);
179 static void free_name_tables(LttvTraceState
*tcs
);
181 static void free_saved_state(LttvTraceState
*tcs
);
183 static void lttv_state_free_process_table(GHashTable
*processes
);
185 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
186 GPtrArray
*quarktable
);
188 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
190 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
194 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
196 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
200 void lttv_state_state_saved_free(LttvTraceState
*self
,
201 LttvAttribute
*container
)
203 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
207 guint
process_hash(gconstpointer key
)
209 guint pid
= ((const LttvProcessState
*)key
)->pid
;
210 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
214 /* If the hash table hash function is well distributed,
215 * the process_equal should compare different pid */
216 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
218 const LttvProcessState
*process_a
, *process_b
;
221 process_a
= (const LttvProcessState
*)a
;
222 process_b
= (const LttvProcessState
*)b
;
224 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
225 else if(likely(process_a
->pid
== 0 &&
226 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
231 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
233 g_tree_destroy((GTree
*)value
);
236 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
238 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
239 g_hash_table_destroy(usertraces
);
245 restore_init_state(LttvTraceState
*self
)
247 guint i
, nb_cpus
, nb_irqs
;
249 LttvTracefileState
*tfcs
;
251 LttTime start_time
, end_time
;
253 /* Free the process tables */
254 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
255 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
256 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
257 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
260 /* Seek time to beginning */
261 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
262 // closest. It's the tracecontext job to seek the trace to the beginning
263 // anyway : the init state might be used at the middle of the trace as well...
264 //g_tree_destroy(self->parent.ts_context->pqueue);
265 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
267 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
269 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
271 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
272 nb_irqs
= self
->nb_irqs
;
274 /* Put the per cpu running_process to beginning state : process 0. */
275 for(i
=0; i
< nb_cpus
; i
++) {
276 LttvExecutionState
*es
;
277 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
278 LTTV_STATE_UNNAMED
, &start_time
);
279 /* We are not sure is it's a kernel thread or normal thread, put the
280 * bottom stack state to unknown */
281 self
->running_process
[i
]->execution_stack
=
282 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
283 es
= self
->running_process
[i
]->state
=
284 &g_array_index(self
->running_process
[i
]->execution_stack
,
285 LttvExecutionState
, 0);
286 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
287 es
->s
= LTTV_STATE_UNNAMED
;
289 //self->running_process[i]->state->s = LTTV_STATE_RUN;
290 self
->running_process
[i
]->cpu
= i
;
292 /* reset cpu states */
293 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
294 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
297 for(i
=0; i
<nb_irqs
; i
++) {
298 if(self
->irq_states
[i
].mode_stack
->len
> 0)
299 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
303 nb_tracefile
= self
->parent
.tracefiles
->len
;
305 for(i
= 0 ; i
< nb_tracefile
; i
++) {
307 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
308 LttvTracefileContext
*, i
));
309 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
310 // tfcs->saved_position = 0;
311 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
312 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
313 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
314 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
319 //static LttTime time_zero = {0,0};
321 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
324 const LttTime
*t1
= (const LttTime
*)a
;
325 const LttTime
*t2
= (const LttTime
*)b
;
327 return ltt_time_compare(*t1
, *t2
);
330 static void free_usertrace_key(gpointer data
)
335 #define MAX_STRING_LEN 4096
338 state_load_saved_states(LttvTraceState
*tcs
)
341 GPtrArray
*quarktable
;
346 tcs
->has_precomputed_states
= FALSE
;
350 gchar buf
[MAX_STRING_LEN
];
353 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
354 strncpy(path
, trace_path
, PATH_MAX
-1);
355 count
= strnlen(trace_path
, PATH_MAX
-1);
356 // quarktable : open, test
357 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
358 fp
= fopen(path
, "r");
360 quarktable
= g_ptr_array_sized_new(4096);
362 /* Index 0 is null */
364 if(hdr
== EOF
) return;
365 g_assert(hdr
== HDR_QUARKS
);
369 if(hdr
== EOF
) break;
370 g_assert(hdr
== HDR_QUARK
);
371 g_ptr_array_set_size(quarktable
, q
+1);
374 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
375 if(buf
[i
] == '\0' || feof(fp
)) break;
378 len
= strnlen(buf
, MAX_STRING_LEN
-1);
379 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
380 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
386 // saved_states : open, test
387 strncpy(path
, trace_path
, PATH_MAX
-1);
388 count
= strnlen(trace_path
, PATH_MAX
-1);
389 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
390 fp
= fopen(path
, "r");
394 if(hdr
!= HDR_TRACE
) goto end
;
396 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
398 tcs
->has_precomputed_states
= TRUE
;
403 /* Free the quarktable */
404 for(i
=0; i
<quarktable
->len
; i
++) {
405 string
= g_ptr_array_index (quarktable
, i
);
408 g_ptr_array_free(quarktable
, TRUE
);
413 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
415 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
418 LttvTraceContext
*tc
;
422 LttvTracefileState
*tfcs
;
424 LttvAttributeValue v
;
426 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
427 init((LttvTracesetContext
*)self
, ts
);
429 nb_trace
= lttv_traceset_number(ts
);
430 for(i
= 0 ; i
< nb_trace
; i
++) {
431 tc
= self
->parent
.traces
[i
];
432 tcs
= LTTV_TRACE_STATE(tc
);
433 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
434 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
438 if(*(v
.v_uint
) == 1) {
439 create_name_tables(tcs
);
440 create_max_time(tcs
);
442 get_name_tables(tcs
);
445 nb_tracefile
= tc
->tracefiles
->len
;
446 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
447 nb_irq
= tcs
->nb_irqs
;
448 tcs
->processes
= NULL
;
449 tcs
->usertraces
= NULL
;
450 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
452 /* init cpu resource stuff */
453 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
454 for(j
= 0; j
<nb_cpu
; j
++) {
455 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
456 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
459 /* init irq resource stuff */
460 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
461 for(j
= 0; j
<nb_irq
; j
++) {
462 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
463 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
466 /* init bdev resource stuff */
467 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
469 restore_init_state(tcs
);
470 for(j
= 0 ; j
< nb_tracefile
; j
++) {
472 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
473 LttvTracefileContext
*, j
));
474 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
475 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
476 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
477 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
478 /* It's a Usertrace */
479 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
480 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
482 if(!usertrace_tree
) {
483 usertrace_tree
= g_tree_new_full(compare_usertraces
,
484 NULL
, free_usertrace_key
, NULL
);
485 g_hash_table_insert(tcs
->usertraces
,
486 (gpointer
)tid
, usertrace_tree
);
488 LttTime
*timestamp
= g_new(LttTime
, 1);
489 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
490 ltt_tracefile_creation(tfcs
->parent
.tf
));
491 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
495 /* See if the trace has saved states */
496 state_load_saved_states(tcs
);
501 fini(LttvTracesetState
*self
)
507 LttvTracefileState
*tfcs
;
509 LttvAttributeValue v
;
511 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
512 for(i
= 0 ; i
< nb_trace
; i
++) {
513 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
514 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
517 g_assert(*(v
.v_uint
) != 0);
520 if(*(v
.v_uint
) == 0) {
521 free_name_tables(tcs
);
523 free_saved_state(tcs
);
525 g_free(tcs
->running_process
);
526 tcs
->running_process
= NULL
;
527 lttv_state_free_process_table(tcs
->processes
);
528 lttv_state_free_usertraces(tcs
->usertraces
);
529 tcs
->processes
= NULL
;
530 tcs
->usertraces
= NULL
;
532 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
533 fini((LttvTracesetContext
*)self
);
537 static LttvTracesetContext
*
538 new_traceset_context(LttvTracesetContext
*self
)
540 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
544 static LttvTraceContext
*
545 new_trace_context(LttvTracesetContext
*self
)
547 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
551 static LttvTracefileContext
*
552 new_tracefile_context(LttvTracesetContext
*self
)
554 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
558 /* Write the process state of the trace */
560 static void write_process_state(gpointer key
, gpointer value
,
563 LttvProcessState
*process
;
565 LttvExecutionState
*es
;
567 FILE *fp
= (FILE *)user_data
;
572 process
= (LttvProcessState
*)value
;
574 " <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",
575 process
, process
->pid
, process
->tgid
, process
->ppid
,
576 g_quark_to_string(process
->type
),
577 process
->creation_time
.tv_sec
,
578 process
->creation_time
.tv_nsec
,
579 process
->insertion_time
.tv_sec
,
580 process
->insertion_time
.tv_nsec
,
581 g_quark_to_string(process
->name
),
582 g_quark_to_string(process
->brand
),
585 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
586 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
587 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
588 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
589 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
590 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
591 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
594 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
595 address
= &g_array_index(process
->user_stack
, guint64
, i
);
596 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
600 if(process
->usertrace
) {
601 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
602 g_quark_to_string(process
->usertrace
->tracefile_name
),
603 process
->usertrace
->cpu
);
607 fprintf(fp
, " </PROCESS>\n");
611 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
613 guint i
, nb_tracefile
, nb_block
, offset
;
616 LttvTracefileState
*tfcs
;
620 LttEventPosition
*ep
;
624 ep
= ltt_event_position_new();
626 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
628 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
630 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
631 for(i
=0;i
<nb_cpus
;i
++) {
632 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
633 i
, self
->running_process
[i
]->pid
);
636 nb_tracefile
= self
->parent
.tracefiles
->len
;
638 for(i
= 0 ; i
< nb_tracefile
; i
++) {
640 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
641 LttvTracefileContext
*, i
));
642 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
643 tfcs
->parent
.timestamp
.tv_sec
,
644 tfcs
->parent
.timestamp
.tv_nsec
);
645 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
646 if(e
== NULL
) fprintf(fp
,"/>\n");
648 ltt_event_position(e
, ep
);
649 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
650 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
655 fprintf(fp
,"</PROCESS_STATE>\n");
659 static void write_process_state_raw(gpointer key
, gpointer value
,
662 LttvProcessState
*process
;
664 LttvExecutionState
*es
;
666 FILE *fp
= (FILE *)user_data
;
671 process
= (LttvProcessState
*)value
;
672 fputc(HDR_PROCESS
, fp
);
673 //fwrite(&header, sizeof(header), 1, fp);
674 //fprintf(fp, "%s", g_quark_to_string(process->type));
676 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
677 //fprintf(fp, "%s", g_quark_to_string(process->name));
679 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
680 //fprintf(fp, "%s", g_quark_to_string(process->brand));
682 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
683 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
684 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
685 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
686 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
687 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
688 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
692 " <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",
693 process
, process
->pid
, process
->tgid
, process
->ppid
,
694 g_quark_to_string(process
->type
),
695 process
->creation_time
.tv_sec
,
696 process
->creation_time
.tv_nsec
,
697 process
->insertion_time
.tv_sec
,
698 process
->insertion_time
.tv_nsec
,
699 g_quark_to_string(process
->name
),
700 g_quark_to_string(process
->brand
),
704 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
705 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
708 //fprintf(fp, "%s", g_quark_to_string(es->t));
710 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
711 //fprintf(fp, "%s", g_quark_to_string(es->n));
713 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
714 //fprintf(fp, "%s", g_quark_to_string(es->s));
716 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
717 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
718 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
719 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
721 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
722 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
723 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
724 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
725 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
729 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
730 address
= &g_array_index(process
->user_stack
, guint64
, i
);
731 fputc(HDR_USER_STACK
, fp
);
732 fwrite(&address
, sizeof(address
), 1, fp
);
734 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
739 if(process
->usertrace
) {
740 fputc(HDR_USERTRACE
, fp
);
741 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
743 fwrite(&process
->usertrace
->tracefile_name
,
744 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
745 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
747 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
748 g_quark_to_string(process
->usertrace
->tracefile_name
),
749 process
->usertrace
->cpu
);
756 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
758 guint i
, nb_tracefile
, nb_block
, offset
;
761 LttvTracefileState
*tfcs
;
765 LttEventPosition
*ep
;
769 ep
= ltt_event_position_new();
771 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
772 fputc(HDR_PROCESS_STATE
, fp
);
773 fwrite(&t
, sizeof(t
), 1, fp
);
775 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
777 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
778 for(i
=0;i
<nb_cpus
;i
++) {
780 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
781 fwrite(&self
->running_process
[i
]->pid
,
782 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
783 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
784 // i, self->running_process[i]->pid);
787 nb_tracefile
= self
->parent
.tracefiles
->len
;
789 for(i
= 0 ; i
< nb_tracefile
; i
++) {
791 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
792 LttvTracefileContext
*, i
));
793 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
794 // tfcs->parent.timestamp.tv_sec,
795 // tfcs->parent.timestamp.tv_nsec);
796 fputc(HDR_TRACEFILE
, fp
);
797 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
798 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
799 * position following : end of trace */
800 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
802 ltt_event_position(e
, ep
);
803 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
804 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
806 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
807 fwrite(&offset
, sizeof(offset
), 1, fp
);
808 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
815 /* Read process state from a file */
817 /* Called because a HDR_PROCESS was found */
818 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
819 GPtrArray
*quarktable
)
821 LttvExecutionState
*es
;
822 LttvProcessState
*process
, *parent_process
;
823 LttvProcessState tmp
;
830 /* TODO : check return value */
831 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
832 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
833 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
834 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
835 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
836 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
837 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
838 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
839 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
842 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
844 /* We must link to the parent */
845 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
847 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
848 if(process
== NULL
) {
849 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
851 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
855 process
->insertion_time
= tmp
.insertion_time
;
856 process
->creation_time
= tmp
.creation_time
;
857 process
->type
= g_quark_from_string(
858 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
859 process
->tgid
= tmp
.tgid
;
860 process
->ppid
= tmp
.ppid
;
861 process
->brand
= g_quark_from_string(
862 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
864 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
868 if(feof(fp
) || ferror(fp
)) goto end_loop
;
870 gint hdr
= fgetc(fp
);
871 if(hdr
== EOF
) goto end_loop
;
875 process
->execution_stack
=
876 g_array_set_size(process
->execution_stack
,
877 process
->execution_stack
->len
+ 1);
878 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
879 process
->execution_stack
->len
-1);
882 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
883 es
->t
= g_quark_from_string(
884 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
885 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
886 es
->n
= g_quark_from_string(
887 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
888 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
889 es
->s
= g_quark_from_string(
890 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
891 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
892 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
893 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
896 process
->user_stack
= g_array_set_size(process
->user_stack
,
897 process
->user_stack
->len
+ 1);
898 address
= &g_array_index(process
->user_stack
, guint64
,
899 process
->user_stack
->len
-1);
900 fread(address
, sizeof(address
), 1, fp
);
901 process
->current_function
= *address
;
904 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
905 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
917 /* Called because a HDR_PROCESS_STATE was found */
918 /* Append a saved state to the trace states */
919 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
921 guint i
, nb_tracefile
, nb_block
, offset
;
923 LttvTracefileState
*tfcs
;
925 LttEventPosition
*ep
;
933 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
935 LttvAttributeValue value
;
936 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
937 ep
= ltt_event_position_new();
939 restore_init_state(self
);
941 fread(&t
, sizeof(t
), 1, fp
);
944 if(feof(fp
) || ferror(fp
)) goto end_loop
;
946 if(hdr
== EOF
) goto end_loop
;
950 /* Call read_process_state_raw */
951 read_process_state_raw(self
, fp
, quarktable
);
961 case HDR_PROCESS_STATE
:
967 g_error("Error while parsing saved state file : unknown data header %d",
973 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
974 for(i
=0;i
<nb_cpus
;i
++) {
977 g_assert(hdr
== HDR_CPU
);
978 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
979 g_assert(i
== cpu_num
);
980 fread(&self
->running_process
[i
]->pid
,
981 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
984 nb_tracefile
= self
->parent
.tracefiles
->len
;
986 for(i
= 0 ; i
< nb_tracefile
; i
++) {
988 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
989 LttvTracefileContext
*, i
));
990 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
991 // tfcs->parent.timestamp.tv_sec,
992 // tfcs->parent.timestamp.tv_nsec);
993 g_tree_remove(pqueue
, &tfcs
->parent
);
995 g_assert(hdr
== HDR_TRACEFILE
);
996 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
997 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
998 * position following : end of trace */
999 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1000 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1001 fread(&offset
, sizeof(offset
), 1, fp
);
1002 fread(&tsc
, sizeof(tsc
), 1, fp
);
1003 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1004 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1006 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1011 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1012 LTTV_STATE_SAVED_STATES
);
1013 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1014 value
= lttv_attribute_add(saved_states_tree
,
1015 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1016 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1017 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1018 *(value
.v_time
) = t
;
1019 lttv_state_save(self
, saved_state_tree
);
1020 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1023 *(self
->max_time_state_recomputed_in_seek
) = t
;
1027 /* Called when a HDR_TRACE is found */
1028 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1029 GPtrArray
*quarktable
)
1034 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1036 if(hdr
== EOF
) goto end_loop
;
1039 case HDR_PROCESS_STATE
:
1040 /* Call read_process_state_raw */
1041 lttv_state_read_raw(tcs
, fp
, quarktable
);
1049 case HDR_USER_STACK
:
1053 g_error("Error while parsing saved state file :"
1054 " unexpected data header %d",
1058 g_error("Error while parsing saved state file : unknown data header %d",
1063 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1064 restore_init_state(tcs
);
1065 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1071 /* Copy each process from an existing hash table to a new one */
1073 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1075 LttvProcessState
*process
, *new_process
;
1077 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1081 process
= (LttvProcessState
*)value
;
1082 new_process
= g_new(LttvProcessState
, 1);
1083 *new_process
= *process
;
1084 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1085 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1086 new_process
->execution_stack
=
1087 g_array_set_size(new_process
->execution_stack
,
1088 process
->execution_stack
->len
);
1089 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1090 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1091 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1093 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1094 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1095 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1096 sizeof(guint64
), 0);
1097 new_process
->user_stack
=
1098 g_array_set_size(new_process
->user_stack
,
1099 process
->user_stack
->len
);
1100 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1101 g_array_index(new_process
->user_stack
, guint64
, i
) =
1102 g_array_index(process
->user_stack
, guint64
, i
);
1104 new_process
->current_function
= process
->current_function
;
1105 g_hash_table_insert(new_processes
, new_process
, new_process
);
1109 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1111 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1113 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1114 return new_processes
;
1117 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1120 LttvCPUState
*retval
;
1122 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1124 for(i
=0; i
<n
; i
++) {
1125 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1126 retval
[i
].last_irq
= states
[i
].last_irq
;
1127 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1128 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1129 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1136 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1140 for(i
=0; i
<n
; i
++) {
1141 g_array_free(states
[i
].mode_stack
, FALSE
);
1147 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1150 LttvIRQState
*retval
;
1152 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1154 for(i
=0; i
<n
; i
++) {
1155 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1156 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1157 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1158 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1165 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1169 for(i
=0; i
<n
; i
++) {
1170 g_array_free(states
[i
].mode_stack
, FALSE
);
1176 /* The saved state for each trace contains a member "processes", which
1177 stores a copy of the process table, and a member "tracefiles" with
1178 one entry per tracefile. Each tracefile has a "process" member pointing
1179 to the current process and a "position" member storing the tracefile
1180 position (needed to seek to the current "next" event. */
1182 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1184 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1186 LttvTracefileState
*tfcs
;
1188 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1190 guint
*running_process
;
1192 LttvAttributeType type
;
1194 LttvAttributeValue value
;
1196 LttvAttributeName name
;
1198 LttEventPosition
*ep
;
1200 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1201 LTTV_STATE_TRACEFILES
);
1203 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1205 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1207 /* Add the currently running processes array */
1208 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1209 running_process
= g_new(guint
, nb_cpus
);
1210 for(i
=0;i
<nb_cpus
;i
++) {
1211 running_process
[i
] = self
->running_process
[i
]->pid
;
1213 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1215 *(value
.v_pointer
) = running_process
;
1217 g_info("State save");
1219 nb_tracefile
= self
->parent
.tracefiles
->len
;
1221 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1223 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1224 LttvTracefileContext
*, i
));
1225 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1226 value
= lttv_attribute_add(tracefiles_tree
, i
,
1228 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1230 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1232 *(value
.v_uint
) = tfcs
->process
->pid
;
1234 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1236 /* Only save the position if the tfs has not infinite time. */
1237 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1238 // && current_tfcs != tfcs) {
1239 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1240 *(value
.v_pointer
) = NULL
;
1242 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1243 ep
= ltt_event_position_new();
1244 ltt_event_position(e
, ep
);
1245 *(value
.v_pointer
) = ep
;
1247 guint nb_block
, offset
;
1250 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1251 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1253 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1257 /* save the cpu state */
1259 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1260 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1262 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1265 /* save the irq state */
1266 nb_irqs
= self
->nb_irqs
;
1268 guint size
= sizeof(LttvCPUState
)*nb_irqs
;
1269 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1271 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1276 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1278 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1280 LttvTracefileState
*tfcs
;
1282 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1284 guint
*running_process
;
1286 LttvAttributeType type
;
1288 LttvAttributeValue value
;
1290 LttvAttributeName name
;
1294 LttEventPosition
*ep
;
1296 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1298 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1299 LTTV_STATE_TRACEFILES
);
1301 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1303 g_assert(type
== LTTV_POINTER
);
1304 lttv_state_free_process_table(self
->processes
);
1305 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1307 /* Add the currently running processes array */
1308 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1309 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1311 g_assert(type
== LTTV_POINTER
);
1312 running_process
= *(value
.v_pointer
);
1313 for(i
=0;i
<nb_cpus
;i
++) {
1314 pid
= running_process
[i
];
1315 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1316 g_assert(self
->running_process
[i
] != NULL
);
1319 nb_tracefile
= self
->parent
.tracefiles
->len
;
1321 //g_tree_destroy(tsc->pqueue);
1322 //tsc->pqueue = g_tree_new(compare_tracefile);
1324 /* restore cpu resource states */
1325 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1326 g_assert(type
== LTTV_POINTER
);
1327 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1328 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1330 /* restore irq resource states */
1331 nb_irqs
= self
->nb_irqs
;
1332 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1333 g_assert(type
== LTTV_POINTER
);
1334 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1335 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1337 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1339 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1340 LttvTracefileContext
*, i
));
1341 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1342 g_assert(type
== LTTV_GOBJECT
);
1343 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1345 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1347 g_assert(type
== LTTV_UINT
);
1348 pid
= *(value
.v_uint
);
1349 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1351 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1353 g_assert(type
== LTTV_POINTER
);
1354 //g_assert(*(value.v_pointer) != NULL);
1355 ep
= *(value
.v_pointer
);
1356 g_assert(tfcs
->parent
.t_context
!= NULL
);
1358 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1360 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1361 g_tree_remove(tsc
->pqueue
, tfc
);
1364 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1365 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1366 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1367 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1368 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1370 tfc
->timestamp
= ltt_time_infinite
;
1376 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1378 guint i
, nb_tracefile
, nb_cpus
;
1380 LttvTracefileState
*tfcs
;
1382 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1384 guint
*running_process
;
1386 LttvAttributeType type
;
1388 LttvAttributeValue value
;
1390 LttvAttributeName name
;
1394 LttEventPosition
*ep
;
1396 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1397 LTTV_STATE_TRACEFILES
);
1398 g_object_ref(G_OBJECT(tracefiles_tree
));
1399 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1401 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1403 g_assert(type
== LTTV_POINTER
);
1404 lttv_state_free_process_table(*(value
.v_pointer
));
1405 *(value
.v_pointer
) = NULL
;
1406 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1408 /* Free running processes array */
1409 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1410 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1412 g_assert(type
== LTTV_POINTER
);
1413 running_process
= *(value
.v_pointer
);
1414 g_free(running_process
);
1416 nb_tracefile
= self
->parent
.tracefiles
->len
;
1418 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1420 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1421 LttvTracefileContext
*, i
));
1422 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1423 g_assert(type
== LTTV_GOBJECT
);
1424 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1426 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1428 g_assert(type
== LTTV_POINTER
);
1429 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1431 g_object_unref(G_OBJECT(tracefiles_tree
));
1435 static void free_saved_state(LttvTraceState
*self
)
1439 LttvAttributeType type
;
1441 LttvAttributeValue value
;
1443 LttvAttributeName name
;
1447 LttvAttribute
*saved_states
;
1449 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1450 LTTV_STATE_SAVED_STATES
);
1452 nb
= lttv_attribute_get_number(saved_states
);
1453 for(i
= 0 ; i
< nb
; i
++) {
1454 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1455 g_assert(type
== LTTV_GOBJECT
);
1456 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1459 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1464 create_max_time(LttvTraceState
*tcs
)
1466 LttvAttributeValue v
;
1468 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1470 g_assert(*(v
.v_pointer
) == NULL
);
1471 *(v
.v_pointer
) = g_new(LttTime
,1);
1472 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1477 get_max_time(LttvTraceState
*tcs
)
1479 LttvAttributeValue v
;
1481 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1483 g_assert(*(v
.v_pointer
) != NULL
);
1484 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1489 free_max_time(LttvTraceState
*tcs
)
1491 LttvAttributeValue v
;
1493 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1495 g_free(*(v
.v_pointer
));
1496 *(v
.v_pointer
) = NULL
;
1500 typedef struct _LttvNameTables
{
1501 // FIXME GQuark *eventtype_names;
1502 GQuark
*syscall_names
;
1508 GQuark
*soft_irq_names
;
1514 create_name_tables(LttvTraceState
*tcs
)
1518 GQuark f_name
, e_name
;
1522 LttvTraceHookByFacility
*thf
;
1528 GString
*fe_name
= g_string_new("");
1530 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1532 LttvAttributeValue v
;
1534 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1536 g_assert(*(v
.v_pointer
) == NULL
);
1537 *(v
.v_pointer
) = name_tables
;
1538 #if 0 // Use iteration over the facilities_by_name and then list all event
1539 // types of each facility
1540 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1541 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1542 for(i
= 0 ; i
< nb
; i
++) {
1543 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1544 e_name
= ltt_eventtype_name(et
);
1545 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1546 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1547 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1550 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1551 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1552 LTT_FIELD_SYSCALL_ID
, 0, 0,
1555 thf
= lttv_trace_hook_get_first(&h
);
1557 t
= ltt_field_type(thf
->f1
);
1558 nb
= ltt_type_element_number(t
);
1560 lttv_trace_hook_destroy(&h
);
1562 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1563 name_tables
->nb_syscalls
= nb
;
1565 for(i
= 0 ; i
< nb
; i
++) {
1566 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1567 if(!name_tables
->syscall_names
[i
]) {
1568 GString
*string
= g_string_new("");
1569 g_string_printf(string
, "syscall %u", i
);
1570 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1571 g_string_free(string
, TRUE
);
1575 //name_tables->syscall_names = g_new(GQuark, 256);
1576 //for(i = 0 ; i < 256 ; i++) {
1577 // g_string_printf(fe_name, "syscall %d", i);
1578 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1581 name_tables
->syscall_names
= NULL
;
1582 name_tables
->nb_syscalls
= 0;
1585 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1586 LTT_EVENT_TRAP_ENTRY
,
1587 LTT_FIELD_TRAP_ID
, 0, 0,
1590 thf
= lttv_trace_hook_get_first(&h
);
1592 t
= ltt_field_type(thf
->f1
);
1593 //nb = ltt_type_element_number(t);
1595 lttv_trace_hook_destroy(&h
);
1598 name_tables->trap_names = g_new(GQuark, nb);
1599 for(i = 0 ; i < nb ; i++) {
1600 name_tables->trap_names[i] = g_quark_from_string(
1601 ltt_enum_string_get(t, i));
1604 name_tables
->nb_traps
= 256;
1605 name_tables
->trap_names
= g_new(GQuark
, 256);
1606 for(i
= 0 ; i
< 256 ; i
++) {
1607 g_string_printf(fe_name
, "trap %d", i
);
1608 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1611 name_tables
->trap_names
= NULL
;
1612 name_tables
->nb_traps
= 0;
1615 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1616 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1617 LTT_FIELD_IRQ_ID
, 0, 0,
1620 thf
= lttv_trace_hook_get_first(&h
);
1622 t
= ltt_field_type(thf
->f1
);
1623 //nb = ltt_type_element_number(t);
1625 lttv_trace_hook_destroy(&h
);
1628 name_tables->irq_names = g_new(GQuark, nb);
1629 for(i = 0 ; i < nb ; i++) {
1630 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1634 name_tables
->nb_irqs
= 256;
1635 name_tables
->irq_names
= g_new(GQuark
, 256);
1636 for(i
= 0 ; i
< 256 ; i
++) {
1637 g_string_printf(fe_name
, "irq %d", i
);
1638 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1641 name_tables
->nb_irqs
= 0;
1642 name_tables
->irq_names
= NULL
;
1645 name_tables->soft_irq_names = g_new(GQuark, nb);
1646 for(i = 0 ; i < nb ; i++) {
1647 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1651 name_tables
->nb_softirqs
= 256;
1652 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1653 for(i
= 0 ; i
< 256 ; i
++) {
1654 g_string_printf(fe_name
, "softirq %d", i
);
1655 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1659 g_string_free(fe_name
, TRUE
);
1664 get_name_tables(LttvTraceState
*tcs
)
1666 LttvNameTables
*name_tables
;
1668 LttvAttributeValue v
;
1670 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1672 g_assert(*(v
.v_pointer
) != NULL
);
1673 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1674 //tcs->eventtype_names = name_tables->eventtype_names;
1675 tcs
->syscall_names
= name_tables
->syscall_names
;
1676 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1677 tcs
->trap_names
= name_tables
->trap_names
;
1678 tcs
->nb_traps
= name_tables
->nb_traps
;
1679 tcs
->irq_names
= name_tables
->irq_names
;
1680 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1681 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1682 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1687 free_name_tables(LttvTraceState
*tcs
)
1689 LttvNameTables
*name_tables
;
1691 LttvAttributeValue v
;
1693 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1695 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1696 *(v
.v_pointer
) = NULL
;
1698 // g_free(name_tables->eventtype_names);
1699 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1700 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1701 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1702 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1703 if(name_tables
) g_free(name_tables
);
1706 #ifdef HASH_TABLE_DEBUG
1708 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1710 LttvProcessState
*process
= (LttvProcessState
*)value
;
1712 /* Test for process corruption */
1713 guint stack_len
= process
->execution_stack
->len
;
1716 static void hash_table_check(GHashTable
*table
)
1718 g_hash_table_foreach(table
, test_process
, NULL
);
1724 /* clears the stack and sets the state passed as argument */
1725 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1727 g_array_set_size(cpust
->mode_stack
, 1);
1728 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1731 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1733 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1734 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1737 static void cpu_pop_mode(LttvCPUState
*cpust
)
1739 if(cpust
->mode_stack
->len
== 1)
1740 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1742 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1745 /* clears the stack and sets the state passed as argument */
1746 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1748 g_array_set_size(bdevst
->mode_stack
, 1);
1749 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1752 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1754 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1755 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1758 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1760 if(bdevst
->mode_stack
->len
== 1)
1761 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1763 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1766 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1768 g_array_set_size(irqst
->mode_stack
, 1);
1769 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1772 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1774 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1775 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1778 static void irq_pop_mode(LttvIRQState
*irqst
)
1780 if(irqst
->mode_stack
->len
== 1)
1781 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1783 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1786 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1789 LttvExecutionState
*es
;
1791 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1792 guint cpu
= tfs
->cpu
;
1794 #ifdef HASH_TABLE_DEBUG
1795 hash_table_check(ts
->processes
);
1797 LttvProcessState
*process
= ts
->running_process
[cpu
];
1799 guint depth
= process
->execution_stack
->len
;
1801 process
->execution_stack
=
1802 g_array_set_size(process
->execution_stack
, depth
+ 1);
1805 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1807 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1810 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1811 es
->cum_cpu_time
= ltt_time_zero
;
1812 es
->s
= process
->state
->s
;
1813 process
->state
= es
;
1817 * return 1 when empty, else 0 */
1818 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1819 LttvTracefileState
*tfs
)
1821 guint cpu
= tfs
->cpu
;
1822 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1824 guint depth
= process
->execution_stack
->len
;
1830 process
->execution_stack
=
1831 g_array_set_size(process
->execution_stack
, depth
- 1);
1832 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1834 process
->state
->change
= tfs
->parent
.timestamp
;
1839 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1841 guint cpu
= tfs
->cpu
;
1842 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1843 LttvProcessState
*process
= ts
->running_process
[cpu
];
1845 guint depth
= process
->execution_stack
->len
;
1847 if(process
->state
->t
!= t
){
1848 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1849 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1850 g_info("process state has %s when pop_int is %s\n",
1851 g_quark_to_string(process
->state
->t
),
1852 g_quark_to_string(t
));
1853 g_info("{ %u, %u, %s, %s, %s }\n",
1856 g_quark_to_string(process
->name
),
1857 g_quark_to_string(process
->brand
),
1858 g_quark_to_string(process
->state
->s
));
1863 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1864 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1868 process
->execution_stack
=
1869 g_array_set_size(process
->execution_stack
, depth
- 1);
1870 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1872 process
->state
->change
= tfs
->parent
.timestamp
;
1875 struct search_result
{
1876 const LttTime
*time
; /* Requested time */
1877 LttTime
*best
; /* Best result */
1880 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1882 const LttTime
*elem_time
= (const LttTime
*)a
;
1883 /* Explicit non const cast */
1884 struct search_result
*res
= (struct search_result
*)b
;
1886 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1887 /* The usertrace was created before the schedchange */
1888 /* Get larger keys */
1890 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1891 /* The usertrace was created after the schedchange time */
1892 /* Get smaller keys */
1894 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1895 res
->best
= elem_time
;
1898 res
->best
= elem_time
;
1905 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1906 guint pid
, const LttTime
*timestamp
)
1908 LttvTracefileState
*tfs
= NULL
;
1909 struct search_result res
;
1910 /* Find the usertrace associated with a pid and time interval.
1911 * Search in the usertraces by PID (within a hash) and then, for each
1912 * corresponding element of the array, find the first one with creation
1913 * timestamp the lowest, but higher or equal to "timestamp". */
1914 res
.time
= timestamp
;
1916 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1917 if(usertrace_tree
) {
1918 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1920 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1928 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1929 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1931 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1933 LttvExecutionState
*es
;
1935 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1940 process
->tgid
= tgid
;
1942 process
->name
= name
;
1943 process
->brand
= LTTV_STATE_UNBRANDED
;
1944 //process->last_cpu = tfs->cpu_name;
1945 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1946 process
->type
= LTTV_STATE_USER_THREAD
;
1947 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1948 process
->current_function
= 0; //function 0x0 by default.
1950 g_info("Process %u, core %p", process
->pid
, process
);
1951 g_hash_table_insert(tcs
->processes
, process
, process
);
1954 process
->ppid
= parent
->pid
;
1955 process
->creation_time
= *timestamp
;
1958 /* No parent. This process exists but we are missing all information about
1959 its creation. The birth time is set to zero but we remember the time of
1964 process
->creation_time
= ltt_time_zero
;
1967 process
->insertion_time
= *timestamp
;
1968 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1969 process
->creation_time
.tv_nsec
);
1970 process
->pid_time
= g_quark_from_string(buffer
);
1972 //process->last_cpu = tfs->cpu_name;
1973 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1974 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1975 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1976 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1977 es
= process
->state
= &g_array_index(process
->execution_stack
,
1978 LttvExecutionState
, 0);
1979 es
->t
= LTTV_STATE_USER_MODE
;
1980 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1981 es
->entry
= *timestamp
;
1982 //g_assert(timestamp->tv_sec != 0);
1983 es
->change
= *timestamp
;
1984 es
->cum_cpu_time
= ltt_time_zero
;
1985 es
->s
= LTTV_STATE_RUN
;
1987 es
= process
->state
= &g_array_index(process
->execution_stack
,
1988 LttvExecutionState
, 1);
1989 es
->t
= LTTV_STATE_SYSCALL
;
1990 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1991 es
->entry
= *timestamp
;
1992 //g_assert(timestamp->tv_sec != 0);
1993 es
->change
= *timestamp
;
1994 es
->cum_cpu_time
= ltt_time_zero
;
1995 es
->s
= LTTV_STATE_WAIT_FORK
;
1997 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1998 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1999 sizeof(guint64
), 0);
2004 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2007 LttvProcessState key
;
2008 LttvProcessState
*process
;
2012 process
= g_hash_table_lookup(ts
->processes
, &key
);
2017 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2018 const LttTime
*timestamp
)
2020 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2021 LttvExecutionState
*es
;
2023 /* Put ltt_time_zero creation time for unexisting processes */
2024 if(unlikely(process
== NULL
)) {
2025 process
= lttv_state_create_process(ts
,
2026 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2027 /* We are not sure is it's a kernel thread or normal thread, put the
2028 * bottom stack state to unknown */
2029 process
->execution_stack
=
2030 g_array_set_size(process
->execution_stack
, 1);
2031 process
->state
= es
=
2032 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2033 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2034 es
->s
= LTTV_STATE_UNNAMED
;
2039 /* FIXME : this function should be called when we receive an event telling that
2040 * release_task has been called in the kernel. In happens generally when
2041 * the parent waits for its child terminaison, but may also happen in special
2042 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2043 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2044 * of a killed thread ground, but isn't the leader.
2046 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2048 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2049 LttvProcessState key
;
2051 key
.pid
= process
->pid
;
2052 key
.cpu
= process
->cpu
;
2053 g_hash_table_remove(ts
->processes
, &key
);
2054 g_array_free(process
->execution_stack
, TRUE
);
2055 g_array_free(process
->user_stack
, TRUE
);
2060 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2062 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2063 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2068 static void lttv_state_free_process_table(GHashTable
*processes
)
2070 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2071 g_hash_table_destroy(processes
);
2075 static gboolean
syscall_entry(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 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2082 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2083 LttField
*f
= thf
->f1
;
2085 LttvExecutionSubmode submode
;
2087 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2088 guint syscall
= ltt_event_get_unsigned(e
, f
);
2090 if(syscall
< nb_syscalls
) {
2091 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2094 /* Fixup an incomplete syscall table */
2095 GString
*string
= g_string_new("");
2096 g_string_printf(string
, "syscall %u", syscall
);
2097 submode
= g_quark_from_string(string
->str
);
2098 g_string_free(string
, TRUE
);
2100 /* There can be no system call from PID 0 : unknown state */
2101 if(process
->pid
!= 0)
2102 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2107 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2109 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2111 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2112 LttvProcessState
*process
= ts
->running_process
[cpu
];
2114 /* There can be no system call from PID 0 : unknown state */
2115 if(process
->pid
!= 0)
2116 pop_state(s
, LTTV_STATE_SYSCALL
);
2121 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2123 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2124 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2125 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2126 LttField
*f
= thf
->f1
;
2128 LttvExecutionSubmode submode
;
2130 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2131 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2133 if(trap
< nb_traps
) {
2134 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2136 /* Fixup an incomplete trap table */
2137 GString
*string
= g_string_new("");
2138 g_string_printf(string
, "trap %llu", trap
);
2139 submode
= g_quark_from_string(string
->str
);
2140 g_string_free(string
, TRUE
);
2143 push_state(s
, LTTV_STATE_TRAP
, submode
);
2145 /* update cpu status */
2146 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2151 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2153 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2155 pop_state(s
, LTTV_STATE_TRAP
);
2157 /* update cpu status */
2158 cpu_pop_mode(s
->cpu_state
);
2163 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2165 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2166 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2167 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2168 guint8 fac_id
= ltt_event_facility_id(e
);
2169 guint8 ev_id
= ltt_event_eventtype_id(e
);
2170 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2171 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2172 g_assert(thf
->f1
!= NULL
);
2173 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2174 LttField
*f
= thf
->f1
;
2176 LttvExecutionSubmode submode
;
2177 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2178 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2182 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2184 /* Fixup an incomplete irq table */
2185 GString
*string
= g_string_new("");
2186 g_string_printf(string
, "irq %llu", irq
);
2187 submode
= g_quark_from_string(string
->str
);
2188 g_string_free(string
, TRUE
);
2191 /* Do something with the info about being in user or system mode when int? */
2192 push_state(s
, LTTV_STATE_IRQ
, submode
);
2194 /* update cpu status */
2195 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2197 /* update irq status */
2198 s
->cpu_state
->last_irq
= irq
;
2199 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2204 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2206 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2208 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2214 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2216 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2217 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2219 pop_state(s
, LTTV_STATE_IRQ
);
2221 /* update cpu status */
2222 cpu_pop_mode(s
->cpu_state
);
2224 /* update irq status */
2225 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2230 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2232 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2233 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2234 guint8 fac_id
= ltt_event_facility_id(e
);
2235 guint8 ev_id
= ltt_event_eventtype_id(e
);
2236 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2237 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2238 g_assert(thf
->f1
!= NULL
);
2239 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2240 LttField
*f
= thf
->f1
;
2242 LttvExecutionSubmode submode
;
2243 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2244 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2247 if(softirq
< nb_softirqs
) {
2248 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2250 /* Fixup an incomplete irq table */
2251 GString
*string
= g_string_new("");
2252 g_string_printf(string
, "softirq %llu", softirq
);
2253 submode
= g_quark_from_string(string
->str
);
2254 g_string_free(string
, TRUE
);
2257 /* Do something with the info about being in user or system mode when int? */
2258 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2262 LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
)
2264 gint devcode_gint
= devcode
;
2265 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2267 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
2268 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
2270 gint
* key
= g_malloc(sizeof(gint
));
2272 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
2273 printf("adding key %u to hash table\n", *key
);
2281 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2283 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2284 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2285 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2286 guint8 fac_id
= ltt_event_facility_id(e
);
2287 guint8 ev_id
= ltt_event_eventtype_id(e
);
2288 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2290 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2291 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2292 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2293 guint16 devcode
= MKDEV(major
,minor
);
2295 /* have we seen this block device before? */
2296 gpointer bdev
= bdev_state_get(ts
, devcode
);
2299 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2301 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2306 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2308 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2309 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2310 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2311 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2313 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2314 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2315 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2316 guint16 devcode
= MKDEV(major
,minor
);
2318 /* have we seen this block device before? */
2319 gpointer bdev
= bdev_state_get(ts
, devcode
);
2321 /* update block device */
2322 bdev_pop_mode(bdev
);
2327 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2331 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2332 guint cpu
= tfs
->cpu
;
2333 LttvProcessState
*process
= ts
->running_process
[cpu
];
2335 guint depth
= process
->user_stack
->len
;
2337 process
->user_stack
=
2338 g_array_set_size(process
->user_stack
, depth
+ 1);
2340 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2341 *new_func
= funcptr
;
2342 process
->current_function
= funcptr
;
2345 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2347 guint cpu
= tfs
->cpu
;
2348 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2349 LttvProcessState
*process
= ts
->running_process
[cpu
];
2351 if(process
->current_function
!= funcptr
){
2352 g_info("Different functions (%lu.%09lu): ignore it\n",
2353 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2354 g_info("process state has %llu when pop_function is %llu\n",
2355 process
->current_function
, funcptr
);
2356 g_info("{ %u, %u, %s, %s, %s }\n",
2359 g_quark_to_string(process
->name
),
2360 g_quark_to_string(process
->brand
),
2361 g_quark_to_string(process
->state
->s
));
2364 guint depth
= process
->user_stack
->len
;
2367 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2368 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2372 process
->user_stack
=
2373 g_array_set_size(process
->user_stack
, depth
- 1);
2374 process
->current_function
=
2375 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2379 static gboolean
function_entry(void *hook_data
, void *call_data
)
2381 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2382 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2383 guint8 fac_id
= ltt_event_facility_id(e
);
2384 guint8 ev_id
= ltt_event_eventtype_id(e
);
2385 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2386 g_assert(thf
->f1
!= NULL
);
2387 LttField
*f
= thf
->f1
;
2388 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2390 push_function(s
, funcptr
);
2394 static gboolean
function_exit(void *hook_data
, void *call_data
)
2396 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2397 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2398 guint8 fac_id
= ltt_event_facility_id(e
);
2399 guint8 ev_id
= ltt_event_eventtype_id(e
);
2400 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2401 g_assert(thf
->f1
!= NULL
);
2402 LttField
*f
= thf
->f1
;
2403 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2405 LttvExecutionSubmode submode
;
2407 pop_function(s
, funcptr
);
2411 static gboolean
schedchange(void *hook_data
, void *call_data
)
2413 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2415 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2416 LttvProcessState
*process
= ts
->running_process
[cpu
];
2417 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2419 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2420 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2421 guint pid_in
, pid_out
;
2424 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2425 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2426 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2428 if(likely(process
!= NULL
)) {
2430 /* We could not know but it was not the idle process executing.
2431 This should only happen at the beginning, before the first schedule
2432 event, and when the initial information (current process for each CPU)
2433 is missing. It is not obvious how we could, after the fact, compensate
2434 the wrongly attributed statistics. */
2436 //This test only makes sense once the state is known and if there is no
2437 //missing events. We need to silently ignore schedchange coming after a
2438 //process_free, or it causes glitches. (FIXME)
2439 //if(unlikely(process->pid != pid_out)) {
2440 // g_assert(process->pid == 0);
2442 if(process
->pid
== 0
2443 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2445 /* Scheduling out of pid 0 at beginning of the trace :
2446 * we know for sure it is in syscall mode at this point. */
2447 g_assert(process
->execution_stack
->len
== 1);
2448 process
->state
->t
= LTTV_STATE_SYSCALL
;
2449 process
->state
->s
= LTTV_STATE_WAIT
;
2450 process
->state
->change
= s
->parent
.timestamp
;
2451 process
->state
->entry
= s
->parent
.timestamp
;
2454 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2455 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2456 process
->state
->change
= s
->parent
.timestamp
;
2458 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2459 else process
->state
->s
= LTTV_STATE_WAIT
;
2460 process
->state
->change
= s
->parent
.timestamp
;
2463 if(state_out
== 32 || state_out
== 128)
2464 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2465 /* see sched.h for states */
2468 process
= ts
->running_process
[cpu
] =
2469 lttv_state_find_process_or_create(
2470 (LttvTraceState
*)s
->parent
.t_context
,
2472 &s
->parent
.timestamp
);
2473 process
->state
->s
= LTTV_STATE_RUN
;
2475 if(process
->usertrace
)
2476 process
->usertrace
->cpu
= cpu
;
2477 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2478 process
->state
->change
= s
->parent
.timestamp
;
2480 /* update cpu status */
2482 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2484 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2489 static gboolean
process_fork(void *hook_data
, void *call_data
)
2491 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2492 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2493 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2495 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2496 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2497 LttvProcessState
*zombie_process
;
2499 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2500 LttvProcessState
*process
= ts
->running_process
[cpu
];
2501 LttvProcessState
*child_process
;
2504 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2507 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2508 s
->parent
.target_pid
= child_pid
;
2511 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2512 else child_tgid
= 0;
2514 /* Mathieu : it seems like the process might have been scheduled in before the
2515 * fork, and, in a rare case, might be the current process. This might happen
2516 * in a SMP case where we don't have enough precision on the clocks.
2518 * Test reenabled after precision fixes on time. (Mathieu) */
2520 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2522 if(unlikely(zombie_process
!= NULL
)) {
2523 /* Reutilisation of PID. Only now we are sure that the old PID
2524 * has been released. FIXME : should know when release_task happens instead.
2526 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2528 for(i
=0; i
< num_cpus
; i
++) {
2529 g_assert(zombie_process
!= ts
->running_process
[i
]);
2532 exit_process(s
, zombie_process
);
2535 g_assert(process
->pid
!= child_pid
);
2536 // FIXME : Add this test in the "known state" section
2537 // g_assert(process->pid == parent_pid);
2538 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2539 if(child_process
== NULL
) {
2540 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2541 child_pid
, child_tgid
,
2542 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2544 /* The process has already been created : due to time imprecision between
2545 * multiple CPUs : it has been scheduled in before creation. Note that we
2546 * shouldn't have this kind of imprecision.
2548 * Simply put a correct parent.
2550 g_assert(0); /* This is a problematic case : the process has been created
2551 before the fork event */
2552 child_process
->ppid
= process
->pid
;
2553 child_process
->tgid
= child_tgid
;
2555 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2556 child_process
->name
= process
->name
;
2557 child_process
->brand
= process
->brand
;
2562 /* We stamp a newly created process as kernel_thread.
2563 * The thread should not be running yet. */
2564 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2566 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2567 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2568 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2571 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2572 LttvProcessState
*process
;
2573 LttvExecutionState
*es
;
2576 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2577 s
->parent
.target_pid
= pid
;
2579 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2581 process
->execution_stack
=
2582 g_array_set_size(process
->execution_stack
, 1);
2583 es
= process
->state
=
2584 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2585 es
->t
= LTTV_STATE_SYSCALL
;
2586 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2591 static gboolean
process_exit(void *hook_data
, void *call_data
)
2593 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2594 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2595 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2599 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2600 LttvProcessState
*process
; // = ts->running_process[cpu];
2602 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2603 s
->parent
.target_pid
= pid
;
2605 // FIXME : Add this test in the "known state" section
2606 // g_assert(process->pid == pid);
2608 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2609 if(likely(process
!= NULL
)) {
2610 process
->state
->s
= LTTV_STATE_EXIT
;
2615 static gboolean
process_free(void *hook_data
, void *call_data
)
2617 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2618 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2619 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2620 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2622 LttvProcessState
*process
;
2624 /* PID of the process to release */
2625 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2626 s
->parent
.target_pid
= release_pid
;
2628 g_assert(release_pid
!= 0);
2630 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2632 if(likely(process
!= NULL
)) {
2633 /* release_task is happening at kernel level : we can now safely release
2634 * the data structure of the process */
2635 //This test is fun, though, as it may happen that
2636 //at time t : CPU 0 : process_free
2637 //at time t+150ns : CPU 1 : schedule out
2638 //Clearly due to time imprecision, we disable it. (Mathieu)
2639 //If this weird case happen, we have no choice but to put the
2640 //Currently running process on the cpu to 0.
2641 //I re-enable it following time precision fixes. (Mathieu)
2642 //Well, in the case where an process is freed by a process on another CPU
2643 //and still scheduled, it happens that this is the schedchange that will
2644 //drop the last reference count. Do not free it here!
2645 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2647 for(i
=0; i
< num_cpus
; i
++) {
2648 //g_assert(process != ts->running_process[i]);
2649 if(process
== ts
->running_process
[i
]) {
2650 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2654 if(i
== num_cpus
) /* process is not scheduled */
2655 exit_process(s
, process
);
2662 static gboolean
process_exec(void *hook_data
, void *call_data
)
2664 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2665 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2666 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2667 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2670 LttvProcessState
*process
= ts
->running_process
[cpu
];
2672 #if 0//how to use a sequence that must be transformed in a string
2673 /* PID of the process to release */
2674 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2675 //name = ltt_event_get_string(e, thf->f1);
2676 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2678 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2679 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2680 memcpy(null_term_name
, name_begin
, name_len
);
2681 null_term_name
[name_len
] = '\0';
2682 process
->name
= g_quark_from_string(null_term_name
);
2685 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2686 process
->brand
= LTTV_STATE_UNBRANDED
;
2687 //g_free(null_term_name);
2691 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2693 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2694 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2695 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2696 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2699 LttvProcessState
*process
= ts
->running_process
[cpu
];
2701 name
= ltt_event_get_string(e
, thf
->f1
);
2702 process
->brand
= g_quark_from_string(name
);
2707 static void fix_process(gpointer key
, gpointer value
,
2710 LttvProcessState
*process
;
2711 LttvExecutionState
*es
;
2712 process
= (LttvProcessState
*)value
;
2713 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2714 LttTime
*timestamp
= (LttTime
*)user_data
;
2716 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2717 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2718 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2719 es
->t
= LTTV_STATE_SYSCALL
;
2720 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2721 es
->entry
= *timestamp
;
2722 es
->change
= *timestamp
;
2723 es
->cum_cpu_time
= ltt_time_zero
;
2724 if(es
->s
== LTTV_STATE_UNNAMED
)
2725 es
->s
= LTTV_STATE_WAIT
;
2728 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2729 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2730 es
->t
= LTTV_STATE_USER_MODE
;
2731 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2732 es
->entry
= *timestamp
;
2733 //g_assert(timestamp->tv_sec != 0);
2734 es
->change
= *timestamp
;
2735 es
->cum_cpu_time
= ltt_time_zero
;
2736 if(es
->s
== LTTV_STATE_UNNAMED
)
2737 es
->s
= LTTV_STATE_RUN
;
2739 if(process
->execution_stack
->len
== 1) {
2740 /* Still in bottom unknown mode, means never did a system call
2741 * May be either in user mode, syscall mode, running or waiting.*/
2742 /* FIXME : we may be tagging syscall mode when being user mode */
2743 process
->execution_stack
=
2744 g_array_set_size(process
->execution_stack
, 2);
2745 es
= process
->state
= &g_array_index(process
->execution_stack
,
2746 LttvExecutionState
, 1);
2747 es
->t
= LTTV_STATE_SYSCALL
;
2748 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2749 es
->entry
= *timestamp
;
2750 //g_assert(timestamp->tv_sec != 0);
2751 es
->change
= *timestamp
;
2752 es
->cum_cpu_time
= ltt_time_zero
;
2753 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2754 es
->s
= LTTV_STATE_WAIT
;
2760 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2762 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2763 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2764 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2765 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2766 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2768 /* For all processes */
2769 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2770 /* else, if stack[0] is unknown, set to user mode, running */
2772 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2775 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2777 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2778 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2779 //It's slow : optimise later by doing this before reading trace.
2780 LttEventType
*et
= ltt_event_eventtype(e
);
2782 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2788 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2789 LttvProcessState
*process
= ts
->running_process
[cpu
];
2790 LttvProcessState
*parent_process
;
2791 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2792 GQuark type
, mode
, submode
, status
;
2793 LttvExecutionState
*es
;
2797 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2798 s
->parent
.target_pid
= pid
;
2801 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2804 command
= ltt_event_get_string(e
, thf
->f3
);
2807 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2808 type
= ltt_enum_string_get(ltt_field_type(f4
),
2809 ltt_event_get_unsigned(e
, f4
));
2812 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2813 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2814 ltt_event_get_unsigned(e
, f5
));
2817 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2818 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2819 ltt_event_get_unsigned(e
, f6
));
2822 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2823 status
= ltt_enum_string_get(ltt_field_type(f7
),
2824 ltt_event_get_unsigned(e
, f7
));
2827 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2828 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2833 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2834 for(i
=0; i
<nb_cpus
; i
++) {
2835 process
= lttv_state_find_process(ts
, i
, pid
);
2836 g_assert(process
!= NULL
);
2838 process
->ppid
= parent_pid
;
2839 process
->tgid
= tgid
;
2840 process
->name
= g_quark_from_string(command
);
2842 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2843 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2847 /* The process might exist if a process was forked while performing the
2849 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2850 if(process
== NULL
) {
2851 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2852 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2853 pid
, tgid
, g_quark_from_string(command
),
2854 &s
->parent
.timestamp
);
2856 /* Keep the stack bottom : a running user mode */
2857 /* Disabled because of inconsistencies in the current statedump states. */
2858 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2859 /* Only keep the bottom
2860 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2861 /* Will cause expected trap when in fact being syscall (even after end of
2863 * Will cause expected interrupt when being syscall. (only before end of
2864 * statedump event) */
2865 // This will cause a "popping last state on stack, ignoring it."
2866 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2867 es
= process
->state
= &g_array_index(process
->execution_stack
,
2868 LttvExecutionState
, 0);
2869 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2870 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2871 es
->s
= LTTV_STATE_UNNAMED
;
2872 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2874 es
->t
= LTTV_STATE_SYSCALL
;
2879 /* User space process :
2880 * bottom : user mode
2881 * either currently running or scheduled out.
2882 * can be scheduled out because interrupted in (user mode or in syscall)
2883 * or because of an explicit call to the scheduler in syscall. Note that
2884 * the scheduler call comes after the irq_exit, so never in interrupt
2886 // temp workaround : set size to 1 : only have user mode bottom of stack.
2887 // will cause g_info message of expected syscall mode when in fact being
2888 // in user mode. Can also cause expected trap when in fact being user
2889 // mode in the event of a page fault reenabling interrupts in the handler.
2890 // Expected syscall and trap can also happen after the end of statedump
2891 // This will cause a "popping last state on stack, ignoring it."
2892 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2893 es
= process
->state
= &g_array_index(process
->execution_stack
,
2894 LttvExecutionState
, 0);
2895 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2896 es
->s
= LTTV_STATE_UNNAMED
;
2897 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2899 es
->t
= LTTV_STATE_USER_MODE
;
2907 es
= process
->state
= &g_array_index(process
->execution_stack
,
2908 LttvExecutionState
, 1);
2909 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2910 es
->s
= LTTV_STATE_UNNAMED
;
2911 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2915 /* The process has already been created :
2916 * Probably was forked while dumping the process state or
2917 * was simply scheduled in prior to get the state dump event.
2919 process
->ppid
= parent_pid
;
2920 process
->tgid
= tgid
;
2921 process
->name
= g_quark_from_string(command
);
2922 process
->type
= type
;
2924 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2926 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2927 if(type
== LTTV_STATE_KERNEL_THREAD
)
2928 es
->t
= LTTV_STATE_SYSCALL
;
2930 es
->t
= LTTV_STATE_USER_MODE
;
2933 /* Don't mess around with the stack, it will eventually become
2934 * ok after the end of state dump. */
2941 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2943 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2945 lttv_state_add_event_hooks(tss
);
2950 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2952 LttvTraceset
*traceset
= self
->parent
.ts
;
2954 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2958 LttvTracefileState
*tfs
;
2962 LttvTraceHookByFacility
*thf
;
2964 LttvTraceHook
*hook
;
2966 LttvAttributeValue val
;
2971 nb_trace
= lttv_traceset_number(traceset
);
2972 for(i
= 0 ; i
< nb_trace
; i
++) {
2973 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2975 /* Find the eventtype id for the following events and register the
2976 associated by id hooks. */
2978 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2979 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2982 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2983 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2984 LTT_FIELD_SYSCALL_ID
, 0, 0,
2985 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2988 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2989 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2991 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2994 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2995 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2996 LTT_FIELD_TRAP_ID
, 0, 0,
2997 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3000 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3001 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3003 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3006 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3007 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3008 LTT_FIELD_IRQ_ID
, 0, 0,
3009 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3012 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3013 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3015 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3018 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3019 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3020 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3021 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3024 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3025 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3027 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3030 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3031 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3032 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3033 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3036 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3037 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3038 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3039 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3042 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3043 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3044 LTT_FIELD_PID
, 0, 0,
3045 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3049 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3050 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3051 LTT_FIELD_PID
, 0, 0,
3052 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3055 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3056 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3057 LTT_FIELD_PID
, 0, 0,
3058 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3061 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3062 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3063 LTT_FIELD_FILENAME
, 0, 0,
3064 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3067 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3068 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3069 LTT_FIELD_NAME
, 0, 0,
3070 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3073 /* statedump-related hooks */
3074 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3075 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3076 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3077 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3080 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3081 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3083 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3086 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3087 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3088 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3089 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3092 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3093 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3094 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3095 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3098 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3099 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3100 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3101 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3104 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3105 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3106 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3107 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3110 hooks
= g_array_set_size(hooks
, hn
);
3112 /* Add these hooks to each event_by_id hooks list */
3114 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3116 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3118 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3119 LttvTracefileContext
*, j
));
3121 for(k
= 0 ; k
< hooks
->len
; k
++) {
3122 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3123 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3124 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3126 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3133 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3134 *(val
.v_pointer
) = hooks
;
3138 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3140 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3142 lttv_state_remove_event_hooks(tss
);
3147 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3149 LttvTraceset
*traceset
= self
->parent
.ts
;
3151 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3155 LttvTracefileState
*tfs
;
3159 LttvTraceHook
*hook
;
3161 LttvTraceHookByFacility
*thf
;
3163 LttvAttributeValue val
;
3165 nb_trace
= lttv_traceset_number(traceset
);
3166 for(i
= 0 ; i
< nb_trace
; i
++) {
3167 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3169 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3170 hooks
= *(val
.v_pointer
);
3172 /* Remove these hooks from each event_by_id hooks list */
3174 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3176 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3178 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3179 LttvTracefileContext
*, j
));
3181 for(k
= 0 ; k
< hooks
->len
; k
++) {
3182 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3183 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3184 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3186 lttv_hooks_remove_data(
3187 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3193 for(k
= 0 ; k
< hooks
->len
; k
++)
3194 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3195 g_array_free(hooks
, TRUE
);
3199 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3201 guint
*event_count
= (guint
*)hook_data
;
3203 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3204 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3209 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3211 LttvTracefileState
*tfcs
;
3213 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3215 LttEventPosition
*ep
;
3221 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3223 LttvAttributeValue value
;
3225 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3226 LTTV_STATE_SAVED_STATES
);
3227 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3228 value
= lttv_attribute_add(saved_states_tree
,
3229 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3230 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3231 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3232 *(value
.v_time
) = self
->parent
.timestamp
;
3233 lttv_state_save(tcs
, saved_state_tree
);
3234 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3235 self
->parent
.timestamp
.tv_nsec
);
3237 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3242 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3244 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3246 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3251 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3259 static gboolean
block_start(void *hook_data
, void *call_data
)
3261 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3263 LttvTracefileState
*tfcs
;
3265 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3267 LttEventPosition
*ep
;
3269 guint i
, nb_block
, nb_event
, nb_tracefile
;
3273 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3275 LttvAttributeValue value
;
3277 ep
= ltt_event_position_new();
3279 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3281 /* Count the number of events added since the last block end in any
3284 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3286 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3287 LttvTracefileContext
, i
));
3288 ltt_event_position(tfcs
->parent
.e
, ep
);
3289 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3290 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3291 tfcs
->saved_position
= nb_event
;
3295 if(tcs
->nb_event
>= tcs
->save_interval
) {
3296 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3297 LTTV_STATE_SAVED_STATES
);
3298 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3299 value
= lttv_attribute_add(saved_states_tree
,
3300 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3301 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3302 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3303 *(value
.v_time
) = self
->parent
.timestamp
;
3304 lttv_state_save(tcs
, saved_state_tree
);
3306 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3307 self
->parent
.timestamp
.tv_nsec
);
3309 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3315 static gboolean
block_end(void *hook_data
, void *call_data
)
3317 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3319 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3323 LttEventPosition
*ep
;
3325 guint nb_block
, nb_event
;
3327 ep
= ltt_event_position_new();
3328 ltt_event_position(self
->parent
.e
, ep
);
3329 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3330 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3331 self
->saved_position
= 0;
3332 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3339 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3341 LttvTraceset
*traceset
= self
->parent
.ts
;
3343 guint i
, j
, nb_trace
, nb_tracefile
;
3347 LttvTracefileState
*tfs
;
3349 LttvTraceHook hook_start
, hook_end
;
3351 nb_trace
= lttv_traceset_number(traceset
);
3352 for(i
= 0 ; i
< nb_trace
; i
++) {
3353 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3355 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3356 NULL
, NULL
, block_start
, &hook_start
);
3357 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3358 NULL
, NULL
, block_end
, &hook_end
);
3360 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3362 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3364 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3365 LttvTracefileContext
, j
));
3366 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3367 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3368 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3369 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3375 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3377 LttvTraceset
*traceset
= self
->parent
.ts
;
3379 guint i
, j
, nb_trace
, nb_tracefile
;
3383 LttvTracefileState
*tfs
;
3386 nb_trace
= lttv_traceset_number(traceset
);
3387 for(i
= 0 ; i
< nb_trace
; i
++) {
3389 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3390 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3392 if(ts
->has_precomputed_states
) continue;
3394 guint
*event_count
= g_new(guint
, 1);
3397 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3399 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3400 LttvTracefileContext
*, j
));
3401 lttv_hooks_add(tfs
->parent
.event
,
3402 state_save_event_hook
,
3409 lttv_process_traceset_begin(&self
->parent
,
3410 NULL
, NULL
, NULL
, NULL
, NULL
);
3414 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3416 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3418 lttv_state_save_add_event_hooks(tss
);
3425 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3427 LttvTraceset
*traceset
= self
->parent
.ts
;
3429 guint i
, j
, nb_trace
, nb_tracefile
;
3433 LttvTracefileState
*tfs
;
3435 LttvTraceHook hook_start
, hook_end
;
3437 nb_trace
= lttv_traceset_number(traceset
);
3438 for(i
= 0 ; i
< nb_trace
; i
++) {
3439 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3441 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3442 NULL
, NULL
, block_start
, &hook_start
);
3444 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3445 NULL
, NULL
, block_end
, &hook_end
);
3447 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3449 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3451 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3452 LttvTracefileContext
, j
));
3453 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3454 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3455 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3456 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3462 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3464 LttvTraceset
*traceset
= self
->parent
.ts
;
3466 guint i
, j
, nb_trace
, nb_tracefile
;
3470 LttvTracefileState
*tfs
;
3472 LttvHooks
*after_trace
= lttv_hooks_new();
3474 lttv_hooks_add(after_trace
,
3475 state_save_after_trace_hook
,
3480 lttv_process_traceset_end(&self
->parent
,
3481 NULL
, after_trace
, NULL
, NULL
, NULL
);
3483 lttv_hooks_destroy(after_trace
);
3485 nb_trace
= lttv_traceset_number(traceset
);
3486 for(i
= 0 ; i
< nb_trace
; i
++) {
3488 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3489 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3491 if(ts
->has_precomputed_states
) continue;
3493 guint
*event_count
= NULL
;
3495 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3497 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3498 LttvTracefileContext
*, j
));
3499 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3500 state_save_event_hook
);
3502 if(event_count
) g_free(event_count
);
3506 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3508 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3510 lttv_state_save_remove_event_hooks(tss
);
3515 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3517 LttvTraceset
*traceset
= self
->parent
.ts
;
3521 int min_pos
, mid_pos
, max_pos
;
3523 guint call_rest
= 0;
3525 LttvTraceState
*tcs
;
3527 LttvAttributeValue value
;
3529 LttvAttributeType type
;
3531 LttvAttributeName name
;
3535 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3537 //g_tree_destroy(self->parent.pqueue);
3538 //self->parent.pqueue = g_tree_new(compare_tracefile);
3540 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3542 nb_trace
= lttv_traceset_number(traceset
);
3543 for(i
= 0 ; i
< nb_trace
; i
++) {
3544 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3546 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3547 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3548 LTTV_STATE_SAVED_STATES
);
3551 if(saved_states_tree
) {
3552 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3553 mid_pos
= max_pos
/ 2;
3554 while(min_pos
< max_pos
) {
3555 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3557 g_assert(type
== LTTV_GOBJECT
);
3558 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3559 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3561 g_assert(type
== LTTV_TIME
);
3562 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3564 closest_tree
= saved_state_tree
;
3566 else max_pos
= mid_pos
- 1;
3568 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3572 /* restore the closest earlier saved state */
3574 lttv_state_restore(tcs
, closest_tree
);
3578 /* There is no saved state, yet we want to have it. Restart at T0 */
3580 restore_init_state(tcs
);
3581 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3584 /* We want to seek quickly without restoring/updating the state */
3586 restore_init_state(tcs
);
3587 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3590 if(!call_rest
) g_info("NOT Calling restore");
3595 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3601 traceset_state_finalize (LttvTracesetState
*self
)
3603 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3604 finalize(G_OBJECT(self
));
3609 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3611 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3613 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3614 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3615 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3616 klass
->new_traceset_context
= new_traceset_context
;
3617 klass
->new_trace_context
= new_trace_context
;
3618 klass
->new_tracefile_context
= new_tracefile_context
;
3623 lttv_traceset_state_get_type(void)
3625 static GType type
= 0;
3627 static const GTypeInfo info
= {
3628 sizeof (LttvTracesetStateClass
),
3629 NULL
, /* base_init */
3630 NULL
, /* base_finalize */
3631 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3632 NULL
, /* class_finalize */
3633 NULL
, /* class_data */
3634 sizeof (LttvTracesetState
),
3635 0, /* n_preallocs */
3636 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3637 NULL
/* value handling */
3640 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3648 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3654 trace_state_finalize (LttvTraceState
*self
)
3656 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3657 finalize(G_OBJECT(self
));
3662 trace_state_class_init (LttvTraceStateClass
*klass
)
3664 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3666 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3667 klass
->state_save
= state_save
;
3668 klass
->state_restore
= state_restore
;
3669 klass
->state_saved_free
= state_saved_free
;
3674 lttv_trace_state_get_type(void)
3676 static GType type
= 0;
3678 static const GTypeInfo info
= {
3679 sizeof (LttvTraceStateClass
),
3680 NULL
, /* base_init */
3681 NULL
, /* base_finalize */
3682 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3683 NULL
, /* class_finalize */
3684 NULL
, /* class_data */
3685 sizeof (LttvTraceState
),
3686 0, /* n_preallocs */
3687 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3688 NULL
/* value handling */
3691 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3692 "LttvTraceStateType", &info
, 0);
3699 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3705 tracefile_state_finalize (LttvTracefileState
*self
)
3707 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3708 finalize(G_OBJECT(self
));
3713 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3715 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3717 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3722 lttv_tracefile_state_get_type(void)
3724 static GType type
= 0;
3726 static const GTypeInfo info
= {
3727 sizeof (LttvTracefileStateClass
),
3728 NULL
, /* base_init */
3729 NULL
, /* base_finalize */
3730 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3731 NULL
, /* class_finalize */
3732 NULL
, /* class_data */
3733 sizeof (LttvTracefileState
),
3734 0, /* n_preallocs */
3735 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3736 NULL
/* value handling */
3739 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3740 "LttvTracefileStateType", &info
, 0);
3746 static void module_init()
3748 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3749 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3750 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3751 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3752 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3753 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3754 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3755 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3756 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3757 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3758 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3759 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3760 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3761 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3762 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3763 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3764 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3765 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3766 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3767 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3768 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3769 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3770 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3771 LTTV_STATE_EVENT
= g_quark_from_string("event");
3772 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3773 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3774 LTTV_STATE_TIME
= g_quark_from_string("time");
3775 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3776 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3777 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3778 g_quark_from_string("trace_state_use_count");
3779 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3782 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3783 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3784 LTT_FACILITY_FS
= g_quark_from_string("fs");
3785 LTT_FACILITY_LIST
= g_quark_from_string("list");
3786 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3787 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3790 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3791 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3792 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3793 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3794 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3795 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3796 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3797 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3798 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3799 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3800 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3801 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3802 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3803 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3804 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3805 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3806 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3807 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3808 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3809 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3810 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3813 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3814 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3815 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3816 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3817 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3818 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3819 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3820 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3821 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3822 LTT_FIELD_PID
= g_quark_from_string("pid");
3823 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3824 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3825 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3826 LTT_FIELD_NAME
= g_quark_from_string("name");
3827 LTT_FIELD_TYPE
= g_quark_from_string("type");
3828 LTT_FIELD_MODE
= g_quark_from_string("mode");
3829 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3830 LTT_FIELD_STATUS
= g_quark_from_string("status");
3831 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3832 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3833 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3834 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3835 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3837 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3838 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3839 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3840 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3841 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3843 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3844 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3845 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3847 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3848 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3849 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3850 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3853 static void module_destroy()
3858 LTTV_MODULE("state", "State computation", \
3859 "Update the system state, possibly saving it at intervals", \
3860 module_init
, module_destroy
)