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,
24 #include <lttv/lttv.h>
25 #include <lttv/module.h>
26 #include <lttv/state.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
34 * usertrace is there only to be able to update the current CPU of the
35 * usertraces when there is a schedchange. it is a way to link the ProcessState
36 * to the associated usertrace. Link only created upon thread creation.
38 * The cpu id is necessary : it gives us back the current ProcessState when we
39 * are considering data from the usertrace.
42 #define PREALLOCATED_EXECUTION_STACK 10
44 /* Facilities Quarks */
48 LTT_FACILITY_KERNEL_ARCH
,
51 LTT_FACILITY_USER_GENERIC
,
57 LTT_EVENT_SYSCALL_ENTRY
,
58 LTT_EVENT_SYSCALL_EXIT
,
63 LTT_EVENT_SOFT_IRQ_ENTRY
,
64 LTT_EVENT_SOFT_IRQ_EXIT
,
65 LTT_EVENT_SCHED_SCHEDULE
,
66 LTT_EVENT_PROCESS_FORK
,
67 LTT_EVENT_KTHREAD_CREATE
,
68 LTT_EVENT_PROCESS_EXIT
,
69 LTT_EVENT_PROCESS_FREE
,
71 LTT_EVENT_PROCESS_STATE
,
72 LTT_EVENT_STATEDUMP_END
,
73 LTT_EVENT_FUNCTION_ENTRY
,
74 LTT_EVENT_FUNCTION_EXIT
,
75 LTT_EVENT_THREAD_BRAND
,
76 LTT_EVENT_REQUEST_ISSUE
,
77 LTT_EVENT_REQUEST_COMPLETE
,
78 LTT_EVENT_LIST_INTERRUPT
;
86 LTT_FIELD_SOFT_IRQ_ID
,
110 LTTV_STATE_MODE_UNKNOWN
,
111 LTTV_STATE_USER_MODE
,
118 LTTV_STATE_SUBMODE_UNKNOWN
,
119 LTTV_STATE_SUBMODE_NONE
;
123 LTTV_STATE_WAIT_FORK
,
132 LTTV_STATE_UNBRANDED
;
135 LTTV_STATE_USER_THREAD
,
136 LTTV_STATE_KERNEL_THREAD
;
153 LTTV_BDEV_BUSY_READING
,
154 LTTV_BDEV_BUSY_WRITING
;
157 LTTV_STATE_TRACEFILES
,
158 LTTV_STATE_PROCESSES
,
160 LTTV_STATE_RUNNING_PROCESS
,
162 LTTV_STATE_SAVED_STATES
,
163 LTTV_STATE_SAVED_STATES_TIME
,
166 LTTV_STATE_NAME_TABLES
,
167 LTTV_STATE_TRACE_STATE_USE_COUNT
,
168 LTTV_STATE_RESOURCE_CPUS
,
169 LTTV_STATE_RESOURCE_IRQS
,
170 LTTV_STATE_RESOURCE_BLKDEVS
;
172 static void create_max_time(LttvTraceState
*tcs
);
174 static void get_max_time(LttvTraceState
*tcs
);
176 static void free_max_time(LttvTraceState
*tcs
);
178 static void create_name_tables(LttvTraceState
*tcs
);
180 static void get_name_tables(LttvTraceState
*tcs
);
182 static void free_name_tables(LttvTraceState
*tcs
);
184 static void free_saved_state(LttvTraceState
*tcs
);
186 static void lttv_state_free_process_table(GHashTable
*processes
);
188 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
189 GPtrArray
*quarktable
);
191 /* Resource function prototypes */
192 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
193 static LttvBdevState
*bdevstate_new(void);
194 static void bdevstate_free(LttvBdevState
*);
195 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
196 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
197 static LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
);
200 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
202 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
206 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
208 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
212 void lttv_state_state_saved_free(LttvTraceState
*self
,
213 LttvAttribute
*container
)
215 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
219 guint
process_hash(gconstpointer key
)
221 guint pid
= ((const LttvProcessState
*)key
)->pid
;
222 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
226 /* If the hash table hash function is well distributed,
227 * the process_equal should compare different pid */
228 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
230 const LttvProcessState
*process_a
, *process_b
;
233 process_a
= (const LttvProcessState
*)a
;
234 process_b
= (const LttvProcessState
*)b
;
236 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
237 else if(likely(process_a
->pid
== 0 &&
238 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
243 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
245 g_tree_destroy((GTree
*)value
);
248 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
250 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
251 g_hash_table_destroy(usertraces
);
257 restore_init_state(LttvTraceState
*self
)
259 guint i
, nb_cpus
, nb_irqs
;
261 //LttvTracefileState *tfcs;
263 LttTime start_time
, end_time
;
265 /* Free the process tables */
266 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
267 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
268 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
269 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
272 /* Seek time to beginning */
273 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
274 // closest. It's the tracecontext job to seek the trace to the beginning
275 // anyway : the init state might be used at the middle of the trace as well...
276 //g_tree_destroy(self->parent.ts_context->pqueue);
277 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
279 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
281 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
283 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
284 nb_irqs
= self
->nb_irqs
;
286 /* Put the per cpu running_process to beginning state : process 0. */
287 for(i
=0; i
< nb_cpus
; i
++) {
288 LttvExecutionState
*es
;
289 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
290 LTTV_STATE_UNNAMED
, &start_time
);
291 /* We are not sure is it's a kernel thread or normal thread, put the
292 * bottom stack state to unknown */
293 self
->running_process
[i
]->execution_stack
=
294 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
295 es
= self
->running_process
[i
]->state
=
296 &g_array_index(self
->running_process
[i
]->execution_stack
,
297 LttvExecutionState
, 0);
298 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
299 es
->s
= LTTV_STATE_UNNAMED
;
301 //self->running_process[i]->state->s = LTTV_STATE_RUN;
302 self
->running_process
[i
]->cpu
= i
;
304 /* reset cpu states */
305 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
306 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
309 /* reset irq states */
310 for(i
=0; i
<nb_irqs
; i
++) {
311 if(self
->irq_states
[i
].mode_stack
->len
> 0)
312 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
315 /* reset bdev states */
316 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
317 g_hash_table_steal_all(self
->bdev_states
);
320 nb_tracefile
= self
->parent
.tracefiles
->len
;
322 for(i
= 0 ; i
< nb_tracefile
; i
++) {
324 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
325 LttvTracefileContext
*, i
));
326 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
327 // tfcs->saved_position = 0;
328 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
329 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
330 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
331 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
336 //static LttTime time_zero = {0,0};
338 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
341 const LttTime
*t1
= (const LttTime
*)a
;
342 const LttTime
*t2
= (const LttTime
*)b
;
344 return ltt_time_compare(*t1
, *t2
);
347 static void free_usertrace_key(gpointer data
)
352 #define MAX_STRING_LEN 4096
355 state_load_saved_states(LttvTraceState
*tcs
)
358 GPtrArray
*quarktable
;
359 const char *trace_path
;
363 tcs
->has_precomputed_states
= FALSE
;
367 gchar buf
[MAX_STRING_LEN
];
370 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
371 strncpy(path
, trace_path
, PATH_MAX
-1);
372 count
= strnlen(trace_path
, PATH_MAX
-1);
373 // quarktable : open, test
374 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
375 fp
= fopen(path
, "r");
377 quarktable
= g_ptr_array_sized_new(4096);
379 /* Index 0 is null */
381 if(hdr
== EOF
) return;
382 g_assert(hdr
== HDR_QUARKS
);
386 if(hdr
== EOF
) break;
387 g_assert(hdr
== HDR_QUARK
);
388 g_ptr_array_set_size(quarktable
, q
+1);
391 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
392 if(buf
[i
] == '\0' || feof(fp
)) break;
395 len
= strnlen(buf
, MAX_STRING_LEN
-1);
396 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
397 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
403 // saved_states : open, test
404 strncpy(path
, trace_path
, PATH_MAX
-1);
405 count
= strnlen(trace_path
, PATH_MAX
-1);
406 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
407 fp
= fopen(path
, "r");
411 if(hdr
!= HDR_TRACE
) goto end
;
413 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
415 tcs
->has_precomputed_states
= TRUE
;
420 /* Free the quarktable */
421 for(i
=0; i
<quarktable
->len
; i
++) {
422 string
= g_ptr_array_index (quarktable
, i
);
425 g_ptr_array_free(quarktable
, TRUE
);
430 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
432 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
435 LttvTraceContext
*tc
;
439 LttvTracefileState
*tfcs
;
441 LttvAttributeValue v
;
443 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
444 init((LttvTracesetContext
*)self
, ts
);
446 nb_trace
= lttv_traceset_number(ts
);
447 for(i
= 0 ; i
< nb_trace
; i
++) {
448 tc
= self
->parent
.traces
[i
];
449 tcs
= LTTV_TRACE_STATE(tc
);
450 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
451 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
455 if(*(v
.v_uint
) == 1) {
456 create_name_tables(tcs
);
457 create_max_time(tcs
);
459 get_name_tables(tcs
);
462 nb_tracefile
= tc
->tracefiles
->len
;
463 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
464 nb_irq
= tcs
->nb_irqs
;
465 tcs
->processes
= NULL
;
466 tcs
->usertraces
= NULL
;
467 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
469 /* init cpu resource stuff */
470 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
471 for(j
= 0; j
<nb_cpu
; j
++) {
472 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
473 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
476 /* init irq resource stuff */
477 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
478 for(j
= 0; j
<nb_irq
; j
++) {
479 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
480 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
483 /* init bdev resource stuff */
484 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
486 restore_init_state(tcs
);
487 for(j
= 0 ; j
< nb_tracefile
; j
++) {
489 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
490 LttvTracefileContext
*, j
));
491 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
492 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
493 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
494 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
495 /* It's a Usertrace */
496 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
497 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
499 if(!usertrace_tree
) {
500 usertrace_tree
= g_tree_new_full(compare_usertraces
,
501 NULL
, free_usertrace_key
, NULL
);
502 g_hash_table_insert(tcs
->usertraces
,
503 (gpointer
)tid
, usertrace_tree
);
505 LttTime
*timestamp
= g_new(LttTime
, 1);
506 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
507 ltt_tracefile_creation(tfcs
->parent
.tf
));
508 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
512 /* See if the trace has saved states */
513 state_load_saved_states(tcs
);
518 fini(LttvTracesetState
*self
)
524 //LttvTracefileState *tfcs;
526 LttvAttributeValue v
;
528 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
529 for(i
= 0 ; i
< nb_trace
; i
++) {
530 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
531 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
534 g_assert(*(v
.v_uint
) != 0);
537 if(*(v
.v_uint
) == 0) {
538 free_name_tables(tcs
);
540 free_saved_state(tcs
);
542 g_free(tcs
->running_process
);
543 tcs
->running_process
= NULL
;
544 lttv_state_free_process_table(tcs
->processes
);
545 lttv_state_free_usertraces(tcs
->usertraces
);
546 tcs
->processes
= NULL
;
547 tcs
->usertraces
= NULL
;
549 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
550 fini((LttvTracesetContext
*)self
);
554 static LttvTracesetContext
*
555 new_traceset_context(LttvTracesetContext
*self
)
557 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
561 static LttvTraceContext
*
562 new_trace_context(LttvTracesetContext
*self
)
564 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
568 static LttvTracefileContext
*
569 new_tracefile_context(LttvTracesetContext
*self
)
571 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
575 /* Write the process state of the trace */
577 static void write_process_state(gpointer key
, gpointer value
,
580 LttvProcessState
*process
;
582 LttvExecutionState
*es
;
584 FILE *fp
= (FILE *)user_data
;
589 process
= (LttvProcessState
*)value
;
591 " <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",
592 process
, process
->pid
, process
->tgid
, process
->ppid
,
593 g_quark_to_string(process
->type
),
594 process
->creation_time
.tv_sec
,
595 process
->creation_time
.tv_nsec
,
596 process
->insertion_time
.tv_sec
,
597 process
->insertion_time
.tv_nsec
,
598 g_quark_to_string(process
->name
),
599 g_quark_to_string(process
->brand
),
602 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
603 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
604 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
605 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
606 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
607 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
608 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
611 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
612 address
= g_array_index(process
->user_stack
, guint64
, i
);
613 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
617 if(process
->usertrace
) {
618 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
619 g_quark_to_string(process
->usertrace
->tracefile_name
),
620 process
->usertrace
->cpu
);
624 fprintf(fp
, " </PROCESS>\n");
628 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
630 guint i
, nb_tracefile
, nb_block
, offset
;
633 LttvTracefileState
*tfcs
;
637 LttEventPosition
*ep
;
641 ep
= ltt_event_position_new();
643 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
645 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
647 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
648 for(i
=0;i
<nb_cpus
;i
++) {
649 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
650 i
, self
->running_process
[i
]->pid
);
653 nb_tracefile
= self
->parent
.tracefiles
->len
;
655 for(i
= 0 ; i
< nb_tracefile
; i
++) {
657 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
658 LttvTracefileContext
*, i
));
659 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
660 tfcs
->parent
.timestamp
.tv_sec
,
661 tfcs
->parent
.timestamp
.tv_nsec
);
662 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
663 if(e
== NULL
) fprintf(fp
,"/>\n");
665 ltt_event_position(e
, ep
);
666 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
667 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
672 fprintf(fp
,"</PROCESS_STATE>\n");
676 static void write_process_state_raw(gpointer key
, gpointer value
,
679 LttvProcessState
*process
;
681 LttvExecutionState
*es
;
683 FILE *fp
= (FILE *)user_data
;
688 process
= (LttvProcessState
*)value
;
689 fputc(HDR_PROCESS
, fp
);
690 //fwrite(&header, sizeof(header), 1, fp);
691 //fprintf(fp, "%s", g_quark_to_string(process->type));
693 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
694 //fprintf(fp, "%s", g_quark_to_string(process->name));
696 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
697 //fprintf(fp, "%s", g_quark_to_string(process->brand));
699 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
700 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
701 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
702 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
703 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
704 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
705 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
709 " <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",
710 process
, process
->pid
, process
->tgid
, process
->ppid
,
711 g_quark_to_string(process
->type
),
712 process
->creation_time
.tv_sec
,
713 process
->creation_time
.tv_nsec
,
714 process
->insertion_time
.tv_sec
,
715 process
->insertion_time
.tv_nsec
,
716 g_quark_to_string(process
->name
),
717 g_quark_to_string(process
->brand
),
721 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
722 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
725 //fprintf(fp, "%s", g_quark_to_string(es->t));
727 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
728 //fprintf(fp, "%s", g_quark_to_string(es->n));
730 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
731 //fprintf(fp, "%s", g_quark_to_string(es->s));
733 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
734 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
735 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
736 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
738 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
739 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
740 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
741 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
742 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
746 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
747 address
= g_array_index(process
->user_stack
, guint64
, i
);
748 fputc(HDR_USER_STACK
, fp
);
749 fwrite(&address
, sizeof(address
), 1, fp
);
751 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
756 if(process
->usertrace
) {
757 fputc(HDR_USERTRACE
, fp
);
758 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
760 fwrite(&process
->usertrace
->tracefile_name
,
761 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
762 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
764 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
765 g_quark_to_string(process
->usertrace
->tracefile_name
),
766 process
->usertrace
->cpu
);
773 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
775 guint i
, nb_tracefile
, nb_block
, offset
;
778 LttvTracefileState
*tfcs
;
782 LttEventPosition
*ep
;
786 ep
= ltt_event_position_new();
788 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
789 fputc(HDR_PROCESS_STATE
, fp
);
790 fwrite(&t
, sizeof(t
), 1, fp
);
792 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
794 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
795 for(i
=0;i
<nb_cpus
;i
++) {
797 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
798 fwrite(&self
->running_process
[i
]->pid
,
799 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
800 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
801 // i, self->running_process[i]->pid);
804 nb_tracefile
= self
->parent
.tracefiles
->len
;
806 for(i
= 0 ; i
< nb_tracefile
; i
++) {
808 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
809 LttvTracefileContext
*, i
));
810 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
811 // tfcs->parent.timestamp.tv_sec,
812 // tfcs->parent.timestamp.tv_nsec);
813 fputc(HDR_TRACEFILE
, fp
);
814 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
815 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
816 * position following : end of trace */
817 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
819 ltt_event_position(e
, ep
);
820 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
821 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
823 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
824 fwrite(&offset
, sizeof(offset
), 1, fp
);
825 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
832 /* Read process state from a file */
834 /* Called because a HDR_PROCESS was found */
835 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
836 GPtrArray
*quarktable
)
838 LttvExecutionState
*es
;
839 LttvProcessState
*process
, *parent_process
;
840 LttvProcessState tmp
;
845 /* TODO : check return value */
846 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
847 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
848 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
849 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
850 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
851 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
852 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
853 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
854 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
857 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
859 /* We must link to the parent */
860 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
862 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
863 if(process
== NULL
) {
864 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
866 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
870 process
->insertion_time
= tmp
.insertion_time
;
871 process
->creation_time
= tmp
.creation_time
;
872 process
->type
= g_quark_from_string(
873 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
874 process
->tgid
= tmp
.tgid
;
875 process
->ppid
= tmp
.ppid
;
876 process
->brand
= g_quark_from_string(
877 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
879 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
883 if(feof(fp
) || ferror(fp
)) goto end_loop
;
885 gint hdr
= fgetc(fp
);
886 if(hdr
== EOF
) goto end_loop
;
890 process
->execution_stack
=
891 g_array_set_size(process
->execution_stack
,
892 process
->execution_stack
->len
+ 1);
893 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
894 process
->execution_stack
->len
-1);
897 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
898 es
->t
= g_quark_from_string(
899 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
900 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
901 es
->n
= g_quark_from_string(
902 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
903 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
904 es
->s
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
906 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
907 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
908 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
911 process
->user_stack
= g_array_set_size(process
->user_stack
,
912 process
->user_stack
->len
+ 1);
913 address
= &g_array_index(process
->user_stack
, guint64
,
914 process
->user_stack
->len
-1);
915 fread(address
, sizeof(address
), 1, fp
);
916 process
->current_function
= *address
;
919 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
920 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
932 /* Called because a HDR_PROCESS_STATE was found */
933 /* Append a saved state to the trace states */
934 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
936 guint i
, nb_tracefile
, nb_block
, offset
;
938 LttvTracefileState
*tfcs
;
940 LttEventPosition
*ep
;
948 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
950 LttvAttributeValue value
;
951 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
952 ep
= ltt_event_position_new();
954 restore_init_state(self
);
956 fread(&t
, sizeof(t
), 1, fp
);
959 if(feof(fp
) || ferror(fp
)) goto end_loop
;
961 if(hdr
== EOF
) goto end_loop
;
965 /* Call read_process_state_raw */
966 read_process_state_raw(self
, fp
, quarktable
);
976 case HDR_PROCESS_STATE
:
982 g_error("Error while parsing saved state file : unknown data header %d",
988 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
989 for(i
=0;i
<nb_cpus
;i
++) {
992 g_assert(hdr
== HDR_CPU
);
993 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
994 g_assert(i
== cpu_num
);
995 fread(&self
->running_process
[i
]->pid
,
996 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
999 nb_tracefile
= self
->parent
.tracefiles
->len
;
1001 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1003 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1004 LttvTracefileContext
*, i
));
1005 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1006 // tfcs->parent.timestamp.tv_sec,
1007 // tfcs->parent.timestamp.tv_nsec);
1008 g_tree_remove(pqueue
, &tfcs
->parent
);
1010 g_assert(hdr
== HDR_TRACEFILE
);
1011 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1012 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1013 * position following : end of trace */
1014 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1015 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1016 fread(&offset
, sizeof(offset
), 1, fp
);
1017 fread(&tsc
, sizeof(tsc
), 1, fp
);
1018 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1019 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1021 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1026 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1027 LTTV_STATE_SAVED_STATES
);
1028 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1029 value
= lttv_attribute_add(saved_states_tree
,
1030 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1031 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1032 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1033 *(value
.v_time
) = t
;
1034 lttv_state_save(self
, saved_state_tree
);
1035 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1038 *(self
->max_time_state_recomputed_in_seek
) = t
;
1042 /* Called when a HDR_TRACE is found */
1043 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1044 GPtrArray
*quarktable
)
1049 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1051 if(hdr
== EOF
) goto end_loop
;
1054 case HDR_PROCESS_STATE
:
1055 /* Call read_process_state_raw */
1056 lttv_state_read_raw(tcs
, fp
, quarktable
);
1064 case HDR_USER_STACK
:
1068 g_error("Error while parsing saved state file :"
1069 " unexpected data header %d",
1073 g_error("Error while parsing saved state file : unknown data header %d",
1078 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1079 restore_init_state(tcs
);
1080 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1086 /* Copy each process from an existing hash table to a new one */
1088 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1090 LttvProcessState
*process
, *new_process
;
1092 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1096 process
= (LttvProcessState
*)value
;
1097 new_process
= g_new(LttvProcessState
, 1);
1098 *new_process
= *process
;
1099 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1100 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1101 new_process
->execution_stack
=
1102 g_array_set_size(new_process
->execution_stack
,
1103 process
->execution_stack
->len
);
1104 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1105 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1106 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1108 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1109 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1110 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1111 sizeof(guint64
), 0);
1112 new_process
->user_stack
=
1113 g_array_set_size(new_process
->user_stack
,
1114 process
->user_stack
->len
);
1115 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1116 g_array_index(new_process
->user_stack
, guint64
, i
) =
1117 g_array_index(process
->user_stack
, guint64
, i
);
1119 new_process
->current_function
= process
->current_function
;
1120 g_hash_table_insert(new_processes
, new_process
, new_process
);
1124 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1126 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1128 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1129 return new_processes
;
1132 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1135 LttvCPUState
*retval
;
1137 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1139 for(i
=0; i
<n
; i
++) {
1140 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1141 retval
[i
].last_irq
= states
[i
].last_irq
;
1142 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1143 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1144 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1151 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1155 for(i
=0; i
<n
; i
++) {
1156 g_array_free(states
[i
].mode_stack
, FALSE
);
1162 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1165 LttvIRQState
*retval
;
1167 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1169 for(i
=0; i
<n
; i
++) {
1170 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1171 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1172 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1173 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1180 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1184 for(i
=0; i
<n
; i
++) {
1185 g_array_free(states
[i
].mode_stack
, FALSE
);
1191 /* bdevstate stuff */
1193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1195 gint devcode_gint
= devcode
;
1196 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1198 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1199 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1201 gint
* key
= g_malloc(sizeof(gint
));
1203 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1211 static LttvBdevState
*bdevstate_new(void)
1213 LttvBdevState
*retval
;
1214 retval
= g_malloc(sizeof(LttvBdevState
));
1215 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1220 static void bdevstate_free(LttvBdevState
*bds
)
1222 g_array_free(bds
->mode_stack
, FALSE
);
1226 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1228 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1230 bdevstate_free(bds
);
1233 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1235 LttvBdevState
*retval
;
1237 retval
= bdevstate_new();
1238 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1243 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1245 //GHashTable *ht = (GHashTable *)u;
1246 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1247 LttvBdevState
*newbds
;
1249 newbds
= bdevstate_copy(bds
);
1251 g_hash_table_insert(u
, k
, newbds
);
1254 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1258 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1260 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1265 /* Free a hashtable and the LttvBdevState structures its values
1268 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1270 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1271 g_hash_table_destroy(ht
);
1274 /* The saved state for each trace contains a member "processes", which
1275 stores a copy of the process table, and a member "tracefiles" with
1276 one entry per tracefile. Each tracefile has a "process" member pointing
1277 to the current process and a "position" member storing the tracefile
1278 position (needed to seek to the current "next" event. */
1280 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1282 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1284 LttvTracefileState
*tfcs
;
1286 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1288 guint
*running_process
;
1290 LttvAttributeValue value
;
1292 LttEventPosition
*ep
;
1294 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1295 LTTV_STATE_TRACEFILES
);
1297 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1299 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1301 /* Add the currently running processes array */
1302 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1303 running_process
= g_new(guint
, nb_cpus
);
1304 for(i
=0;i
<nb_cpus
;i
++) {
1305 running_process
[i
] = self
->running_process
[i
]->pid
;
1307 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1309 *(value
.v_pointer
) = running_process
;
1311 g_info("State save");
1313 nb_tracefile
= self
->parent
.tracefiles
->len
;
1315 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1317 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1318 LttvTracefileContext
*, i
));
1319 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1320 value
= lttv_attribute_add(tracefiles_tree
, i
,
1322 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1324 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1326 *(value
.v_uint
) = tfcs
->process
->pid
;
1328 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1330 /* Only save the position if the tfs has not infinite time. */
1331 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1332 // && current_tfcs != tfcs) {
1333 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1334 *(value
.v_pointer
) = NULL
;
1336 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1337 ep
= ltt_event_position_new();
1338 ltt_event_position(e
, ep
);
1339 *(value
.v_pointer
) = ep
;
1341 guint nb_block
, offset
;
1344 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1345 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1347 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1351 /* save the cpu state */
1353 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1355 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1358 /* save the irq state */
1359 nb_irqs
= self
->nb_irqs
;
1361 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1363 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1366 /* save the blkdev states */
1367 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1369 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1373 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1375 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1377 LttvTracefileState
*tfcs
;
1379 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1381 guint
*running_process
;
1383 LttvAttributeType type
;
1385 LttvAttributeValue value
;
1387 LttvAttributeName name
;
1391 LttEventPosition
*ep
;
1393 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1395 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1396 LTTV_STATE_TRACEFILES
);
1398 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1400 g_assert(type
== LTTV_POINTER
);
1401 lttv_state_free_process_table(self
->processes
);
1402 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1404 /* Add the currently running processes array */
1405 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1406 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1408 g_assert(type
== LTTV_POINTER
);
1409 running_process
= *(value
.v_pointer
);
1410 for(i
=0;i
<nb_cpus
;i
++) {
1411 pid
= running_process
[i
];
1412 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1413 g_assert(self
->running_process
[i
] != NULL
);
1416 nb_tracefile
= self
->parent
.tracefiles
->len
;
1418 //g_tree_destroy(tsc->pqueue);
1419 //tsc->pqueue = g_tree_new(compare_tracefile);
1421 /* restore cpu resource states */
1422 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1423 g_assert(type
== LTTV_POINTER
);
1424 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1425 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1427 /* restore irq resource states */
1428 nb_irqs
= self
->nb_irqs
;
1429 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1430 g_assert(type
== LTTV_POINTER
);
1431 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1432 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1434 /* restore the blkdev states */
1435 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1436 g_assert(type
== LTTV_POINTER
);
1437 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1438 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1440 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1442 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1443 LttvTracefileContext
*, i
));
1444 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1445 g_assert(type
== LTTV_GOBJECT
);
1446 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1448 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1450 g_assert(type
== LTTV_UINT
);
1451 pid
= *(value
.v_uint
);
1452 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1454 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1456 g_assert(type
== LTTV_POINTER
);
1457 //g_assert(*(value.v_pointer) != NULL);
1458 ep
= *(value
.v_pointer
);
1459 g_assert(tfcs
->parent
.t_context
!= NULL
);
1461 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1463 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1464 g_tree_remove(tsc
->pqueue
, tfc
);
1467 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1468 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1469 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1470 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1471 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1473 tfc
->timestamp
= ltt_time_infinite
;
1479 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1481 guint i
, nb_tracefile
, nb_cpus
;
1483 LttvTracefileState
*tfcs
;
1485 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1487 guint
*running_process
;
1489 LttvAttributeType type
;
1491 LttvAttributeValue value
;
1493 LttvAttributeName name
;
1497 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1498 LTTV_STATE_TRACEFILES
);
1499 g_object_ref(G_OBJECT(tracefiles_tree
));
1500 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1502 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1504 g_assert(type
== LTTV_POINTER
);
1505 lttv_state_free_process_table(*(value
.v_pointer
));
1506 *(value
.v_pointer
) = NULL
;
1507 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1509 /* Free running processes array */
1510 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1511 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1513 g_assert(type
== LTTV_POINTER
);
1514 running_process
= *(value
.v_pointer
);
1515 g_free(running_process
);
1517 nb_tracefile
= self
->parent
.tracefiles
->len
;
1519 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1521 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1522 LttvTracefileContext
*, i
));
1523 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1524 g_assert(type
== LTTV_GOBJECT
);
1525 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1527 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1529 g_assert(type
== LTTV_POINTER
);
1530 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1532 g_object_unref(G_OBJECT(tracefiles_tree
));
1536 static void free_saved_state(LttvTraceState
*self
)
1540 LttvAttributeType type
;
1542 LttvAttributeValue value
;
1544 LttvAttributeName name
;
1548 LttvAttribute
*saved_states
;
1550 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1551 LTTV_STATE_SAVED_STATES
);
1553 nb
= lttv_attribute_get_number(saved_states
);
1554 for(i
= 0 ; i
< nb
; i
++) {
1555 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1556 g_assert(type
== LTTV_GOBJECT
);
1557 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1560 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1565 create_max_time(LttvTraceState
*tcs
)
1567 LttvAttributeValue v
;
1569 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1571 g_assert(*(v
.v_pointer
) == NULL
);
1572 *(v
.v_pointer
) = g_new(LttTime
,1);
1573 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1578 get_max_time(LttvTraceState
*tcs
)
1580 LttvAttributeValue v
;
1582 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1584 g_assert(*(v
.v_pointer
) != NULL
);
1585 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1590 free_max_time(LttvTraceState
*tcs
)
1592 LttvAttributeValue v
;
1594 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1596 g_free(*(v
.v_pointer
));
1597 *(v
.v_pointer
) = NULL
;
1601 typedef struct _LttvNameTables
{
1602 // FIXME GQuark *eventtype_names;
1603 GQuark
*syscall_names
;
1609 GQuark
*soft_irq_names
;
1615 create_name_tables(LttvTraceState
*tcs
)
1619 GQuark f_name
, e_name
;
1623 LttvTraceHookByFacility
*thf
;
1629 GString
*fe_name
= g_string_new("");
1631 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1633 LttvAttributeValue v
;
1635 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1637 g_assert(*(v
.v_pointer
) == NULL
);
1638 *(v
.v_pointer
) = name_tables
;
1639 #if 0 // Use iteration over the facilities_by_name and then list all event
1640 // types of each facility
1641 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1642 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1643 for(i
= 0 ; i
< nb
; i
++) {
1644 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1645 e_name
= ltt_eventtype_name(et
);
1646 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1647 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1648 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1651 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1652 LTT_EVENT_SYSCALL_ENTRY
,
1653 LTT_FIELD_SYSCALL_ID
, 0, 0,
1656 thf
= lttv_trace_hook_get_first(&h
);
1658 t
= ltt_field_type(thf
->f1
);
1659 nb
= ltt_type_element_number(t
);
1661 lttv_trace_hook_destroy(&h
);
1663 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1664 name_tables
->nb_syscalls
= nb
;
1666 for(i
= 0 ; i
< nb
; i
++) {
1667 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1668 if(!name_tables
->syscall_names
[i
]) {
1669 GString
*string
= g_string_new("");
1670 g_string_printf(string
, "syscall %u", i
);
1671 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1672 g_string_free(string
, TRUE
);
1676 //name_tables->syscall_names = g_new(GQuark, 256);
1677 //for(i = 0 ; i < 256 ; i++) {
1678 // g_string_printf(fe_name, "syscall %d", i);
1679 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1682 name_tables
->syscall_names
= NULL
;
1683 name_tables
->nb_syscalls
= 0;
1686 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1687 LTT_EVENT_TRAP_ENTRY
,
1688 LTT_FIELD_TRAP_ID
, 0, 0,
1691 thf
= lttv_trace_hook_get_first(&h
);
1693 t
= ltt_field_type(thf
->f1
);
1694 //nb = ltt_type_element_number(t);
1696 lttv_trace_hook_destroy(&h
);
1699 name_tables->trap_names = g_new(GQuark, nb);
1700 for(i = 0 ; i < nb ; i++) {
1701 name_tables->trap_names[i] = g_quark_from_string(
1702 ltt_enum_string_get(t, i));
1705 name_tables
->nb_traps
= 256;
1706 name_tables
->trap_names
= g_new(GQuark
, 256);
1707 for(i
= 0 ; i
< 256 ; i
++) {
1708 g_string_printf(fe_name
, "trap %d", i
);
1709 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1712 name_tables
->trap_names
= NULL
;
1713 name_tables
->nb_traps
= 0;
1716 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1717 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1718 LTT_FIELD_IRQ_ID
, 0, 0,
1721 thf
= lttv_trace_hook_get_first(&h
);
1723 t
= ltt_field_type(thf
->f1
);
1724 //nb = ltt_type_element_number(t);
1726 lttv_trace_hook_destroy(&h
);
1729 name_tables->irq_names = g_new(GQuark, nb);
1730 for(i = 0 ; i < nb ; i++) {
1731 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1735 name_tables
->nb_irqs
= 256;
1736 name_tables
->irq_names
= g_new(GQuark
, 256);
1737 for(i
= 0 ; i
< 256 ; i
++) {
1738 g_string_printf(fe_name
, "irq %d", i
);
1739 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1742 name_tables
->nb_irqs
= 0;
1743 name_tables
->irq_names
= NULL
;
1746 name_tables->soft_irq_names = g_new(GQuark, nb);
1747 for(i = 0 ; i < nb ; i++) {
1748 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1752 name_tables
->nb_softirqs
= 256;
1753 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1754 for(i
= 0 ; i
< 256 ; i
++) {
1755 g_string_printf(fe_name
, "softirq %d", i
);
1756 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1760 g_string_free(fe_name
, TRUE
);
1765 get_name_tables(LttvTraceState
*tcs
)
1767 LttvNameTables
*name_tables
;
1769 LttvAttributeValue v
;
1771 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1773 g_assert(*(v
.v_pointer
) != NULL
);
1774 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1775 //tcs->eventtype_names = name_tables->eventtype_names;
1776 tcs
->syscall_names
= name_tables
->syscall_names
;
1777 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1778 tcs
->trap_names
= name_tables
->trap_names
;
1779 tcs
->nb_traps
= name_tables
->nb_traps
;
1780 tcs
->irq_names
= name_tables
->irq_names
;
1781 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1782 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1783 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1788 free_name_tables(LttvTraceState
*tcs
)
1790 LttvNameTables
*name_tables
;
1792 LttvAttributeValue v
;
1794 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1796 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1797 *(v
.v_pointer
) = NULL
;
1799 // g_free(name_tables->eventtype_names);
1800 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1801 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1802 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1803 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1804 if(name_tables
) g_free(name_tables
);
1807 #ifdef HASH_TABLE_DEBUG
1809 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1811 LttvProcessState
*process
= (LttvProcessState
*)value
;
1813 /* Test for process corruption */
1814 guint stack_len
= process
->execution_stack
->len
;
1817 static void hash_table_check(GHashTable
*table
)
1819 g_hash_table_foreach(table
, test_process
, NULL
);
1825 /* clears the stack and sets the state passed as argument */
1826 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1828 g_array_set_size(cpust
->mode_stack
, 1);
1829 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1832 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1834 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1835 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1838 static void cpu_pop_mode(LttvCPUState
*cpust
)
1840 if(cpust
->mode_stack
->len
<= 1)
1841 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1843 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1846 /* clears the stack and sets the state passed as argument */
1847 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1849 g_array_set_size(bdevst
->mode_stack
, 1);
1850 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1853 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1855 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1856 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1859 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1861 if(bdevst
->mode_stack
->len
<= 1)
1862 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1864 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1867 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1869 g_array_set_size(irqst
->mode_stack
, 1);
1870 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1873 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1875 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1876 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1879 static void irq_pop_mode(LttvIRQState
*irqst
)
1881 if(irqst
->mode_stack
->len
<= 1)
1882 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1884 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1887 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1890 LttvExecutionState
*es
;
1892 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1893 guint cpu
= tfs
->cpu
;
1895 #ifdef HASH_TABLE_DEBUG
1896 hash_table_check(ts
->processes
);
1898 LttvProcessState
*process
= ts
->running_process
[cpu
];
1900 guint depth
= process
->execution_stack
->len
;
1902 process
->execution_stack
=
1903 g_array_set_size(process
->execution_stack
, depth
+ 1);
1906 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1908 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1911 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1912 es
->cum_cpu_time
= ltt_time_zero
;
1913 es
->s
= process
->state
->s
;
1914 process
->state
= es
;
1918 * return 1 when empty, else 0 */
1919 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1920 LttvTracefileState
*tfs
)
1922 guint cpu
= tfs
->cpu
;
1923 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1925 guint depth
= process
->execution_stack
->len
;
1931 process
->execution_stack
=
1932 g_array_set_size(process
->execution_stack
, depth
- 1);
1933 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1935 process
->state
->change
= tfs
->parent
.timestamp
;
1940 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1942 guint cpu
= tfs
->cpu
;
1943 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1944 LttvProcessState
*process
= ts
->running_process
[cpu
];
1946 guint depth
= process
->execution_stack
->len
;
1948 if(process
->state
->t
!= t
){
1949 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1950 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1951 g_info("process state has %s when pop_int is %s\n",
1952 g_quark_to_string(process
->state
->t
),
1953 g_quark_to_string(t
));
1954 g_info("{ %u, %u, %s, %s, %s }\n",
1957 g_quark_to_string(process
->name
),
1958 g_quark_to_string(process
->brand
),
1959 g_quark_to_string(process
->state
->s
));
1964 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1965 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1969 process
->execution_stack
=
1970 g_array_set_size(process
->execution_stack
, depth
- 1);
1971 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1973 process
->state
->change
= tfs
->parent
.timestamp
;
1976 struct search_result
{
1977 const LttTime
*time
; /* Requested time */
1978 LttTime
*best
; /* Best result */
1981 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1983 const LttTime
*elem_time
= (const LttTime
*)a
;
1984 /* Explicit non const cast */
1985 struct search_result
*res
= (struct search_result
*)b
;
1987 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1988 /* The usertrace was created before the schedchange */
1989 /* Get larger keys */
1991 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1992 /* The usertrace was created after the schedchange time */
1993 /* Get smaller keys */
1995 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1996 res
->best
= elem_time
;
1999 res
->best
= elem_time
;
2006 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2007 guint pid
, const LttTime
*timestamp
)
2009 LttvTracefileState
*tfs
= NULL
;
2010 struct search_result res
;
2011 /* Find the usertrace associated with a pid and time interval.
2012 * Search in the usertraces by PID (within a hash) and then, for each
2013 * corresponding element of the array, find the first one with creation
2014 * timestamp the lowest, but higher or equal to "timestamp". */
2015 res
.time
= timestamp
;
2017 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2018 if(usertrace_tree
) {
2019 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2021 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2029 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2030 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2032 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2034 LttvExecutionState
*es
;
2036 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
2041 process
->tgid
= tgid
;
2043 process
->name
= name
;
2044 process
->brand
= LTTV_STATE_UNBRANDED
;
2045 //process->last_cpu = tfs->cpu_name;
2046 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2047 process
->type
= LTTV_STATE_USER_THREAD
;
2048 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2049 process
->current_function
= 0; //function 0x0 by default.
2051 g_info("Process %u, core %p", process
->pid
, process
);
2052 g_hash_table_insert(tcs
->processes
, process
, process
);
2055 process
->ppid
= parent
->pid
;
2056 process
->creation_time
= *timestamp
;
2059 /* No parent. This process exists but we are missing all information about
2060 its creation. The birth time is set to zero but we remember the time of
2065 process
->creation_time
= ltt_time_zero
;
2068 process
->insertion_time
= *timestamp
;
2069 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2070 process
->creation_time
.tv_nsec
);
2071 process
->pid_time
= g_quark_from_string(buffer
);
2073 //process->last_cpu = tfs->cpu_name;
2074 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2075 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2076 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2077 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2078 es
= process
->state
= &g_array_index(process
->execution_stack
,
2079 LttvExecutionState
, 0);
2080 es
->t
= LTTV_STATE_USER_MODE
;
2081 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2082 es
->entry
= *timestamp
;
2083 //g_assert(timestamp->tv_sec != 0);
2084 es
->change
= *timestamp
;
2085 es
->cum_cpu_time
= ltt_time_zero
;
2086 es
->s
= LTTV_STATE_RUN
;
2088 es
= process
->state
= &g_array_index(process
->execution_stack
,
2089 LttvExecutionState
, 1);
2090 es
->t
= LTTV_STATE_SYSCALL
;
2091 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2092 es
->entry
= *timestamp
;
2093 //g_assert(timestamp->tv_sec != 0);
2094 es
->change
= *timestamp
;
2095 es
->cum_cpu_time
= ltt_time_zero
;
2096 es
->s
= LTTV_STATE_WAIT_FORK
;
2098 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2099 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2100 sizeof(guint64
), 0);
2105 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2108 LttvProcessState key
;
2109 LttvProcessState
*process
;
2113 process
= g_hash_table_lookup(ts
->processes
, &key
);
2118 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2119 const LttTime
*timestamp
)
2121 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2122 LttvExecutionState
*es
;
2124 /* Put ltt_time_zero creation time for unexisting processes */
2125 if(unlikely(process
== NULL
)) {
2126 process
= lttv_state_create_process(ts
,
2127 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2128 /* We are not sure is it's a kernel thread or normal thread, put the
2129 * bottom stack state to unknown */
2130 process
->execution_stack
=
2131 g_array_set_size(process
->execution_stack
, 1);
2132 process
->state
= es
=
2133 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2134 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2135 es
->s
= LTTV_STATE_UNNAMED
;
2140 /* FIXME : this function should be called when we receive an event telling that
2141 * release_task has been called in the kernel. In happens generally when
2142 * the parent waits for its child terminaison, but may also happen in special
2143 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2144 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2145 * of a killed thread ground, but isn't the leader.
2147 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2149 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2150 LttvProcessState key
;
2152 key
.pid
= process
->pid
;
2153 key
.cpu
= process
->cpu
;
2154 g_hash_table_remove(ts
->processes
, &key
);
2155 g_array_free(process
->execution_stack
, TRUE
);
2156 g_array_free(process
->user_stack
, TRUE
);
2161 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2163 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2164 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2169 static void lttv_state_free_process_table(GHashTable
*processes
)
2171 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2172 g_hash_table_destroy(processes
);
2176 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2178 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2180 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2181 LttvProcessState
*process
= ts
->running_process
[cpu
];
2182 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2183 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2184 LttField
*f
= thf
->f1
;
2186 LttvExecutionSubmode submode
;
2188 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2189 guint syscall
= ltt_event_get_unsigned(e
, f
);
2191 if(syscall
< nb_syscalls
) {
2192 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2195 /* Fixup an incomplete syscall table */
2196 GString
*string
= g_string_new("");
2197 g_string_printf(string
, "syscall %u", syscall
);
2198 submode
= g_quark_from_string(string
->str
);
2199 g_string_free(string
, TRUE
);
2201 /* There can be no system call from PID 0 : unknown state */
2202 if(process
->pid
!= 0)
2203 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2208 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2210 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2212 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2213 LttvProcessState
*process
= ts
->running_process
[cpu
];
2215 /* There can be no system call from PID 0 : unknown state */
2216 if(process
->pid
!= 0)
2217 pop_state(s
, LTTV_STATE_SYSCALL
);
2222 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2225 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2226 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2227 LttField
*f
= thf
->f1
;
2229 LttvExecutionSubmode submode
;
2231 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2232 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2234 if(trap
< nb_traps
) {
2235 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2237 /* Fixup an incomplete trap table */
2238 GString
*string
= g_string_new("");
2239 g_string_printf(string
, "trap %llu", trap
);
2240 submode
= g_quark_from_string(string
->str
);
2241 g_string_free(string
, TRUE
);
2244 push_state(s
, LTTV_STATE_TRAP
, submode
);
2246 /* update cpu status */
2247 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2252 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2254 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2256 pop_state(s
, LTTV_STATE_TRAP
);
2258 /* update cpu status */
2259 cpu_pop_mode(s
->cpu_state
);
2264 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2266 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2267 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2268 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2269 guint8 fac_id
= ltt_event_facility_id(e
);
2270 guint8 ev_id
= ltt_event_eventtype_id(e
);
2271 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2272 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2273 g_assert(thf
->f1
!= NULL
);
2274 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2275 LttField
*f
= thf
->f1
;
2277 LttvExecutionSubmode submode
;
2278 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2279 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2283 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2285 /* Fixup an incomplete irq table */
2286 GString
*string
= g_string_new("");
2287 g_string_printf(string
, "irq %llu", irq
);
2288 submode
= g_quark_from_string(string
->str
);
2289 g_string_free(string
, TRUE
);
2292 /* Do something with the info about being in user or system mode when int? */
2293 push_state(s
, LTTV_STATE_IRQ
, submode
);
2295 /* update cpu status */
2296 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2298 /* update irq status */
2299 s
->cpu_state
->last_irq
= irq
;
2300 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2305 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2307 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2309 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2315 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2317 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2318 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2320 pop_state(s
, LTTV_STATE_IRQ
);
2322 /* update cpu status */
2323 cpu_pop_mode(s
->cpu_state
);
2325 /* update irq status */
2326 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2331 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2333 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2334 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2335 guint8 fac_id
= ltt_event_facility_id(e
);
2336 guint8 ev_id
= ltt_event_eventtype_id(e
);
2337 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2338 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2339 g_assert(thf
->f1
!= NULL
);
2340 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2341 LttField
*f
= thf
->f1
;
2343 LttvExecutionSubmode submode
;
2344 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2345 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2348 if(softirq
< nb_softirqs
) {
2349 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2351 /* Fixup an incomplete irq table */
2352 GString
*string
= g_string_new("");
2353 g_string_printf(string
, "softirq %llu", softirq
);
2354 submode
= g_quark_from_string(string
->str
);
2355 g_string_free(string
, TRUE
);
2358 /* Do something with the info about being in user or system mode when int? */
2359 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2363 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2365 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2366 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2367 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2368 guint8 fac_id
= ltt_event_facility_id(e
);
2369 guint8 ev_id
= ltt_event_eventtype_id(e
);
2370 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2372 GQuark action
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2373 guint irq
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2375 ts
->irq_names
[irq
] = action
;
2381 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2383 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2384 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2385 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2386 guint8 fac_id
= ltt_event_facility_id(e
);
2387 guint8 ev_id
= ltt_event_eventtype_id(e
);
2388 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2390 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2391 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2392 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2393 guint16 devcode
= MKDEV(major
,minor
);
2395 /* have we seen this block device before? */
2396 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2399 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2401 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2406 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2408 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2409 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2410 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2411 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2413 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2414 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2415 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2416 guint16 devcode
= MKDEV(major
,minor
);
2418 /* have we seen this block device before? */
2419 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2421 /* update block device */
2422 bdev_pop_mode(bdev
);
2427 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2431 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2432 guint cpu
= tfs
->cpu
;
2433 LttvProcessState
*process
= ts
->running_process
[cpu
];
2435 guint depth
= process
->user_stack
->len
;
2437 process
->user_stack
=
2438 g_array_set_size(process
->user_stack
, depth
+ 1);
2440 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2441 *new_func
= funcptr
;
2442 process
->current_function
= funcptr
;
2445 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2447 guint cpu
= tfs
->cpu
;
2448 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2449 LttvProcessState
*process
= ts
->running_process
[cpu
];
2451 if(process
->current_function
!= funcptr
){
2452 g_info("Different functions (%lu.%09lu): ignore it\n",
2453 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2454 g_info("process state has %llu when pop_function is %llu\n",
2455 process
->current_function
, funcptr
);
2456 g_info("{ %u, %u, %s, %s, %s }\n",
2459 g_quark_to_string(process
->name
),
2460 g_quark_to_string(process
->brand
),
2461 g_quark_to_string(process
->state
->s
));
2464 guint depth
= process
->user_stack
->len
;
2467 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2468 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2472 process
->user_stack
=
2473 g_array_set_size(process
->user_stack
, depth
- 1);
2474 process
->current_function
=
2475 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2479 static gboolean
function_entry(void *hook_data
, void *call_data
)
2481 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2482 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2483 guint8 fac_id
= ltt_event_facility_id(e
);
2484 guint8 ev_id
= ltt_event_eventtype_id(e
);
2485 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2486 g_assert(thf
->f1
!= NULL
);
2487 LttField
*f
= thf
->f1
;
2488 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2490 push_function(s
, funcptr
);
2494 static gboolean
function_exit(void *hook_data
, void *call_data
)
2496 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2497 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2498 guint8 fac_id
= ltt_event_facility_id(e
);
2499 guint8 ev_id
= ltt_event_eventtype_id(e
);
2500 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2501 g_assert(thf
->f1
!= NULL
);
2502 LttField
*f
= thf
->f1
;
2503 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2505 LttvExecutionSubmode submode
;
2507 pop_function(s
, funcptr
);
2511 static gboolean
schedchange(void *hook_data
, void *call_data
)
2513 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2515 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2516 LttvProcessState
*process
= ts
->running_process
[cpu
];
2517 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2519 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2520 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2521 guint pid_in
, pid_out
;
2524 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2525 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2526 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2528 if(likely(process
!= NULL
)) {
2530 /* We could not know but it was not the idle process executing.
2531 This should only happen at the beginning, before the first schedule
2532 event, and when the initial information (current process for each CPU)
2533 is missing. It is not obvious how we could, after the fact, compensate
2534 the wrongly attributed statistics. */
2536 //This test only makes sense once the state is known and if there is no
2537 //missing events. We need to silently ignore schedchange coming after a
2538 //process_free, or it causes glitches. (FIXME)
2539 //if(unlikely(process->pid != pid_out)) {
2540 // g_assert(process->pid == 0);
2542 if(process
->pid
== 0
2543 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2545 /* Scheduling out of pid 0 at beginning of the trace :
2546 * we know for sure it is in syscall mode at this point. */
2547 g_assert(process
->execution_stack
->len
== 1);
2548 process
->state
->t
= LTTV_STATE_SYSCALL
;
2549 process
->state
->s
= LTTV_STATE_WAIT
;
2550 process
->state
->change
= s
->parent
.timestamp
;
2551 process
->state
->entry
= s
->parent
.timestamp
;
2554 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2555 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2556 process
->state
->change
= s
->parent
.timestamp
;
2558 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2559 else process
->state
->s
= LTTV_STATE_WAIT
;
2560 process
->state
->change
= s
->parent
.timestamp
;
2563 if(state_out
== 32 || state_out
== 128)
2564 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2565 /* see sched.h for states */
2568 process
= ts
->running_process
[cpu
] =
2569 lttv_state_find_process_or_create(
2570 (LttvTraceState
*)s
->parent
.t_context
,
2572 &s
->parent
.timestamp
);
2573 process
->state
->s
= LTTV_STATE_RUN
;
2575 if(process
->usertrace
)
2576 process
->usertrace
->cpu
= cpu
;
2577 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2578 process
->state
->change
= s
->parent
.timestamp
;
2580 /* update cpu status */
2582 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2584 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2589 static gboolean
process_fork(void *hook_data
, void *call_data
)
2591 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2592 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2593 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2595 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2596 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2597 LttvProcessState
*zombie_process
;
2599 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2600 LttvProcessState
*process
= ts
->running_process
[cpu
];
2601 LttvProcessState
*child_process
;
2604 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2607 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2608 s
->parent
.target_pid
= child_pid
;
2611 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2612 else child_tgid
= 0;
2614 /* Mathieu : it seems like the process might have been scheduled in before the
2615 * fork, and, in a rare case, might be the current process. This might happen
2616 * in a SMP case where we don't have enough precision on the clocks.
2618 * Test reenabled after precision fixes on time. (Mathieu) */
2620 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2622 if(unlikely(zombie_process
!= NULL
)) {
2623 /* Reutilisation of PID. Only now we are sure that the old PID
2624 * has been released. FIXME : should know when release_task happens instead.
2626 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2628 for(i
=0; i
< num_cpus
; i
++) {
2629 g_assert(zombie_process
!= ts
->running_process
[i
]);
2632 exit_process(s
, zombie_process
);
2635 g_assert(process
->pid
!= child_pid
);
2636 // FIXME : Add this test in the "known state" section
2637 // g_assert(process->pid == parent_pid);
2638 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2639 if(child_process
== NULL
) {
2640 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2641 child_pid
, child_tgid
,
2642 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2644 /* The process has already been created : due to time imprecision between
2645 * multiple CPUs : it has been scheduled in before creation. Note that we
2646 * shouldn't have this kind of imprecision.
2648 * Simply put a correct parent.
2650 g_assert(0); /* This is a problematic case : the process has been created
2651 before the fork event */
2652 child_process
->ppid
= process
->pid
;
2653 child_process
->tgid
= child_tgid
;
2655 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2656 child_process
->name
= process
->name
;
2657 child_process
->brand
= process
->brand
;
2662 /* We stamp a newly created process as kernel_thread.
2663 * The thread should not be running yet. */
2664 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2666 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2667 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2668 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2671 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2672 LttvProcessState
*process
;
2673 LttvExecutionState
*es
;
2676 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2677 s
->parent
.target_pid
= pid
;
2679 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2681 process
->execution_stack
=
2682 g_array_set_size(process
->execution_stack
, 1);
2683 es
= process
->state
=
2684 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2685 es
->t
= LTTV_STATE_SYSCALL
;
2686 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2691 static gboolean
process_exit(void *hook_data
, void *call_data
)
2693 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2694 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2695 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2699 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2700 LttvProcessState
*process
; // = ts->running_process[cpu];
2702 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2703 s
->parent
.target_pid
= pid
;
2705 // FIXME : Add this test in the "known state" section
2706 // g_assert(process->pid == pid);
2708 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2709 if(likely(process
!= NULL
)) {
2710 process
->state
->s
= LTTV_STATE_EXIT
;
2715 static gboolean
process_free(void *hook_data
, void *call_data
)
2717 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2718 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2719 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2720 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2722 LttvProcessState
*process
;
2724 /* PID of the process to release */
2725 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2726 s
->parent
.target_pid
= release_pid
;
2728 g_assert(release_pid
!= 0);
2730 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2732 if(likely(process
!= NULL
)) {
2733 /* release_task is happening at kernel level : we can now safely release
2734 * the data structure of the process */
2735 //This test is fun, though, as it may happen that
2736 //at time t : CPU 0 : process_free
2737 //at time t+150ns : CPU 1 : schedule out
2738 //Clearly due to time imprecision, we disable it. (Mathieu)
2739 //If this weird case happen, we have no choice but to put the
2740 //Currently running process on the cpu to 0.
2741 //I re-enable it following time precision fixes. (Mathieu)
2742 //Well, in the case where an process is freed by a process on another CPU
2743 //and still scheduled, it happens that this is the schedchange that will
2744 //drop the last reference count. Do not free it here!
2745 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2747 for(i
=0; i
< num_cpus
; i
++) {
2748 //g_assert(process != ts->running_process[i]);
2749 if(process
== ts
->running_process
[i
]) {
2750 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2754 if(i
== num_cpus
) /* process is not scheduled */
2755 exit_process(s
, process
);
2762 static gboolean
process_exec(void *hook_data
, void *call_data
)
2764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2765 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2767 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2770 LttvProcessState
*process
= ts
->running_process
[cpu
];
2772 #if 0//how to use a sequence that must be transformed in a string
2773 /* PID of the process to release */
2774 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2775 //name = ltt_event_get_string(e, thf->f1);
2776 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2778 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2779 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2780 memcpy(null_term_name
, name_begin
, name_len
);
2781 null_term_name
[name_len
] = '\0';
2782 process
->name
= g_quark_from_string(null_term_name
);
2785 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2786 process
->brand
= LTTV_STATE_UNBRANDED
;
2787 //g_free(null_term_name);
2791 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2793 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2794 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2795 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2796 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2799 LttvProcessState
*process
= ts
->running_process
[cpu
];
2801 name
= ltt_event_get_string(e
, thf
->f1
);
2802 process
->brand
= g_quark_from_string(name
);
2807 static void fix_process(gpointer key
, gpointer value
,
2810 LttvProcessState
*process
;
2811 LttvExecutionState
*es
;
2812 process
= (LttvProcessState
*)value
;
2813 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2814 LttTime
*timestamp
= (LttTime
*)user_data
;
2816 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2817 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2818 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2819 es
->t
= LTTV_STATE_SYSCALL
;
2820 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2821 es
->entry
= *timestamp
;
2822 es
->change
= *timestamp
;
2823 es
->cum_cpu_time
= ltt_time_zero
;
2824 if(es
->s
== LTTV_STATE_UNNAMED
)
2825 es
->s
= LTTV_STATE_WAIT
;
2828 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2829 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2830 es
->t
= LTTV_STATE_USER_MODE
;
2831 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2832 es
->entry
= *timestamp
;
2833 //g_assert(timestamp->tv_sec != 0);
2834 es
->change
= *timestamp
;
2835 es
->cum_cpu_time
= ltt_time_zero
;
2836 if(es
->s
== LTTV_STATE_UNNAMED
)
2837 es
->s
= LTTV_STATE_RUN
;
2839 if(process
->execution_stack
->len
== 1) {
2840 /* Still in bottom unknown mode, means never did a system call
2841 * May be either in user mode, syscall mode, running or waiting.*/
2842 /* FIXME : we may be tagging syscall mode when being user mode */
2843 process
->execution_stack
=
2844 g_array_set_size(process
->execution_stack
, 2);
2845 es
= process
->state
= &g_array_index(process
->execution_stack
,
2846 LttvExecutionState
, 1);
2847 es
->t
= LTTV_STATE_SYSCALL
;
2848 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2849 es
->entry
= *timestamp
;
2850 //g_assert(timestamp->tv_sec != 0);
2851 es
->change
= *timestamp
;
2852 es
->cum_cpu_time
= ltt_time_zero
;
2853 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2854 es
->s
= LTTV_STATE_WAIT
;
2860 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2862 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2863 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2864 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2865 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2866 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2868 /* For all processes */
2869 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2870 /* else, if stack[0] is unknown, set to user mode, running */
2872 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2875 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2877 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2878 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2879 //It's slow : optimise later by doing this before reading trace.
2880 LttEventType
*et
= ltt_event_eventtype(e
);
2882 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2888 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2889 LttvProcessState
*process
= ts
->running_process
[cpu
];
2890 LttvProcessState
*parent_process
;
2891 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2892 GQuark type
, mode
, submode
, status
;
2893 LttvExecutionState
*es
;
2897 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2898 s
->parent
.target_pid
= pid
;
2901 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2904 command
= ltt_event_get_string(e
, thf
->f3
);
2907 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2908 type
= ltt_enum_string_get(ltt_field_type(f4
),
2909 ltt_event_get_unsigned(e
, f4
));
2912 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2913 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2914 ltt_event_get_unsigned(e
, f5
));
2917 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2918 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2919 ltt_event_get_unsigned(e
, f6
));
2922 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2923 status
= ltt_enum_string_get(ltt_field_type(f7
),
2924 ltt_event_get_unsigned(e
, f7
));
2927 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2928 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2933 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2934 for(i
=0; i
<nb_cpus
; i
++) {
2935 process
= lttv_state_find_process(ts
, i
, pid
);
2936 g_assert(process
!= NULL
);
2938 process
->ppid
= parent_pid
;
2939 process
->tgid
= tgid
;
2940 process
->name
= g_quark_from_string(command
);
2942 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2943 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2947 /* The process might exist if a process was forked while performing the
2949 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2950 if(process
== NULL
) {
2951 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2952 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2953 pid
, tgid
, g_quark_from_string(command
),
2954 &s
->parent
.timestamp
);
2956 /* Keep the stack bottom : a running user mode */
2957 /* Disabled because of inconsistencies in the current statedump states. */
2958 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2959 /* Only keep the bottom
2960 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2961 /* Will cause expected trap when in fact being syscall (even after end of
2963 * Will cause expected interrupt when being syscall. (only before end of
2964 * statedump event) */
2965 // This will cause a "popping last state on stack, ignoring it."
2966 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2967 es
= process
->state
= &g_array_index(process
->execution_stack
,
2968 LttvExecutionState
, 0);
2969 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2970 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2971 es
->s
= LTTV_STATE_UNNAMED
;
2972 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2974 es
->t
= LTTV_STATE_SYSCALL
;
2979 /* User space process :
2980 * bottom : user mode
2981 * either currently running or scheduled out.
2982 * can be scheduled out because interrupted in (user mode or in syscall)
2983 * or because of an explicit call to the scheduler in syscall. Note that
2984 * the scheduler call comes after the irq_exit, so never in interrupt
2986 // temp workaround : set size to 1 : only have user mode bottom of stack.
2987 // will cause g_info message of expected syscall mode when in fact being
2988 // in user mode. Can also cause expected trap when in fact being user
2989 // mode in the event of a page fault reenabling interrupts in the handler.
2990 // Expected syscall and trap can also happen after the end of statedump
2991 // This will cause a "popping last state on stack, ignoring it."
2992 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2993 es
= process
->state
= &g_array_index(process
->execution_stack
,
2994 LttvExecutionState
, 0);
2995 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2996 es
->s
= LTTV_STATE_UNNAMED
;
2997 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2999 es
->t
= LTTV_STATE_USER_MODE
;
3007 es
= process
->state
= &g_array_index(process
->execution_stack
,
3008 LttvExecutionState
, 1);
3009 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3010 es
->s
= LTTV_STATE_UNNAMED
;
3011 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3015 /* The process has already been created :
3016 * Probably was forked while dumping the process state or
3017 * was simply scheduled in prior to get the state dump event.
3019 process
->ppid
= parent_pid
;
3020 process
->tgid
= tgid
;
3021 process
->name
= g_quark_from_string(command
);
3022 process
->type
= type
;
3024 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3026 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3027 if(type
== LTTV_STATE_KERNEL_THREAD
)
3028 es
->t
= LTTV_STATE_SYSCALL
;
3030 es
->t
= LTTV_STATE_USER_MODE
;
3033 /* Don't mess around with the stack, it will eventually become
3034 * ok after the end of state dump. */
3041 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3043 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3045 lttv_state_add_event_hooks(tss
);
3050 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3052 LttvTraceset
*traceset
= self
->parent
.ts
;
3054 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3058 LttvTracefileState
*tfs
;
3062 LttvTraceHookByFacility
*thf
;
3064 LttvTraceHook
*hook
;
3066 LttvAttributeValue val
;
3071 nb_trace
= lttv_traceset_number(traceset
);
3072 for(i
= 0 ; i
< nb_trace
; i
++) {
3073 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3075 /* Find the eventtype id for the following events and register the
3076 associated by id hooks. */
3078 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3079 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
3082 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3083 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3084 LTT_FIELD_SYSCALL_ID
, 0, 0,
3085 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3088 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3089 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3091 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3094 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3095 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
3096 LTT_FIELD_TRAP_ID
, 0, 0,
3097 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3100 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3101 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3103 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3106 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3107 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3108 LTT_FIELD_IRQ_ID
, 0, 0,
3109 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3112 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3113 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3115 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3118 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3119 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3120 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3121 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3124 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3125 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3127 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3130 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3131 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3132 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3133 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3136 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3137 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3138 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3139 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3142 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3143 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3144 LTT_FIELD_PID
, 0, 0,
3145 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3149 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3150 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3151 LTT_FIELD_PID
, 0, 0,
3152 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3155 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3156 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3157 LTT_FIELD_PID
, 0, 0,
3158 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3161 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3162 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3163 LTT_FIELD_FILENAME
, 0, 0,
3164 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3167 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3168 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3169 LTT_FIELD_NAME
, 0, 0,
3170 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3173 /* statedump-related hooks */
3174 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3175 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3176 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3177 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3180 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3181 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3183 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3186 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3187 LTT_FACILITY_LIST
, LTT_EVENT_LIST_INTERRUPT
,
3188 LTT_FIELD_ACTION
, LTT_FIELD_NUM
, 0,
3189 enum_interrupt
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3192 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3193 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3194 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3195 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3198 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3199 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3200 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3201 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3204 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3205 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3206 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3207 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3210 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3211 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3212 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3213 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3216 hooks
= g_array_set_size(hooks
, hn
);
3218 /* Add these hooks to each event_by_id hooks list */
3220 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3222 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3224 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3225 LttvTracefileContext
*, j
));
3227 for(k
= 0 ; k
< hooks
->len
; k
++) {
3228 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3229 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3230 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3232 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3239 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3240 *(val
.v_pointer
) = hooks
;
3244 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3246 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3248 lttv_state_remove_event_hooks(tss
);
3253 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3255 LttvTraceset
*traceset
= self
->parent
.ts
;
3257 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3261 LttvTracefileState
*tfs
;
3265 LttvTraceHook
*hook
;
3267 LttvTraceHookByFacility
*thf
;
3269 LttvAttributeValue val
;
3271 nb_trace
= lttv_traceset_number(traceset
);
3272 for(i
= 0 ; i
< nb_trace
; i
++) {
3273 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3275 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3276 hooks
= *(val
.v_pointer
);
3278 /* Remove these hooks from each event_by_id hooks list */
3280 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3282 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3284 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3285 LttvTracefileContext
*, j
));
3287 for(k
= 0 ; k
< hooks
->len
; k
++) {
3288 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3289 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3290 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3292 lttv_hooks_remove_data(
3293 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3299 for(k
= 0 ; k
< hooks
->len
; k
++)
3300 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3301 g_array_free(hooks
, TRUE
);
3305 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3307 guint
*event_count
= (guint
*)hook_data
;
3309 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3310 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3315 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3317 LttvTracefileState
*tfcs
;
3319 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3321 LttEventPosition
*ep
;
3327 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3329 LttvAttributeValue value
;
3331 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3332 LTTV_STATE_SAVED_STATES
);
3333 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3334 value
= lttv_attribute_add(saved_states_tree
,
3335 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3336 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3337 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3338 *(value
.v_time
) = self
->parent
.timestamp
;
3339 lttv_state_save(tcs
, saved_state_tree
);
3340 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3341 self
->parent
.timestamp
.tv_nsec
);
3343 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3348 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3350 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3352 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3357 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3365 static gboolean
block_start(void *hook_data
, void *call_data
)
3367 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3369 LttvTracefileState
*tfcs
;
3371 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3373 LttEventPosition
*ep
;
3375 guint i
, nb_block
, nb_event
, nb_tracefile
;
3379 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3381 LttvAttributeValue value
;
3383 ep
= ltt_event_position_new();
3385 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3387 /* Count the number of events added since the last block end in any
3390 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3392 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3393 LttvTracefileContext
, i
));
3394 ltt_event_position(tfcs
->parent
.e
, ep
);
3395 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3396 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3397 tfcs
->saved_position
= nb_event
;
3401 if(tcs
->nb_event
>= tcs
->save_interval
) {
3402 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3403 LTTV_STATE_SAVED_STATES
);
3404 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3405 value
= lttv_attribute_add(saved_states_tree
,
3406 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3407 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3408 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3409 *(value
.v_time
) = self
->parent
.timestamp
;
3410 lttv_state_save(tcs
, saved_state_tree
);
3412 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3413 self
->parent
.timestamp
.tv_nsec
);
3415 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3421 static gboolean
block_end(void *hook_data
, void *call_data
)
3423 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3425 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3429 LttEventPosition
*ep
;
3431 guint nb_block
, nb_event
;
3433 ep
= ltt_event_position_new();
3434 ltt_event_position(self
->parent
.e
, ep
);
3435 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3436 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3437 self
->saved_position
= 0;
3438 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3445 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3447 LttvTraceset
*traceset
= self
->parent
.ts
;
3449 guint i
, j
, nb_trace
, nb_tracefile
;
3453 LttvTracefileState
*tfs
;
3455 LttvTraceHook hook_start
, hook_end
;
3457 nb_trace
= lttv_traceset_number(traceset
);
3458 for(i
= 0 ; i
< nb_trace
; i
++) {
3459 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3461 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3462 NULL
, NULL
, block_start
, &hook_start
);
3463 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3464 NULL
, NULL
, block_end
, &hook_end
);
3466 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3468 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3470 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3471 LttvTracefileContext
, j
));
3472 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3473 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3474 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3475 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3481 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3483 LttvTraceset
*traceset
= self
->parent
.ts
;
3485 guint i
, j
, nb_trace
, nb_tracefile
;
3489 LttvTracefileState
*tfs
;
3492 nb_trace
= lttv_traceset_number(traceset
);
3493 for(i
= 0 ; i
< nb_trace
; i
++) {
3495 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3496 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3498 if(ts
->has_precomputed_states
) continue;
3500 guint
*event_count
= g_new(guint
, 1);
3503 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3505 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3506 LttvTracefileContext
*, j
));
3507 lttv_hooks_add(tfs
->parent
.event
,
3508 state_save_event_hook
,
3515 lttv_process_traceset_begin(&self
->parent
,
3516 NULL
, NULL
, NULL
, NULL
, NULL
);
3520 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3522 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3524 lttv_state_save_add_event_hooks(tss
);
3531 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3533 LttvTraceset
*traceset
= self
->parent
.ts
;
3535 guint i
, j
, nb_trace
, nb_tracefile
;
3539 LttvTracefileState
*tfs
;
3541 LttvTraceHook hook_start
, hook_end
;
3543 nb_trace
= lttv_traceset_number(traceset
);
3544 for(i
= 0 ; i
< nb_trace
; i
++) {
3545 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3547 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3548 NULL
, NULL
, block_start
, &hook_start
);
3550 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3551 NULL
, NULL
, block_end
, &hook_end
);
3553 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3555 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3557 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3558 LttvTracefileContext
, j
));
3559 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3560 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3561 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3562 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3568 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3570 LttvTraceset
*traceset
= self
->parent
.ts
;
3572 guint i
, j
, nb_trace
, nb_tracefile
;
3576 LttvTracefileState
*tfs
;
3578 LttvHooks
*after_trace
= lttv_hooks_new();
3580 lttv_hooks_add(after_trace
,
3581 state_save_after_trace_hook
,
3586 lttv_process_traceset_end(&self
->parent
,
3587 NULL
, after_trace
, NULL
, NULL
, NULL
);
3589 lttv_hooks_destroy(after_trace
);
3591 nb_trace
= lttv_traceset_number(traceset
);
3592 for(i
= 0 ; i
< nb_trace
; i
++) {
3594 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3595 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3597 if(ts
->has_precomputed_states
) continue;
3599 guint
*event_count
= NULL
;
3601 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3603 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3604 LttvTracefileContext
*, j
));
3605 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3606 state_save_event_hook
);
3608 if(event_count
) g_free(event_count
);
3612 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3614 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3616 lttv_state_save_remove_event_hooks(tss
);
3621 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3623 LttvTraceset
*traceset
= self
->parent
.ts
;
3627 int min_pos
, mid_pos
, max_pos
;
3629 guint call_rest
= 0;
3631 LttvTraceState
*tcs
;
3633 LttvAttributeValue value
;
3635 LttvAttributeType type
;
3637 LttvAttributeName name
;
3641 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3643 //g_tree_destroy(self->parent.pqueue);
3644 //self->parent.pqueue = g_tree_new(compare_tracefile);
3646 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3648 nb_trace
= lttv_traceset_number(traceset
);
3649 for(i
= 0 ; i
< nb_trace
; i
++) {
3650 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3652 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3653 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3654 LTTV_STATE_SAVED_STATES
);
3657 if(saved_states_tree
) {
3658 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3659 mid_pos
= max_pos
/ 2;
3660 while(min_pos
< max_pos
) {
3661 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3663 g_assert(type
== LTTV_GOBJECT
);
3664 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3665 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3667 g_assert(type
== LTTV_TIME
);
3668 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3670 closest_tree
= saved_state_tree
;
3672 else max_pos
= mid_pos
- 1;
3674 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3678 /* restore the closest earlier saved state */
3680 lttv_state_restore(tcs
, closest_tree
);
3684 /* There is no saved state, yet we want to have it. Restart at T0 */
3686 restore_init_state(tcs
);
3687 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3690 /* We want to seek quickly without restoring/updating the state */
3692 restore_init_state(tcs
);
3693 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3696 if(!call_rest
) g_info("NOT Calling restore");
3701 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3707 traceset_state_finalize (LttvTracesetState
*self
)
3709 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3710 finalize(G_OBJECT(self
));
3715 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3717 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3719 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3720 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3721 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3722 klass
->new_traceset_context
= new_traceset_context
;
3723 klass
->new_trace_context
= new_trace_context
;
3724 klass
->new_tracefile_context
= new_tracefile_context
;
3729 lttv_traceset_state_get_type(void)
3731 static GType type
= 0;
3733 static const GTypeInfo info
= {
3734 sizeof (LttvTracesetStateClass
),
3735 NULL
, /* base_init */
3736 NULL
, /* base_finalize */
3737 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3738 NULL
, /* class_finalize */
3739 NULL
, /* class_data */
3740 sizeof (LttvTracesetState
),
3741 0, /* n_preallocs */
3742 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3743 NULL
/* value handling */
3746 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3754 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3760 trace_state_finalize (LttvTraceState
*self
)
3762 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3763 finalize(G_OBJECT(self
));
3768 trace_state_class_init (LttvTraceStateClass
*klass
)
3770 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3772 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3773 klass
->state_save
= state_save
;
3774 klass
->state_restore
= state_restore
;
3775 klass
->state_saved_free
= state_saved_free
;
3780 lttv_trace_state_get_type(void)
3782 static GType type
= 0;
3784 static const GTypeInfo info
= {
3785 sizeof (LttvTraceStateClass
),
3786 NULL
, /* base_init */
3787 NULL
, /* base_finalize */
3788 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3789 NULL
, /* class_finalize */
3790 NULL
, /* class_data */
3791 sizeof (LttvTraceState
),
3792 0, /* n_preallocs */
3793 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3794 NULL
/* value handling */
3797 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3798 "LttvTraceStateType", &info
, 0);
3805 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3811 tracefile_state_finalize (LttvTracefileState
*self
)
3813 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3814 finalize(G_OBJECT(self
));
3819 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3821 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3823 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3828 lttv_tracefile_state_get_type(void)
3830 static GType type
= 0;
3832 static const GTypeInfo info
= {
3833 sizeof (LttvTracefileStateClass
),
3834 NULL
, /* base_init */
3835 NULL
, /* base_finalize */
3836 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3837 NULL
, /* class_finalize */
3838 NULL
, /* class_data */
3839 sizeof (LttvTracefileState
),
3840 0, /* n_preallocs */
3841 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3842 NULL
/* value handling */
3845 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3846 "LttvTracefileStateType", &info
, 0);
3852 static void module_init()
3854 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3855 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3856 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3857 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3858 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3859 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3860 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3861 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3862 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3863 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3864 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3865 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3866 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3867 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3868 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3869 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3870 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3871 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3872 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3873 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3874 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3875 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3876 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3877 LTTV_STATE_EVENT
= g_quark_from_string("event");
3878 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3879 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3880 LTTV_STATE_TIME
= g_quark_from_string("time");
3881 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3882 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3883 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3884 g_quark_from_string("trace_state_use_count");
3885 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3886 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3887 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3890 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3891 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3892 LTT_FACILITY_FS
= g_quark_from_string("fs");
3893 LTT_FACILITY_LIST
= g_quark_from_string("list");
3894 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3895 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3898 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3899 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3900 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3901 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3902 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3903 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3904 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3905 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3906 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3907 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3908 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3909 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3910 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3911 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3912 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3913 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3914 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3915 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3916 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3917 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3918 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3919 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3922 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3923 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3924 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3925 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3926 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3927 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3928 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3929 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3930 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3931 LTT_FIELD_PID
= g_quark_from_string("pid");
3932 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3933 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3934 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3935 LTT_FIELD_NAME
= g_quark_from_string("name");
3936 LTT_FIELD_TYPE
= g_quark_from_string("type");
3937 LTT_FIELD_MODE
= g_quark_from_string("mode");
3938 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3939 LTT_FIELD_STATUS
= g_quark_from_string("status");
3940 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3941 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3942 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3943 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3944 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3945 LTT_FIELD_ACTION
= g_quark_from_string("action");
3946 LTT_FIELD_NUM
= g_quark_from_string("num");
3948 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3949 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3950 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3951 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3952 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3954 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3955 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3956 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3958 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3959 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3960 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3961 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3964 static void module_destroy()
3969 LTTV_MODULE("state", "State computation", \
3970 "Update the system state, possibly saving it at intervals", \
3971 module_init
, module_destroy
)