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
;
847 /* TODO : check return value */
848 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
849 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
850 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
851 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
852 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
853 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
854 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
855 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
856 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
859 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
861 /* We must link to the parent */
862 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
864 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
865 if(process
== NULL
) {
866 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
868 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
872 process
->insertion_time
= tmp
.insertion_time
;
873 process
->creation_time
= tmp
.creation_time
;
874 process
->type
= g_quark_from_string(
875 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
876 process
->tgid
= tmp
.tgid
;
877 process
->ppid
= tmp
.ppid
;
878 process
->brand
= g_quark_from_string(
879 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
881 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
885 if(feof(fp
) || ferror(fp
)) goto end_loop
;
887 gint hdr
= fgetc(fp
);
888 if(hdr
== EOF
) goto end_loop
;
892 process
->execution_stack
=
893 g_array_set_size(process
->execution_stack
,
894 process
->execution_stack
->len
+ 1);
895 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
896 process
->execution_stack
->len
-1);
899 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
900 es
->t
= g_quark_from_string(
901 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
902 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
903 es
->n
= g_quark_from_string(
904 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
905 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
906 es
->s
= g_quark_from_string(
907 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
908 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
909 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
910 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
913 process
->user_stack
= g_array_set_size(process
->user_stack
,
914 process
->user_stack
->len
+ 1);
915 address
= &g_array_index(process
->user_stack
, guint64
,
916 process
->user_stack
->len
-1);
917 fread(address
, sizeof(address
), 1, fp
);
918 process
->current_function
= *address
;
921 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
922 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
934 /* Called because a HDR_PROCESS_STATE was found */
935 /* Append a saved state to the trace states */
936 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
938 guint i
, nb_tracefile
, nb_block
, offset
;
940 LttvTracefileState
*tfcs
;
942 LttEventPosition
*ep
;
950 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
952 LttvAttributeValue value
;
953 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
954 ep
= ltt_event_position_new();
956 restore_init_state(self
);
958 fread(&t
, sizeof(t
), 1, fp
);
961 if(feof(fp
) || ferror(fp
)) goto end_loop
;
963 if(hdr
== EOF
) goto end_loop
;
967 /* Call read_process_state_raw */
968 read_process_state_raw(self
, fp
, quarktable
);
978 case HDR_PROCESS_STATE
:
984 g_error("Error while parsing saved state file : unknown data header %d",
990 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
991 for(i
=0;i
<nb_cpus
;i
++) {
994 g_assert(hdr
== HDR_CPU
);
995 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
996 g_assert(i
== cpu_num
);
997 fread(&self
->running_process
[i
]->pid
,
998 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1001 nb_tracefile
= self
->parent
.tracefiles
->len
;
1003 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1005 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1006 LttvTracefileContext
*, i
));
1007 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1008 // tfcs->parent.timestamp.tv_sec,
1009 // tfcs->parent.timestamp.tv_nsec);
1010 g_tree_remove(pqueue
, &tfcs
->parent
);
1012 g_assert(hdr
== HDR_TRACEFILE
);
1013 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1014 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1015 * position following : end of trace */
1016 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1017 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1018 fread(&offset
, sizeof(offset
), 1, fp
);
1019 fread(&tsc
, sizeof(tsc
), 1, fp
);
1020 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1021 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1023 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1028 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1029 LTTV_STATE_SAVED_STATES
);
1030 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1031 value
= lttv_attribute_add(saved_states_tree
,
1032 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1033 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1034 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1035 *(value
.v_time
) = t
;
1036 lttv_state_save(self
, saved_state_tree
);
1037 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1040 *(self
->max_time_state_recomputed_in_seek
) = t
;
1044 /* Called when a HDR_TRACE is found */
1045 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1046 GPtrArray
*quarktable
)
1051 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1053 if(hdr
== EOF
) goto end_loop
;
1056 case HDR_PROCESS_STATE
:
1057 /* Call read_process_state_raw */
1058 lttv_state_read_raw(tcs
, fp
, quarktable
);
1066 case HDR_USER_STACK
:
1070 g_error("Error while parsing saved state file :"
1071 " unexpected data header %d",
1075 g_error("Error while parsing saved state file : unknown data header %d",
1080 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1081 restore_init_state(&tcs
->parent
);
1082 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1088 /* Copy each process from an existing hash table to a new one */
1090 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1092 LttvProcessState
*process
, *new_process
;
1094 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1098 process
= (LttvProcessState
*)value
;
1099 new_process
= g_new(LttvProcessState
, 1);
1100 *new_process
= *process
;
1101 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1102 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1103 new_process
->execution_stack
=
1104 g_array_set_size(new_process
->execution_stack
,
1105 process
->execution_stack
->len
);
1106 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1107 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1108 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1110 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1111 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1112 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1113 sizeof(guint64
), 0);
1114 new_process
->user_stack
=
1115 g_array_set_size(new_process
->user_stack
,
1116 process
->user_stack
->len
);
1117 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1118 g_array_index(new_process
->user_stack
, guint64
, i
) =
1119 g_array_index(process
->user_stack
, guint64
, i
);
1121 new_process
->current_function
= process
->current_function
;
1122 g_hash_table_insert(new_processes
, new_process
, new_process
);
1126 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1128 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1130 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1131 return new_processes
;
1134 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1137 LttvCPUState
*retval
;
1139 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1141 for(i
=0; i
<n
; i
++) {
1142 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1143 retval
[i
].last_irq
= states
[i
].last_irq
;
1144 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1145 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1146 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1153 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1157 for(i
=0; i
<n
; i
++) {
1158 g_array_free(states
[i
].mode_stack
, FALSE
);
1164 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1167 LttvIRQState
*retval
;
1169 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1171 for(i
=0; i
<n
; i
++) {
1172 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1173 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1174 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1175 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1182 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1186 for(i
=0; i
<n
; i
++) {
1187 g_array_free(states
[i
].mode_stack
, FALSE
);
1193 /* bdevstate stuff */
1195 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1197 gint devcode_gint
= devcode
;
1198 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1200 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1201 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1203 gint
* key
= g_malloc(sizeof(gint
));
1205 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1213 static LttvBdevState
*bdevstate_new(void)
1215 LttvBdevState
*retval
;
1216 retval
= g_malloc(sizeof(LttvBdevState
));
1217 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1222 static void bdevstate_free(LttvBdevState
*bds
)
1224 g_array_free(bds
->mode_stack
, FALSE
);
1228 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1230 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1232 bdevstate_free(bds
);
1235 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1237 LttvBdevState
*retval
;
1239 retval
= bdevstate_new();
1240 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1245 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1247 GHashTable
*ht
= (GHashTable
*)u
;
1248 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1249 LttvBdevState
*newbds
;
1251 newbds
= bdevstate_copy(v
);
1253 g_hash_table_insert(u
, k
, newbds
);
1256 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1260 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1262 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1267 /* Free a hashtable and the LttvBdevState structures its values
1270 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1272 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1273 g_hash_table_destroy(ht
);
1276 /* The saved state for each trace contains a member "processes", which
1277 stores a copy of the process table, and a member "tracefiles" with
1278 one entry per tracefile. Each tracefile has a "process" member pointing
1279 to the current process and a "position" member storing the tracefile
1280 position (needed to seek to the current "next" event. */
1282 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1284 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1286 LttvTracefileState
*tfcs
;
1288 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1290 guint
*running_process
;
1292 LttvAttributeType type
;
1294 LttvAttributeValue value
;
1296 LttvAttributeName name
;
1298 LttEventPosition
*ep
;
1300 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1301 LTTV_STATE_TRACEFILES
);
1303 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1305 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1307 /* Add the currently running processes array */
1308 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1309 running_process
= g_new(guint
, nb_cpus
);
1310 for(i
=0;i
<nb_cpus
;i
++) {
1311 running_process
[i
] = self
->running_process
[i
]->pid
;
1313 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1315 *(value
.v_pointer
) = running_process
;
1317 g_info("State save");
1319 nb_tracefile
= self
->parent
.tracefiles
->len
;
1321 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1323 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1324 LttvTracefileContext
*, i
));
1325 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1326 value
= lttv_attribute_add(tracefiles_tree
, i
,
1328 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1330 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1332 *(value
.v_uint
) = tfcs
->process
->pid
;
1334 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1336 /* Only save the position if the tfs has not infinite time. */
1337 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1338 // && current_tfcs != tfcs) {
1339 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1340 *(value
.v_pointer
) = NULL
;
1342 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1343 ep
= ltt_event_position_new();
1344 ltt_event_position(e
, ep
);
1345 *(value
.v_pointer
) = ep
;
1347 guint nb_block
, offset
;
1350 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1351 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1353 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1357 /* save the cpu state */
1359 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1360 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1362 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1365 /* save the irq state */
1366 nb_irqs
= self
->nb_irqs
;
1368 guint size
= sizeof(LttvCPUState
)*nb_irqs
;
1369 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1371 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1374 /* save the blkdev states */
1375 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1377 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1381 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1383 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1385 LttvTracefileState
*tfcs
;
1387 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1389 guint
*running_process
;
1391 LttvAttributeType type
;
1393 LttvAttributeValue value
;
1395 LttvAttributeName name
;
1399 LttEventPosition
*ep
;
1401 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1403 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1404 LTTV_STATE_TRACEFILES
);
1406 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1408 g_assert(type
== LTTV_POINTER
);
1409 lttv_state_free_process_table(self
->processes
);
1410 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1412 /* Add the currently running processes array */
1413 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1414 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1416 g_assert(type
== LTTV_POINTER
);
1417 running_process
= *(value
.v_pointer
);
1418 for(i
=0;i
<nb_cpus
;i
++) {
1419 pid
= running_process
[i
];
1420 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1421 g_assert(self
->running_process
[i
] != NULL
);
1424 nb_tracefile
= self
->parent
.tracefiles
->len
;
1426 //g_tree_destroy(tsc->pqueue);
1427 //tsc->pqueue = g_tree_new(compare_tracefile);
1429 /* restore cpu resource states */
1430 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1431 g_assert(type
== LTTV_POINTER
);
1432 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1433 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1435 /* restore irq resource states */
1436 nb_irqs
= self
->nb_irqs
;
1437 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1438 g_assert(type
== LTTV_POINTER
);
1439 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1440 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1442 /* restore the blkdev states */
1443 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1444 g_assert(type
== LTTV_POINTER
);
1445 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1446 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1448 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1450 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1451 LttvTracefileContext
*, i
));
1452 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1453 g_assert(type
== LTTV_GOBJECT
);
1454 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1456 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1458 g_assert(type
== LTTV_UINT
);
1459 pid
= *(value
.v_uint
);
1460 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1462 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1464 g_assert(type
== LTTV_POINTER
);
1465 //g_assert(*(value.v_pointer) != NULL);
1466 ep
= *(value
.v_pointer
);
1467 g_assert(tfcs
->parent
.t_context
!= NULL
);
1469 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1471 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1472 g_tree_remove(tsc
->pqueue
, tfc
);
1475 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1476 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1477 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1478 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1479 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1481 tfc
->timestamp
= ltt_time_infinite
;
1487 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1489 guint i
, nb_tracefile
, nb_cpus
;
1491 LttvTracefileState
*tfcs
;
1493 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1495 guint
*running_process
;
1497 LttvAttributeType type
;
1499 LttvAttributeValue value
;
1501 LttvAttributeName name
;
1505 LttEventPosition
*ep
;
1507 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1508 LTTV_STATE_TRACEFILES
);
1509 g_object_ref(G_OBJECT(tracefiles_tree
));
1510 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1512 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1514 g_assert(type
== LTTV_POINTER
);
1515 lttv_state_free_process_table(*(value
.v_pointer
));
1516 *(value
.v_pointer
) = NULL
;
1517 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1519 /* Free running processes array */
1520 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1521 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1523 g_assert(type
== LTTV_POINTER
);
1524 running_process
= *(value
.v_pointer
);
1525 g_free(running_process
);
1527 nb_tracefile
= self
->parent
.tracefiles
->len
;
1529 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1531 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1532 LttvTracefileContext
*, i
));
1533 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1534 g_assert(type
== LTTV_GOBJECT
);
1535 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1537 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1539 g_assert(type
== LTTV_POINTER
);
1540 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1542 g_object_unref(G_OBJECT(tracefiles_tree
));
1546 static void free_saved_state(LttvTraceState
*self
)
1550 LttvAttributeType type
;
1552 LttvAttributeValue value
;
1554 LttvAttributeName name
;
1558 LttvAttribute
*saved_states
;
1560 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1561 LTTV_STATE_SAVED_STATES
);
1563 nb
= lttv_attribute_get_number(saved_states
);
1564 for(i
= 0 ; i
< nb
; i
++) {
1565 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1566 g_assert(type
== LTTV_GOBJECT
);
1567 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1570 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1575 create_max_time(LttvTraceState
*tcs
)
1577 LttvAttributeValue v
;
1579 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1581 g_assert(*(v
.v_pointer
) == NULL
);
1582 *(v
.v_pointer
) = g_new(LttTime
,1);
1583 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1588 get_max_time(LttvTraceState
*tcs
)
1590 LttvAttributeValue v
;
1592 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1594 g_assert(*(v
.v_pointer
) != NULL
);
1595 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1600 free_max_time(LttvTraceState
*tcs
)
1602 LttvAttributeValue v
;
1604 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1606 g_free(*(v
.v_pointer
));
1607 *(v
.v_pointer
) = NULL
;
1611 typedef struct _LttvNameTables
{
1612 // FIXME GQuark *eventtype_names;
1613 GQuark
*syscall_names
;
1619 GQuark
*soft_irq_names
;
1625 create_name_tables(LttvTraceState
*tcs
)
1629 GQuark f_name
, e_name
;
1633 LttvTraceHookByFacility
*thf
;
1639 GString
*fe_name
= g_string_new("");
1641 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1643 LttvAttributeValue v
;
1645 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1647 g_assert(*(v
.v_pointer
) == NULL
);
1648 *(v
.v_pointer
) = name_tables
;
1649 #if 0 // Use iteration over the facilities_by_name and then list all event
1650 // types of each facility
1651 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1652 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1653 for(i
= 0 ; i
< nb
; i
++) {
1654 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1655 e_name
= ltt_eventtype_name(et
);
1656 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1657 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1658 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1661 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1662 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1663 LTT_FIELD_SYSCALL_ID
, 0, 0,
1666 thf
= lttv_trace_hook_get_first(&h
);
1668 t
= ltt_field_type(thf
->f1
);
1669 nb
= ltt_type_element_number(t
);
1671 lttv_trace_hook_destroy(&h
);
1673 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1674 name_tables
->nb_syscalls
= nb
;
1676 for(i
= 0 ; i
< nb
; i
++) {
1677 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1678 if(!name_tables
->syscall_names
[i
]) {
1679 GString
*string
= g_string_new("");
1680 g_string_printf(string
, "syscall %u", i
);
1681 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1682 g_string_free(string
, TRUE
);
1686 //name_tables->syscall_names = g_new(GQuark, 256);
1687 //for(i = 0 ; i < 256 ; i++) {
1688 // g_string_printf(fe_name, "syscall %d", i);
1689 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1692 name_tables
->syscall_names
= NULL
;
1693 name_tables
->nb_syscalls
= 0;
1696 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1697 LTT_EVENT_TRAP_ENTRY
,
1698 LTT_FIELD_TRAP_ID
, 0, 0,
1701 thf
= lttv_trace_hook_get_first(&h
);
1703 t
= ltt_field_type(thf
->f1
);
1704 //nb = ltt_type_element_number(t);
1706 lttv_trace_hook_destroy(&h
);
1709 name_tables->trap_names = g_new(GQuark, nb);
1710 for(i = 0 ; i < nb ; i++) {
1711 name_tables->trap_names[i] = g_quark_from_string(
1712 ltt_enum_string_get(t, i));
1715 name_tables
->nb_traps
= 256;
1716 name_tables
->trap_names
= g_new(GQuark
, 256);
1717 for(i
= 0 ; i
< 256 ; i
++) {
1718 g_string_printf(fe_name
, "trap %d", i
);
1719 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1722 name_tables
->trap_names
= NULL
;
1723 name_tables
->nb_traps
= 0;
1726 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1727 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1728 LTT_FIELD_IRQ_ID
, 0, 0,
1731 thf
= lttv_trace_hook_get_first(&h
);
1733 t
= ltt_field_type(thf
->f1
);
1734 //nb = ltt_type_element_number(t);
1736 lttv_trace_hook_destroy(&h
);
1739 name_tables->irq_names = g_new(GQuark, nb);
1740 for(i = 0 ; i < nb ; i++) {
1741 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1745 name_tables
->nb_irqs
= 256;
1746 name_tables
->irq_names
= g_new(GQuark
, 256);
1747 for(i
= 0 ; i
< 256 ; i
++) {
1748 g_string_printf(fe_name
, "irq %d", i
);
1749 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1752 name_tables
->nb_irqs
= 0;
1753 name_tables
->irq_names
= NULL
;
1756 name_tables->soft_irq_names = g_new(GQuark, nb);
1757 for(i = 0 ; i < nb ; i++) {
1758 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1762 name_tables
->nb_softirqs
= 256;
1763 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1764 for(i
= 0 ; i
< 256 ; i
++) {
1765 g_string_printf(fe_name
, "softirq %d", i
);
1766 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1770 g_string_free(fe_name
, TRUE
);
1775 get_name_tables(LttvTraceState
*tcs
)
1777 LttvNameTables
*name_tables
;
1779 LttvAttributeValue v
;
1781 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1783 g_assert(*(v
.v_pointer
) != NULL
);
1784 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1785 //tcs->eventtype_names = name_tables->eventtype_names;
1786 tcs
->syscall_names
= name_tables
->syscall_names
;
1787 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1788 tcs
->trap_names
= name_tables
->trap_names
;
1789 tcs
->nb_traps
= name_tables
->nb_traps
;
1790 tcs
->irq_names
= name_tables
->irq_names
;
1791 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1792 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1793 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1798 free_name_tables(LttvTraceState
*tcs
)
1800 LttvNameTables
*name_tables
;
1802 LttvAttributeValue v
;
1804 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1806 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1807 *(v
.v_pointer
) = NULL
;
1809 // g_free(name_tables->eventtype_names);
1810 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1811 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1812 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1813 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1814 if(name_tables
) g_free(name_tables
);
1817 #ifdef HASH_TABLE_DEBUG
1819 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1821 LttvProcessState
*process
= (LttvProcessState
*)value
;
1823 /* Test for process corruption */
1824 guint stack_len
= process
->execution_stack
->len
;
1827 static void hash_table_check(GHashTable
*table
)
1829 g_hash_table_foreach(table
, test_process
, NULL
);
1835 /* clears the stack and sets the state passed as argument */
1836 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1838 g_array_set_size(cpust
->mode_stack
, 1);
1839 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1842 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1844 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1845 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1848 static void cpu_pop_mode(LttvCPUState
*cpust
)
1850 if(cpust
->mode_stack
->len
<= 1)
1851 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1853 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1856 /* clears the stack and sets the state passed as argument */
1857 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1859 g_array_set_size(bdevst
->mode_stack
, 1);
1860 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1863 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1865 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1866 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1869 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1871 if(bdevst
->mode_stack
->len
<= 1)
1872 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1874 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1877 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1879 g_array_set_size(irqst
->mode_stack
, 1);
1880 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1883 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1885 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1886 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1889 static void irq_pop_mode(LttvIRQState
*irqst
)
1891 if(irqst
->mode_stack
->len
<= 1)
1892 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1894 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1897 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1900 LttvExecutionState
*es
;
1902 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1903 guint cpu
= tfs
->cpu
;
1905 #ifdef HASH_TABLE_DEBUG
1906 hash_table_check(ts
->processes
);
1908 LttvProcessState
*process
= ts
->running_process
[cpu
];
1910 guint depth
= process
->execution_stack
->len
;
1912 process
->execution_stack
=
1913 g_array_set_size(process
->execution_stack
, depth
+ 1);
1916 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1918 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1921 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1922 es
->cum_cpu_time
= ltt_time_zero
;
1923 es
->s
= process
->state
->s
;
1924 process
->state
= es
;
1928 * return 1 when empty, else 0 */
1929 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1930 LttvTracefileState
*tfs
)
1932 guint cpu
= tfs
->cpu
;
1933 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1935 guint depth
= process
->execution_stack
->len
;
1941 process
->execution_stack
=
1942 g_array_set_size(process
->execution_stack
, depth
- 1);
1943 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1945 process
->state
->change
= tfs
->parent
.timestamp
;
1950 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1952 guint cpu
= tfs
->cpu
;
1953 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1954 LttvProcessState
*process
= ts
->running_process
[cpu
];
1956 guint depth
= process
->execution_stack
->len
;
1958 if(process
->state
->t
!= t
){
1959 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1960 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1961 g_info("process state has %s when pop_int is %s\n",
1962 g_quark_to_string(process
->state
->t
),
1963 g_quark_to_string(t
));
1964 g_info("{ %u, %u, %s, %s, %s }\n",
1967 g_quark_to_string(process
->name
),
1968 g_quark_to_string(process
->brand
),
1969 g_quark_to_string(process
->state
->s
));
1974 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1975 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1979 process
->execution_stack
=
1980 g_array_set_size(process
->execution_stack
, depth
- 1);
1981 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1983 process
->state
->change
= tfs
->parent
.timestamp
;
1986 struct search_result
{
1987 const LttTime
*time
; /* Requested time */
1988 LttTime
*best
; /* Best result */
1991 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1993 const LttTime
*elem_time
= (const LttTime
*)a
;
1994 /* Explicit non const cast */
1995 struct search_result
*res
= (struct search_result
*)b
;
1997 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1998 /* The usertrace was created before the schedchange */
1999 /* Get larger keys */
2001 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2002 /* The usertrace was created after the schedchange time */
2003 /* Get smaller keys */
2005 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2006 res
->best
= elem_time
;
2009 res
->best
= elem_time
;
2016 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2017 guint pid
, const LttTime
*timestamp
)
2019 LttvTracefileState
*tfs
= NULL
;
2020 struct search_result res
;
2021 /* Find the usertrace associated with a pid and time interval.
2022 * Search in the usertraces by PID (within a hash) and then, for each
2023 * corresponding element of the array, find the first one with creation
2024 * timestamp the lowest, but higher or equal to "timestamp". */
2025 res
.time
= timestamp
;
2027 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2028 if(usertrace_tree
) {
2029 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2031 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2039 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2040 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2042 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2044 LttvExecutionState
*es
;
2046 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
2051 process
->tgid
= tgid
;
2053 process
->name
= name
;
2054 process
->brand
= LTTV_STATE_UNBRANDED
;
2055 //process->last_cpu = tfs->cpu_name;
2056 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2057 process
->type
= LTTV_STATE_USER_THREAD
;
2058 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2059 process
->current_function
= 0; //function 0x0 by default.
2061 g_info("Process %u, core %p", process
->pid
, process
);
2062 g_hash_table_insert(tcs
->processes
, process
, process
);
2065 process
->ppid
= parent
->pid
;
2066 process
->creation_time
= *timestamp
;
2069 /* No parent. This process exists but we are missing all information about
2070 its creation. The birth time is set to zero but we remember the time of
2075 process
->creation_time
= ltt_time_zero
;
2078 process
->insertion_time
= *timestamp
;
2079 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2080 process
->creation_time
.tv_nsec
);
2081 process
->pid_time
= g_quark_from_string(buffer
);
2083 //process->last_cpu = tfs->cpu_name;
2084 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2085 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2086 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2087 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2088 es
= process
->state
= &g_array_index(process
->execution_stack
,
2089 LttvExecutionState
, 0);
2090 es
->t
= LTTV_STATE_USER_MODE
;
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_RUN
;
2098 es
= process
->state
= &g_array_index(process
->execution_stack
,
2099 LttvExecutionState
, 1);
2100 es
->t
= LTTV_STATE_SYSCALL
;
2101 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2102 es
->entry
= *timestamp
;
2103 //g_assert(timestamp->tv_sec != 0);
2104 es
->change
= *timestamp
;
2105 es
->cum_cpu_time
= ltt_time_zero
;
2106 es
->s
= LTTV_STATE_WAIT_FORK
;
2108 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2109 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2110 sizeof(guint64
), 0);
2115 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2118 LttvProcessState key
;
2119 LttvProcessState
*process
;
2123 process
= g_hash_table_lookup(ts
->processes
, &key
);
2128 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2129 const LttTime
*timestamp
)
2131 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2132 LttvExecutionState
*es
;
2134 /* Put ltt_time_zero creation time for unexisting processes */
2135 if(unlikely(process
== NULL
)) {
2136 process
= lttv_state_create_process(ts
,
2137 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2138 /* We are not sure is it's a kernel thread or normal thread, put the
2139 * bottom stack state to unknown */
2140 process
->execution_stack
=
2141 g_array_set_size(process
->execution_stack
, 1);
2142 process
->state
= es
=
2143 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2144 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2145 es
->s
= LTTV_STATE_UNNAMED
;
2150 /* FIXME : this function should be called when we receive an event telling that
2151 * release_task has been called in the kernel. In happens generally when
2152 * the parent waits for its child terminaison, but may also happen in special
2153 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2154 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2155 * of a killed thread ground, but isn't the leader.
2157 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2159 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2160 LttvProcessState key
;
2162 key
.pid
= process
->pid
;
2163 key
.cpu
= process
->cpu
;
2164 g_hash_table_remove(ts
->processes
, &key
);
2165 g_array_free(process
->execution_stack
, TRUE
);
2166 g_array_free(process
->user_stack
, TRUE
);
2171 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2173 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2174 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2179 static void lttv_state_free_process_table(GHashTable
*processes
)
2181 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2182 g_hash_table_destroy(processes
);
2186 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2188 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2190 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2191 LttvProcessState
*process
= ts
->running_process
[cpu
];
2192 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2193 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2194 LttField
*f
= thf
->f1
;
2196 LttvExecutionSubmode submode
;
2198 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2199 guint syscall
= ltt_event_get_unsigned(e
, f
);
2201 if(syscall
< nb_syscalls
) {
2202 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2205 /* Fixup an incomplete syscall table */
2206 GString
*string
= g_string_new("");
2207 g_string_printf(string
, "syscall %u", syscall
);
2208 submode
= g_quark_from_string(string
->str
);
2209 g_string_free(string
, TRUE
);
2211 /* There can be no system call from PID 0 : unknown state */
2212 if(process
->pid
!= 0)
2213 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2218 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2220 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2222 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2223 LttvProcessState
*process
= ts
->running_process
[cpu
];
2225 /* There can be no system call from PID 0 : unknown state */
2226 if(process
->pid
!= 0)
2227 pop_state(s
, LTTV_STATE_SYSCALL
);
2232 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2234 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2235 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2236 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2237 LttField
*f
= thf
->f1
;
2239 LttvExecutionSubmode submode
;
2241 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2242 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2244 if(trap
< nb_traps
) {
2245 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2247 /* Fixup an incomplete trap table */
2248 GString
*string
= g_string_new("");
2249 g_string_printf(string
, "trap %llu", trap
);
2250 submode
= g_quark_from_string(string
->str
);
2251 g_string_free(string
, TRUE
);
2254 push_state(s
, LTTV_STATE_TRAP
, submode
);
2256 /* update cpu status */
2257 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2262 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2264 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2266 pop_state(s
, LTTV_STATE_TRAP
);
2268 /* update cpu status */
2269 cpu_pop_mode(s
->cpu_state
);
2274 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2276 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2277 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2278 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2279 guint8 fac_id
= ltt_event_facility_id(e
);
2280 guint8 ev_id
= ltt_event_eventtype_id(e
);
2281 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2282 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2283 g_assert(thf
->f1
!= NULL
);
2284 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2285 LttField
*f
= thf
->f1
;
2287 LttvExecutionSubmode submode
;
2288 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2289 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2293 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2295 /* Fixup an incomplete irq table */
2296 GString
*string
= g_string_new("");
2297 g_string_printf(string
, "irq %llu", irq
);
2298 submode
= g_quark_from_string(string
->str
);
2299 g_string_free(string
, TRUE
);
2302 /* Do something with the info about being in user or system mode when int? */
2303 push_state(s
, LTTV_STATE_IRQ
, submode
);
2305 /* update cpu status */
2306 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2308 /* update irq status */
2309 s
->cpu_state
->last_irq
= irq
;
2310 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2315 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2317 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2319 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2325 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2327 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2328 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2330 pop_state(s
, LTTV_STATE_IRQ
);
2332 /* update cpu status */
2333 cpu_pop_mode(s
->cpu_state
);
2335 /* update irq status */
2336 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2341 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2343 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2344 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2345 guint8 fac_id
= ltt_event_facility_id(e
);
2346 guint8 ev_id
= ltt_event_eventtype_id(e
);
2347 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2348 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2349 g_assert(thf
->f1
!= NULL
);
2350 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2351 LttField
*f
= thf
->f1
;
2353 LttvExecutionSubmode submode
;
2354 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2355 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2358 if(softirq
< nb_softirqs
) {
2359 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2361 /* Fixup an incomplete irq table */
2362 GString
*string
= g_string_new("");
2363 g_string_printf(string
, "softirq %llu", softirq
);
2364 submode
= g_quark_from_string(string
->str
);
2365 g_string_free(string
, TRUE
);
2368 /* Do something with the info about being in user or system mode when int? */
2369 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2373 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2375 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2376 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2377 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2378 guint8 fac_id
= ltt_event_facility_id(e
);
2379 guint8 ev_id
= ltt_event_eventtype_id(e
);
2380 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2382 GQuark action
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2383 guint irq
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2385 ts
->irq_names
[irq
] = action
;
2391 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2393 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2394 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2395 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2396 guint8 fac_id
= ltt_event_facility_id(e
);
2397 guint8 ev_id
= ltt_event_eventtype_id(e
);
2398 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2400 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2401 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2402 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2403 guint16 devcode
= MKDEV(major
,minor
);
2405 /* have we seen this block device before? */
2406 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2409 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2411 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2416 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2418 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2419 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2420 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2421 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2423 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2424 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2425 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2426 guint16 devcode
= MKDEV(major
,minor
);
2428 /* have we seen this block device before? */
2429 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2431 /* update block device */
2432 bdev_pop_mode(bdev
);
2437 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2441 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2442 guint cpu
= tfs
->cpu
;
2443 LttvProcessState
*process
= ts
->running_process
[cpu
];
2445 guint depth
= process
->user_stack
->len
;
2447 process
->user_stack
=
2448 g_array_set_size(process
->user_stack
, depth
+ 1);
2450 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2451 *new_func
= funcptr
;
2452 process
->current_function
= funcptr
;
2455 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2457 guint cpu
= tfs
->cpu
;
2458 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2459 LttvProcessState
*process
= ts
->running_process
[cpu
];
2461 if(process
->current_function
!= funcptr
){
2462 g_info("Different functions (%lu.%09lu): ignore it\n",
2463 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2464 g_info("process state has %llu when pop_function is %llu\n",
2465 process
->current_function
, funcptr
);
2466 g_info("{ %u, %u, %s, %s, %s }\n",
2469 g_quark_to_string(process
->name
),
2470 g_quark_to_string(process
->brand
),
2471 g_quark_to_string(process
->state
->s
));
2474 guint depth
= process
->user_stack
->len
;
2477 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2478 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2482 process
->user_stack
=
2483 g_array_set_size(process
->user_stack
, depth
- 1);
2484 process
->current_function
=
2485 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2489 static gboolean
function_entry(void *hook_data
, void *call_data
)
2491 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2492 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2493 guint8 fac_id
= ltt_event_facility_id(e
);
2494 guint8 ev_id
= ltt_event_eventtype_id(e
);
2495 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2496 g_assert(thf
->f1
!= NULL
);
2497 LttField
*f
= thf
->f1
;
2498 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2500 push_function(s
, funcptr
);
2504 static gboolean
function_exit(void *hook_data
, void *call_data
)
2506 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2507 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2508 guint8 fac_id
= ltt_event_facility_id(e
);
2509 guint8 ev_id
= ltt_event_eventtype_id(e
);
2510 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2511 g_assert(thf
->f1
!= NULL
);
2512 LttField
*f
= thf
->f1
;
2513 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2515 LttvExecutionSubmode submode
;
2517 pop_function(s
, funcptr
);
2521 static gboolean
schedchange(void *hook_data
, void *call_data
)
2523 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2525 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2526 LttvProcessState
*process
= ts
->running_process
[cpu
];
2527 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2529 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2530 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2531 guint pid_in
, pid_out
;
2534 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2535 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2536 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2538 if(likely(process
!= NULL
)) {
2540 /* We could not know but it was not the idle process executing.
2541 This should only happen at the beginning, before the first schedule
2542 event, and when the initial information (current process for each CPU)
2543 is missing. It is not obvious how we could, after the fact, compensate
2544 the wrongly attributed statistics. */
2546 //This test only makes sense once the state is known and if there is no
2547 //missing events. We need to silently ignore schedchange coming after a
2548 //process_free, or it causes glitches. (FIXME)
2549 //if(unlikely(process->pid != pid_out)) {
2550 // g_assert(process->pid == 0);
2552 if(process
->pid
== 0
2553 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2555 /* Scheduling out of pid 0 at beginning of the trace :
2556 * we know for sure it is in syscall mode at this point. */
2557 g_assert(process
->execution_stack
->len
== 1);
2558 process
->state
->t
= LTTV_STATE_SYSCALL
;
2559 process
->state
->s
= LTTV_STATE_WAIT
;
2560 process
->state
->change
= s
->parent
.timestamp
;
2561 process
->state
->entry
= s
->parent
.timestamp
;
2564 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2565 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2566 process
->state
->change
= s
->parent
.timestamp
;
2568 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2569 else process
->state
->s
= LTTV_STATE_WAIT
;
2570 process
->state
->change
= s
->parent
.timestamp
;
2573 if(state_out
== 32 || state_out
== 128)
2574 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2575 /* see sched.h for states */
2578 process
= ts
->running_process
[cpu
] =
2579 lttv_state_find_process_or_create(
2580 (LttvTraceState
*)s
->parent
.t_context
,
2582 &s
->parent
.timestamp
);
2583 process
->state
->s
= LTTV_STATE_RUN
;
2585 if(process
->usertrace
)
2586 process
->usertrace
->cpu
= cpu
;
2587 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2588 process
->state
->change
= s
->parent
.timestamp
;
2590 /* update cpu status */
2592 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2594 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2599 static gboolean
process_fork(void *hook_data
, void *call_data
)
2601 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2602 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2603 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2605 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2606 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2607 LttvProcessState
*zombie_process
;
2609 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2610 LttvProcessState
*process
= ts
->running_process
[cpu
];
2611 LttvProcessState
*child_process
;
2614 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2617 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2618 s
->parent
.target_pid
= child_pid
;
2621 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2622 else child_tgid
= 0;
2624 /* Mathieu : it seems like the process might have been scheduled in before the
2625 * fork, and, in a rare case, might be the current process. This might happen
2626 * in a SMP case where we don't have enough precision on the clocks.
2628 * Test reenabled after precision fixes on time. (Mathieu) */
2630 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2632 if(unlikely(zombie_process
!= NULL
)) {
2633 /* Reutilisation of PID. Only now we are sure that the old PID
2634 * has been released. FIXME : should know when release_task happens instead.
2636 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2638 for(i
=0; i
< num_cpus
; i
++) {
2639 g_assert(zombie_process
!= ts
->running_process
[i
]);
2642 exit_process(s
, zombie_process
);
2645 g_assert(process
->pid
!= child_pid
);
2646 // FIXME : Add this test in the "known state" section
2647 // g_assert(process->pid == parent_pid);
2648 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2649 if(child_process
== NULL
) {
2650 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2651 child_pid
, child_tgid
,
2652 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2654 /* The process has already been created : due to time imprecision between
2655 * multiple CPUs : it has been scheduled in before creation. Note that we
2656 * shouldn't have this kind of imprecision.
2658 * Simply put a correct parent.
2660 g_assert(0); /* This is a problematic case : the process has been created
2661 before the fork event */
2662 child_process
->ppid
= process
->pid
;
2663 child_process
->tgid
= child_tgid
;
2665 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2666 child_process
->name
= process
->name
;
2667 child_process
->brand
= process
->brand
;
2672 /* We stamp a newly created process as kernel_thread.
2673 * The thread should not be running yet. */
2674 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2676 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2677 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2678 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2681 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2682 LttvProcessState
*process
;
2683 LttvExecutionState
*es
;
2686 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2687 s
->parent
.target_pid
= pid
;
2689 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2691 process
->execution_stack
=
2692 g_array_set_size(process
->execution_stack
, 1);
2693 es
= process
->state
=
2694 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2695 es
->t
= LTTV_STATE_SYSCALL
;
2696 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2701 static gboolean
process_exit(void *hook_data
, void *call_data
)
2703 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2704 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2705 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2709 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2710 LttvProcessState
*process
; // = ts->running_process[cpu];
2712 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2713 s
->parent
.target_pid
= pid
;
2715 // FIXME : Add this test in the "known state" section
2716 // g_assert(process->pid == pid);
2718 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2719 if(likely(process
!= NULL
)) {
2720 process
->state
->s
= LTTV_STATE_EXIT
;
2725 static gboolean
process_free(void *hook_data
, void *call_data
)
2727 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2728 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2729 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2730 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2732 LttvProcessState
*process
;
2734 /* PID of the process to release */
2735 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2736 s
->parent
.target_pid
= release_pid
;
2738 g_assert(release_pid
!= 0);
2740 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2742 if(likely(process
!= NULL
)) {
2743 /* release_task is happening at kernel level : we can now safely release
2744 * the data structure of the process */
2745 //This test is fun, though, as it may happen that
2746 //at time t : CPU 0 : process_free
2747 //at time t+150ns : CPU 1 : schedule out
2748 //Clearly due to time imprecision, we disable it. (Mathieu)
2749 //If this weird case happen, we have no choice but to put the
2750 //Currently running process on the cpu to 0.
2751 //I re-enable it following time precision fixes. (Mathieu)
2752 //Well, in the case where an process is freed by a process on another CPU
2753 //and still scheduled, it happens that this is the schedchange that will
2754 //drop the last reference count. Do not free it here!
2755 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2757 for(i
=0; i
< num_cpus
; i
++) {
2758 //g_assert(process != ts->running_process[i]);
2759 if(process
== ts
->running_process
[i
]) {
2760 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2764 if(i
== num_cpus
) /* process is not scheduled */
2765 exit_process(s
, process
);
2772 static gboolean
process_exec(void *hook_data
, void *call_data
)
2774 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2775 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2776 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2777 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2780 LttvProcessState
*process
= ts
->running_process
[cpu
];
2782 #if 0//how to use a sequence that must be transformed in a string
2783 /* PID of the process to release */
2784 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2785 //name = ltt_event_get_string(e, thf->f1);
2786 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2788 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2789 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2790 memcpy(null_term_name
, name_begin
, name_len
);
2791 null_term_name
[name_len
] = '\0';
2792 process
->name
= g_quark_from_string(null_term_name
);
2795 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2796 process
->brand
= LTTV_STATE_UNBRANDED
;
2797 //g_free(null_term_name);
2801 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2803 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2804 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2805 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2806 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2809 LttvProcessState
*process
= ts
->running_process
[cpu
];
2811 name
= ltt_event_get_string(e
, thf
->f1
);
2812 process
->brand
= g_quark_from_string(name
);
2817 static void fix_process(gpointer key
, gpointer value
,
2820 LttvProcessState
*process
;
2821 LttvExecutionState
*es
;
2822 process
= (LttvProcessState
*)value
;
2823 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2824 LttTime
*timestamp
= (LttTime
*)user_data
;
2826 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2827 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2828 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2829 es
->t
= LTTV_STATE_SYSCALL
;
2830 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2831 es
->entry
= *timestamp
;
2832 es
->change
= *timestamp
;
2833 es
->cum_cpu_time
= ltt_time_zero
;
2834 if(es
->s
== LTTV_STATE_UNNAMED
)
2835 es
->s
= LTTV_STATE_WAIT
;
2838 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2839 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2840 es
->t
= LTTV_STATE_USER_MODE
;
2841 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2842 es
->entry
= *timestamp
;
2843 //g_assert(timestamp->tv_sec != 0);
2844 es
->change
= *timestamp
;
2845 es
->cum_cpu_time
= ltt_time_zero
;
2846 if(es
->s
== LTTV_STATE_UNNAMED
)
2847 es
->s
= LTTV_STATE_RUN
;
2849 if(process
->execution_stack
->len
== 1) {
2850 /* Still in bottom unknown mode, means never did a system call
2851 * May be either in user mode, syscall mode, running or waiting.*/
2852 /* FIXME : we may be tagging syscall mode when being user mode */
2853 process
->execution_stack
=
2854 g_array_set_size(process
->execution_stack
, 2);
2855 es
= process
->state
= &g_array_index(process
->execution_stack
,
2856 LttvExecutionState
, 1);
2857 es
->t
= LTTV_STATE_SYSCALL
;
2858 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2859 es
->entry
= *timestamp
;
2860 //g_assert(timestamp->tv_sec != 0);
2861 es
->change
= *timestamp
;
2862 es
->cum_cpu_time
= ltt_time_zero
;
2863 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2864 es
->s
= LTTV_STATE_WAIT
;
2870 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2872 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2873 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2874 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2875 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2876 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2878 /* For all processes */
2879 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2880 /* else, if stack[0] is unknown, set to user mode, running */
2882 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2885 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2887 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2888 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2889 //It's slow : optimise later by doing this before reading trace.
2890 LttEventType
*et
= ltt_event_eventtype(e
);
2892 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2898 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2899 LttvProcessState
*process
= ts
->running_process
[cpu
];
2900 LttvProcessState
*parent_process
;
2901 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2902 GQuark type
, mode
, submode
, status
;
2903 LttvExecutionState
*es
;
2907 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2908 s
->parent
.target_pid
= pid
;
2911 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2914 command
= ltt_event_get_string(e
, thf
->f3
);
2917 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2918 type
= ltt_enum_string_get(ltt_field_type(f4
),
2919 ltt_event_get_unsigned(e
, f4
));
2922 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2923 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2924 ltt_event_get_unsigned(e
, f5
));
2927 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2928 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2929 ltt_event_get_unsigned(e
, f6
));
2932 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2933 status
= ltt_enum_string_get(ltt_field_type(f7
),
2934 ltt_event_get_unsigned(e
, f7
));
2937 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2938 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2943 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2944 for(i
=0; i
<nb_cpus
; i
++) {
2945 process
= lttv_state_find_process(ts
, i
, pid
);
2946 g_assert(process
!= NULL
);
2948 process
->ppid
= parent_pid
;
2949 process
->tgid
= tgid
;
2950 process
->name
= g_quark_from_string(command
);
2952 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2953 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2957 /* The process might exist if a process was forked while performing the
2959 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2960 if(process
== NULL
) {
2961 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2962 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2963 pid
, tgid
, g_quark_from_string(command
),
2964 &s
->parent
.timestamp
);
2966 /* Keep the stack bottom : a running user mode */
2967 /* Disabled because of inconsistencies in the current statedump states. */
2968 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2969 /* Only keep the bottom
2970 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2971 /* Will cause expected trap when in fact being syscall (even after end of
2973 * Will cause expected interrupt when being syscall. (only before end of
2974 * statedump event) */
2975 // This will cause a "popping last state on stack, ignoring it."
2976 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2977 es
= process
->state
= &g_array_index(process
->execution_stack
,
2978 LttvExecutionState
, 0);
2979 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2980 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2981 es
->s
= LTTV_STATE_UNNAMED
;
2982 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2984 es
->t
= LTTV_STATE_SYSCALL
;
2989 /* User space process :
2990 * bottom : user mode
2991 * either currently running or scheduled out.
2992 * can be scheduled out because interrupted in (user mode or in syscall)
2993 * or because of an explicit call to the scheduler in syscall. Note that
2994 * the scheduler call comes after the irq_exit, so never in interrupt
2996 // temp workaround : set size to 1 : only have user mode bottom of stack.
2997 // will cause g_info message of expected syscall mode when in fact being
2998 // in user mode. Can also cause expected trap when in fact being user
2999 // mode in the event of a page fault reenabling interrupts in the handler.
3000 // Expected syscall and trap can also happen after the end of statedump
3001 // This will cause a "popping last state on stack, ignoring it."
3002 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3003 es
= process
->state
= &g_array_index(process
->execution_stack
,
3004 LttvExecutionState
, 0);
3005 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3006 es
->s
= LTTV_STATE_UNNAMED
;
3007 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3009 es
->t
= LTTV_STATE_USER_MODE
;
3017 es
= process
->state
= &g_array_index(process
->execution_stack
,
3018 LttvExecutionState
, 1);
3019 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3020 es
->s
= LTTV_STATE_UNNAMED
;
3021 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3025 /* The process has already been created :
3026 * Probably was forked while dumping the process state or
3027 * was simply scheduled in prior to get the state dump event.
3029 process
->ppid
= parent_pid
;
3030 process
->tgid
= tgid
;
3031 process
->name
= g_quark_from_string(command
);
3032 process
->type
= type
;
3034 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3036 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3037 if(type
== LTTV_STATE_KERNEL_THREAD
)
3038 es
->t
= LTTV_STATE_SYSCALL
;
3040 es
->t
= LTTV_STATE_USER_MODE
;
3043 /* Don't mess around with the stack, it will eventually become
3044 * ok after the end of state dump. */
3051 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3053 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3055 lttv_state_add_event_hooks(tss
);
3060 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3062 LttvTraceset
*traceset
= self
->parent
.ts
;
3064 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3068 LttvTracefileState
*tfs
;
3072 LttvTraceHookByFacility
*thf
;
3074 LttvTraceHook
*hook
;
3076 LttvAttributeValue val
;
3081 nb_trace
= lttv_traceset_number(traceset
);
3082 for(i
= 0 ; i
< nb_trace
; i
++) {
3083 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3085 /* Find the eventtype id for the following events and register the
3086 associated by id hooks. */
3088 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3089 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
3092 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3093 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3094 LTT_FIELD_SYSCALL_ID
, 0, 0,
3095 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3098 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3099 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3101 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3104 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3105 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
3106 LTT_FIELD_TRAP_ID
, 0, 0,
3107 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3110 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3111 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3113 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3116 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3117 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3118 LTT_FIELD_IRQ_ID
, 0, 0,
3119 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3122 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3123 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3125 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3128 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3129 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3130 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3131 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3134 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3135 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3137 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3140 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3141 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3142 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3143 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3146 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3147 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3148 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3149 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3152 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3153 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3154 LTT_FIELD_PID
, 0, 0,
3155 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3159 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3160 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3161 LTT_FIELD_PID
, 0, 0,
3162 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3165 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3166 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3167 LTT_FIELD_PID
, 0, 0,
3168 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3171 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3172 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3173 LTT_FIELD_FILENAME
, 0, 0,
3174 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3177 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3178 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3179 LTT_FIELD_NAME
, 0, 0,
3180 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3183 /* statedump-related hooks */
3184 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3185 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3186 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3187 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3190 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3191 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3193 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3196 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3197 LTT_FACILITY_LIST
, LTT_EVENT_LIST_INTERRUPT
,
3198 LTT_FIELD_ACTION
, LTT_FIELD_NUM
, 0,
3199 enum_interrupt
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3202 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3203 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3204 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3205 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3208 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3209 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3210 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3211 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3214 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3215 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3216 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3217 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3220 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3221 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3222 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3223 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3226 hooks
= g_array_set_size(hooks
, hn
);
3228 /* Add these hooks to each event_by_id hooks list */
3230 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3232 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3234 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3235 LttvTracefileContext
*, j
));
3237 for(k
= 0 ; k
< hooks
->len
; k
++) {
3238 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3239 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3240 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3242 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3249 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3250 *(val
.v_pointer
) = hooks
;
3254 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3256 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3258 lttv_state_remove_event_hooks(tss
);
3263 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3265 LttvTraceset
*traceset
= self
->parent
.ts
;
3267 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3271 LttvTracefileState
*tfs
;
3275 LttvTraceHook
*hook
;
3277 LttvTraceHookByFacility
*thf
;
3279 LttvAttributeValue val
;
3281 nb_trace
= lttv_traceset_number(traceset
);
3282 for(i
= 0 ; i
< nb_trace
; i
++) {
3283 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3285 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3286 hooks
= *(val
.v_pointer
);
3288 /* Remove these hooks from each event_by_id hooks list */
3290 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3292 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3294 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3295 LttvTracefileContext
*, j
));
3297 for(k
= 0 ; k
< hooks
->len
; k
++) {
3298 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3299 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3300 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3302 lttv_hooks_remove_data(
3303 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3309 for(k
= 0 ; k
< hooks
->len
; k
++)
3310 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3311 g_array_free(hooks
, TRUE
);
3315 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3317 guint
*event_count
= (guint
*)hook_data
;
3319 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3320 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3325 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3327 LttvTracefileState
*tfcs
;
3329 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3331 LttEventPosition
*ep
;
3337 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3339 LttvAttributeValue value
;
3341 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3342 LTTV_STATE_SAVED_STATES
);
3343 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3344 value
= lttv_attribute_add(saved_states_tree
,
3345 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3346 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3347 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3348 *(value
.v_time
) = self
->parent
.timestamp
;
3349 lttv_state_save(tcs
, saved_state_tree
);
3350 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3351 self
->parent
.timestamp
.tv_nsec
);
3353 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3358 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3360 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3362 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3367 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3375 static gboolean
block_start(void *hook_data
, void *call_data
)
3377 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3379 LttvTracefileState
*tfcs
;
3381 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3383 LttEventPosition
*ep
;
3385 guint i
, nb_block
, nb_event
, nb_tracefile
;
3389 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3391 LttvAttributeValue value
;
3393 ep
= ltt_event_position_new();
3395 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3397 /* Count the number of events added since the last block end in any
3400 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3402 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3403 LttvTracefileContext
, i
));
3404 ltt_event_position(tfcs
->parent
.e
, ep
);
3405 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3406 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3407 tfcs
->saved_position
= nb_event
;
3411 if(tcs
->nb_event
>= tcs
->save_interval
) {
3412 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3413 LTTV_STATE_SAVED_STATES
);
3414 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3415 value
= lttv_attribute_add(saved_states_tree
,
3416 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3417 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3418 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3419 *(value
.v_time
) = self
->parent
.timestamp
;
3420 lttv_state_save(tcs
, saved_state_tree
);
3422 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3423 self
->parent
.timestamp
.tv_nsec
);
3425 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3431 static gboolean
block_end(void *hook_data
, void *call_data
)
3433 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3435 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3439 LttEventPosition
*ep
;
3441 guint nb_block
, nb_event
;
3443 ep
= ltt_event_position_new();
3444 ltt_event_position(self
->parent
.e
, ep
);
3445 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3446 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3447 self
->saved_position
= 0;
3448 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3455 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3457 LttvTraceset
*traceset
= self
->parent
.ts
;
3459 guint i
, j
, nb_trace
, nb_tracefile
;
3463 LttvTracefileState
*tfs
;
3465 LttvTraceHook hook_start
, hook_end
;
3467 nb_trace
= lttv_traceset_number(traceset
);
3468 for(i
= 0 ; i
< nb_trace
; i
++) {
3469 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3471 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3472 NULL
, NULL
, block_start
, &hook_start
);
3473 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3474 NULL
, NULL
, block_end
, &hook_end
);
3476 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3478 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3480 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3481 LttvTracefileContext
, j
));
3482 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3483 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3484 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3485 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3491 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3493 LttvTraceset
*traceset
= self
->parent
.ts
;
3495 guint i
, j
, nb_trace
, nb_tracefile
;
3499 LttvTracefileState
*tfs
;
3502 nb_trace
= lttv_traceset_number(traceset
);
3503 for(i
= 0 ; i
< nb_trace
; i
++) {
3505 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3506 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3508 if(ts
->has_precomputed_states
) continue;
3510 guint
*event_count
= g_new(guint
, 1);
3513 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3515 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3516 LttvTracefileContext
*, j
));
3517 lttv_hooks_add(tfs
->parent
.event
,
3518 state_save_event_hook
,
3525 lttv_process_traceset_begin(&self
->parent
,
3526 NULL
, NULL
, NULL
, NULL
, NULL
);
3530 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3532 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3534 lttv_state_save_add_event_hooks(tss
);
3541 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3543 LttvTraceset
*traceset
= self
->parent
.ts
;
3545 guint i
, j
, nb_trace
, nb_tracefile
;
3549 LttvTracefileState
*tfs
;
3551 LttvTraceHook hook_start
, hook_end
;
3553 nb_trace
= lttv_traceset_number(traceset
);
3554 for(i
= 0 ; i
< nb_trace
; i
++) {
3555 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3557 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3558 NULL
, NULL
, block_start
, &hook_start
);
3560 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3561 NULL
, NULL
, block_end
, &hook_end
);
3563 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3565 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3567 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3568 LttvTracefileContext
, j
));
3569 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3570 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3571 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3572 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3578 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3580 LttvTraceset
*traceset
= self
->parent
.ts
;
3582 guint i
, j
, nb_trace
, nb_tracefile
;
3586 LttvTracefileState
*tfs
;
3588 LttvHooks
*after_trace
= lttv_hooks_new();
3590 lttv_hooks_add(after_trace
,
3591 state_save_after_trace_hook
,
3596 lttv_process_traceset_end(&self
->parent
,
3597 NULL
, after_trace
, NULL
, NULL
, NULL
);
3599 lttv_hooks_destroy(after_trace
);
3601 nb_trace
= lttv_traceset_number(traceset
);
3602 for(i
= 0 ; i
< nb_trace
; i
++) {
3604 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3605 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3607 if(ts
->has_precomputed_states
) continue;
3609 guint
*event_count
= NULL
;
3611 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3613 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3614 LttvTracefileContext
*, j
));
3615 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3616 state_save_event_hook
);
3618 if(event_count
) g_free(event_count
);
3622 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3624 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3626 lttv_state_save_remove_event_hooks(tss
);
3631 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3633 LttvTraceset
*traceset
= self
->parent
.ts
;
3637 int min_pos
, mid_pos
, max_pos
;
3639 guint call_rest
= 0;
3641 LttvTraceState
*tcs
;
3643 LttvAttributeValue value
;
3645 LttvAttributeType type
;
3647 LttvAttributeName name
;
3651 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3653 //g_tree_destroy(self->parent.pqueue);
3654 //self->parent.pqueue = g_tree_new(compare_tracefile);
3656 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3658 nb_trace
= lttv_traceset_number(traceset
);
3659 for(i
= 0 ; i
< nb_trace
; i
++) {
3660 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3662 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3663 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3664 LTTV_STATE_SAVED_STATES
);
3667 if(saved_states_tree
) {
3668 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3669 mid_pos
= max_pos
/ 2;
3670 while(min_pos
< max_pos
) {
3671 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3673 g_assert(type
== LTTV_GOBJECT
);
3674 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3675 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3677 g_assert(type
== LTTV_TIME
);
3678 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3680 closest_tree
= saved_state_tree
;
3682 else max_pos
= mid_pos
- 1;
3684 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3688 /* restore the closest earlier saved state */
3690 lttv_state_restore(tcs
, closest_tree
);
3694 /* There is no saved state, yet we want to have it. Restart at T0 */
3696 restore_init_state(tcs
);
3697 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3700 /* We want to seek quickly without restoring/updating the state */
3702 restore_init_state(tcs
);
3703 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3706 if(!call_rest
) g_info("NOT Calling restore");
3711 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3717 traceset_state_finalize (LttvTracesetState
*self
)
3719 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3720 finalize(G_OBJECT(self
));
3725 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3727 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3729 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3730 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3731 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3732 klass
->new_traceset_context
= new_traceset_context
;
3733 klass
->new_trace_context
= new_trace_context
;
3734 klass
->new_tracefile_context
= new_tracefile_context
;
3739 lttv_traceset_state_get_type(void)
3741 static GType type
= 0;
3743 static const GTypeInfo info
= {
3744 sizeof (LttvTracesetStateClass
),
3745 NULL
, /* base_init */
3746 NULL
, /* base_finalize */
3747 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3748 NULL
, /* class_finalize */
3749 NULL
, /* class_data */
3750 sizeof (LttvTracesetState
),
3751 0, /* n_preallocs */
3752 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3753 NULL
/* value handling */
3756 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3764 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3770 trace_state_finalize (LttvTraceState
*self
)
3772 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3773 finalize(G_OBJECT(self
));
3778 trace_state_class_init (LttvTraceStateClass
*klass
)
3780 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3782 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3783 klass
->state_save
= state_save
;
3784 klass
->state_restore
= state_restore
;
3785 klass
->state_saved_free
= state_saved_free
;
3790 lttv_trace_state_get_type(void)
3792 static GType type
= 0;
3794 static const GTypeInfo info
= {
3795 sizeof (LttvTraceStateClass
),
3796 NULL
, /* base_init */
3797 NULL
, /* base_finalize */
3798 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3799 NULL
, /* class_finalize */
3800 NULL
, /* class_data */
3801 sizeof (LttvTraceState
),
3802 0, /* n_preallocs */
3803 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3804 NULL
/* value handling */
3807 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3808 "LttvTraceStateType", &info
, 0);
3815 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3821 tracefile_state_finalize (LttvTracefileState
*self
)
3823 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3824 finalize(G_OBJECT(self
));
3829 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3831 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3833 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3838 lttv_tracefile_state_get_type(void)
3840 static GType type
= 0;
3842 static const GTypeInfo info
= {
3843 sizeof (LttvTracefileStateClass
),
3844 NULL
, /* base_init */
3845 NULL
, /* base_finalize */
3846 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3847 NULL
, /* class_finalize */
3848 NULL
, /* class_data */
3849 sizeof (LttvTracefileState
),
3850 0, /* n_preallocs */
3851 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3852 NULL
/* value handling */
3855 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3856 "LttvTracefileStateType", &info
, 0);
3862 static void module_init()
3864 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3865 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3866 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3867 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3868 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3869 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3870 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3871 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3872 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3873 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3874 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3875 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3876 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3877 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3878 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3879 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3880 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3881 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3882 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3883 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3884 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3885 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3886 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3887 LTTV_STATE_EVENT
= g_quark_from_string("event");
3888 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3889 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3890 LTTV_STATE_TIME
= g_quark_from_string("time");
3891 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3892 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3893 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3894 g_quark_from_string("trace_state_use_count");
3895 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3896 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3897 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3900 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3901 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3902 LTT_FACILITY_FS
= g_quark_from_string("fs");
3903 LTT_FACILITY_LIST
= g_quark_from_string("list");
3904 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3905 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3908 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3909 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3910 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3911 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3912 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3913 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3914 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3915 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3916 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3917 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3918 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3919 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3920 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3921 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3922 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3923 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3924 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3925 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3926 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3927 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3928 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3929 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3932 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3933 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3934 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3935 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3936 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3937 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3938 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3939 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3940 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3941 LTT_FIELD_PID
= g_quark_from_string("pid");
3942 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3943 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3944 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3945 LTT_FIELD_NAME
= g_quark_from_string("name");
3946 LTT_FIELD_TYPE
= g_quark_from_string("type");
3947 LTT_FIELD_MODE
= g_quark_from_string("mode");
3948 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3949 LTT_FIELD_STATUS
= g_quark_from_string("status");
3950 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3951 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3952 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3953 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3954 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3955 LTT_FIELD_ACTION
= g_quark_from_string("action");
3956 LTT_FIELD_NUM
= g_quark_from_string("num");
3958 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3959 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3960 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3961 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3962 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3964 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3965 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3966 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3968 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3969 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3970 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3971 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3974 static void module_destroy()
3979 LTTV_MODULE("state", "State computation", \
3980 "Update the system state, possibly saving it at intervals", \
3981 module_init
, module_destroy
)