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>
30 #include <ltt/marker-desc.h>
36 * usertrace is there only to be able to update the current CPU of the
37 * usertraces when there is a schedchange. it is a way to link the ProcessState
38 * to the associated usertrace. Link only created upon thread creation.
40 * The cpu id is necessary : it gives us back the current ProcessState when we
41 * are considering data from the usertrace.
44 #define PREALLOCATED_EXECUTION_STACK 10
46 /* Facilities Quarks */
50 LTT_FACILITY_KERNEL_ARCH
,
53 LTT_FACILITY_USER_GENERIC
,
59 LTT_EVENT_SYSCALL_ENTRY
,
60 LTT_EVENT_SYSCALL_EXIT
,
65 LTT_EVENT_SOFT_IRQ_ENTRY
,
66 LTT_EVENT_SOFT_IRQ_EXIT
,
67 LTT_EVENT_SCHED_SCHEDULE
,
68 LTT_EVENT_PROCESS_FORK
,
69 LTT_EVENT_KTHREAD_CREATE
,
70 LTT_EVENT_PROCESS_EXIT
,
71 LTT_EVENT_PROCESS_FREE
,
73 LTT_EVENT_PROCESS_STATE
,
74 LTT_EVENT_STATEDUMP_END
,
75 LTT_EVENT_FUNCTION_ENTRY
,
76 LTT_EVENT_FUNCTION_EXIT
,
77 LTT_EVENT_THREAD_BRAND
,
78 LTT_EVENT_REQUEST_ISSUE
,
79 LTT_EVENT_REQUEST_COMPLETE
,
80 LTT_EVENT_LIST_INTERRUPT
;
88 LTT_FIELD_SOFT_IRQ_ID
,
111 LTTV_STATE_MODE_UNKNOWN
,
112 LTTV_STATE_USER_MODE
,
119 LTTV_STATE_SUBMODE_UNKNOWN
,
120 LTTV_STATE_SUBMODE_NONE
;
124 LTTV_STATE_WAIT_FORK
,
133 LTTV_STATE_UNBRANDED
;
136 LTTV_STATE_USER_THREAD
,
137 LTTV_STATE_KERNEL_THREAD
;
154 LTTV_BDEV_BUSY_READING
,
155 LTTV_BDEV_BUSY_WRITING
;
158 LTTV_STATE_TRACEFILES
,
159 LTTV_STATE_PROCESSES
,
161 LTTV_STATE_RUNNING_PROCESS
,
163 LTTV_STATE_SAVED_STATES
,
164 LTTV_STATE_SAVED_STATES_TIME
,
167 LTTV_STATE_NAME_TABLES
,
168 LTTV_STATE_TRACE_STATE_USE_COUNT
,
169 LTTV_STATE_RESOURCE_CPUS
,
170 LTTV_STATE_RESOURCE_IRQS
,
171 LTTV_STATE_RESOURCE_BLKDEVS
;
173 static void create_max_time(LttvTraceState
*tcs
);
175 static void get_max_time(LttvTraceState
*tcs
);
177 static void free_max_time(LttvTraceState
*tcs
);
179 static void create_name_tables(LttvTraceState
*tcs
);
181 static void get_name_tables(LttvTraceState
*tcs
);
183 static void free_name_tables(LttvTraceState
*tcs
);
185 static void free_saved_state(LttvTraceState
*tcs
);
187 static void lttv_state_free_process_table(GHashTable
*processes
);
189 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
190 GPtrArray
*quarktable
);
192 /* Resource function prototypes */
193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
194 static LttvBdevState
*bdevstate_new(void);
195 static void bdevstate_free(LttvBdevState
*);
196 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
197 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
200 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
202 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
206 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
208 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
212 void lttv_state_state_saved_free(LttvTraceState
*self
,
213 LttvAttribute
*container
)
215 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
219 guint
process_hash(gconstpointer key
)
221 guint pid
= ((const LttvProcessState
*)key
)->pid
;
222 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
226 /* If the hash table hash function is well distributed,
227 * the process_equal should compare different pid */
228 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
230 const LttvProcessState
*process_a
, *process_b
;
233 process_a
= (const LttvProcessState
*)a
;
234 process_b
= (const LttvProcessState
*)b
;
236 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
237 else if(likely(process_a
->pid
== 0 &&
238 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
243 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
245 g_tree_destroy((GTree
*)value
);
248 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
250 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
251 g_hash_table_destroy(usertraces
);
257 restore_init_state(LttvTraceState
*self
)
259 guint i
, nb_cpus
, nb_irqs
;
261 //LttvTracefileState *tfcs;
263 LttTime start_time
, end_time
;
265 /* Free the process tables */
266 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
267 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
268 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
269 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
272 /* Seek time to beginning */
273 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
274 // closest. It's the tracecontext job to seek the trace to the beginning
275 // anyway : the init state might be used at the middle of the trace as well...
276 //g_tree_destroy(self->parent.ts_context->pqueue);
277 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
279 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
281 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
283 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
284 nb_irqs
= self
->nb_irqs
;
286 /* Put the per cpu running_process to beginning state : process 0. */
287 for(i
=0; i
< nb_cpus
; i
++) {
288 LttvExecutionState
*es
;
289 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
290 LTTV_STATE_UNNAMED
, &start_time
);
291 /* We are not sure is it's a kernel thread or normal thread, put the
292 * bottom stack state to unknown */
293 self
->running_process
[i
]->execution_stack
=
294 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
295 es
= self
->running_process
[i
]->state
=
296 &g_array_index(self
->running_process
[i
]->execution_stack
,
297 LttvExecutionState
, 0);
298 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
299 es
->s
= LTTV_STATE_UNNAMED
;
301 //self->running_process[i]->state->s = LTTV_STATE_RUN;
302 self
->running_process
[i
]->cpu
= i
;
304 /* reset cpu states */
305 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
306 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
309 /* reset irq states */
310 for(i
=0; i
<nb_irqs
; i
++) {
311 if(self
->irq_states
[i
].mode_stack
->len
> 0)
312 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
315 /* reset bdev states */
316 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
317 g_hash_table_steal_all(self
->bdev_states
);
320 nb_tracefile
= self
->parent
.tracefiles
->len
;
322 for(i
= 0 ; i
< nb_tracefile
; i
++) {
324 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
325 LttvTracefileContext
*, i
));
326 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
327 // tfcs->saved_position = 0;
328 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
329 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
330 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
331 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
336 //static LttTime time_zero = {0,0};
338 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
341 const LttTime
*t1
= (const LttTime
*)a
;
342 const LttTime
*t2
= (const LttTime
*)b
;
344 return ltt_time_compare(*t1
, *t2
);
347 static void free_usertrace_key(gpointer data
)
352 #define MAX_STRING_LEN 4096
355 state_load_saved_states(LttvTraceState
*tcs
)
358 GPtrArray
*quarktable
;
359 const char *trace_path
;
363 tcs
->has_precomputed_states
= FALSE
;
367 gchar buf
[MAX_STRING_LEN
];
370 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
371 strncpy(path
, trace_path
, PATH_MAX
-1);
372 count
= strnlen(trace_path
, PATH_MAX
-1);
373 // quarktable : open, test
374 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
375 fp
= fopen(path
, "r");
377 quarktable
= g_ptr_array_sized_new(4096);
379 /* Index 0 is null */
381 if(hdr
== EOF
) return;
382 g_assert(hdr
== HDR_QUARKS
);
386 if(hdr
== EOF
) break;
387 g_assert(hdr
== HDR_QUARK
);
388 g_ptr_array_set_size(quarktable
, q
+1);
391 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
392 if(buf
[i
] == '\0' || feof(fp
)) break;
395 len
= strnlen(buf
, MAX_STRING_LEN
-1);
396 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
397 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
403 // saved_states : open, test
404 strncpy(path
, trace_path
, PATH_MAX
-1);
405 count
= strnlen(trace_path
, PATH_MAX
-1);
406 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
407 fp
= fopen(path
, "r");
411 if(hdr
!= HDR_TRACE
) goto end
;
413 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
415 tcs
->has_precomputed_states
= TRUE
;
420 /* Free the quarktable */
421 for(i
=0; i
<quarktable
->len
; i
++) {
422 string
= g_ptr_array_index (quarktable
, i
);
425 g_ptr_array_free(quarktable
, TRUE
);
430 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
432 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
435 LttvTraceContext
*tc
;
439 LttvTracefileState
*tfcs
;
441 LttvAttributeValue v
;
443 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
444 init((LttvTracesetContext
*)self
, ts
);
446 nb_trace
= lttv_traceset_number(ts
);
447 for(i
= 0 ; i
< nb_trace
; i
++) {
448 tc
= self
->parent
.traces
[i
];
449 tcs
= LTTV_TRACE_STATE(tc
);
450 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
451 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
455 if(*(v
.v_uint
) == 1) {
456 create_name_tables(tcs
);
457 create_max_time(tcs
);
459 get_name_tables(tcs
);
462 nb_tracefile
= tc
->tracefiles
->len
;
463 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
464 nb_irq
= tcs
->nb_irqs
;
465 tcs
->processes
= NULL
;
466 tcs
->usertraces
= NULL
;
467 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
469 /* init cpu resource stuff */
470 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
471 for(j
= 0; j
<nb_cpu
; j
++) {
472 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
473 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
476 /* init irq resource stuff */
477 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
478 for(j
= 0; j
<nb_irq
; j
++) {
479 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
480 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
483 /* init bdev resource stuff */
484 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
486 restore_init_state(tcs
);
487 for(j
= 0 ; j
< nb_tracefile
; j
++) {
489 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
490 LttvTracefileContext
*, j
));
491 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
492 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
493 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
494 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
495 /* It's a Usertrace */
496 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
497 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
499 if(!usertrace_tree
) {
500 usertrace_tree
= g_tree_new_full(compare_usertraces
,
501 NULL
, free_usertrace_key
, NULL
);
502 g_hash_table_insert(tcs
->usertraces
,
503 (gpointer
)tid
, usertrace_tree
);
505 LttTime
*timestamp
= g_new(LttTime
, 1);
506 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
507 ltt_tracefile_creation(tfcs
->parent
.tf
));
508 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
512 /* See if the trace has saved states */
513 state_load_saved_states(tcs
);
518 fini(LttvTracesetState
*self
)
524 //LttvTracefileState *tfcs;
526 LttvAttributeValue v
;
528 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
529 for(i
= 0 ; i
< nb_trace
; i
++) {
530 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
531 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
534 g_assert(*(v
.v_uint
) != 0);
537 if(*(v
.v_uint
) == 0) {
538 free_name_tables(tcs
);
540 free_saved_state(tcs
);
542 g_free(tcs
->running_process
);
543 tcs
->running_process
= NULL
;
544 lttv_state_free_process_table(tcs
->processes
);
545 lttv_state_free_usertraces(tcs
->usertraces
);
546 tcs
->processes
= NULL
;
547 tcs
->usertraces
= NULL
;
549 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
550 fini((LttvTracesetContext
*)self
);
554 static LttvTracesetContext
*
555 new_traceset_context(LttvTracesetContext
*self
)
557 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
561 static LttvTraceContext
*
562 new_trace_context(LttvTracesetContext
*self
)
564 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
568 static LttvTracefileContext
*
569 new_tracefile_context(LttvTracesetContext
*self
)
571 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
575 /* Write the process state of the trace */
577 static void write_process_state(gpointer key
, gpointer value
,
580 LttvProcessState
*process
;
582 LttvExecutionState
*es
;
584 FILE *fp
= (FILE *)user_data
;
589 process
= (LttvProcessState
*)value
;
591 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
592 process
, process
->pid
, process
->tgid
, process
->ppid
,
593 g_quark_to_string(process
->type
),
594 process
->creation_time
.tv_sec
,
595 process
->creation_time
.tv_nsec
,
596 process
->insertion_time
.tv_sec
,
597 process
->insertion_time
.tv_nsec
,
598 g_quark_to_string(process
->name
),
599 g_quark_to_string(process
->brand
),
602 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
603 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
604 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
605 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
606 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
607 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
608 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
611 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
612 address
= g_array_index(process
->user_stack
, guint64
, i
);
613 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
617 if(process
->usertrace
) {
618 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
619 g_quark_to_string(process
->usertrace
->tracefile_name
),
620 process
->usertrace
->cpu
);
624 fprintf(fp
, " </PROCESS>\n");
628 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
630 guint i
, nb_tracefile
, nb_block
, offset
;
633 LttvTracefileState
*tfcs
;
637 LttEventPosition
*ep
;
641 ep
= ltt_event_position_new();
643 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
645 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
647 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
648 for(i
=0;i
<nb_cpus
;i
++) {
649 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
650 i
, self
->running_process
[i
]->pid
);
653 nb_tracefile
= self
->parent
.tracefiles
->len
;
655 for(i
= 0 ; i
< nb_tracefile
; i
++) {
657 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
658 LttvTracefileContext
*, i
));
659 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
660 tfcs
->parent
.timestamp
.tv_sec
,
661 tfcs
->parent
.timestamp
.tv_nsec
);
662 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
663 if(e
== NULL
) fprintf(fp
,"/>\n");
665 ltt_event_position(e
, ep
);
666 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
667 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
672 fprintf(fp
,"</PROCESS_STATE>\n");
676 static void write_process_state_raw(gpointer key
, gpointer value
,
679 LttvProcessState
*process
;
681 LttvExecutionState
*es
;
683 FILE *fp
= (FILE *)user_data
;
688 process
= (LttvProcessState
*)value
;
689 fputc(HDR_PROCESS
, fp
);
690 //fwrite(&header, sizeof(header), 1, fp);
691 //fprintf(fp, "%s", g_quark_to_string(process->type));
693 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
694 //fprintf(fp, "%s", g_quark_to_string(process->name));
696 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
697 //fprintf(fp, "%s", g_quark_to_string(process->brand));
699 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
700 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
701 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
702 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
703 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
704 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
705 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
709 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
710 process
, process
->pid
, process
->tgid
, process
->ppid
,
711 g_quark_to_string(process
->type
),
712 process
->creation_time
.tv_sec
,
713 process
->creation_time
.tv_nsec
,
714 process
->insertion_time
.tv_sec
,
715 process
->insertion_time
.tv_nsec
,
716 g_quark_to_string(process
->name
),
717 g_quark_to_string(process
->brand
),
721 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
722 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
725 //fprintf(fp, "%s", g_quark_to_string(es->t));
727 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
728 //fprintf(fp, "%s", g_quark_to_string(es->n));
730 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
731 //fprintf(fp, "%s", g_quark_to_string(es->s));
733 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
734 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
735 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
736 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
738 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
739 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
740 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
741 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
742 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
746 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
747 address
= g_array_index(process
->user_stack
, guint64
, i
);
748 fputc(HDR_USER_STACK
, fp
);
749 fwrite(&address
, sizeof(address
), 1, fp
);
751 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
756 if(process
->usertrace
) {
757 fputc(HDR_USERTRACE
, fp
);
758 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
760 fwrite(&process
->usertrace
->tracefile_name
,
761 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
762 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
764 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
765 g_quark_to_string(process
->usertrace
->tracefile_name
),
766 process
->usertrace
->cpu
);
773 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
775 guint i
, nb_tracefile
, nb_block
, offset
;
778 LttvTracefileState
*tfcs
;
782 LttEventPosition
*ep
;
786 ep
= ltt_event_position_new();
788 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
789 fputc(HDR_PROCESS_STATE
, fp
);
790 fwrite(&t
, sizeof(t
), 1, fp
);
792 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
794 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
795 for(i
=0;i
<nb_cpus
;i
++) {
797 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
798 fwrite(&self
->running_process
[i
]->pid
,
799 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
800 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
801 // i, self->running_process[i]->pid);
804 nb_tracefile
= self
->parent
.tracefiles
->len
;
806 for(i
= 0 ; i
< nb_tracefile
; i
++) {
808 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
809 LttvTracefileContext
*, i
));
810 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
811 // tfcs->parent.timestamp.tv_sec,
812 // tfcs->parent.timestamp.tv_nsec);
813 fputc(HDR_TRACEFILE
, fp
);
814 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
815 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
816 * position following : end of trace */
817 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
819 ltt_event_position(e
, ep
);
820 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
821 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
823 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
824 fwrite(&offset
, sizeof(offset
), 1, fp
);
825 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
832 /* Read process state from a file */
834 /* Called because a HDR_PROCESS was found */
835 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
836 GPtrArray
*quarktable
)
838 LttvExecutionState
*es
;
839 LttvProcessState
*process
, *parent_process
;
840 LttvProcessState tmp
;
845 /* TODO : check return value */
846 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
847 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
848 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
849 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
850 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
851 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
852 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
853 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
854 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
857 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
859 /* We must link to the parent */
860 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
862 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
863 if(process
== NULL
) {
864 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
866 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
870 process
->insertion_time
= tmp
.insertion_time
;
871 process
->creation_time
= tmp
.creation_time
;
872 process
->type
= g_quark_from_string(
873 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
874 process
->tgid
= tmp
.tgid
;
875 process
->ppid
= tmp
.ppid
;
876 process
->brand
= g_quark_from_string(
877 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
879 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
883 if(feof(fp
) || ferror(fp
)) goto end_loop
;
885 gint hdr
= fgetc(fp
);
886 if(hdr
== EOF
) goto end_loop
;
890 process
->execution_stack
=
891 g_array_set_size(process
->execution_stack
,
892 process
->execution_stack
->len
+ 1);
893 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
894 process
->execution_stack
->len
-1);
897 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
898 es
->t
= g_quark_from_string(
899 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
900 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
901 es
->n
= g_quark_from_string(
902 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
903 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
904 es
->s
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
906 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
907 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
908 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
911 process
->user_stack
= g_array_set_size(process
->user_stack
,
912 process
->user_stack
->len
+ 1);
913 address
= &g_array_index(process
->user_stack
, guint64
,
914 process
->user_stack
->len
-1);
915 fread(address
, sizeof(address
), 1, fp
);
916 process
->current_function
= *address
;
919 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
920 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
932 /* Called because a HDR_PROCESS_STATE was found */
933 /* Append a saved state to the trace states */
934 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
936 guint i
, nb_tracefile
, nb_block
, offset
;
938 LttvTracefileState
*tfcs
;
940 LttEventPosition
*ep
;
948 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
950 LttvAttributeValue value
;
951 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
952 ep
= ltt_event_position_new();
954 restore_init_state(self
);
956 fread(&t
, sizeof(t
), 1, fp
);
959 if(feof(fp
) || ferror(fp
)) goto end_loop
;
961 if(hdr
== EOF
) goto end_loop
;
965 /* Call read_process_state_raw */
966 read_process_state_raw(self
, fp
, quarktable
);
976 case HDR_PROCESS_STATE
:
982 g_error("Error while parsing saved state file : unknown data header %d",
988 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
989 for(i
=0;i
<nb_cpus
;i
++) {
992 g_assert(hdr
== HDR_CPU
);
993 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
994 g_assert(i
== cpu_num
);
995 fread(&self
->running_process
[i
]->pid
,
996 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
999 nb_tracefile
= self
->parent
.tracefiles
->len
;
1001 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1003 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1004 LttvTracefileContext
*, i
));
1005 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1006 // tfcs->parent.timestamp.tv_sec,
1007 // tfcs->parent.timestamp.tv_nsec);
1008 g_tree_remove(pqueue
, &tfcs
->parent
);
1010 g_assert(hdr
== HDR_TRACEFILE
);
1011 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1012 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1013 * position following : end of trace */
1014 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1015 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1016 fread(&offset
, sizeof(offset
), 1, fp
);
1017 fread(&tsc
, sizeof(tsc
), 1, fp
);
1018 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1019 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1021 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1026 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1027 LTTV_STATE_SAVED_STATES
);
1028 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1029 value
= lttv_attribute_add(saved_states_tree
,
1030 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1031 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1032 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1033 *(value
.v_time
) = t
;
1034 lttv_state_save(self
, saved_state_tree
);
1035 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1038 *(self
->max_time_state_recomputed_in_seek
) = t
;
1042 /* Called when a HDR_TRACE is found */
1043 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1044 GPtrArray
*quarktable
)
1049 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1051 if(hdr
== EOF
) goto end_loop
;
1054 case HDR_PROCESS_STATE
:
1055 /* Call read_process_state_raw */
1056 lttv_state_read_raw(tcs
, fp
, quarktable
);
1064 case HDR_USER_STACK
:
1068 g_error("Error while parsing saved state file :"
1069 " unexpected data header %d",
1073 g_error("Error while parsing saved state file : unknown data header %d",
1078 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1079 restore_init_state(tcs
);
1080 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1086 /* Copy each process from an existing hash table to a new one */
1088 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1090 LttvProcessState
*process
, *new_process
;
1092 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1096 process
= (LttvProcessState
*)value
;
1097 new_process
= g_new(LttvProcessState
, 1);
1098 *new_process
= *process
;
1099 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1100 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1101 new_process
->execution_stack
=
1102 g_array_set_size(new_process
->execution_stack
,
1103 process
->execution_stack
->len
);
1104 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1105 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1106 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1108 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1109 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1110 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1111 sizeof(guint64
), 0);
1112 new_process
->user_stack
=
1113 g_array_set_size(new_process
->user_stack
,
1114 process
->user_stack
->len
);
1115 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1116 g_array_index(new_process
->user_stack
, guint64
, i
) =
1117 g_array_index(process
->user_stack
, guint64
, i
);
1119 new_process
->current_function
= process
->current_function
;
1120 g_hash_table_insert(new_processes
, new_process
, new_process
);
1124 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1126 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1128 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1129 return new_processes
;
1132 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1135 LttvCPUState
*retval
;
1137 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1139 for(i
=0; i
<n
; i
++) {
1140 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1141 retval
[i
].last_irq
= states
[i
].last_irq
;
1142 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1143 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1144 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1151 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1155 for(i
=0; i
<n
; i
++) {
1156 g_array_free(states
[i
].mode_stack
, FALSE
);
1162 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1165 LttvIRQState
*retval
;
1167 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1169 for(i
=0; i
<n
; i
++) {
1170 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1171 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1172 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1173 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1180 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1184 for(i
=0; i
<n
; i
++) {
1185 g_array_free(states
[i
].mode_stack
, FALSE
);
1191 /* bdevstate stuff */
1193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1195 gint devcode_gint
= devcode
;
1196 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1198 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1199 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1201 gint
* key
= g_malloc(sizeof(gint
));
1203 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1211 static LttvBdevState
*bdevstate_new(void)
1213 LttvBdevState
*retval
;
1214 retval
= g_malloc(sizeof(LttvBdevState
));
1215 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1220 static void bdevstate_free(LttvBdevState
*bds
)
1222 g_array_free(bds
->mode_stack
, FALSE
);
1226 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1228 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1230 bdevstate_free(bds
);
1233 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1235 LttvBdevState
*retval
;
1237 retval
= bdevstate_new();
1238 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1243 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1245 //GHashTable *ht = (GHashTable *)u;
1246 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1247 LttvBdevState
*newbds
;
1249 newbds
= bdevstate_copy(bds
);
1251 g_hash_table_insert(u
, k
, newbds
);
1254 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1258 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1260 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1265 /* Free a hashtable and the LttvBdevState structures its values
1268 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1270 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1271 g_hash_table_destroy(ht
);
1274 /* The saved state for each trace contains a member "processes", which
1275 stores a copy of the process table, and a member "tracefiles" with
1276 one entry per tracefile. Each tracefile has a "process" member pointing
1277 to the current process and a "position" member storing the tracefile
1278 position (needed to seek to the current "next" event. */
1280 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1282 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1284 LttvTracefileState
*tfcs
;
1286 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1288 guint
*running_process
;
1290 LttvAttributeValue value
;
1292 LttEventPosition
*ep
;
1294 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1295 LTTV_STATE_TRACEFILES
);
1297 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1299 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1301 /* Add the currently running processes array */
1302 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1303 running_process
= g_new(guint
, nb_cpus
);
1304 for(i
=0;i
<nb_cpus
;i
++) {
1305 running_process
[i
] = self
->running_process
[i
]->pid
;
1307 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1309 *(value
.v_pointer
) = running_process
;
1311 g_info("State save");
1313 nb_tracefile
= self
->parent
.tracefiles
->len
;
1315 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1317 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1318 LttvTracefileContext
*, i
));
1319 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1320 value
= lttv_attribute_add(tracefiles_tree
, i
,
1322 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1324 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1326 *(value
.v_uint
) = tfcs
->process
->pid
;
1328 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1330 /* Only save the position if the tfs has not infinite time. */
1331 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1332 // && current_tfcs != tfcs) {
1333 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1334 *(value
.v_pointer
) = NULL
;
1336 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1337 ep
= ltt_event_position_new();
1338 ltt_event_position(e
, ep
);
1339 *(value
.v_pointer
) = ep
;
1341 guint nb_block
, offset
;
1344 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1345 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1347 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1351 /* save the cpu state */
1353 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1355 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1358 /* save the irq state */
1359 nb_irqs
= self
->nb_irqs
;
1361 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1363 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1366 /* save the blkdev states */
1367 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1369 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1373 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1375 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1377 LttvTracefileState
*tfcs
;
1379 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1381 guint
*running_process
;
1383 LttvAttributeType type
;
1385 LttvAttributeValue value
;
1387 LttvAttributeName name
;
1391 LttEventPosition
*ep
;
1393 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1395 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1396 LTTV_STATE_TRACEFILES
);
1398 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1400 g_assert(type
== LTTV_POINTER
);
1401 lttv_state_free_process_table(self
->processes
);
1402 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1404 /* Add the currently running processes array */
1405 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1406 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1408 g_assert(type
== LTTV_POINTER
);
1409 running_process
= *(value
.v_pointer
);
1410 for(i
=0;i
<nb_cpus
;i
++) {
1411 pid
= running_process
[i
];
1412 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1413 g_assert(self
->running_process
[i
] != NULL
);
1416 nb_tracefile
= self
->parent
.tracefiles
->len
;
1418 //g_tree_destroy(tsc->pqueue);
1419 //tsc->pqueue = g_tree_new(compare_tracefile);
1421 /* restore cpu resource states */
1422 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1423 g_assert(type
== LTTV_POINTER
);
1424 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1425 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1427 /* restore irq resource states */
1428 nb_irqs
= self
->nb_irqs
;
1429 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1430 g_assert(type
== LTTV_POINTER
);
1431 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1432 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1434 /* restore the blkdev states */
1435 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1436 g_assert(type
== LTTV_POINTER
);
1437 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1438 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1440 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1442 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1443 LttvTracefileContext
*, i
));
1444 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1445 g_assert(type
== LTTV_GOBJECT
);
1446 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1448 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1450 g_assert(type
== LTTV_UINT
);
1451 pid
= *(value
.v_uint
);
1452 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1454 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1456 g_assert(type
== LTTV_POINTER
);
1457 //g_assert(*(value.v_pointer) != NULL);
1458 ep
= *(value
.v_pointer
);
1459 g_assert(tfcs
->parent
.t_context
!= NULL
);
1461 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1463 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1464 g_tree_remove(tsc
->pqueue
, tfc
);
1467 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1468 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1469 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1470 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1471 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1473 tfc
->timestamp
= ltt_time_infinite
;
1479 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1481 guint i
, nb_tracefile
, nb_cpus
;
1483 LttvTracefileState
*tfcs
;
1485 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1487 guint
*running_process
;
1489 LttvAttributeType type
;
1491 LttvAttributeValue value
;
1493 LttvAttributeName name
;
1497 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1498 LTTV_STATE_TRACEFILES
);
1499 g_object_ref(G_OBJECT(tracefiles_tree
));
1500 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1502 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1504 g_assert(type
== LTTV_POINTER
);
1505 lttv_state_free_process_table(*(value
.v_pointer
));
1506 *(value
.v_pointer
) = NULL
;
1507 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1509 /* Free running processes array */
1510 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1511 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1513 g_assert(type
== LTTV_POINTER
);
1514 running_process
= *(value
.v_pointer
);
1515 g_free(running_process
);
1517 nb_tracefile
= self
->parent
.tracefiles
->len
;
1519 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1521 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1522 LttvTracefileContext
*, i
));
1523 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1524 g_assert(type
== LTTV_GOBJECT
);
1525 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1527 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1529 g_assert(type
== LTTV_POINTER
);
1530 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1532 g_object_unref(G_OBJECT(tracefiles_tree
));
1536 static void free_saved_state(LttvTraceState
*self
)
1540 LttvAttributeType type
;
1542 LttvAttributeValue value
;
1544 LttvAttributeName name
;
1548 LttvAttribute
*saved_states
;
1550 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1551 LTTV_STATE_SAVED_STATES
);
1553 nb
= lttv_attribute_get_number(saved_states
);
1554 for(i
= 0 ; i
< nb
; i
++) {
1555 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1556 g_assert(type
== LTTV_GOBJECT
);
1557 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1560 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1565 create_max_time(LttvTraceState
*tcs
)
1567 LttvAttributeValue v
;
1569 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1571 g_assert(*(v
.v_pointer
) == NULL
);
1572 *(v
.v_pointer
) = g_new(LttTime
,1);
1573 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1578 get_max_time(LttvTraceState
*tcs
)
1580 LttvAttributeValue v
;
1582 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1584 g_assert(*(v
.v_pointer
) != NULL
);
1585 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1590 free_max_time(LttvTraceState
*tcs
)
1592 LttvAttributeValue v
;
1594 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1596 g_free(*(v
.v_pointer
));
1597 *(v
.v_pointer
) = NULL
;
1601 typedef struct _LttvNameTables
{
1602 // FIXME GQuark *eventtype_names;
1603 GQuark
*syscall_names
;
1609 GQuark
*soft_irq_names
;
1615 create_name_tables(LttvTraceState
*tcs
)
1619 GString
*fe_name
= g_string_new("");
1621 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1623 LttvAttributeValue v
;
1627 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1629 g_assert(*(v
.v_pointer
) == NULL
);
1630 *(v
.v_pointer
) = name_tables
;
1632 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1634 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1635 LTT_FACILITY_KERNEL_ARCH
,
1636 LTT_EVENT_SYSCALL_ENTRY
,
1637 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1638 NULL
, NULL
, &hooks
)) {
1640 // th = lttv_trace_hook_get_first(&th);
1642 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1643 // nb = ltt_type_element_number(t);
1645 // name_tables->syscall_names = g_new(GQuark, nb);
1646 // name_tables->nb_syscalls = nb;
1648 // for(i = 0 ; i < nb ; i++) {
1649 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1650 // if(!name_tables->syscall_names[i]) {
1651 // GString *string = g_string_new("");
1652 // g_string_printf(string, "syscall %u", i);
1653 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1654 // g_string_free(string, TRUE);
1658 name_tables
->syscall_names
= g_new(GQuark
, 256);
1659 for(i
= 0 ; i
< 256 ; i
++) {
1660 g_string_printf(fe_name
, "syscall %d", i
);
1661 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1664 name_tables
->syscall_names
= NULL
;
1665 name_tables
->nb_syscalls
= 0;
1667 lttv_trace_hook_remove_all(&hooks
);
1669 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1670 LTT_FACILITY_KERNEL_ARCH
,
1671 LTT_EVENT_TRAP_ENTRY
,
1672 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1673 NULL
, NULL
, &hooks
)) {
1675 // th = lttv_trace_hook_get_first(&th);
1677 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1678 // //nb = ltt_type_element_number(t);
1680 // name_tables->trap_names = g_new(GQuark, nb);
1681 // for(i = 0 ; i < nb ; i++) {
1682 // name_tables->trap_names[i] = g_quark_from_string(
1683 // ltt_enum_string_get(t, i));
1686 name_tables
->nb_traps
= 256;
1687 name_tables
->trap_names
= g_new(GQuark
, 256);
1688 for(i
= 0 ; i
< 256 ; i
++) {
1689 g_string_printf(fe_name
, "trap %d", i
);
1690 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1693 name_tables
->trap_names
= NULL
;
1694 name_tables
->nb_traps
= 0;
1696 lttv_trace_hook_remove_all(&hooks
);
1698 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1699 LTT_FACILITY_KERNEL
,
1700 LTT_EVENT_IRQ_ENTRY
,
1701 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1702 NULL
, NULL
, &hooks
)) {
1705 name_tables->irq_names = g_new(GQuark, nb);
1706 for(i = 0 ; i < nb ; i++) {
1707 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1711 name_tables
->nb_irqs
= 256;
1712 name_tables
->irq_names
= g_new(GQuark
, 256);
1713 for(i
= 0 ; i
< 256 ; i
++) {
1714 g_string_printf(fe_name
, "irq %d", i
);
1715 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1718 name_tables
->nb_irqs
= 0;
1719 name_tables
->irq_names
= NULL
;
1721 lttv_trace_hook_remove_all(&hooks
);
1723 name_tables->soft_irq_names = g_new(GQuark, nb);
1724 for(i = 0 ; i < nb ; i++) {
1725 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1729 name_tables
->nb_softirqs
= 256;
1730 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1731 for(i
= 0 ; i
< 256 ; i
++) {
1732 g_string_printf(fe_name
, "softirq %d", i
);
1733 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1735 g_array_free(hooks
, TRUE
);
1737 g_string_free(fe_name
, TRUE
);
1742 get_name_tables(LttvTraceState
*tcs
)
1744 LttvNameTables
*name_tables
;
1746 LttvAttributeValue v
;
1748 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1750 g_assert(*(v
.v_pointer
) != NULL
);
1751 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1752 //tcs->eventtype_names = name_tables->eventtype_names;
1753 tcs
->syscall_names
= name_tables
->syscall_names
;
1754 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1755 tcs
->trap_names
= name_tables
->trap_names
;
1756 tcs
->nb_traps
= name_tables
->nb_traps
;
1757 tcs
->irq_names
= name_tables
->irq_names
;
1758 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1759 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1760 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1765 free_name_tables(LttvTraceState
*tcs
)
1767 LttvNameTables
*name_tables
;
1769 LttvAttributeValue v
;
1771 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1773 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1774 *(v
.v_pointer
) = NULL
;
1776 // g_free(name_tables->eventtype_names);
1777 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1778 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1779 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1780 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1781 if(name_tables
) g_free(name_tables
);
1784 #ifdef HASH_TABLE_DEBUG
1786 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1788 LttvProcessState
*process
= (LttvProcessState
*)value
;
1790 /* Test for process corruption */
1791 guint stack_len
= process
->execution_stack
->len
;
1794 static void hash_table_check(GHashTable
*table
)
1796 g_hash_table_foreach(table
, test_process
, NULL
);
1802 /* clears the stack and sets the state passed as argument */
1803 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1805 g_array_set_size(cpust
->mode_stack
, 1);
1806 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1809 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1811 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1812 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1815 static void cpu_pop_mode(LttvCPUState
*cpust
)
1817 if(cpust
->mode_stack
->len
<= 1)
1818 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1820 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1823 /* clears the stack and sets the state passed as argument */
1824 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1826 g_array_set_size(bdevst
->mode_stack
, 1);
1827 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1830 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1832 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1833 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1836 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1838 if(bdevst
->mode_stack
->len
<= 1)
1839 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1841 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1844 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1846 g_array_set_size(irqst
->mode_stack
, 1);
1847 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1850 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1852 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1853 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1856 static void irq_pop_mode(LttvIRQState
*irqst
)
1858 if(irqst
->mode_stack
->len
<= 1)
1859 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1861 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1864 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1867 LttvExecutionState
*es
;
1869 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1870 guint cpu
= tfs
->cpu
;
1872 #ifdef HASH_TABLE_DEBUG
1873 hash_table_check(ts
->processes
);
1875 LttvProcessState
*process
= ts
->running_process
[cpu
];
1877 guint depth
= process
->execution_stack
->len
;
1879 process
->execution_stack
=
1880 g_array_set_size(process
->execution_stack
, depth
+ 1);
1883 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1885 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1888 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1889 es
->cum_cpu_time
= ltt_time_zero
;
1890 es
->s
= process
->state
->s
;
1891 process
->state
= es
;
1895 * return 1 when empty, else 0 */
1896 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1897 LttvTracefileState
*tfs
)
1899 guint depth
= process
->execution_stack
->len
;
1905 process
->execution_stack
=
1906 g_array_set_size(process
->execution_stack
, depth
- 1);
1907 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1909 process
->state
->change
= tfs
->parent
.timestamp
;
1914 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1916 guint cpu
= tfs
->cpu
;
1917 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1918 LttvProcessState
*process
= ts
->running_process
[cpu
];
1920 guint depth
= process
->execution_stack
->len
;
1922 if(process
->state
->t
!= t
){
1923 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1924 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1925 g_info("process state has %s when pop_int is %s\n",
1926 g_quark_to_string(process
->state
->t
),
1927 g_quark_to_string(t
));
1928 g_info("{ %u, %u, %s, %s, %s }\n",
1931 g_quark_to_string(process
->name
),
1932 g_quark_to_string(process
->brand
),
1933 g_quark_to_string(process
->state
->s
));
1938 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1939 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1943 process
->execution_stack
=
1944 g_array_set_size(process
->execution_stack
, depth
- 1);
1945 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1947 process
->state
->change
= tfs
->parent
.timestamp
;
1950 struct search_result
{
1951 const LttTime
*time
; /* Requested time */
1952 LttTime
*best
; /* Best result */
1955 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1957 const LttTime
*elem_time
= (const LttTime
*)a
;
1958 /* Explicit non const cast */
1959 struct search_result
*res
= (struct search_result
*)b
;
1961 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1962 /* The usertrace was created before the schedchange */
1963 /* Get larger keys */
1965 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1966 /* The usertrace was created after the schedchange time */
1967 /* Get smaller keys */
1969 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1970 res
->best
= (LttTime
*)elem_time
;
1973 res
->best
= (LttTime
*)elem_time
;
1980 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1981 guint pid
, const LttTime
*timestamp
)
1983 LttvTracefileState
*tfs
= NULL
;
1984 struct search_result res
;
1985 /* Find the usertrace associated with a pid and time interval.
1986 * Search in the usertraces by PID (within a hash) and then, for each
1987 * corresponding element of the array, find the first one with creation
1988 * timestamp the lowest, but higher or equal to "timestamp". */
1989 res
.time
= timestamp
;
1991 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1992 if(usertrace_tree
) {
1993 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1995 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2003 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2004 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2006 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2008 LttvExecutionState
*es
;
2013 process
->tgid
= tgid
;
2015 process
->name
= name
;
2016 process
->brand
= LTTV_STATE_UNBRANDED
;
2017 //process->last_cpu = tfs->cpu_name;
2018 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2019 process
->type
= LTTV_STATE_USER_THREAD
;
2020 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2021 process
->current_function
= 0; //function 0x0 by default.
2023 g_info("Process %u, core %p", process
->pid
, process
);
2024 g_hash_table_insert(tcs
->processes
, process
, process
);
2027 process
->ppid
= parent
->pid
;
2028 process
->creation_time
= *timestamp
;
2031 /* No parent. This process exists but we are missing all information about
2032 its creation. The birth time is set to zero but we remember the time of
2037 process
->creation_time
= ltt_time_zero
;
2040 process
->insertion_time
= *timestamp
;
2041 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2042 process
->creation_time
.tv_nsec
);
2043 process
->pid_time
= g_quark_from_string(buffer
);
2045 //process->last_cpu = tfs->cpu_name;
2046 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2047 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2048 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2049 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2050 es
= process
->state
= &g_array_index(process
->execution_stack
,
2051 LttvExecutionState
, 0);
2052 es
->t
= LTTV_STATE_USER_MODE
;
2053 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2054 es
->entry
= *timestamp
;
2055 //g_assert(timestamp->tv_sec != 0);
2056 es
->change
= *timestamp
;
2057 es
->cum_cpu_time
= ltt_time_zero
;
2058 es
->s
= LTTV_STATE_RUN
;
2060 es
= process
->state
= &g_array_index(process
->execution_stack
,
2061 LttvExecutionState
, 1);
2062 es
->t
= LTTV_STATE_SYSCALL
;
2063 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2064 es
->entry
= *timestamp
;
2065 //g_assert(timestamp->tv_sec != 0);
2066 es
->change
= *timestamp
;
2067 es
->cum_cpu_time
= ltt_time_zero
;
2068 es
->s
= LTTV_STATE_WAIT_FORK
;
2070 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2071 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2072 sizeof(guint64
), 0);
2077 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2080 LttvProcessState key
;
2081 LttvProcessState
*process
;
2085 process
= g_hash_table_lookup(ts
->processes
, &key
);
2090 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2091 const LttTime
*timestamp
)
2093 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2094 LttvExecutionState
*es
;
2096 /* Put ltt_time_zero creation time for unexisting processes */
2097 if(unlikely(process
== NULL
)) {
2098 process
= lttv_state_create_process(ts
,
2099 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2100 /* We are not sure is it's a kernel thread or normal thread, put the
2101 * bottom stack state to unknown */
2102 process
->execution_stack
=
2103 g_array_set_size(process
->execution_stack
, 1);
2104 process
->state
= es
=
2105 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2106 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2107 es
->s
= LTTV_STATE_UNNAMED
;
2112 /* FIXME : this function should be called when we receive an event telling that
2113 * release_task has been called in the kernel. In happens generally when
2114 * the parent waits for its child terminaison, but may also happen in special
2115 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2116 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2117 * of a killed thread ground, but isn't the leader.
2119 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2121 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2122 LttvProcessState key
;
2124 key
.pid
= process
->pid
;
2125 key
.cpu
= process
->cpu
;
2126 g_hash_table_remove(ts
->processes
, &key
);
2127 g_array_free(process
->execution_stack
, TRUE
);
2128 g_array_free(process
->user_stack
, TRUE
);
2133 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2135 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2136 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2141 static void lttv_state_free_process_table(GHashTable
*processes
)
2143 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2144 g_hash_table_destroy(processes
);
2148 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2150 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2152 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2153 LttvProcessState
*process
= ts
->running_process
[cpu
];
2154 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2155 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2156 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2158 LttvExecutionSubmode submode
;
2160 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2161 guint syscall
= ltt_event_get_unsigned(e
, f
);
2163 if(syscall
< nb_syscalls
) {
2164 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2167 /* Fixup an incomplete syscall table */
2168 GString
*string
= g_string_new("");
2169 g_string_printf(string
, "syscall %u", syscall
);
2170 submode
= g_quark_from_string(string
->str
);
2171 g_string_free(string
, TRUE
);
2173 /* There can be no system call from PID 0 : unknown state */
2174 if(process
->pid
!= 0)
2175 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2180 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2182 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2184 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2185 LttvProcessState
*process
= ts
->running_process
[cpu
];
2187 /* There can be no system call from PID 0 : unknown state */
2188 if(process
->pid
!= 0)
2189 pop_state(s
, LTTV_STATE_SYSCALL
);
2194 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2196 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2197 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2198 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2199 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2201 LttvExecutionSubmode submode
;
2203 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2204 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2206 if(trap
< nb_traps
) {
2207 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2209 /* Fixup an incomplete trap table */
2210 GString
*string
= g_string_new("");
2211 g_string_printf(string
, "trap %llu", trap
);
2212 submode
= g_quark_from_string(string
->str
);
2213 g_string_free(string
, TRUE
);
2216 push_state(s
, LTTV_STATE_TRAP
, submode
);
2218 /* update cpu status */
2219 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2224 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2226 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2228 pop_state(s
, LTTV_STATE_TRAP
);
2230 /* update cpu status */
2231 cpu_pop_mode(s
->cpu_state
);
2236 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2238 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2239 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2240 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2241 //guint8 ev_id = ltt_event_eventtype_id(e);
2242 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2243 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2245 LttvExecutionSubmode submode
;
2246 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2247 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2250 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2252 /* Fixup an incomplete irq table */
2253 GString
*string
= g_string_new("");
2254 g_string_printf(string
, "irq %llu", irq
);
2255 submode
= g_quark_from_string(string
->str
);
2256 g_string_free(string
, TRUE
);
2259 /* Do something with the info about being in user or system mode when int? */
2260 push_state(s
, LTTV_STATE_IRQ
, submode
);
2262 /* update cpu status */
2263 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2265 /* update irq status */
2266 s
->cpu_state
->last_irq
= irq
;
2267 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2272 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2274 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2276 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2282 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2284 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2285 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2287 pop_state(s
, LTTV_STATE_IRQ
);
2289 /* update cpu status */
2290 cpu_pop_mode(s
->cpu_state
);
2292 /* update irq status */
2293 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2298 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2300 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2301 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2302 //guint8 ev_id = ltt_event_eventtype_id(e);
2303 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2304 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2306 LttvExecutionSubmode submode
;
2307 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2308 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2310 if(softirq
< nb_softirqs
) {
2311 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2313 /* Fixup an incomplete irq table */
2314 GString
*string
= g_string_new("");
2315 g_string_printf(string
, "softirq %llu", softirq
);
2316 submode
= g_quark_from_string(string
->str
);
2317 g_string_free(string
, TRUE
);
2320 /* Do something with the info about being in user or system mode when int? */
2321 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2325 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2327 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2328 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2329 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2330 //guint8 ev_id = ltt_event_eventtype_id(e);
2331 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2333 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2334 lttv_trace_get_hook_field(th
, 0)));
2335 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2337 ts
->irq_names
[irq
] = action
;
2343 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2345 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2346 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2347 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2348 //guint8 ev_id = ltt_event_eventtype_id(e);
2349 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2351 guint major
= ltt_event_get_long_unsigned(e
,
2352 lttv_trace_get_hook_field(th
, 0));
2353 guint minor
= ltt_event_get_long_unsigned(e
,
2354 lttv_trace_get_hook_field(th
, 1));
2355 guint oper
= ltt_event_get_long_unsigned(e
,
2356 lttv_trace_get_hook_field(th
, 2));
2357 guint16 devcode
= MKDEV(major
,minor
);
2359 /* have we seen this block device before? */
2360 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2363 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2365 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2370 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2372 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2373 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2374 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2375 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2377 guint major
= ltt_event_get_long_unsigned(e
,
2378 lttv_trace_get_hook_field(th
, 0));
2379 guint minor
= ltt_event_get_long_unsigned(e
,
2380 lttv_trace_get_hook_field(th
, 1));
2381 //guint oper = ltt_event_get_long_unsigned(e,
2382 // lttv_trace_get_hook_field(th, 2));
2383 guint16 devcode
= MKDEV(major
,minor
);
2385 /* have we seen this block device before? */
2386 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2388 /* update block device */
2389 bdev_pop_mode(bdev
);
2394 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2398 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2399 guint cpu
= tfs
->cpu
;
2400 LttvProcessState
*process
= ts
->running_process
[cpu
];
2402 guint depth
= process
->user_stack
->len
;
2404 process
->user_stack
=
2405 g_array_set_size(process
->user_stack
, depth
+ 1);
2407 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2408 *new_func
= funcptr
;
2409 process
->current_function
= funcptr
;
2412 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2414 guint cpu
= tfs
->cpu
;
2415 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2416 LttvProcessState
*process
= ts
->running_process
[cpu
];
2418 if(process
->current_function
!= funcptr
){
2419 g_info("Different functions (%lu.%09lu): ignore it\n",
2420 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2421 g_info("process state has %llu when pop_function is %llu\n",
2422 process
->current_function
, funcptr
);
2423 g_info("{ %u, %u, %s, %s, %s }\n",
2426 g_quark_to_string(process
->name
),
2427 g_quark_to_string(process
->brand
),
2428 g_quark_to_string(process
->state
->s
));
2431 guint depth
= process
->user_stack
->len
;
2434 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2435 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2439 process
->user_stack
=
2440 g_array_set_size(process
->user_stack
, depth
- 1);
2441 process
->current_function
=
2442 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2446 static gboolean
function_entry(void *hook_data
, void *call_data
)
2448 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2449 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2450 //guint8 ev_id = ltt_event_eventtype_id(e);
2451 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2452 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2453 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2455 push_function(s
, funcptr
);
2459 static gboolean
function_exit(void *hook_data
, void *call_data
)
2461 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2462 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2463 //guint8 ev_id = ltt_event_eventtype_id(e);
2464 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2465 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2466 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2468 pop_function(s
, funcptr
);
2472 static gboolean
schedchange(void *hook_data
, void *call_data
)
2474 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2476 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2477 LttvProcessState
*process
= ts
->running_process
[cpu
];
2478 //LttvProcessState *old_process = ts->running_process[cpu];
2480 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2481 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2482 guint pid_in
, pid_out
;
2485 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2486 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2487 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2489 if(likely(process
!= NULL
)) {
2491 /* We could not know but it was not the idle process executing.
2492 This should only happen at the beginning, before the first schedule
2493 event, and when the initial information (current process for each CPU)
2494 is missing. It is not obvious how we could, after the fact, compensate
2495 the wrongly attributed statistics. */
2497 //This test only makes sense once the state is known and if there is no
2498 //missing events. We need to silently ignore schedchange coming after a
2499 //process_free, or it causes glitches. (FIXME)
2500 //if(unlikely(process->pid != pid_out)) {
2501 // g_assert(process->pid == 0);
2503 if(process
->pid
== 0
2504 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2506 /* Scheduling out of pid 0 at beginning of the trace :
2507 * we know for sure it is in syscall mode at this point. */
2508 g_assert(process
->execution_stack
->len
== 1);
2509 process
->state
->t
= LTTV_STATE_SYSCALL
;
2510 process
->state
->s
= LTTV_STATE_WAIT
;
2511 process
->state
->change
= s
->parent
.timestamp
;
2512 process
->state
->entry
= s
->parent
.timestamp
;
2515 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2516 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2517 process
->state
->change
= s
->parent
.timestamp
;
2519 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2520 else process
->state
->s
= LTTV_STATE_WAIT
;
2521 process
->state
->change
= s
->parent
.timestamp
;
2524 if(state_out
== 32 || state_out
== 128)
2525 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2526 /* see sched.h for states */
2529 process
= ts
->running_process
[cpu
] =
2530 lttv_state_find_process_or_create(
2531 (LttvTraceState
*)s
->parent
.t_context
,
2533 &s
->parent
.timestamp
);
2534 process
->state
->s
= LTTV_STATE_RUN
;
2536 if(process
->usertrace
)
2537 process
->usertrace
->cpu
= cpu
;
2538 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2539 process
->state
->change
= s
->parent
.timestamp
;
2541 /* update cpu status */
2543 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2545 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2550 static gboolean
process_fork(void *hook_data
, void *call_data
)
2552 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2553 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2554 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2556 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2557 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2558 //LttvProcessState *zombie_process;
2560 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2561 LttvProcessState
*process
= ts
->running_process
[cpu
];
2562 LttvProcessState
*child_process
;
2563 struct marker_field
*f
;
2566 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2569 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2570 s
->parent
.target_pid
= child_pid
;
2573 f
= lttv_trace_get_hook_field(th
, 2);
2575 child_tgid
= ltt_event_get_unsigned(e
, f
);
2579 /* Mathieu : it seems like the process might have been scheduled in before the
2580 * fork, and, in a rare case, might be the current process. This might happen
2581 * in a SMP case where we don't have enough precision on the clocks.
2583 * Test reenabled after precision fixes on time. (Mathieu) */
2585 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2587 if(unlikely(zombie_process
!= NULL
)) {
2588 /* Reutilisation of PID. Only now we are sure that the old PID
2589 * has been released. FIXME : should know when release_task happens instead.
2591 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2593 for(i
=0; i
< num_cpus
; i
++) {
2594 g_assert(zombie_process
!= ts
->running_process
[i
]);
2597 exit_process(s
, zombie_process
);
2600 g_assert(process
->pid
!= child_pid
);
2601 // FIXME : Add this test in the "known state" section
2602 // g_assert(process->pid == parent_pid);
2603 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2604 if(child_process
== NULL
) {
2605 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2606 child_pid
, child_tgid
,
2607 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2609 /* The process has already been created : due to time imprecision between
2610 * multiple CPUs : it has been scheduled in before creation. Note that we
2611 * shouldn't have this kind of imprecision.
2613 * Simply put a correct parent.
2615 g_assert(0); /* This is a problematic case : the process has been created
2616 before the fork event */
2617 child_process
->ppid
= process
->pid
;
2618 child_process
->tgid
= child_tgid
;
2620 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2621 child_process
->name
= process
->name
;
2622 child_process
->brand
= process
->brand
;
2627 /* We stamp a newly created process as kernel_thread.
2628 * The thread should not be running yet. */
2629 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2631 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2632 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2633 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2635 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2636 LttvProcessState
*process
;
2637 LttvExecutionState
*es
;
2640 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2641 s
->parent
.target_pid
= pid
;
2643 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2645 process
->execution_stack
=
2646 g_array_set_size(process
->execution_stack
, 1);
2647 es
= process
->state
=
2648 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2649 es
->t
= LTTV_STATE_SYSCALL
;
2650 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2655 static gboolean
process_exit(void *hook_data
, void *call_data
)
2657 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2658 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2659 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2661 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2662 LttvProcessState
*process
; // = ts->running_process[cpu];
2664 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2665 s
->parent
.target_pid
= pid
;
2667 // FIXME : Add this test in the "known state" section
2668 // g_assert(process->pid == pid);
2670 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2671 if(likely(process
!= NULL
)) {
2672 process
->state
->s
= LTTV_STATE_EXIT
;
2677 static gboolean
process_free(void *hook_data
, void *call_data
)
2679 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2680 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2681 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2682 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2684 LttvProcessState
*process
;
2686 /* PID of the process to release */
2687 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2688 s
->parent
.target_pid
= release_pid
;
2690 g_assert(release_pid
!= 0);
2692 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2694 if(likely(process
!= NULL
)) {
2695 /* release_task is happening at kernel level : we can now safely release
2696 * the data structure of the process */
2697 //This test is fun, though, as it may happen that
2698 //at time t : CPU 0 : process_free
2699 //at time t+150ns : CPU 1 : schedule out
2700 //Clearly due to time imprecision, we disable it. (Mathieu)
2701 //If this weird case happen, we have no choice but to put the
2702 //Currently running process on the cpu to 0.
2703 //I re-enable it following time precision fixes. (Mathieu)
2704 //Well, in the case where an process is freed by a process on another CPU
2705 //and still scheduled, it happens that this is the schedchange that will
2706 //drop the last reference count. Do not free it here!
2707 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2709 for(i
=0; i
< num_cpus
; i
++) {
2710 //g_assert(process != ts->running_process[i]);
2711 if(process
== ts
->running_process
[i
]) {
2712 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2716 if(i
== num_cpus
) /* process is not scheduled */
2717 exit_process(s
, process
);
2724 static gboolean
process_exec(void *hook_data
, void *call_data
)
2726 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2727 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2728 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2729 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2732 LttvProcessState
*process
= ts
->running_process
[cpu
];
2734 #if 0//how to use a sequence that must be transformed in a string
2735 /* PID of the process to release */
2736 guint64 name_len
= ltt_event_field_element_number(e
,
2737 lttv_trace_get_hook_field(th
, 0));
2738 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2739 LttField
*child
= ltt_event_field_element_select(e
,
2740 lttv_trace_get_hook_field(th
, 0), 0);
2742 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2743 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2744 memcpy(null_term_name
, name_begin
, name_len
);
2745 null_term_name
[name_len
] = '\0';
2746 process
->name
= g_quark_from_string(null_term_name
);
2749 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2750 lttv_trace_get_hook_field(th
, 0)));
2751 process
->brand
= LTTV_STATE_UNBRANDED
;
2752 //g_free(null_term_name);
2756 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2758 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2759 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2760 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2761 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2764 LttvProcessState
*process
= ts
->running_process
[cpu
];
2766 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2767 process
->brand
= g_quark_from_string(name
);
2772 static void fix_process(gpointer key
, gpointer value
,
2775 LttvProcessState
*process
;
2776 LttvExecutionState
*es
;
2777 process
= (LttvProcessState
*)value
;
2778 LttTime
*timestamp
= (LttTime
*)user_data
;
2780 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2781 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2782 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2783 es
->t
= LTTV_STATE_SYSCALL
;
2784 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2785 es
->entry
= *timestamp
;
2786 es
->change
= *timestamp
;
2787 es
->cum_cpu_time
= ltt_time_zero
;
2788 if(es
->s
== LTTV_STATE_UNNAMED
)
2789 es
->s
= LTTV_STATE_WAIT
;
2792 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2793 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2794 es
->t
= LTTV_STATE_USER_MODE
;
2795 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2796 es
->entry
= *timestamp
;
2797 //g_assert(timestamp->tv_sec != 0);
2798 es
->change
= *timestamp
;
2799 es
->cum_cpu_time
= ltt_time_zero
;
2800 if(es
->s
== LTTV_STATE_UNNAMED
)
2801 es
->s
= LTTV_STATE_RUN
;
2803 if(process
->execution_stack
->len
== 1) {
2804 /* Still in bottom unknown mode, means never did a system call
2805 * May be either in user mode, syscall mode, running or waiting.*/
2806 /* FIXME : we may be tagging syscall mode when being user mode */
2807 process
->execution_stack
=
2808 g_array_set_size(process
->execution_stack
, 2);
2809 es
= process
->state
= &g_array_index(process
->execution_stack
,
2810 LttvExecutionState
, 1);
2811 es
->t
= LTTV_STATE_SYSCALL
;
2812 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2813 es
->entry
= *timestamp
;
2814 //g_assert(timestamp->tv_sec != 0);
2815 es
->change
= *timestamp
;
2816 es
->cum_cpu_time
= ltt_time_zero
;
2817 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2818 es
->s
= LTTV_STATE_WAIT
;
2824 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2826 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2827 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2828 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2829 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2830 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2832 /* For all processes */
2833 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2834 /* else, if stack[0] is unknown, set to user mode, running */
2836 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2841 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2843 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2844 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2845 //It's slow : optimise later by doing this before reading trace.
2846 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2852 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2853 LttvProcessState
*process
= ts
->running_process
[cpu
];
2854 LttvProcessState
*parent_process
;
2855 struct marker_field
*f
;
2856 GQuark type
, mode
, submode
, status
;
2857 LttvExecutionState
*es
;
2861 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2862 s
->parent
.target_pid
= pid
;
2865 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2868 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2871 f
= lttv_trace_get_hook_field(th
, 3);
2872 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2875 f
= lttv_trace_get_hook_field(th
, 4);
2876 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2879 f
= lttv_trace_get_hook_field(th
, 5);
2880 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2883 f
= lttv_trace_get_hook_field(th
, 6);
2884 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2887 f
= lttv_trace_get_hook_field(th
, 7);
2889 tgid
= ltt_event_get_unsigned(e
, f
);
2894 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2895 for(i
=0; i
<nb_cpus
; i
++) {
2896 process
= lttv_state_find_process(ts
, i
, pid
);
2897 g_assert(process
!= NULL
);
2899 process
->ppid
= parent_pid
;
2900 process
->tgid
= tgid
;
2901 process
->name
= g_quark_from_string(command
);
2903 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2904 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2908 /* The process might exist if a process was forked while performing the
2910 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2911 if(process
== NULL
) {
2912 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2913 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2914 pid
, tgid
, g_quark_from_string(command
),
2915 &s
->parent
.timestamp
);
2917 /* Keep the stack bottom : a running user mode */
2918 /* Disabled because of inconsistencies in the current statedump states. */
2919 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2920 /* Only keep the bottom
2921 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2922 /* Will cause expected trap when in fact being syscall (even after end of
2924 * Will cause expected interrupt when being syscall. (only before end of
2925 * statedump event) */
2926 // This will cause a "popping last state on stack, ignoring it."
2927 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2928 es
= process
->state
= &g_array_index(process
->execution_stack
,
2929 LttvExecutionState
, 0);
2930 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2931 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2932 es
->s
= LTTV_STATE_UNNAMED
;
2933 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2935 es
->t
= LTTV_STATE_SYSCALL
;
2940 /* User space process :
2941 * bottom : user mode
2942 * either currently running or scheduled out.
2943 * can be scheduled out because interrupted in (user mode or in syscall)
2944 * or because of an explicit call to the scheduler in syscall. Note that
2945 * the scheduler call comes after the irq_exit, so never in interrupt
2947 // temp workaround : set size to 1 : only have user mode bottom of stack.
2948 // will cause g_info message of expected syscall mode when in fact being
2949 // in user mode. Can also cause expected trap when in fact being user
2950 // mode in the event of a page fault reenabling interrupts in the handler.
2951 // Expected syscall and trap can also happen after the end of statedump
2952 // This will cause a "popping last state on stack, ignoring it."
2953 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2954 es
= process
->state
= &g_array_index(process
->execution_stack
,
2955 LttvExecutionState
, 0);
2956 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2957 es
->s
= LTTV_STATE_UNNAMED
;
2958 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2960 es
->t
= LTTV_STATE_USER_MODE
;
2968 es
= process
->state
= &g_array_index(process
->execution_stack
,
2969 LttvExecutionState
, 1);
2970 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2971 es
->s
= LTTV_STATE_UNNAMED
;
2972 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2976 /* The process has already been created :
2977 * Probably was forked while dumping the process state or
2978 * was simply scheduled in prior to get the state dump event.
2980 process
->ppid
= parent_pid
;
2981 process
->tgid
= tgid
;
2982 process
->name
= g_quark_from_string(command
);
2983 process
->type
= type
;
2985 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2987 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2988 if(type
== LTTV_STATE_KERNEL_THREAD
)
2989 es
->t
= LTTV_STATE_SYSCALL
;
2991 es
->t
= LTTV_STATE_USER_MODE
;
2994 /* Don't mess around with the stack, it will eventually become
2995 * ok after the end of state dump. */
3002 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3004 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3006 lttv_state_add_event_hooks(tss
);
3011 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3013 LttvTraceset
*traceset
= self
->parent
.ts
;
3015 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3019 LttvTracefileState
*tfs
;
3025 LttvAttributeValue val
;
3027 nb_trace
= lttv_traceset_number(traceset
);
3028 for(i
= 0 ; i
< nb_trace
; i
++) {
3029 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3031 /* Find the eventtype id for the following events and register the
3032 associated by id hooks. */
3034 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3035 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3038 lttv_trace_find_hook(ts
->parent
.t
,
3039 LTT_FACILITY_KERNEL_ARCH
,
3040 LTT_EVENT_SYSCALL_ENTRY
,
3041 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3042 syscall_entry
, NULL
, &hooks
);
3044 lttv_trace_find_hook(ts
->parent
.t
,
3045 LTT_FACILITY_KERNEL_ARCH
,
3046 LTT_EVENT_SYSCALL_EXIT
,
3048 syscall_exit
, NULL
, &hooks
);
3050 lttv_trace_find_hook(ts
->parent
.t
,
3051 LTT_FACILITY_KERNEL_ARCH
,
3052 LTT_EVENT_TRAP_ENTRY
,
3053 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3054 trap_entry
, NULL
, &hooks
);
3056 lttv_trace_find_hook(ts
->parent
.t
,
3057 LTT_FACILITY_KERNEL_ARCH
,
3058 LTT_EVENT_TRAP_EXIT
,
3060 trap_exit
, NULL
, &hooks
);
3062 lttv_trace_find_hook(ts
->parent
.t
,
3063 LTT_FACILITY_KERNEL
,
3064 LTT_EVENT_IRQ_ENTRY
,
3065 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3066 irq_entry
, NULL
, &hooks
);
3068 lttv_trace_find_hook(ts
->parent
.t
,
3069 LTT_FACILITY_KERNEL
,
3072 irq_exit
, NULL
, &hooks
);
3074 lttv_trace_find_hook(ts
->parent
.t
,
3075 LTT_FACILITY_KERNEL
,
3076 LTT_EVENT_SOFT_IRQ_ENTRY
,
3077 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3078 soft_irq_entry
, NULL
, &hooks
);
3080 lttv_trace_find_hook(ts
->parent
.t
,
3081 LTT_FACILITY_KERNEL
,
3082 LTT_EVENT_SOFT_IRQ_EXIT
,
3084 soft_irq_exit
, NULL
, &hooks
);
3086 lttv_trace_find_hook(ts
->parent
.t
,
3087 LTT_FACILITY_KERNEL
,
3088 LTT_EVENT_SCHED_SCHEDULE
,
3089 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3090 LTT_FIELD_PREV_STATE
),
3091 schedchange
, NULL
, &hooks
);
3093 lttv_trace_find_hook(ts
->parent
.t
,
3094 LTT_FACILITY_KERNEL
,
3095 LTT_EVENT_PROCESS_FORK
,
3096 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3097 LTT_FIELD_CHILD_TGID
),
3098 process_fork
, NULL
, &hooks
);
3100 lttv_trace_find_hook(ts
->parent
.t
,
3101 LTT_FACILITY_KERNEL_ARCH
,
3102 LTT_EVENT_KTHREAD_CREATE
,
3103 FIELD_ARRAY(LTT_FIELD_PID
),
3104 process_kernel_thread
, NULL
, &hooks
);
3106 lttv_trace_find_hook(ts
->parent
.t
,
3107 LTT_FACILITY_KERNEL
,
3108 LTT_EVENT_PROCESS_EXIT
,
3109 FIELD_ARRAY(LTT_FIELD_PID
),
3110 process_exit
, NULL
, &hooks
);
3112 lttv_trace_find_hook(ts
->parent
.t
,
3113 LTT_FACILITY_KERNEL
,
3114 LTT_EVENT_PROCESS_FREE
,
3115 FIELD_ARRAY(LTT_FIELD_PID
),
3116 process_free
, NULL
, &hooks
);
3118 lttv_trace_find_hook(ts
->parent
.t
,
3121 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3122 process_exec
, NULL
, &hooks
);
3124 lttv_trace_find_hook(ts
->parent
.t
,
3125 LTT_FACILITY_USER_GENERIC
,
3126 LTT_EVENT_THREAD_BRAND
,
3127 FIELD_ARRAY(LTT_FIELD_NAME
),
3128 thread_brand
, NULL
, &hooks
);
3130 /* statedump-related hooks */
3131 lttv_trace_find_hook(ts
->parent
.t
,
3133 LTT_EVENT_PROCESS_STATE
,
3134 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3135 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3136 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3137 enum_process_state
, NULL
, &hooks
);
3139 lttv_trace_find_hook(ts
->parent
.t
,
3141 LTT_EVENT_STATEDUMP_END
,
3143 statedump_end
, NULL
, &hooks
);
3145 lttv_trace_find_hook(ts
->parent
.t
,
3147 LTT_EVENT_LIST_INTERRUPT
,
3148 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3149 enum_interrupt
, NULL
, &hooks
);
3151 lttv_trace_find_hook(ts
->parent
.t
,
3153 LTT_EVENT_REQUEST_ISSUE
,
3154 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3155 bdev_request_issue
, NULL
, &hooks
);
3157 lttv_trace_find_hook(ts
->parent
.t
,
3159 LTT_EVENT_REQUEST_COMPLETE
,
3160 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3161 bdev_request_complete
, NULL
, &hooks
);
3163 lttv_trace_find_hook(ts
->parent
.t
,
3164 LTT_FACILITY_USER_GENERIC
,
3165 LTT_EVENT_FUNCTION_ENTRY
,
3166 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3167 function_entry
, NULL
, &hooks
);
3169 lttv_trace_find_hook(ts
->parent
.t
,
3170 LTT_FACILITY_USER_GENERIC
,
3171 LTT_EVENT_FUNCTION_EXIT
,
3172 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3173 function_exit
, NULL
, &hooks
);
3175 /* Add these hooks to each event_by_id hooks list */
3177 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3179 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3181 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3182 LttvTracefileContext
*, j
));
3184 for(k
= 0 ; k
< hooks
->len
; k
++) {
3185 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3187 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3193 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3194 *(val
.v_pointer
) = hooks
;
3198 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3200 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3202 lttv_state_remove_event_hooks(tss
);
3207 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3209 LttvTraceset
*traceset
= self
->parent
.ts
;
3211 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3215 LttvTracefileState
*tfs
;
3221 LttvAttributeValue val
;
3223 nb_trace
= lttv_traceset_number(traceset
);
3224 for(i
= 0 ; i
< nb_trace
; i
++) {
3225 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3227 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3228 hooks
= *(val
.v_pointer
);
3230 /* Remove these hooks from each event_by_id hooks list */
3232 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3234 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3236 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3237 LttvTracefileContext
*, j
));
3239 for(k
= 0 ; k
< hooks
->len
; k
++) {
3240 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3241 lttv_hooks_remove_data(
3242 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3247 lttv_trace_hook_remove_all(&hooks
);
3248 g_array_free(hooks
, TRUE
);
3252 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3254 guint
*event_count
= (guint
*)hook_data
;
3256 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3257 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3262 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3264 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3266 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3268 LttvAttributeValue value
;
3270 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3271 LTTV_STATE_SAVED_STATES
);
3272 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3273 value
= lttv_attribute_add(saved_states_tree
,
3274 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3275 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3276 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3277 *(value
.v_time
) = self
->parent
.timestamp
;
3278 lttv_state_save(tcs
, saved_state_tree
);
3279 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3280 self
->parent
.timestamp
.tv_nsec
);
3282 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3287 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3289 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3291 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3296 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3304 static gboolean
block_start(void *hook_data
, void *call_data
)
3306 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3308 LttvTracefileState
*tfcs
;
3310 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3312 LttEventPosition
*ep
;
3314 guint i
, nb_block
, nb_event
, nb_tracefile
;
3318 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3320 LttvAttributeValue value
;
3322 ep
= ltt_event_position_new();
3324 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3326 /* Count the number of events added since the last block end in any
3329 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3331 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3332 LttvTracefileContext
, i
));
3333 ltt_event_position(tfcs
->parent
.e
, ep
);
3334 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3335 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3336 tfcs
->saved_position
= nb_event
;
3340 if(tcs
->nb_event
>= tcs
->save_interval
) {
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
);
3351 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3352 self
->parent
.timestamp
.tv_nsec
);
3354 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3360 static gboolean
block_end(void *hook_data
, void *call_data
)
3362 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3364 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3368 LttEventPosition
*ep
;
3370 guint nb_block
, nb_event
;
3372 ep
= ltt_event_position_new();
3373 ltt_event_position(self
->parent
.e
, ep
);
3374 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3375 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3376 self
->saved_position
= 0;
3377 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3384 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3386 LttvTraceset
*traceset
= self
->parent
.ts
;
3388 guint i
, j
, nb_trace
, nb_tracefile
;
3392 LttvTracefileState
*tfs
;
3394 LttvTraceHook hook_start
, hook_end
;
3396 nb_trace
= lttv_traceset_number(traceset
);
3397 for(i
= 0 ; i
< nb_trace
; i
++) {
3398 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3400 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3401 NULL
, NULL
, block_start
, &hook_start
);
3402 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3403 NULL
, NULL
, block_end
, &hook_end
);
3405 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3407 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3409 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3410 LttvTracefileContext
, j
));
3411 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3412 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3413 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3414 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3420 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3422 LttvTraceset
*traceset
= self
->parent
.ts
;
3424 guint i
, j
, nb_trace
, nb_tracefile
;
3428 LttvTracefileState
*tfs
;
3431 nb_trace
= lttv_traceset_number(traceset
);
3432 for(i
= 0 ; i
< nb_trace
; i
++) {
3434 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3435 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3437 if(ts
->has_precomputed_states
) continue;
3439 guint
*event_count
= g_new(guint
, 1);
3442 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3444 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3445 LttvTracefileContext
*, j
));
3446 lttv_hooks_add(tfs
->parent
.event
,
3447 state_save_event_hook
,
3454 lttv_process_traceset_begin(&self
->parent
,
3455 NULL
, NULL
, NULL
, NULL
, NULL
);
3459 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3461 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3463 lttv_state_save_add_event_hooks(tss
);
3470 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3472 LttvTraceset
*traceset
= self
->parent
.ts
;
3474 guint i
, j
, nb_trace
, nb_tracefile
;
3478 LttvTracefileState
*tfs
;
3480 LttvTraceHook hook_start
, hook_end
;
3482 nb_trace
= lttv_traceset_number(traceset
);
3483 for(i
= 0 ; i
< nb_trace
; i
++) {
3484 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3486 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3487 NULL
, NULL
, block_start
, &hook_start
);
3489 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3490 NULL
, NULL
, block_end
, &hook_end
);
3492 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3494 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3496 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3497 LttvTracefileContext
, j
));
3498 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3499 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3500 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3501 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3507 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3509 LttvTraceset
*traceset
= self
->parent
.ts
;
3511 guint i
, j
, nb_trace
, nb_tracefile
;
3515 LttvTracefileState
*tfs
;
3517 LttvHooks
*after_trace
= lttv_hooks_new();
3519 lttv_hooks_add(after_trace
,
3520 state_save_after_trace_hook
,
3525 lttv_process_traceset_end(&self
->parent
,
3526 NULL
, after_trace
, NULL
, NULL
, NULL
);
3528 lttv_hooks_destroy(after_trace
);
3530 nb_trace
= lttv_traceset_number(traceset
);
3531 for(i
= 0 ; i
< nb_trace
; i
++) {
3533 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3534 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3536 if(ts
->has_precomputed_states
) continue;
3538 guint
*event_count
= NULL
;
3540 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3542 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3543 LttvTracefileContext
*, j
));
3544 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3545 state_save_event_hook
);
3547 if(event_count
) g_free(event_count
);
3551 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3553 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3555 lttv_state_save_remove_event_hooks(tss
);
3560 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3562 LttvTraceset
*traceset
= self
->parent
.ts
;
3566 int min_pos
, mid_pos
, max_pos
;
3568 guint call_rest
= 0;
3570 LttvTraceState
*tcs
;
3572 LttvAttributeValue value
;
3574 LttvAttributeType type
;
3576 LttvAttributeName name
;
3580 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3582 //g_tree_destroy(self->parent.pqueue);
3583 //self->parent.pqueue = g_tree_new(compare_tracefile);
3585 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3587 nb_trace
= lttv_traceset_number(traceset
);
3588 for(i
= 0 ; i
< nb_trace
; i
++) {
3589 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3591 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3592 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3593 LTTV_STATE_SAVED_STATES
);
3596 if(saved_states_tree
) {
3597 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3598 mid_pos
= max_pos
/ 2;
3599 while(min_pos
< max_pos
) {
3600 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3602 g_assert(type
== LTTV_GOBJECT
);
3603 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3604 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3606 g_assert(type
== LTTV_TIME
);
3607 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3609 closest_tree
= saved_state_tree
;
3611 else max_pos
= mid_pos
- 1;
3613 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3617 /* restore the closest earlier saved state */
3619 lttv_state_restore(tcs
, closest_tree
);
3623 /* There is no saved state, yet we want to have it. Restart at T0 */
3625 restore_init_state(tcs
);
3626 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3629 /* We want to seek quickly without restoring/updating the state */
3631 restore_init_state(tcs
);
3632 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3635 if(!call_rest
) g_info("NOT Calling restore");
3640 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3646 traceset_state_finalize (LttvTracesetState
*self
)
3648 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3649 finalize(G_OBJECT(self
));
3654 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3656 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3658 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3659 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3660 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3661 klass
->new_traceset_context
= new_traceset_context
;
3662 klass
->new_trace_context
= new_trace_context
;
3663 klass
->new_tracefile_context
= new_tracefile_context
;
3668 lttv_traceset_state_get_type(void)
3670 static GType type
= 0;
3672 static const GTypeInfo info
= {
3673 sizeof (LttvTracesetStateClass
),
3674 NULL
, /* base_init */
3675 NULL
, /* base_finalize */
3676 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3677 NULL
, /* class_finalize */
3678 NULL
, /* class_data */
3679 sizeof (LttvTracesetState
),
3680 0, /* n_preallocs */
3681 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3682 NULL
/* value handling */
3685 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3693 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3699 trace_state_finalize (LttvTraceState
*self
)
3701 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3702 finalize(G_OBJECT(self
));
3707 trace_state_class_init (LttvTraceStateClass
*klass
)
3709 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3711 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3712 klass
->state_save
= state_save
;
3713 klass
->state_restore
= state_restore
;
3714 klass
->state_saved_free
= state_saved_free
;
3719 lttv_trace_state_get_type(void)
3721 static GType type
= 0;
3723 static const GTypeInfo info
= {
3724 sizeof (LttvTraceStateClass
),
3725 NULL
, /* base_init */
3726 NULL
, /* base_finalize */
3727 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3728 NULL
, /* class_finalize */
3729 NULL
, /* class_data */
3730 sizeof (LttvTraceState
),
3731 0, /* n_preallocs */
3732 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3733 NULL
/* value handling */
3736 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3737 "LttvTraceStateType", &info
, 0);
3744 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3750 tracefile_state_finalize (LttvTracefileState
*self
)
3752 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3753 finalize(G_OBJECT(self
));
3758 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3760 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3762 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3767 lttv_tracefile_state_get_type(void)
3769 static GType type
= 0;
3771 static const GTypeInfo info
= {
3772 sizeof (LttvTracefileStateClass
),
3773 NULL
, /* base_init */
3774 NULL
, /* base_finalize */
3775 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3776 NULL
, /* class_finalize */
3777 NULL
, /* class_data */
3778 sizeof (LttvTracefileState
),
3779 0, /* n_preallocs */
3780 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3781 NULL
/* value handling */
3784 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3785 "LttvTracefileStateType", &info
, 0);
3791 static void module_init()
3793 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3794 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3795 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3796 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3797 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3798 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3799 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3800 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3801 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3802 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3803 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3804 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3805 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3806 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3807 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3808 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3809 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3810 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3811 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3812 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3813 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3814 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3815 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3816 LTTV_STATE_EVENT
= g_quark_from_string("event");
3817 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3818 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3819 LTTV_STATE_TIME
= g_quark_from_string("time");
3820 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3821 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3822 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3823 g_quark_from_string("trace_state_use_count");
3824 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3825 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3826 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3829 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3830 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3831 LTT_FACILITY_FS
= g_quark_from_string("fs");
3832 LTT_FACILITY_LIST
= g_quark_from_string("list");
3833 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3834 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3837 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3838 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3839 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3840 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3841 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3842 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3843 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3844 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3845 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3846 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3847 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3848 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3849 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3850 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3851 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3852 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3853 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3854 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3855 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3856 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3857 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3858 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3861 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3862 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3863 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3864 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3865 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3866 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3867 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3868 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3869 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3870 LTT_FIELD_PID
= g_quark_from_string("pid");
3871 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3872 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3873 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3874 LTT_FIELD_NAME
= g_quark_from_string("name");
3875 LTT_FIELD_TYPE
= g_quark_from_string("type");
3876 LTT_FIELD_MODE
= g_quark_from_string("mode");
3877 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3878 LTT_FIELD_STATUS
= g_quark_from_string("status");
3879 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3880 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3881 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3882 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3883 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3884 LTT_FIELD_ACTION
= g_quark_from_string("action");
3886 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3887 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3888 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3889 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3890 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3892 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3893 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3894 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3896 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3897 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3898 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3899 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3902 static void module_destroy()
3907 LTTV_MODULE("state", "State computation", \
3908 "Update the system state, possibly saving it at intervals", \
3909 module_init
, module_destroy
)