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,
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <ltt/trace.h>
29 #include <ltt/event.h>
31 #include <ltt/marker-desc.h>
37 * usertrace is there only to be able to update the current CPU of the
38 * usertraces when there is a schedchange. it is a way to link the ProcessState
39 * to the associated usertrace. Link only created upon thread creation.
41 * The cpu id is necessary : it gives us back the current ProcessState when we
42 * are considering data from the usertrace.
45 #define PREALLOCATED_EXECUTION_STACK 10
47 /* Facilities Quarks */
51 LTT_FACILITY_KERNEL_ARCH
,
54 LTT_FACILITY_USER_GENERIC
,
60 LTT_EVENT_SYSCALL_ENTRY
,
61 LTT_EVENT_SYSCALL_EXIT
,
66 LTT_EVENT_SOFT_IRQ_ENTRY
,
67 LTT_EVENT_SOFT_IRQ_EXIT
,
68 LTT_EVENT_SCHED_SCHEDULE
,
69 LTT_EVENT_PROCESS_FORK
,
70 LTT_EVENT_KTHREAD_CREATE
,
71 LTT_EVENT_PROCESS_EXIT
,
72 LTT_EVENT_PROCESS_FREE
,
74 LTT_EVENT_PROCESS_STATE
,
75 LTT_EVENT_STATEDUMP_END
,
76 LTT_EVENT_FUNCTION_ENTRY
,
77 LTT_EVENT_FUNCTION_EXIT
,
78 LTT_EVENT_THREAD_BRAND
,
79 LTT_EVENT_REQUEST_ISSUE
,
80 LTT_EVENT_REQUEST_COMPLETE
,
81 LTT_EVENT_LIST_INTERRUPT
;
89 LTT_FIELD_SOFT_IRQ_ID
,
112 LTTV_STATE_MODE_UNKNOWN
,
113 LTTV_STATE_USER_MODE
,
120 LTTV_STATE_SUBMODE_UNKNOWN
,
121 LTTV_STATE_SUBMODE_NONE
;
125 LTTV_STATE_WAIT_FORK
,
134 LTTV_STATE_UNBRANDED
;
137 LTTV_STATE_USER_THREAD
,
138 LTTV_STATE_KERNEL_THREAD
;
155 LTTV_BDEV_BUSY_READING
,
156 LTTV_BDEV_BUSY_WRITING
;
159 LTTV_STATE_TRACEFILES
,
160 LTTV_STATE_PROCESSES
,
162 LTTV_STATE_RUNNING_PROCESS
,
164 LTTV_STATE_SAVED_STATES
,
165 LTTV_STATE_SAVED_STATES_TIME
,
168 LTTV_STATE_NAME_TABLES
,
169 LTTV_STATE_TRACE_STATE_USE_COUNT
,
170 LTTV_STATE_RESOURCE_CPUS
,
171 LTTV_STATE_RESOURCE_CPUS_COUNT
,
172 LTTV_STATE_RESOURCE_IRQS
,
173 LTTV_STATE_RESOURCE_SOFT_IRQS
,
174 LTTV_STATE_RESOURCE_BLKDEVS
;
176 static void create_max_time(LttvTraceState
*tcs
);
178 static void get_max_time(LttvTraceState
*tcs
);
180 static void free_max_time(LttvTraceState
*tcs
);
182 static void create_name_tables(LttvTraceState
*tcs
);
184 static void get_name_tables(LttvTraceState
*tcs
);
186 static void free_name_tables(LttvTraceState
*tcs
);
188 static void free_saved_state(LttvTraceState
*tcs
);
190 static void lttv_state_free_process_table(GHashTable
*processes
);
192 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
193 GPtrArray
*quarktable
);
195 /* Resource function prototypes */
196 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
197 static LttvBdevState
*bdevstate_new(void);
198 static void bdevstate_free(LttvBdevState
*);
199 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
200 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
203 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
205 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
209 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
211 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
215 void lttv_state_state_saved_free(LttvTraceState
*self
,
216 LttvAttribute
*container
)
218 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
222 guint
process_hash(gconstpointer key
)
224 guint pid
= ((const LttvProcessState
*)key
)->pid
;
225 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
229 /* If the hash table hash function is well distributed,
230 * the process_equal should compare different pid */
231 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
233 const LttvProcessState
*process_a
, *process_b
;
236 process_a
= (const LttvProcessState
*)a
;
237 process_b
= (const LttvProcessState
*)b
;
239 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
240 else if(likely(process_a
->pid
== 0 &&
241 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
246 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
248 g_tree_destroy((GTree
*)value
);
251 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
253 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
254 g_hash_table_destroy(usertraces
);
257 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
263 restore_init_state(LttvTraceState
*self
)
265 guint i
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
267 //LttvTracefileState *tfcs;
269 LttTime start_time
, end_time
;
271 /* Free the process tables */
272 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
273 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
274 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
275 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
278 /* Seek time to beginning */
279 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
280 // closest. It's the tracecontext job to seek the trace to the beginning
281 // anyway : the init state might be used at the middle of the trace as well...
282 //g_tree_destroy(self->parent.ts_context->pqueue);
283 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
285 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
287 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
289 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
290 nb_irqs
= self
->nb_irqs
;
291 nb_soft_irqs
= self
->nb_soft_irqs
;
293 /* Put the per cpu running_process to beginning state : process 0. */
294 for(i
=0; i
< nb_cpus
; i
++) {
295 LttvExecutionState
*es
;
296 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
297 LTTV_STATE_UNNAMED
, &start_time
);
298 /* We are not sure is it's a kernel thread or normal thread, put the
299 * bottom stack state to unknown */
300 self
->running_process
[i
]->execution_stack
=
301 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
302 es
= self
->running_process
[i
]->state
=
303 &g_array_index(self
->running_process
[i
]->execution_stack
,
304 LttvExecutionState
, 0);
305 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
306 es
->s
= LTTV_STATE_UNNAMED
;
308 //self->running_process[i]->state->s = LTTV_STATE_RUN;
309 self
->running_process
[i
]->cpu
= i
;
311 /* reset cpu states */
312 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
313 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
316 /* reset irq states */
317 for(i
=0; i
<nb_irqs
; i
++) {
318 if(self
->irq_states
[i
].mode_stack
->len
> 0)
319 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
322 /* reset softirq states */
323 for(i
=0; i
<nb_soft_irqs
; i
++) {
324 self
->soft_irq_states
[i
].running
= 0;
327 /* reset bdev states */
328 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
329 //g_hash_table_steal_all(self->bdev_states);
330 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
333 nb_tracefile
= self
->parent
.tracefiles
->len
;
335 for(i
= 0 ; i
< nb_tracefile
; i
++) {
337 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
338 LttvTracefileContext
*, i
));
339 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
340 // tfcs->saved_position = 0;
341 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
342 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
343 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
344 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
349 //static LttTime time_zero = {0,0};
351 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
354 const LttTime
*t1
= (const LttTime
*)a
;
355 const LttTime
*t2
= (const LttTime
*)b
;
357 return ltt_time_compare(*t1
, *t2
);
360 static void free_usertrace_key(gpointer data
)
365 #define MAX_STRING_LEN 4096
368 state_load_saved_states(LttvTraceState
*tcs
)
371 GPtrArray
*quarktable
;
372 const char *trace_path
;
376 tcs
->has_precomputed_states
= FALSE
;
380 gchar buf
[MAX_STRING_LEN
];
383 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
384 strncpy(path
, trace_path
, PATH_MAX
-1);
385 count
= strnlen(trace_path
, PATH_MAX
-1);
386 // quarktable : open, test
387 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
388 fp
= fopen(path
, "r");
390 quarktable
= g_ptr_array_sized_new(4096);
392 /* Index 0 is null */
394 if(hdr
== EOF
) return;
395 g_assert(hdr
== HDR_QUARKS
);
399 if(hdr
== EOF
) break;
400 g_assert(hdr
== HDR_QUARK
);
401 g_ptr_array_set_size(quarktable
, q
+1);
404 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
405 if(buf
[i
] == '\0' || feof(fp
)) break;
408 len
= strnlen(buf
, MAX_STRING_LEN
-1);
409 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
410 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
416 // saved_states : open, test
417 strncpy(path
, trace_path
, PATH_MAX
-1);
418 count
= strnlen(trace_path
, PATH_MAX
-1);
419 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
420 fp
= fopen(path
, "r");
424 if(hdr
!= HDR_TRACE
) goto end
;
426 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
428 tcs
->has_precomputed_states
= TRUE
;
433 /* Free the quarktable */
434 for(i
=0; i
<quarktable
->len
; i
++) {
435 string
= g_ptr_array_index (quarktable
, i
);
438 g_ptr_array_free(quarktable
, TRUE
);
443 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
445 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
448 LttvTraceContext
*tc
;
452 LttvTracefileState
*tfcs
;
454 LttvAttributeValue v
;
456 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
457 init((LttvTracesetContext
*)self
, ts
);
459 nb_trace
= lttv_traceset_number(ts
);
460 for(i
= 0 ; i
< nb_trace
; i
++) {
461 tc
= self
->parent
.traces
[i
];
462 tcs
= LTTV_TRACE_STATE(tc
);
463 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
464 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
468 if(*(v
.v_uint
) == 1) {
469 create_name_tables(tcs
);
470 create_max_time(tcs
);
472 get_name_tables(tcs
);
475 nb_tracefile
= tc
->tracefiles
->len
;
476 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
477 nb_irq
= tcs
->nb_irqs
;
478 tcs
->processes
= NULL
;
479 tcs
->usertraces
= NULL
;
480 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
482 /* init cpu resource stuff */
483 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
484 for(j
= 0; j
<nb_cpu
; j
++) {
485 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
486 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
489 /* init irq resource stuff */
490 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
491 for(j
= 0; j
<nb_irq
; j
++) {
492 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
493 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
496 /* init soft irq stuff */
497 /* the kernel has a statically fixed max of 32 softirqs */
498 tcs
->soft_irq_states
= g_new(LttvSoftIRQState
, tcs
->nb_soft_irqs
);
500 /* init bdev resource stuff */
501 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
503 restore_init_state(tcs
);
504 for(j
= 0 ; j
< nb_tracefile
; j
++) {
506 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
507 LttvTracefileContext
*, j
));
508 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
509 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
510 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
511 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
512 /* It's a Usertrace */
513 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
514 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
516 if(!usertrace_tree
) {
517 usertrace_tree
= g_tree_new_full(compare_usertraces
,
518 NULL
, free_usertrace_key
, NULL
);
519 g_hash_table_insert(tcs
->usertraces
,
520 (gpointer
)tid
, usertrace_tree
);
522 LttTime
*timestamp
= g_new(LttTime
, 1);
523 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
524 ltt_tracefile_creation(tfcs
->parent
.tf
));
525 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
529 /* See if the trace has saved states */
530 state_load_saved_states(tcs
);
535 fini(LttvTracesetState
*self
)
541 //LttvTracefileState *tfcs;
543 LttvAttributeValue v
;
545 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
546 for(i
= 0 ; i
< nb_trace
; i
++) {
547 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
548 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
551 g_assert(*(v
.v_uint
) != 0);
554 if(*(v
.v_uint
) == 0) {
555 free_name_tables(tcs
);
557 free_saved_state(tcs
);
559 g_free(tcs
->running_process
);
560 tcs
->running_process
= NULL
;
561 lttv_state_free_process_table(tcs
->processes
);
562 lttv_state_free_usertraces(tcs
->usertraces
);
563 tcs
->processes
= NULL
;
564 tcs
->usertraces
= NULL
;
566 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
567 fini((LttvTracesetContext
*)self
);
571 static LttvTracesetContext
*
572 new_traceset_context(LttvTracesetContext
*self
)
574 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
578 static LttvTraceContext
*
579 new_trace_context(LttvTracesetContext
*self
)
581 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
585 static LttvTracefileContext
*
586 new_tracefile_context(LttvTracesetContext
*self
)
588 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
592 /* Write the process state of the trace */
594 static void write_process_state(gpointer key
, gpointer value
,
597 LttvProcessState
*process
;
599 LttvExecutionState
*es
;
601 FILE *fp
= (FILE *)user_data
;
606 process
= (LttvProcessState
*)value
;
608 " <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",
609 process
, process
->pid
, process
->tgid
, process
->ppid
,
610 g_quark_to_string(process
->type
),
611 process
->creation_time
.tv_sec
,
612 process
->creation_time
.tv_nsec
,
613 process
->insertion_time
.tv_sec
,
614 process
->insertion_time
.tv_nsec
,
615 g_quark_to_string(process
->name
),
616 g_quark_to_string(process
->brand
),
619 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
620 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
621 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
622 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
623 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
624 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
625 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
628 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
629 address
= g_array_index(process
->user_stack
, guint64
, i
);
630 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
634 if(process
->usertrace
) {
635 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
636 g_quark_to_string(process
->usertrace
->tracefile_name
),
637 process
->usertrace
->cpu
);
641 fprintf(fp
, " </PROCESS>\n");
645 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
647 guint i
, nb_tracefile
, nb_block
, offset
;
650 LttvTracefileState
*tfcs
;
654 LttEventPosition
*ep
;
658 ep
= ltt_event_position_new();
660 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
662 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
664 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
665 for(i
=0;i
<nb_cpus
;i
++) {
666 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
667 i
, self
->running_process
[i
]->pid
);
670 nb_tracefile
= self
->parent
.tracefiles
->len
;
672 for(i
= 0 ; i
< nb_tracefile
; i
++) {
674 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
675 LttvTracefileContext
*, i
));
676 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
677 tfcs
->parent
.timestamp
.tv_sec
,
678 tfcs
->parent
.timestamp
.tv_nsec
);
679 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
680 if(e
== NULL
) fprintf(fp
,"/>\n");
682 ltt_event_position(e
, ep
);
683 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
684 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
689 fprintf(fp
,"</PROCESS_STATE>\n");
693 static void write_process_state_raw(gpointer key
, gpointer value
,
696 LttvProcessState
*process
;
698 LttvExecutionState
*es
;
700 FILE *fp
= (FILE *)user_data
;
705 process
= (LttvProcessState
*)value
;
706 fputc(HDR_PROCESS
, fp
);
707 //fwrite(&header, sizeof(header), 1, fp);
708 //fprintf(fp, "%s", g_quark_to_string(process->type));
710 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
711 //fprintf(fp, "%s", g_quark_to_string(process->name));
713 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
714 //fprintf(fp, "%s", g_quark_to_string(process->brand));
716 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
717 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
718 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
719 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
720 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
721 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
722 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
726 " <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",
727 process
, process
->pid
, process
->tgid
, process
->ppid
,
728 g_quark_to_string(process
->type
),
729 process
->creation_time
.tv_sec
,
730 process
->creation_time
.tv_nsec
,
731 process
->insertion_time
.tv_sec
,
732 process
->insertion_time
.tv_nsec
,
733 g_quark_to_string(process
->name
),
734 g_quark_to_string(process
->brand
),
738 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
739 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
742 //fprintf(fp, "%s", g_quark_to_string(es->t));
744 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
745 //fprintf(fp, "%s", g_quark_to_string(es->n));
747 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
748 //fprintf(fp, "%s", g_quark_to_string(es->s));
750 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
751 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
752 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
753 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
755 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
756 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
757 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
758 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
759 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
763 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
764 address
= g_array_index(process
->user_stack
, guint64
, i
);
765 fputc(HDR_USER_STACK
, fp
);
766 fwrite(&address
, sizeof(address
), 1, fp
);
768 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
773 if(process
->usertrace
) {
774 fputc(HDR_USERTRACE
, fp
);
775 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
777 fwrite(&process
->usertrace
->tracefile_name
,
778 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
779 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
781 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
782 g_quark_to_string(process
->usertrace
->tracefile_name
),
783 process
->usertrace
->cpu
);
790 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
792 guint i
, nb_tracefile
, nb_block
, offset
;
795 LttvTracefileState
*tfcs
;
799 LttEventPosition
*ep
;
803 ep
= ltt_event_position_new();
805 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
806 fputc(HDR_PROCESS_STATE
, fp
);
807 fwrite(&t
, sizeof(t
), 1, fp
);
809 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
811 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
812 for(i
=0;i
<nb_cpus
;i
++) {
814 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
815 fwrite(&self
->running_process
[i
]->pid
,
816 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
817 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
818 // i, self->running_process[i]->pid);
821 nb_tracefile
= self
->parent
.tracefiles
->len
;
823 for(i
= 0 ; i
< nb_tracefile
; i
++) {
825 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
826 LttvTracefileContext
*, i
));
827 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
828 // tfcs->parent.timestamp.tv_sec,
829 // tfcs->parent.timestamp.tv_nsec);
830 fputc(HDR_TRACEFILE
, fp
);
831 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
832 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
833 * position following : end of trace */
834 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
836 ltt_event_position(e
, ep
);
837 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
838 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
840 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
841 fwrite(&offset
, sizeof(offset
), 1, fp
);
842 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
849 /* Read process state from a file */
851 /* Called because a HDR_PROCESS was found */
852 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
853 GPtrArray
*quarktable
)
855 LttvExecutionState
*es
;
856 LttvProcessState
*process
, *parent_process
;
857 LttvProcessState tmp
;
862 /* TODO : check return value */
863 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
864 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
865 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
866 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
867 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
868 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
869 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
870 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
871 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
874 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
876 /* We must link to the parent */
877 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
879 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
880 if(process
== NULL
) {
881 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
883 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
887 process
->insertion_time
= tmp
.insertion_time
;
888 process
->creation_time
= tmp
.creation_time
;
889 process
->type
= g_quark_from_string(
890 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
891 process
->tgid
= tmp
.tgid
;
892 process
->ppid
= tmp
.ppid
;
893 process
->brand
= g_quark_from_string(
894 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
896 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
900 if(feof(fp
) || ferror(fp
)) goto end_loop
;
902 gint hdr
= fgetc(fp
);
903 if(hdr
== EOF
) goto end_loop
;
907 process
->execution_stack
=
908 g_array_set_size(process
->execution_stack
,
909 process
->execution_stack
->len
+ 1);
910 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
911 process
->execution_stack
->len
-1);
914 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
915 es
->t
= g_quark_from_string(
916 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
917 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
918 es
->n
= g_quark_from_string(
919 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
920 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
921 es
->s
= g_quark_from_string(
922 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
923 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
924 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
925 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
928 process
->user_stack
= g_array_set_size(process
->user_stack
,
929 process
->user_stack
->len
+ 1);
930 address
= &g_array_index(process
->user_stack
, guint64
,
931 process
->user_stack
->len
-1);
932 fread(address
, sizeof(address
), 1, fp
);
933 process
->current_function
= *address
;
936 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
937 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
949 /* Called because a HDR_PROCESS_STATE was found */
950 /* Append a saved state to the trace states */
951 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
953 guint i
, nb_tracefile
, nb_block
, offset
;
955 LttvTracefileState
*tfcs
;
957 LttEventPosition
*ep
;
965 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
967 LttvAttributeValue value
;
968 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
969 ep
= ltt_event_position_new();
971 restore_init_state(self
);
973 fread(&t
, sizeof(t
), 1, fp
);
976 if(feof(fp
) || ferror(fp
)) goto end_loop
;
978 if(hdr
== EOF
) goto end_loop
;
982 /* Call read_process_state_raw */
983 read_process_state_raw(self
, fp
, quarktable
);
993 case HDR_PROCESS_STATE
:
999 g_error("Error while parsing saved state file : unknown data header %d",
1005 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1006 for(i
=0;i
<nb_cpus
;i
++) {
1009 g_assert(hdr
== HDR_CPU
);
1010 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1011 g_assert(i
== cpu_num
);
1012 fread(&self
->running_process
[i
]->pid
,
1013 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1016 nb_tracefile
= self
->parent
.tracefiles
->len
;
1018 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1020 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1021 LttvTracefileContext
*, i
));
1022 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1023 // tfcs->parent.timestamp.tv_sec,
1024 // tfcs->parent.timestamp.tv_nsec);
1025 g_tree_remove(pqueue
, &tfcs
->parent
);
1027 g_assert(hdr
== HDR_TRACEFILE
);
1028 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1029 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1030 * position following : end of trace */
1031 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1032 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1033 fread(&offset
, sizeof(offset
), 1, fp
);
1034 fread(&tsc
, sizeof(tsc
), 1, fp
);
1035 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1036 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1038 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1043 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1044 LTTV_STATE_SAVED_STATES
);
1045 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1046 value
= lttv_attribute_add(saved_states_tree
,
1047 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1048 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1049 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1050 *(value
.v_time
) = t
;
1051 lttv_state_save(self
, saved_state_tree
);
1052 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1055 *(self
->max_time_state_recomputed_in_seek
) = t
;
1059 /* Called when a HDR_TRACE is found */
1060 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1061 GPtrArray
*quarktable
)
1066 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1068 if(hdr
== EOF
) goto end_loop
;
1071 case HDR_PROCESS_STATE
:
1072 /* Call read_process_state_raw */
1073 lttv_state_read_raw(tcs
, fp
, quarktable
);
1081 case HDR_USER_STACK
:
1085 g_error("Error while parsing saved state file :"
1086 " unexpected data header %d",
1090 g_error("Error while parsing saved state file : unknown data header %d",
1095 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1096 restore_init_state(tcs
);
1097 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1103 /* Copy each process from an existing hash table to a new one */
1105 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1107 LttvProcessState
*process
, *new_process
;
1109 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1113 process
= (LttvProcessState
*)value
;
1114 new_process
= g_new(LttvProcessState
, 1);
1115 *new_process
= *process
;
1116 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1117 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1118 new_process
->execution_stack
=
1119 g_array_set_size(new_process
->execution_stack
,
1120 process
->execution_stack
->len
);
1121 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1122 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1123 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1125 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1126 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1127 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1128 sizeof(guint64
), 0);
1129 new_process
->user_stack
=
1130 g_array_set_size(new_process
->user_stack
,
1131 process
->user_stack
->len
);
1132 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1133 g_array_index(new_process
->user_stack
, guint64
, i
) =
1134 g_array_index(process
->user_stack
, guint64
, i
);
1136 new_process
->current_function
= process
->current_function
;
1137 g_hash_table_insert(new_processes
, new_process
, new_process
);
1141 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1143 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1145 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1146 return new_processes
;
1149 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1152 LttvCPUState
*retval
;
1154 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1156 for(i
=0; i
<n
; i
++) {
1157 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1158 retval
[i
].last_irq
= states
[i
].last_irq
;
1159 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1160 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1161 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1168 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1172 for(i
=0; i
<n
; i
++) {
1173 g_array_free(states
[i
].mode_stack
, TRUE
);
1179 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1182 LttvIRQState
*retval
;
1184 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1186 for(i
=0; i
<n
; i
++) {
1187 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1188 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1189 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1190 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1197 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1201 for(i
=0; i
<n
; i
++) {
1202 g_array_free(states
[i
].mode_stack
, TRUE
);
1208 static LttvSoftIRQState
*lttv_state_copy_soft_irq_states(LttvSoftIRQState
*states
, guint n
)
1211 LttvSoftIRQState
*retval
;
1213 retval
= g_malloc(n
*sizeof(LttvSoftIRQState
));
1215 for(i
=0; i
<n
; i
++) {
1216 retval
[i
].running
= states
[i
].running
;
1222 static void lttv_state_free_soft_irq_states(LttvIRQState
*states
, guint n
)
1227 /* bdevstate stuff */
1229 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1231 gint devcode_gint
= devcode
;
1232 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1234 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1235 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1237 gint
* key
= g_malloc(sizeof(gint
));
1239 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1247 static LttvBdevState
*bdevstate_new(void)
1249 LttvBdevState
*retval
;
1250 retval
= g_malloc(sizeof(LttvBdevState
));
1251 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1256 static void bdevstate_free(LttvBdevState
*bds
)
1258 g_array_free(bds
->mode_stack
, TRUE
);
1262 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1264 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1266 bdevstate_free(bds
);
1269 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1271 LttvBdevState
*retval
;
1273 retval
= bdevstate_new();
1274 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1279 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1281 //GHashTable *ht = (GHashTable *)u;
1282 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1283 LttvBdevState
*newbds
;
1285 newbds
= bdevstate_copy(bds
);
1287 g_hash_table_insert(u
, k
, newbds
);
1290 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1294 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1296 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1301 /* Free a hashtable and the LttvBdevState structures its values
1304 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1306 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1307 g_hash_table_destroy(ht
);
1310 /* The saved state for each trace contains a member "processes", which
1311 stores a copy of the process table, and a member "tracefiles" with
1312 one entry per tracefile. Each tracefile has a "process" member pointing
1313 to the current process and a "position" member storing the tracefile
1314 position (needed to seek to the current "next" event. */
1316 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1318 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1320 LttvTracefileState
*tfcs
;
1322 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1324 guint
*running_process
;
1326 LttvAttributeValue value
;
1328 LttEventPosition
*ep
;
1330 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1331 LTTV_STATE_TRACEFILES
);
1333 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1335 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1337 /* Add the currently running processes array */
1338 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1339 running_process
= g_new(guint
, nb_cpus
);
1340 for(i
=0;i
<nb_cpus
;i
++) {
1341 running_process
[i
] = self
->running_process
[i
]->pid
;
1343 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1345 *(value
.v_pointer
) = running_process
;
1347 g_info("State save");
1349 nb_tracefile
= self
->parent
.tracefiles
->len
;
1351 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1353 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1354 LttvTracefileContext
*, i
));
1355 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1356 value
= lttv_attribute_add(tracefiles_tree
, i
,
1358 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1360 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1362 *(value
.v_uint
) = tfcs
->process
->pid
;
1364 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1366 /* Only save the position if the tfs has not infinite time. */
1367 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1368 // && current_tfcs != tfcs) {
1369 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1370 *(value
.v_pointer
) = NULL
;
1372 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1373 ep
= ltt_event_position_new();
1374 ltt_event_position(e
, ep
);
1375 *(value
.v_pointer
) = ep
;
1377 guint nb_block
, offset
;
1380 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1381 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1383 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1387 /* save the cpu state */
1389 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1391 *(value
.v_uint
) = nb_cpus
;
1393 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1395 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1398 /* save the irq state */
1399 nb_irqs
= self
->nb_irqs
;
1401 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1403 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1406 /* save the soft irq state */
1407 nb_irqs
= self
->nb_irqs
;
1409 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
,
1411 *(value
.v_pointer
) = lttv_state_copy_soft_irq_states(self
->soft_irq_states
, nb_irqs
);
1414 /* save the blkdev states */
1415 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1417 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1421 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1423 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
, nb_soft_irqs
;
1425 LttvTracefileState
*tfcs
;
1427 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1429 guint
*running_process
;
1431 LttvAttributeType type
;
1433 LttvAttributeValue value
;
1435 LttvAttributeName name
;
1439 LttEventPosition
*ep
;
1441 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1443 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1444 LTTV_STATE_TRACEFILES
);
1446 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1448 g_assert(type
== LTTV_POINTER
);
1449 lttv_state_free_process_table(self
->processes
);
1450 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1452 /* Add the currently running processes array */
1453 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1454 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1456 g_assert(type
== LTTV_POINTER
);
1457 running_process
= *(value
.v_pointer
);
1458 for(i
=0;i
<nb_cpus
;i
++) {
1459 pid
= running_process
[i
];
1460 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1461 g_assert(self
->running_process
[i
] != NULL
);
1464 nb_tracefile
= self
->parent
.tracefiles
->len
;
1466 //g_tree_destroy(tsc->pqueue);
1467 //tsc->pqueue = g_tree_new(compare_tracefile);
1469 /* restore cpu resource states */
1470 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1471 g_assert(type
== LTTV_POINTER
);
1472 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1473 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1475 /* restore irq resource states */
1476 nb_irqs
= self
->nb_irqs
;
1477 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1478 g_assert(type
== LTTV_POINTER
);
1479 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1480 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1482 /* restore soft irq resource states */
1483 nb_soft_irqs
= self
->nb_soft_irqs
;
1484 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_SOFT_IRQS
, &value
);
1485 g_assert(type
== LTTV_POINTER
);
1486 lttv_state_free_soft_irq_states(self
->soft_irq_states
, nb_soft_irqs
);
1487 self
->soft_irq_states
= lttv_state_copy_soft_irq_states(*(value
.v_pointer
), nb_soft_irqs
);
1489 /* restore the blkdev states */
1490 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1491 g_assert(type
== LTTV_POINTER
);
1492 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1493 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1495 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1497 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1498 LttvTracefileContext
*, i
));
1499 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1500 g_assert(type
== LTTV_GOBJECT
);
1501 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1503 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1505 g_assert(type
== LTTV_UINT
);
1506 pid
= *(value
.v_uint
);
1507 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1509 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1511 g_assert(type
== LTTV_POINTER
);
1512 //g_assert(*(value.v_pointer) != NULL);
1513 ep
= *(value
.v_pointer
);
1514 g_assert(tfcs
->parent
.t_context
!= NULL
);
1516 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1518 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1519 g_tree_remove(tsc
->pqueue
, tfc
);
1522 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1523 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1524 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1525 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1526 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1528 tfc
->timestamp
= ltt_time_infinite
;
1534 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1536 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1538 LttvTracefileState
*tfcs
;
1540 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1542 guint
*running_process
;
1544 LttvAttributeType type
;
1546 LttvAttributeValue value
;
1548 LttvAttributeName name
;
1552 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1553 LTTV_STATE_TRACEFILES
);
1554 g_object_ref(G_OBJECT(tracefiles_tree
));
1555 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1557 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1559 g_assert(type
== LTTV_POINTER
);
1560 lttv_state_free_process_table(*(value
.v_pointer
));
1561 *(value
.v_pointer
) = NULL
;
1562 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1564 /* Free running processes array */
1565 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1567 g_assert(type
== LTTV_POINTER
);
1568 running_process
= *(value
.v_pointer
);
1569 g_free(running_process
);
1571 /* free cpu resource states */
1572 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1573 g_assert(type
== LTTV_UINT
);
1574 nb_cpus
= *value
.v_uint
;
1575 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1576 g_assert(type
== LTTV_POINTER
);
1577 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1579 /* free irq resource states */
1580 nb_irqs
= self
->nb_irqs
;
1581 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1582 g_assert(type
== LTTV_POINTER
);
1583 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1585 /* free the blkdev states */
1586 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1587 g_assert(type
== LTTV_POINTER
);
1588 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1590 nb_tracefile
= self
->parent
.tracefiles
->len
;
1592 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1594 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1595 LttvTracefileContext
*, i
));
1596 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1597 g_assert(type
== LTTV_GOBJECT
);
1598 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1600 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1602 g_assert(type
== LTTV_POINTER
);
1603 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1605 g_object_unref(G_OBJECT(tracefiles_tree
));
1609 static void free_saved_state(LttvTraceState
*self
)
1613 LttvAttributeType type
;
1615 LttvAttributeValue value
;
1617 LttvAttributeName name
;
1621 LttvAttribute
*saved_states
;
1623 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1624 LTTV_STATE_SAVED_STATES
);
1626 nb
= lttv_attribute_get_number(saved_states
);
1627 for(i
= 0 ; i
< nb
; i
++) {
1628 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1629 g_assert(type
== LTTV_GOBJECT
);
1630 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1633 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1638 create_max_time(LttvTraceState
*tcs
)
1640 LttvAttributeValue v
;
1642 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1644 g_assert(*(v
.v_pointer
) == NULL
);
1645 *(v
.v_pointer
) = g_new(LttTime
,1);
1646 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1651 get_max_time(LttvTraceState
*tcs
)
1653 LttvAttributeValue v
;
1655 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1657 g_assert(*(v
.v_pointer
) != NULL
);
1658 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1663 free_max_time(LttvTraceState
*tcs
)
1665 LttvAttributeValue v
;
1667 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1669 g_free(*(v
.v_pointer
));
1670 *(v
.v_pointer
) = NULL
;
1674 typedef struct _LttvNameTables
{
1675 // FIXME GQuark *eventtype_names;
1676 GQuark
*syscall_names
;
1682 GQuark
*soft_irq_names
;
1688 create_name_tables(LttvTraceState
*tcs
)
1692 GString
*fe_name
= g_string_new("");
1694 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1696 LttvAttributeValue v
;
1700 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1702 g_assert(*(v
.v_pointer
) == NULL
);
1703 *(v
.v_pointer
) = name_tables
;
1705 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1707 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1708 LTT_FACILITY_KERNEL_ARCH
,
1709 LTT_EVENT_SYSCALL_ENTRY
,
1710 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1711 NULL
, NULL
, &hooks
)) {
1713 // th = lttv_trace_hook_get_first(&th);
1715 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1716 // nb = ltt_type_element_number(t);
1718 // name_tables->syscall_names = g_new(GQuark, nb);
1719 // name_tables->nb_syscalls = nb;
1721 // for(i = 0 ; i < nb ; i++) {
1722 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1723 // if(!name_tables->syscall_names[i]) {
1724 // GString *string = g_string_new("");
1725 // g_string_printf(string, "syscall %u", i);
1726 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1727 // g_string_free(string, TRUE);
1731 name_tables
->nb_syscalls
= 256;
1732 name_tables
->syscall_names
= g_new(GQuark
, 256);
1733 for(i
= 0 ; i
< 256 ; i
++) {
1734 g_string_printf(fe_name
, "syscall %d", i
);
1735 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1738 name_tables
->syscall_names
= NULL
;
1739 name_tables
->nb_syscalls
= 0;
1741 lttv_trace_hook_remove_all(&hooks
);
1743 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1744 LTT_FACILITY_KERNEL_ARCH
,
1745 LTT_EVENT_TRAP_ENTRY
,
1746 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1747 NULL
, NULL
, &hooks
)) {
1749 // th = lttv_trace_hook_get_first(&th);
1751 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1752 // //nb = ltt_type_element_number(t);
1754 // name_tables->trap_names = g_new(GQuark, nb);
1755 // for(i = 0 ; i < nb ; i++) {
1756 // name_tables->trap_names[i] = g_quark_from_string(
1757 // ltt_enum_string_get(t, i));
1760 name_tables
->nb_traps
= 256;
1761 name_tables
->trap_names
= g_new(GQuark
, 256);
1762 for(i
= 0 ; i
< 256 ; i
++) {
1763 g_string_printf(fe_name
, "trap %d", i
);
1764 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1767 name_tables
->trap_names
= NULL
;
1768 name_tables
->nb_traps
= 0;
1770 lttv_trace_hook_remove_all(&hooks
);
1772 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1773 LTT_FACILITY_KERNEL
,
1774 LTT_EVENT_IRQ_ENTRY
,
1775 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1776 NULL
, NULL
, &hooks
)) {
1779 name_tables->irq_names = g_new(GQuark, nb);
1780 for(i = 0 ; i < nb ; i++) {
1781 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1785 name_tables
->nb_irqs
= 256;
1786 name_tables
->irq_names
= g_new(GQuark
, 256);
1787 for(i
= 0 ; i
< 256 ; i
++) {
1788 g_string_printf(fe_name
, "irq %d", i
);
1789 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1792 name_tables
->nb_irqs
= 0;
1793 name_tables
->irq_names
= NULL
;
1795 lttv_trace_hook_remove_all(&hooks
);
1797 name_tables->soft_irq_names = g_new(GQuark, nb);
1798 for(i = 0 ; i < nb ; i++) {
1799 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1803 /* the kernel is limited to 32 statically defined softirqs */
1804 name_tables
->nb_softirqs
= 32;
1805 name_tables
->soft_irq_names
= g_new(GQuark
, name_tables
->nb_softirqs
);
1806 for(i
= 0 ; i
< name_tables
->nb_softirqs
; i
++) {
1807 g_string_printf(fe_name
, "softirq %d", i
);
1808 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1810 g_array_free(hooks
, TRUE
);
1812 g_string_free(fe_name
, TRUE
);
1817 get_name_tables(LttvTraceState
*tcs
)
1819 LttvNameTables
*name_tables
;
1821 LttvAttributeValue v
;
1823 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1825 g_assert(*(v
.v_pointer
) != NULL
);
1826 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1827 //tcs->eventtype_names = name_tables->eventtype_names;
1828 tcs
->syscall_names
= name_tables
->syscall_names
;
1829 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1830 tcs
->trap_names
= name_tables
->trap_names
;
1831 tcs
->nb_traps
= name_tables
->nb_traps
;
1832 tcs
->irq_names
= name_tables
->irq_names
;
1833 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1834 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1835 tcs
->nb_soft_irqs
= name_tables
->nb_softirqs
;
1840 free_name_tables(LttvTraceState
*tcs
)
1842 LttvNameTables
*name_tables
;
1844 LttvAttributeValue v
;
1846 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1848 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1849 *(v
.v_pointer
) = NULL
;
1851 // g_free(name_tables->eventtype_names);
1852 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1853 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1854 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1855 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1856 if(name_tables
) g_free(name_tables
);
1859 #ifdef HASH_TABLE_DEBUG
1861 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1863 LttvProcessState
*process
= (LttvProcessState
*)value
;
1865 /* Test for process corruption */
1866 guint stack_len
= process
->execution_stack
->len
;
1869 static void hash_table_check(GHashTable
*table
)
1871 g_hash_table_foreach(table
, test_process
, NULL
);
1877 /* clears the stack and sets the state passed as argument */
1878 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1880 g_array_set_size(cpust
->mode_stack
, 1);
1881 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1884 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1886 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1887 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1890 static void cpu_pop_mode(LttvCPUState
*cpust
)
1892 if(cpust
->mode_stack
->len
<= 1)
1893 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1895 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1898 /* clears the stack and sets the state passed as argument */
1899 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1901 g_array_set_size(bdevst
->mode_stack
, 1);
1902 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1905 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1907 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1908 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1911 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1913 if(bdevst
->mode_stack
->len
<= 1)
1914 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1916 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1919 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1921 g_array_set_size(irqst
->mode_stack
, 1);
1922 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1925 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1927 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1928 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1931 static void irq_pop_mode(LttvIRQState
*irqst
)
1933 if(irqst
->mode_stack
->len
<= 1)
1934 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1936 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1939 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1942 LttvExecutionState
*es
;
1944 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1945 guint cpu
= tfs
->cpu
;
1947 #ifdef HASH_TABLE_DEBUG
1948 hash_table_check(ts
->processes
);
1950 LttvProcessState
*process
= ts
->running_process
[cpu
];
1952 guint depth
= process
->execution_stack
->len
;
1954 process
->execution_stack
=
1955 g_array_set_size(process
->execution_stack
, depth
+ 1);
1958 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1960 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1963 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1964 es
->cum_cpu_time
= ltt_time_zero
;
1965 es
->s
= process
->state
->s
;
1966 process
->state
= es
;
1970 * return 1 when empty, else 0 */
1971 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1972 LttvTracefileState
*tfs
)
1974 guint depth
= process
->execution_stack
->len
;
1980 process
->execution_stack
=
1981 g_array_set_size(process
->execution_stack
, depth
- 1);
1982 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1984 process
->state
->change
= tfs
->parent
.timestamp
;
1989 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1991 guint cpu
= tfs
->cpu
;
1992 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1993 LttvProcessState
*process
= ts
->running_process
[cpu
];
1995 guint depth
= process
->execution_stack
->len
;
1997 if(process
->state
->t
!= t
){
1998 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1999 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2000 g_info("process state has %s when pop_int is %s\n",
2001 g_quark_to_string(process
->state
->t
),
2002 g_quark_to_string(t
));
2003 g_info("{ %u, %u, %s, %s, %s }\n",
2006 g_quark_to_string(process
->name
),
2007 g_quark_to_string(process
->brand
),
2008 g_quark_to_string(process
->state
->s
));
2013 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2014 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2018 process
->execution_stack
=
2019 g_array_set_size(process
->execution_stack
, depth
- 1);
2020 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
2022 process
->state
->change
= tfs
->parent
.timestamp
;
2025 struct search_result
{
2026 const LttTime
*time
; /* Requested time */
2027 LttTime
*best
; /* Best result */
2030 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
2032 const LttTime
*elem_time
= (const LttTime
*)a
;
2033 /* Explicit non const cast */
2034 struct search_result
*res
= (struct search_result
*)b
;
2036 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
2037 /* The usertrace was created before the schedchange */
2038 /* Get larger keys */
2040 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2041 /* The usertrace was created after the schedchange time */
2042 /* Get smaller keys */
2044 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2045 res
->best
= (LttTime
*)elem_time
;
2048 res
->best
= (LttTime
*)elem_time
;
2055 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2056 guint pid
, const LttTime
*timestamp
)
2058 LttvTracefileState
*tfs
= NULL
;
2059 struct search_result res
;
2060 /* Find the usertrace associated with a pid and time interval.
2061 * Search in the usertraces by PID (within a hash) and then, for each
2062 * corresponding element of the array, find the first one with creation
2063 * timestamp the lowest, but higher or equal to "timestamp". */
2064 res
.time
= timestamp
;
2066 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2067 if(usertrace_tree
) {
2068 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2070 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2078 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2079 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2081 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2083 LttvExecutionState
*es
;
2088 process
->tgid
= tgid
;
2090 process
->name
= name
;
2091 process
->brand
= LTTV_STATE_UNBRANDED
;
2092 //process->last_cpu = tfs->cpu_name;
2093 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2094 process
->type
= LTTV_STATE_USER_THREAD
;
2095 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2096 process
->current_function
= 0; //function 0x0 by default.
2098 g_info("Process %u, core %p", process
->pid
, process
);
2099 g_hash_table_insert(tcs
->processes
, process
, process
);
2102 process
->ppid
= parent
->pid
;
2103 process
->creation_time
= *timestamp
;
2106 /* No parent. This process exists but we are missing all information about
2107 its creation. The birth time is set to zero but we remember the time of
2112 process
->creation_time
= ltt_time_zero
;
2115 process
->insertion_time
= *timestamp
;
2116 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2117 process
->creation_time
.tv_nsec
);
2118 process
->pid_time
= g_quark_from_string(buffer
);
2120 //process->last_cpu = tfs->cpu_name;
2121 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2122 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2123 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2124 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2125 es
= process
->state
= &g_array_index(process
->execution_stack
,
2126 LttvExecutionState
, 0);
2127 es
->t
= LTTV_STATE_USER_MODE
;
2128 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2129 es
->entry
= *timestamp
;
2130 //g_assert(timestamp->tv_sec != 0);
2131 es
->change
= *timestamp
;
2132 es
->cum_cpu_time
= ltt_time_zero
;
2133 es
->s
= LTTV_STATE_RUN
;
2135 es
= process
->state
= &g_array_index(process
->execution_stack
,
2136 LttvExecutionState
, 1);
2137 es
->t
= LTTV_STATE_SYSCALL
;
2138 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2139 es
->entry
= *timestamp
;
2140 //g_assert(timestamp->tv_sec != 0);
2141 es
->change
= *timestamp
;
2142 es
->cum_cpu_time
= ltt_time_zero
;
2143 es
->s
= LTTV_STATE_WAIT_FORK
;
2145 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2146 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2147 sizeof(guint64
), 0);
2152 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2155 LttvProcessState key
;
2156 LttvProcessState
*process
;
2160 process
= g_hash_table_lookup(ts
->processes
, &key
);
2165 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2166 const LttTime
*timestamp
)
2168 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2169 LttvExecutionState
*es
;
2171 /* Put ltt_time_zero creation time for unexisting processes */
2172 if(unlikely(process
== NULL
)) {
2173 process
= lttv_state_create_process(ts
,
2174 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2175 /* We are not sure is it's a kernel thread or normal thread, put the
2176 * bottom stack state to unknown */
2177 process
->execution_stack
=
2178 g_array_set_size(process
->execution_stack
, 1);
2179 process
->state
= es
=
2180 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2181 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2182 es
->s
= LTTV_STATE_UNNAMED
;
2187 /* FIXME : this function should be called when we receive an event telling that
2188 * release_task has been called in the kernel. In happens generally when
2189 * the parent waits for its child terminaison, but may also happen in special
2190 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2191 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2192 * of a killed thread group, but isn't the leader.
2194 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2196 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2197 LttvProcessState key
;
2199 key
.pid
= process
->pid
;
2200 key
.cpu
= process
->cpu
;
2201 g_hash_table_remove(ts
->processes
, &key
);
2202 g_array_free(process
->execution_stack
, TRUE
);
2203 g_array_free(process
->user_stack
, TRUE
);
2208 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2210 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2211 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2216 static void lttv_state_free_process_table(GHashTable
*processes
)
2218 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2219 g_hash_table_destroy(processes
);
2223 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2225 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2227 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2228 LttvProcessState
*process
= ts
->running_process
[cpu
];
2229 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2230 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2231 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2233 LttvExecutionSubmode submode
;
2235 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2236 guint syscall
= ltt_event_get_unsigned(e
, f
);
2238 if(syscall
< nb_syscalls
) {
2239 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2242 /* Fixup an incomplete syscall table */
2243 GString
*string
= g_string_new("");
2244 g_string_printf(string
, "syscall %u", syscall
);
2245 submode
= g_quark_from_string(string
->str
);
2246 g_string_free(string
, TRUE
);
2248 /* There can be no system call from PID 0 : unknown state */
2249 if(process
->pid
!= 0)
2250 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2255 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2257 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2259 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2260 LttvProcessState
*process
= ts
->running_process
[cpu
];
2262 /* There can be no system call from PID 0 : unknown state */
2263 if(process
->pid
!= 0)
2264 pop_state(s
, LTTV_STATE_SYSCALL
);
2269 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2271 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2272 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2273 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2274 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2276 LttvExecutionSubmode submode
;
2278 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2279 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2281 if(trap
< nb_traps
) {
2282 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2284 /* Fixup an incomplete trap table */
2285 GString
*string
= g_string_new("");
2286 g_string_printf(string
, "trap %llu", trap
);
2287 submode
= g_quark_from_string(string
->str
);
2288 g_string_free(string
, TRUE
);
2291 push_state(s
, LTTV_STATE_TRAP
, submode
);
2293 /* update cpu status */
2294 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2299 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2301 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2303 pop_state(s
, LTTV_STATE_TRAP
);
2305 /* update cpu status */
2306 cpu_pop_mode(s
->cpu_state
);
2311 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2313 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2314 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2315 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2316 //guint8 ev_id = ltt_event_eventtype_id(e);
2317 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2318 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2320 LttvExecutionSubmode submode
;
2321 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2322 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2325 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2327 /* Fixup an incomplete irq table */
2328 GString
*string
= g_string_new("");
2329 g_string_printf(string
, "irq %llu", irq
);
2330 submode
= g_quark_from_string(string
->str
);
2331 g_string_free(string
, TRUE
);
2334 /* Do something with the info about being in user or system mode when int? */
2335 push_state(s
, LTTV_STATE_IRQ
, submode
);
2337 /* update cpu status */
2338 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2340 /* update irq status */
2341 s
->cpu_state
->last_irq
= irq
;
2342 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2347 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2349 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2350 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2351 guint softirq
= s
->cpu_state
->last_soft_irq
;
2353 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2355 /* update softirq status */
2356 if(ts
->soft_irq_states
[softirq
].running
)
2357 ts
->soft_irq_states
[softirq
].running
--;
2362 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2364 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2365 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2367 pop_state(s
, LTTV_STATE_IRQ
);
2369 /* update cpu status */
2370 cpu_pop_mode(s
->cpu_state
);
2372 /* update irq status */
2373 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2378 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2380 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2381 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2382 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2383 //guint8 ev_id = ltt_event_eventtype_id(e);
2384 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2385 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2387 LttvExecutionSubmode submode
;
2388 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2389 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_soft_irqs
;
2391 if(softirq
< nb_softirqs
) {
2392 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2394 /* Fixup an incomplete irq table */
2395 GString
*string
= g_string_new("");
2396 g_string_printf(string
, "softirq %llu", softirq
);
2397 submode
= g_quark_from_string(string
->str
);
2398 g_string_free(string
, TRUE
);
2401 /* Do something with the info about being in user or system mode when int? */
2402 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2404 /* update softirq status */
2405 s
->cpu_state
->last_soft_irq
= softirq
;
2406 ts
->soft_irq_states
[softirq
].running
++;
2411 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2413 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2414 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2415 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2416 //guint8 ev_id = ltt_event_eventtype_id(e);
2417 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2419 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2420 lttv_trace_get_hook_field(th
, 0)));
2421 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2423 ts
->irq_names
[irq
] = action
;
2429 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2431 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2432 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2433 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2434 //guint8 ev_id = ltt_event_eventtype_id(e);
2435 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2437 guint major
= ltt_event_get_long_unsigned(e
,
2438 lttv_trace_get_hook_field(th
, 0));
2439 guint minor
= ltt_event_get_long_unsigned(e
,
2440 lttv_trace_get_hook_field(th
, 1));
2441 guint oper
= ltt_event_get_long_unsigned(e
,
2442 lttv_trace_get_hook_field(th
, 2));
2443 guint16 devcode
= MKDEV(major
,minor
);
2445 /* have we seen this block device before? */
2446 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2449 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2451 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2456 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2458 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2459 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2460 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2461 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2463 guint major
= ltt_event_get_long_unsigned(e
,
2464 lttv_trace_get_hook_field(th
, 0));
2465 guint minor
= ltt_event_get_long_unsigned(e
,
2466 lttv_trace_get_hook_field(th
, 1));
2467 //guint oper = ltt_event_get_long_unsigned(e,
2468 // lttv_trace_get_hook_field(th, 2));
2469 guint16 devcode
= MKDEV(major
,minor
);
2471 /* have we seen this block device before? */
2472 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2474 /* update block device */
2475 bdev_pop_mode(bdev
);
2480 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2484 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2485 guint cpu
= tfs
->cpu
;
2486 LttvProcessState
*process
= ts
->running_process
[cpu
];
2488 guint depth
= process
->user_stack
->len
;
2490 process
->user_stack
=
2491 g_array_set_size(process
->user_stack
, depth
+ 1);
2493 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2494 *new_func
= funcptr
;
2495 process
->current_function
= funcptr
;
2498 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2500 guint cpu
= tfs
->cpu
;
2501 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2502 LttvProcessState
*process
= ts
->running_process
[cpu
];
2504 if(process
->current_function
!= funcptr
){
2505 g_info("Different functions (%lu.%09lu): ignore it\n",
2506 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2507 g_info("process state has %llu when pop_function is %llu\n",
2508 process
->current_function
, funcptr
);
2509 g_info("{ %u, %u, %s, %s, %s }\n",
2512 g_quark_to_string(process
->name
),
2513 g_quark_to_string(process
->brand
),
2514 g_quark_to_string(process
->state
->s
));
2517 guint depth
= process
->user_stack
->len
;
2520 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2521 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2525 process
->user_stack
=
2526 g_array_set_size(process
->user_stack
, depth
- 1);
2527 process
->current_function
=
2528 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2532 static gboolean
function_entry(void *hook_data
, void *call_data
)
2534 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2535 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2536 //guint8 ev_id = ltt_event_eventtype_id(e);
2537 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2538 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2539 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2541 push_function(s
, funcptr
);
2545 static gboolean
function_exit(void *hook_data
, void *call_data
)
2547 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2548 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2549 //guint8 ev_id = ltt_event_eventtype_id(e);
2550 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2551 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2552 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2554 pop_function(s
, funcptr
);
2558 static gboolean
schedchange(void *hook_data
, void *call_data
)
2560 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2562 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2563 LttvProcessState
*process
= ts
->running_process
[cpu
];
2564 //LttvProcessState *old_process = ts->running_process[cpu];
2566 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2567 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2568 guint pid_in
, pid_out
;
2571 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2572 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2573 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2575 if(likely(process
!= NULL
)) {
2577 /* We could not know but it was not the idle process executing.
2578 This should only happen at the beginning, before the first schedule
2579 event, and when the initial information (current process for each CPU)
2580 is missing. It is not obvious how we could, after the fact, compensate
2581 the wrongly attributed statistics. */
2583 //This test only makes sense once the state is known and if there is no
2584 //missing events. We need to silently ignore schedchange coming after a
2585 //process_free, or it causes glitches. (FIXME)
2586 //if(unlikely(process->pid != pid_out)) {
2587 // g_assert(process->pid == 0);
2589 if(process
->pid
== 0
2590 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2592 /* Scheduling out of pid 0 at beginning of the trace :
2593 * we know for sure it is in syscall mode at this point. */
2594 g_assert(process
->execution_stack
->len
== 1);
2595 process
->state
->t
= LTTV_STATE_SYSCALL
;
2596 process
->state
->s
= LTTV_STATE_WAIT
;
2597 process
->state
->change
= s
->parent
.timestamp
;
2598 process
->state
->entry
= s
->parent
.timestamp
;
2601 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2602 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2603 process
->state
->change
= s
->parent
.timestamp
;
2605 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2606 else process
->state
->s
= LTTV_STATE_WAIT
;
2607 process
->state
->change
= s
->parent
.timestamp
;
2610 if(state_out
== 32 || state_out
== 64)
2611 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2612 /* see sched.h for states */
2615 process
= ts
->running_process
[cpu
] =
2616 lttv_state_find_process_or_create(
2617 (LttvTraceState
*)s
->parent
.t_context
,
2619 &s
->parent
.timestamp
);
2620 process
->state
->s
= LTTV_STATE_RUN
;
2622 if(process
->usertrace
)
2623 process
->usertrace
->cpu
= cpu
;
2624 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2625 process
->state
->change
= s
->parent
.timestamp
;
2627 /* update cpu status */
2629 /* going to idle task */
2630 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2632 /* scheduling a real task.
2633 * we must be careful here:
2634 * if we just schedule()'ed to a process that is
2635 * in a trap, we must put the cpu in trap mode
2637 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2638 if(process
->state
->t
== LTTV_STATE_TRAP
)
2639 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2645 static gboolean
process_fork(void *hook_data
, void *call_data
)
2647 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2648 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2649 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2651 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2652 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2653 //LttvProcessState *zombie_process;
2655 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2656 LttvProcessState
*process
= ts
->running_process
[cpu
];
2657 LttvProcessState
*child_process
;
2658 struct marker_field
*f
;
2661 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2664 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2665 s
->parent
.target_pid
= child_pid
;
2668 f
= lttv_trace_get_hook_field(th
, 2);
2670 child_tgid
= ltt_event_get_unsigned(e
, f
);
2674 /* Mathieu : it seems like the process might have been scheduled in before the
2675 * fork, and, in a rare case, might be the current process. This might happen
2676 * in a SMP case where we don't have enough precision on the clocks.
2678 * Test reenabled after precision fixes on time. (Mathieu) */
2680 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2682 if(unlikely(zombie_process
!= NULL
)) {
2683 /* Reutilisation of PID. Only now we are sure that the old PID
2684 * has been released. FIXME : should know when release_task happens instead.
2686 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2688 for(i
=0; i
< num_cpus
; i
++) {
2689 g_assert(zombie_process
!= ts
->running_process
[i
]);
2692 exit_process(s
, zombie_process
);
2695 g_assert(process
->pid
!= child_pid
);
2696 // FIXME : Add this test in the "known state" section
2697 // g_assert(process->pid == parent_pid);
2698 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2699 if(child_process
== NULL
) {
2700 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2701 child_pid
, child_tgid
,
2702 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2704 /* The process has already been created : due to time imprecision between
2705 * multiple CPUs : it has been scheduled in before creation. Note that we
2706 * shouldn't have this kind of imprecision.
2708 * Simply put a correct parent.
2710 g_assert(0); /* This is a problematic case : the process has been created
2711 before the fork event */
2712 child_process
->ppid
= process
->pid
;
2713 child_process
->tgid
= child_tgid
;
2715 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2716 child_process
->name
= process
->name
;
2717 child_process
->brand
= process
->brand
;
2722 /* We stamp a newly created process as kernel_thread.
2723 * The thread should not be running yet. */
2724 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2726 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2727 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2728 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2730 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2731 LttvProcessState
*process
;
2732 LttvExecutionState
*es
;
2735 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2736 s
->parent
.target_pid
= pid
;
2738 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2740 process
->execution_stack
=
2741 g_array_set_size(process
->execution_stack
, 1);
2742 es
= process
->state
=
2743 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2744 es
->t
= LTTV_STATE_SYSCALL
;
2745 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2750 static gboolean
process_exit(void *hook_data
, void *call_data
)
2752 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2753 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2754 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2756 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2757 LttvProcessState
*process
; // = ts->running_process[cpu];
2759 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2760 s
->parent
.target_pid
= pid
;
2762 // FIXME : Add this test in the "known state" section
2763 // g_assert(process->pid == pid);
2765 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2766 if(likely(process
!= NULL
)) {
2767 process
->state
->s
= LTTV_STATE_EXIT
;
2772 static gboolean
process_free(void *hook_data
, void *call_data
)
2774 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2775 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2776 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2777 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2779 LttvProcessState
*process
;
2781 /* PID of the process to release */
2782 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2783 s
->parent
.target_pid
= release_pid
;
2785 g_assert(release_pid
!= 0);
2787 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2789 if(likely(process
!= NULL
)) {
2790 /* release_task is happening at kernel level : we can now safely release
2791 * the data structure of the process */
2792 //This test is fun, though, as it may happen that
2793 //at time t : CPU 0 : process_free
2794 //at time t+150ns : CPU 1 : schedule out
2795 //Clearly due to time imprecision, we disable it. (Mathieu)
2796 //If this weird case happen, we have no choice but to put the
2797 //Currently running process on the cpu to 0.
2798 //I re-enable it following time precision fixes. (Mathieu)
2799 //Well, in the case where an process is freed by a process on another CPU
2800 //and still scheduled, it happens that this is the schedchange that will
2801 //drop the last reference count. Do not free it here!
2802 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2804 for(i
=0; i
< num_cpus
; i
++) {
2805 //g_assert(process != ts->running_process[i]);
2806 if(process
== ts
->running_process
[i
]) {
2807 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2811 if(i
== num_cpus
) /* process is not scheduled */
2812 exit_process(s
, process
);
2819 static gboolean
process_exec(void *hook_data
, void *call_data
)
2821 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2822 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2823 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2824 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2827 LttvProcessState
*process
= ts
->running_process
[cpu
];
2829 #if 0//how to use a sequence that must be transformed in a string
2830 /* PID of the process to release */
2831 guint64 name_len
= ltt_event_field_element_number(e
,
2832 lttv_trace_get_hook_field(th
, 0));
2833 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2834 LttField
*child
= ltt_event_field_element_select(e
,
2835 lttv_trace_get_hook_field(th
, 0), 0);
2837 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2838 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2839 memcpy(null_term_name
, name_begin
, name_len
);
2840 null_term_name
[name_len
] = '\0';
2841 process
->name
= g_quark_from_string(null_term_name
);
2844 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2845 lttv_trace_get_hook_field(th
, 0)));
2846 process
->brand
= LTTV_STATE_UNBRANDED
;
2847 //g_free(null_term_name);
2851 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2853 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2854 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2855 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2856 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2859 LttvProcessState
*process
= ts
->running_process
[cpu
];
2861 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2862 process
->brand
= g_quark_from_string(name
);
2867 static void fix_process(gpointer key
, gpointer value
,
2870 LttvProcessState
*process
;
2871 LttvExecutionState
*es
;
2872 process
= (LttvProcessState
*)value
;
2873 LttTime
*timestamp
= (LttTime
*)user_data
;
2875 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2876 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2877 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2878 es
->t
= LTTV_STATE_SYSCALL
;
2879 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2880 es
->entry
= *timestamp
;
2881 es
->change
= *timestamp
;
2882 es
->cum_cpu_time
= ltt_time_zero
;
2883 if(es
->s
== LTTV_STATE_UNNAMED
)
2884 es
->s
= LTTV_STATE_WAIT
;
2887 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2888 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2889 es
->t
= LTTV_STATE_USER_MODE
;
2890 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2891 es
->entry
= *timestamp
;
2892 //g_assert(timestamp->tv_sec != 0);
2893 es
->change
= *timestamp
;
2894 es
->cum_cpu_time
= ltt_time_zero
;
2895 if(es
->s
== LTTV_STATE_UNNAMED
)
2896 es
->s
= LTTV_STATE_RUN
;
2898 if(process
->execution_stack
->len
== 1) {
2899 /* Still in bottom unknown mode, means never did a system call
2900 * May be either in user mode, syscall mode, running or waiting.*/
2901 /* FIXME : we may be tagging syscall mode when being user mode */
2902 process
->execution_stack
=
2903 g_array_set_size(process
->execution_stack
, 2);
2904 es
= process
->state
= &g_array_index(process
->execution_stack
,
2905 LttvExecutionState
, 1);
2906 es
->t
= LTTV_STATE_SYSCALL
;
2907 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2908 es
->entry
= *timestamp
;
2909 //g_assert(timestamp->tv_sec != 0);
2910 es
->change
= *timestamp
;
2911 es
->cum_cpu_time
= ltt_time_zero
;
2912 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2913 es
->s
= LTTV_STATE_WAIT
;
2919 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2921 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2922 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2923 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2924 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2925 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2927 /* For all processes */
2928 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2929 /* else, if stack[0] is unknown, set to user mode, running */
2931 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2936 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2938 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2939 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2940 //It's slow : optimise later by doing this before reading trace.
2941 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2947 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2948 LttvProcessState
*process
= ts
->running_process
[cpu
];
2949 LttvProcessState
*parent_process
;
2950 struct marker_field
*f
;
2951 GQuark type
, mode
, submode
, status
;
2952 LttvExecutionState
*es
;
2956 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2957 s
->parent
.target_pid
= pid
;
2960 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2963 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2966 f
= lttv_trace_get_hook_field(th
, 3);
2967 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2969 //FIXME: type is rarely used, enum must match possible types.
2972 f
= lttv_trace_get_hook_field(th
, 4);
2973 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2976 f
= lttv_trace_get_hook_field(th
, 5);
2977 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2980 f
= lttv_trace_get_hook_field(th
, 6);
2981 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2984 f
= lttv_trace_get_hook_field(th
, 7);
2986 tgid
= ltt_event_get_unsigned(e
, f
);
2991 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2992 for(i
=0; i
<nb_cpus
; i
++) {
2993 process
= lttv_state_find_process(ts
, i
, pid
);
2994 g_assert(process
!= NULL
);
2996 process
->ppid
= parent_pid
;
2997 process
->tgid
= tgid
;
2998 process
->name
= g_quark_from_string(command
);
3000 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3001 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3005 /* The process might exist if a process was forked while performing the
3007 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
3008 if(process
== NULL
) {
3009 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
3010 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
3011 pid
, tgid
, g_quark_from_string(command
),
3012 &s
->parent
.timestamp
);
3014 /* Keep the stack bottom : a running user mode */
3015 /* Disabled because of inconsistencies in the current statedump states. */
3016 if(type
== LTTV_STATE_KERNEL_THREAD
) {
3017 /* Only keep the bottom
3018 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3019 /* Will cause expected trap when in fact being syscall (even after end of
3021 * Will cause expected interrupt when being syscall. (only before end of
3022 * statedump event) */
3023 // This will cause a "popping last state on stack, ignoring it."
3024 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3025 es
= process
->state
= &g_array_index(process
->execution_stack
,
3026 LttvExecutionState
, 0);
3027 process
->type
= LTTV_STATE_KERNEL_THREAD
;
3028 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3029 es
->s
= LTTV_STATE_UNNAMED
;
3030 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3032 es
->t
= LTTV_STATE_SYSCALL
;
3037 /* User space process :
3038 * bottom : user mode
3039 * either currently running or scheduled out.
3040 * can be scheduled out because interrupted in (user mode or in syscall)
3041 * or because of an explicit call to the scheduler in syscall. Note that
3042 * the scheduler call comes after the irq_exit, so never in interrupt
3044 // temp workaround : set size to 1 : only have user mode bottom of stack.
3045 // will cause g_info message of expected syscall mode when in fact being
3046 // in user mode. Can also cause expected trap when in fact being user
3047 // mode in the event of a page fault reenabling interrupts in the handler.
3048 // Expected syscall and trap can also happen after the end of statedump
3049 // This will cause a "popping last state on stack, ignoring it."
3050 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3051 es
= process
->state
= &g_array_index(process
->execution_stack
,
3052 LttvExecutionState
, 0);
3053 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3054 es
->s
= LTTV_STATE_UNNAMED
;
3055 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3057 es
->t
= LTTV_STATE_USER_MODE
;
3065 es
= process
->state
= &g_array_index(process
->execution_stack
,
3066 LttvExecutionState
, 1);
3067 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3068 es
->s
= LTTV_STATE_UNNAMED
;
3069 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3073 /* The process has already been created :
3074 * Probably was forked while dumping the process state or
3075 * was simply scheduled in prior to get the state dump event.
3077 process
->ppid
= parent_pid
;
3078 process
->tgid
= tgid
;
3079 process
->name
= g_quark_from_string(command
);
3080 process
->type
= type
;
3082 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3084 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3085 if(type
== LTTV_STATE_KERNEL_THREAD
)
3086 es
->t
= LTTV_STATE_SYSCALL
;
3088 es
->t
= LTTV_STATE_USER_MODE
;
3091 /* Don't mess around with the stack, it will eventually become
3092 * ok after the end of state dump. */
3099 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3101 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3103 lttv_state_add_event_hooks(tss
);
3108 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3110 LttvTraceset
*traceset
= self
->parent
.ts
;
3112 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3116 LttvTracefileState
*tfs
;
3122 LttvAttributeValue val
;
3124 nb_trace
= lttv_traceset_number(traceset
);
3125 for(i
= 0 ; i
< nb_trace
; i
++) {
3126 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3128 /* Find the eventtype id for the following events and register the
3129 associated by id hooks. */
3131 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3132 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3135 lttv_trace_find_hook(ts
->parent
.t
,
3136 LTT_FACILITY_KERNEL_ARCH
,
3137 LTT_EVENT_SYSCALL_ENTRY
,
3138 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3139 syscall_entry
, NULL
, &hooks
);
3141 lttv_trace_find_hook(ts
->parent
.t
,
3142 LTT_FACILITY_KERNEL_ARCH
,
3143 LTT_EVENT_SYSCALL_EXIT
,
3145 syscall_exit
, NULL
, &hooks
);
3147 lttv_trace_find_hook(ts
->parent
.t
,
3148 LTT_FACILITY_KERNEL_ARCH
,
3149 LTT_EVENT_TRAP_ENTRY
,
3150 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3151 trap_entry
, NULL
, &hooks
);
3153 lttv_trace_find_hook(ts
->parent
.t
,
3154 LTT_FACILITY_KERNEL_ARCH
,
3155 LTT_EVENT_TRAP_EXIT
,
3157 trap_exit
, NULL
, &hooks
);
3159 lttv_trace_find_hook(ts
->parent
.t
,
3160 LTT_FACILITY_KERNEL
,
3161 LTT_EVENT_IRQ_ENTRY
,
3162 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3163 irq_entry
, NULL
, &hooks
);
3165 lttv_trace_find_hook(ts
->parent
.t
,
3166 LTT_FACILITY_KERNEL
,
3169 irq_exit
, NULL
, &hooks
);
3171 lttv_trace_find_hook(ts
->parent
.t
,
3172 LTT_FACILITY_KERNEL
,
3173 LTT_EVENT_SOFT_IRQ_ENTRY
,
3174 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3175 soft_irq_entry
, NULL
, &hooks
);
3177 lttv_trace_find_hook(ts
->parent
.t
,
3178 LTT_FACILITY_KERNEL
,
3179 LTT_EVENT_SOFT_IRQ_EXIT
,
3181 soft_irq_exit
, NULL
, &hooks
);
3183 lttv_trace_find_hook(ts
->parent
.t
,
3184 LTT_FACILITY_KERNEL
,
3185 LTT_EVENT_SCHED_SCHEDULE
,
3186 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3187 LTT_FIELD_PREV_STATE
),
3188 schedchange
, NULL
, &hooks
);
3190 lttv_trace_find_hook(ts
->parent
.t
,
3191 LTT_FACILITY_KERNEL
,
3192 LTT_EVENT_PROCESS_FORK
,
3193 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3194 LTT_FIELD_CHILD_TGID
),
3195 process_fork
, NULL
, &hooks
);
3197 lttv_trace_find_hook(ts
->parent
.t
,
3198 LTT_FACILITY_KERNEL_ARCH
,
3199 LTT_EVENT_KTHREAD_CREATE
,
3200 FIELD_ARRAY(LTT_FIELD_PID
),
3201 process_kernel_thread
, NULL
, &hooks
);
3203 lttv_trace_find_hook(ts
->parent
.t
,
3204 LTT_FACILITY_KERNEL
,
3205 LTT_EVENT_PROCESS_EXIT
,
3206 FIELD_ARRAY(LTT_FIELD_PID
),
3207 process_exit
, NULL
, &hooks
);
3209 lttv_trace_find_hook(ts
->parent
.t
,
3210 LTT_FACILITY_KERNEL
,
3211 LTT_EVENT_PROCESS_FREE
,
3212 FIELD_ARRAY(LTT_FIELD_PID
),
3213 process_free
, NULL
, &hooks
);
3215 lttv_trace_find_hook(ts
->parent
.t
,
3218 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3219 process_exec
, NULL
, &hooks
);
3221 lttv_trace_find_hook(ts
->parent
.t
,
3222 LTT_FACILITY_USER_GENERIC
,
3223 LTT_EVENT_THREAD_BRAND
,
3224 FIELD_ARRAY(LTT_FIELD_NAME
),
3225 thread_brand
, NULL
, &hooks
);
3227 /* statedump-related hooks */
3228 lttv_trace_find_hook(ts
->parent
.t
,
3230 LTT_EVENT_PROCESS_STATE
,
3231 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3232 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3233 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3234 enum_process_state
, NULL
, &hooks
);
3236 lttv_trace_find_hook(ts
->parent
.t
,
3238 LTT_EVENT_STATEDUMP_END
,
3240 statedump_end
, NULL
, &hooks
);
3242 lttv_trace_find_hook(ts
->parent
.t
,
3244 LTT_EVENT_LIST_INTERRUPT
,
3245 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3246 enum_interrupt
, NULL
, &hooks
);
3248 lttv_trace_find_hook(ts
->parent
.t
,
3250 LTT_EVENT_REQUEST_ISSUE
,
3251 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3252 bdev_request_issue
, NULL
, &hooks
);
3254 lttv_trace_find_hook(ts
->parent
.t
,
3256 LTT_EVENT_REQUEST_COMPLETE
,
3257 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3258 bdev_request_complete
, NULL
, &hooks
);
3260 lttv_trace_find_hook(ts
->parent
.t
,
3261 LTT_FACILITY_USER_GENERIC
,
3262 LTT_EVENT_FUNCTION_ENTRY
,
3263 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3264 function_entry
, NULL
, &hooks
);
3266 lttv_trace_find_hook(ts
->parent
.t
,
3267 LTT_FACILITY_USER_GENERIC
,
3268 LTT_EVENT_FUNCTION_EXIT
,
3269 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3270 function_exit
, NULL
, &hooks
);
3272 /* Add these hooks to each event_by_id hooks list */
3274 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3276 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3278 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3279 LttvTracefileContext
*, j
));
3281 for(k
= 0 ; k
< hooks
->len
; k
++) {
3282 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3284 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3290 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3291 *(val
.v_pointer
) = hooks
;
3295 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3297 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3299 lttv_state_remove_event_hooks(tss
);
3304 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3306 LttvTraceset
*traceset
= self
->parent
.ts
;
3308 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3312 LttvTracefileState
*tfs
;
3318 LttvAttributeValue val
;
3320 nb_trace
= lttv_traceset_number(traceset
);
3321 for(i
= 0 ; i
< nb_trace
; i
++) {
3322 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3324 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3325 hooks
= *(val
.v_pointer
);
3327 /* Remove these hooks from each event_by_id hooks list */
3329 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3331 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3333 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3334 LttvTracefileContext
*, j
));
3336 for(k
= 0 ; k
< hooks
->len
; k
++) {
3337 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3338 lttv_hooks_remove_data(
3339 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3344 lttv_trace_hook_remove_all(&hooks
);
3345 g_array_free(hooks
, TRUE
);
3349 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3351 guint
*event_count
= (guint
*)hook_data
;
3353 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3354 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3359 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3361 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3363 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3365 LttvAttributeValue value
;
3367 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3368 LTTV_STATE_SAVED_STATES
);
3369 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3370 value
= lttv_attribute_add(saved_states_tree
,
3371 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3372 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3373 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3374 *(value
.v_time
) = self
->parent
.timestamp
;
3375 lttv_state_save(tcs
, saved_state_tree
);
3376 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3377 self
->parent
.timestamp
.tv_nsec
);
3379 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3384 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3386 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3388 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3393 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3401 static gboolean
block_start(void *hook_data
, void *call_data
)
3403 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3405 LttvTracefileState
*tfcs
;
3407 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3409 LttEventPosition
*ep
;
3411 guint i
, nb_block
, nb_event
, nb_tracefile
;
3415 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3417 LttvAttributeValue value
;
3419 ep
= ltt_event_position_new();
3421 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3423 /* Count the number of events added since the last block end in any
3426 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3428 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3429 LttvTracefileContext
, i
));
3430 ltt_event_position(tfcs
->parent
.e
, ep
);
3431 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3432 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3433 tfcs
->saved_position
= nb_event
;
3437 if(tcs
->nb_event
>= tcs
->save_interval
) {
3438 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3439 LTTV_STATE_SAVED_STATES
);
3440 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3441 value
= lttv_attribute_add(saved_states_tree
,
3442 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3443 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3444 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3445 *(value
.v_time
) = self
->parent
.timestamp
;
3446 lttv_state_save(tcs
, saved_state_tree
);
3448 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3449 self
->parent
.timestamp
.tv_nsec
);
3451 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3457 static gboolean
block_end(void *hook_data
, void *call_data
)
3459 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3461 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3465 LttEventPosition
*ep
;
3467 guint nb_block
, nb_event
;
3469 ep
= ltt_event_position_new();
3470 ltt_event_position(self
->parent
.e
, ep
);
3471 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3472 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3473 self
->saved_position
= 0;
3474 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3481 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3483 LttvTraceset
*traceset
= self
->parent
.ts
;
3485 guint i
, j
, nb_trace
, nb_tracefile
;
3489 LttvTracefileState
*tfs
;
3491 LttvTraceHook hook_start
, hook_end
;
3493 nb_trace
= lttv_traceset_number(traceset
);
3494 for(i
= 0 ; i
< nb_trace
; i
++) {
3495 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3497 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3498 NULL
, NULL
, block_start
, &hook_start
);
3499 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3500 NULL
, NULL
, block_end
, &hook_end
);
3502 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3504 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3506 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3507 LttvTracefileContext
, j
));
3508 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3509 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3510 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3511 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3517 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3519 LttvTraceset
*traceset
= self
->parent
.ts
;
3521 guint i
, j
, nb_trace
, nb_tracefile
;
3525 LttvTracefileState
*tfs
;
3528 nb_trace
= lttv_traceset_number(traceset
);
3529 for(i
= 0 ; i
< nb_trace
; i
++) {
3531 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3532 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3534 if(ts
->has_precomputed_states
) continue;
3536 guint
*event_count
= g_new(guint
, 1);
3539 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3541 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3542 LttvTracefileContext
*, j
));
3543 lttv_hooks_add(tfs
->parent
.event
,
3544 state_save_event_hook
,
3551 lttv_process_traceset_begin(&self
->parent
,
3552 NULL
, NULL
, NULL
, NULL
, NULL
);
3556 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3558 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3560 lttv_state_save_add_event_hooks(tss
);
3567 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3569 LttvTraceset
*traceset
= self
->parent
.ts
;
3571 guint i
, j
, nb_trace
, nb_tracefile
;
3575 LttvTracefileState
*tfs
;
3577 LttvTraceHook hook_start
, hook_end
;
3579 nb_trace
= lttv_traceset_number(traceset
);
3580 for(i
= 0 ; i
< nb_trace
; i
++) {
3581 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3583 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3584 NULL
, NULL
, block_start
, &hook_start
);
3586 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3587 NULL
, NULL
, block_end
, &hook_end
);
3589 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3591 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3593 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3594 LttvTracefileContext
, j
));
3595 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3596 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3597 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3598 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3604 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3606 LttvTraceset
*traceset
= self
->parent
.ts
;
3608 guint i
, j
, nb_trace
, nb_tracefile
;
3612 LttvTracefileState
*tfs
;
3614 LttvHooks
*after_trace
= lttv_hooks_new();
3616 lttv_hooks_add(after_trace
,
3617 state_save_after_trace_hook
,
3622 lttv_process_traceset_end(&self
->parent
,
3623 NULL
, after_trace
, NULL
, NULL
, NULL
);
3625 lttv_hooks_destroy(after_trace
);
3627 nb_trace
= lttv_traceset_number(traceset
);
3628 for(i
= 0 ; i
< nb_trace
; i
++) {
3630 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3631 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3633 if(ts
->has_precomputed_states
) continue;
3635 guint
*event_count
= NULL
;
3637 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3639 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3640 LttvTracefileContext
*, j
));
3641 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3642 state_save_event_hook
);
3644 if(event_count
) g_free(event_count
);
3648 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3650 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3652 lttv_state_save_remove_event_hooks(tss
);
3657 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3659 LttvTraceset
*traceset
= self
->parent
.ts
;
3663 int min_pos
, mid_pos
, max_pos
;
3665 guint call_rest
= 0;
3667 LttvTraceState
*tcs
;
3669 LttvAttributeValue value
;
3671 LttvAttributeType type
;
3673 LttvAttributeName name
;
3677 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3679 //g_tree_destroy(self->parent.pqueue);
3680 //self->parent.pqueue = g_tree_new(compare_tracefile);
3682 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3684 nb_trace
= lttv_traceset_number(traceset
);
3685 for(i
= 0 ; i
< nb_trace
; i
++) {
3686 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3688 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3689 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3690 LTTV_STATE_SAVED_STATES
);
3693 if(saved_states_tree
) {
3694 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3695 mid_pos
= max_pos
/ 2;
3696 while(min_pos
< max_pos
) {
3697 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3699 g_assert(type
== LTTV_GOBJECT
);
3700 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3701 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3703 g_assert(type
== LTTV_TIME
);
3704 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3706 closest_tree
= saved_state_tree
;
3708 else max_pos
= mid_pos
- 1;
3710 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3714 /* restore the closest earlier saved state */
3716 lttv_state_restore(tcs
, closest_tree
);
3720 /* There is no saved state, yet we want to have it. Restart at T0 */
3722 restore_init_state(tcs
);
3723 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3726 /* We want to seek quickly without restoring/updating the state */
3728 restore_init_state(tcs
);
3729 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3732 if(!call_rest
) g_info("NOT Calling restore");
3737 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3743 traceset_state_finalize (LttvTracesetState
*self
)
3745 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3746 finalize(G_OBJECT(self
));
3751 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3753 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3755 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3756 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3757 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3758 klass
->new_traceset_context
= new_traceset_context
;
3759 klass
->new_trace_context
= new_trace_context
;
3760 klass
->new_tracefile_context
= new_tracefile_context
;
3765 lttv_traceset_state_get_type(void)
3767 static GType type
= 0;
3769 static const GTypeInfo info
= {
3770 sizeof (LttvTracesetStateClass
),
3771 NULL
, /* base_init */
3772 NULL
, /* base_finalize */
3773 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3774 NULL
, /* class_finalize */
3775 NULL
, /* class_data */
3776 sizeof (LttvTracesetState
),
3777 0, /* n_preallocs */
3778 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3779 NULL
/* value handling */
3782 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3790 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3796 trace_state_finalize (LttvTraceState
*self
)
3798 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3799 finalize(G_OBJECT(self
));
3804 trace_state_class_init (LttvTraceStateClass
*klass
)
3806 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3808 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3809 klass
->state_save
= state_save
;
3810 klass
->state_restore
= state_restore
;
3811 klass
->state_saved_free
= state_saved_free
;
3816 lttv_trace_state_get_type(void)
3818 static GType type
= 0;
3820 static const GTypeInfo info
= {
3821 sizeof (LttvTraceStateClass
),
3822 NULL
, /* base_init */
3823 NULL
, /* base_finalize */
3824 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3825 NULL
, /* class_finalize */
3826 NULL
, /* class_data */
3827 sizeof (LttvTraceState
),
3828 0, /* n_preallocs */
3829 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3830 NULL
/* value handling */
3833 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3834 "LttvTraceStateType", &info
, 0);
3841 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3847 tracefile_state_finalize (LttvTracefileState
*self
)
3849 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3850 finalize(G_OBJECT(self
));
3855 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3857 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3859 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3864 lttv_tracefile_state_get_type(void)
3866 static GType type
= 0;
3868 static const GTypeInfo info
= {
3869 sizeof (LttvTracefileStateClass
),
3870 NULL
, /* base_init */
3871 NULL
, /* base_finalize */
3872 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3873 NULL
, /* class_finalize */
3874 NULL
, /* class_data */
3875 sizeof (LttvTracefileState
),
3876 0, /* n_preallocs */
3877 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3878 NULL
/* value handling */
3881 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3882 "LttvTracefileStateType", &info
, 0);
3888 static void module_init()
3890 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3891 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3892 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3893 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3894 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3895 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3896 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3897 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3898 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3899 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3900 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3901 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3902 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3903 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3904 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3905 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3906 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3907 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3908 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3909 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3910 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3911 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3912 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3913 LTTV_STATE_EVENT
= g_quark_from_string("event");
3914 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3915 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3916 LTTV_STATE_TIME
= g_quark_from_string("time");
3917 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3918 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3919 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3920 g_quark_from_string("trace_state_use_count");
3921 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3922 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
3923 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3924 LTTV_STATE_RESOURCE_SOFT_IRQS
= g_quark_from_string("soft irq resource states");
3925 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3928 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3929 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3930 LTT_FACILITY_FS
= g_quark_from_string("fs");
3931 LTT_FACILITY_LIST
= g_quark_from_string("list");
3932 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3933 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3936 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3937 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3938 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3939 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3940 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3941 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3942 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3943 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3944 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3945 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3946 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3947 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3948 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3949 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3950 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3951 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3952 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3953 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3954 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3955 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3956 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3957 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3960 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3961 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3962 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3963 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3964 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3965 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3966 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3967 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3968 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3969 LTT_FIELD_PID
= g_quark_from_string("pid");
3970 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3971 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3972 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3973 LTT_FIELD_NAME
= g_quark_from_string("name");
3974 LTT_FIELD_TYPE
= g_quark_from_string("type");
3975 LTT_FIELD_MODE
= g_quark_from_string("mode");
3976 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3977 LTT_FIELD_STATUS
= g_quark_from_string("status");
3978 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3979 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3980 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3981 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3982 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3983 LTT_FIELD_ACTION
= g_quark_from_string("action");
3985 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3986 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3987 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3988 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3989 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3991 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3992 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3993 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3995 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3996 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3997 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3998 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
4001 static void module_destroy()
4006 LTTV_MODULE("state", "State computation", \
4007 "Update the system state, possibly saving it at intervals", \
4008 module_init
, module_destroy
)