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_BLKDEVS
;
175 static void create_max_time(LttvTraceState
*tcs
);
177 static void get_max_time(LttvTraceState
*tcs
);
179 static void free_max_time(LttvTraceState
*tcs
);
181 static void create_name_tables(LttvTraceState
*tcs
);
183 static void get_name_tables(LttvTraceState
*tcs
);
185 static void free_name_tables(LttvTraceState
*tcs
);
187 static void free_saved_state(LttvTraceState
*tcs
);
189 static void lttv_state_free_process_table(GHashTable
*processes
);
191 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
192 GPtrArray
*quarktable
);
194 /* Resource function prototypes */
195 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
196 static LttvBdevState
*bdevstate_new(void);
197 static void bdevstate_free(LttvBdevState
*);
198 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
199 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
202 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
204 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
208 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
210 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
214 void lttv_state_state_saved_free(LttvTraceState
*self
,
215 LttvAttribute
*container
)
217 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
221 guint
process_hash(gconstpointer key
)
223 guint pid
= ((const LttvProcessState
*)key
)->pid
;
224 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
228 /* If the hash table hash function is well distributed,
229 * the process_equal should compare different pid */
230 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
232 const LttvProcessState
*process_a
, *process_b
;
235 process_a
= (const LttvProcessState
*)a
;
236 process_b
= (const LttvProcessState
*)b
;
238 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
239 else if(likely(process_a
->pid
== 0 &&
240 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
245 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
247 g_tree_destroy((GTree
*)value
);
250 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
252 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
253 g_hash_table_destroy(usertraces
);
256 gboolean
rettrue(gpointer key
, gpointer value
, gpointer user_data
)
262 restore_init_state(LttvTraceState
*self
)
264 guint i
, nb_cpus
, nb_irqs
;
266 //LttvTracefileState *tfcs;
268 LttTime start_time
, end_time
;
270 /* Free the process tables */
271 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
272 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
273 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
274 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
277 /* Seek time to beginning */
278 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
279 // closest. It's the tracecontext job to seek the trace to the beginning
280 // anyway : the init state might be used at the middle of the trace as well...
281 //g_tree_destroy(self->parent.ts_context->pqueue);
282 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
284 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
286 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
288 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
289 nb_irqs
= self
->nb_irqs
;
291 /* Put the per cpu running_process to beginning state : process 0. */
292 for(i
=0; i
< nb_cpus
; i
++) {
293 LttvExecutionState
*es
;
294 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
295 LTTV_STATE_UNNAMED
, &start_time
);
296 /* We are not sure is it's a kernel thread or normal thread, put the
297 * bottom stack state to unknown */
298 self
->running_process
[i
]->execution_stack
=
299 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
300 es
= self
->running_process
[i
]->state
=
301 &g_array_index(self
->running_process
[i
]->execution_stack
,
302 LttvExecutionState
, 0);
303 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
304 es
->s
= LTTV_STATE_UNNAMED
;
306 //self->running_process[i]->state->s = LTTV_STATE_RUN;
307 self
->running_process
[i
]->cpu
= i
;
309 /* reset cpu states */
310 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
311 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
314 /* reset irq states */
315 for(i
=0; i
<nb_irqs
; i
++) {
316 if(self
->irq_states
[i
].mode_stack
->len
> 0)
317 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
320 /* reset bdev states */
321 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
322 //g_hash_table_steal_all(self->bdev_states);
323 g_hash_table_foreach_steal(self
->bdev_states
, rettrue
, NULL
);
326 nb_tracefile
= self
->parent
.tracefiles
->len
;
328 for(i
= 0 ; i
< nb_tracefile
; i
++) {
330 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
331 LttvTracefileContext
*, i
));
332 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
333 // tfcs->saved_position = 0;
334 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
335 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
336 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
337 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
342 //static LttTime time_zero = {0,0};
344 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
347 const LttTime
*t1
= (const LttTime
*)a
;
348 const LttTime
*t2
= (const LttTime
*)b
;
350 return ltt_time_compare(*t1
, *t2
);
353 static void free_usertrace_key(gpointer data
)
358 #define MAX_STRING_LEN 4096
361 state_load_saved_states(LttvTraceState
*tcs
)
364 GPtrArray
*quarktable
;
365 const char *trace_path
;
369 tcs
->has_precomputed_states
= FALSE
;
373 gchar buf
[MAX_STRING_LEN
];
376 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
377 strncpy(path
, trace_path
, PATH_MAX
-1);
378 count
= strnlen(trace_path
, PATH_MAX
-1);
379 // quarktable : open, test
380 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
381 fp
= fopen(path
, "r");
383 quarktable
= g_ptr_array_sized_new(4096);
385 /* Index 0 is null */
387 if(hdr
== EOF
) return;
388 g_assert(hdr
== HDR_QUARKS
);
392 if(hdr
== EOF
) break;
393 g_assert(hdr
== HDR_QUARK
);
394 g_ptr_array_set_size(quarktable
, q
+1);
397 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
398 if(buf
[i
] == '\0' || feof(fp
)) break;
401 len
= strnlen(buf
, MAX_STRING_LEN
-1);
402 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
403 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
409 // saved_states : open, test
410 strncpy(path
, trace_path
, PATH_MAX
-1);
411 count
= strnlen(trace_path
, PATH_MAX
-1);
412 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
413 fp
= fopen(path
, "r");
417 if(hdr
!= HDR_TRACE
) goto end
;
419 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
421 tcs
->has_precomputed_states
= TRUE
;
426 /* Free the quarktable */
427 for(i
=0; i
<quarktable
->len
; i
++) {
428 string
= g_ptr_array_index (quarktable
, i
);
431 g_ptr_array_free(quarktable
, TRUE
);
436 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
438 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
441 LttvTraceContext
*tc
;
445 LttvTracefileState
*tfcs
;
447 LttvAttributeValue v
;
449 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
450 init((LttvTracesetContext
*)self
, ts
);
452 nb_trace
= lttv_traceset_number(ts
);
453 for(i
= 0 ; i
< nb_trace
; i
++) {
454 tc
= self
->parent
.traces
[i
];
455 tcs
= LTTV_TRACE_STATE(tc
);
456 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
457 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
461 if(*(v
.v_uint
) == 1) {
462 create_name_tables(tcs
);
463 create_max_time(tcs
);
465 get_name_tables(tcs
);
468 nb_tracefile
= tc
->tracefiles
->len
;
469 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
470 nb_irq
= tcs
->nb_irqs
;
471 tcs
->processes
= NULL
;
472 tcs
->usertraces
= NULL
;
473 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
475 /* init cpu resource stuff */
476 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
477 for(j
= 0; j
<nb_cpu
; j
++) {
478 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
479 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
482 /* init irq resource stuff */
483 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
484 for(j
= 0; j
<nb_irq
; j
++) {
485 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
486 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
489 /* init bdev resource stuff */
490 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
492 restore_init_state(tcs
);
493 for(j
= 0 ; j
< nb_tracefile
; j
++) {
495 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
496 LttvTracefileContext
*, j
));
497 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
498 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
499 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
500 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
501 /* It's a Usertrace */
502 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
503 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
505 if(!usertrace_tree
) {
506 usertrace_tree
= g_tree_new_full(compare_usertraces
,
507 NULL
, free_usertrace_key
, NULL
);
508 g_hash_table_insert(tcs
->usertraces
,
509 (gpointer
)tid
, usertrace_tree
);
511 LttTime
*timestamp
= g_new(LttTime
, 1);
512 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
513 ltt_tracefile_creation(tfcs
->parent
.tf
));
514 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
518 /* See if the trace has saved states */
519 state_load_saved_states(tcs
);
524 fini(LttvTracesetState
*self
)
530 //LttvTracefileState *tfcs;
532 LttvAttributeValue v
;
534 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
535 for(i
= 0 ; i
< nb_trace
; i
++) {
536 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
537 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
540 g_assert(*(v
.v_uint
) != 0);
543 if(*(v
.v_uint
) == 0) {
544 free_name_tables(tcs
);
546 free_saved_state(tcs
);
548 g_free(tcs
->running_process
);
549 tcs
->running_process
= NULL
;
550 lttv_state_free_process_table(tcs
->processes
);
551 lttv_state_free_usertraces(tcs
->usertraces
);
552 tcs
->processes
= NULL
;
553 tcs
->usertraces
= NULL
;
555 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
556 fini((LttvTracesetContext
*)self
);
560 static LttvTracesetContext
*
561 new_traceset_context(LttvTracesetContext
*self
)
563 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
567 static LttvTraceContext
*
568 new_trace_context(LttvTracesetContext
*self
)
570 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
574 static LttvTracefileContext
*
575 new_tracefile_context(LttvTracesetContext
*self
)
577 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
581 /* Write the process state of the trace */
583 static void write_process_state(gpointer key
, gpointer value
,
586 LttvProcessState
*process
;
588 LttvExecutionState
*es
;
590 FILE *fp
= (FILE *)user_data
;
595 process
= (LttvProcessState
*)value
;
597 " <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",
598 process
, process
->pid
, process
->tgid
, process
->ppid
,
599 g_quark_to_string(process
->type
),
600 process
->creation_time
.tv_sec
,
601 process
->creation_time
.tv_nsec
,
602 process
->insertion_time
.tv_sec
,
603 process
->insertion_time
.tv_nsec
,
604 g_quark_to_string(process
->name
),
605 g_quark_to_string(process
->brand
),
608 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
609 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
610 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
611 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
612 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
613 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
614 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
617 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
618 address
= g_array_index(process
->user_stack
, guint64
, i
);
619 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
623 if(process
->usertrace
) {
624 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
625 g_quark_to_string(process
->usertrace
->tracefile_name
),
626 process
->usertrace
->cpu
);
630 fprintf(fp
, " </PROCESS>\n");
634 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
636 guint i
, nb_tracefile
, nb_block
, offset
;
639 LttvTracefileState
*tfcs
;
643 LttEventPosition
*ep
;
647 ep
= ltt_event_position_new();
649 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
651 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
653 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
654 for(i
=0;i
<nb_cpus
;i
++) {
655 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
656 i
, self
->running_process
[i
]->pid
);
659 nb_tracefile
= self
->parent
.tracefiles
->len
;
661 for(i
= 0 ; i
< nb_tracefile
; i
++) {
663 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
664 LttvTracefileContext
*, i
));
665 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
666 tfcs
->parent
.timestamp
.tv_sec
,
667 tfcs
->parent
.timestamp
.tv_nsec
);
668 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
669 if(e
== NULL
) fprintf(fp
,"/>\n");
671 ltt_event_position(e
, ep
);
672 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
673 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
678 fprintf(fp
,"</PROCESS_STATE>\n");
682 static void write_process_state_raw(gpointer key
, gpointer value
,
685 LttvProcessState
*process
;
687 LttvExecutionState
*es
;
689 FILE *fp
= (FILE *)user_data
;
694 process
= (LttvProcessState
*)value
;
695 fputc(HDR_PROCESS
, fp
);
696 //fwrite(&header, sizeof(header), 1, fp);
697 //fprintf(fp, "%s", g_quark_to_string(process->type));
699 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
700 //fprintf(fp, "%s", g_quark_to_string(process->name));
702 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
703 //fprintf(fp, "%s", g_quark_to_string(process->brand));
705 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
706 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
707 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
708 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
709 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
710 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
711 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
715 " <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",
716 process
, process
->pid
, process
->tgid
, process
->ppid
,
717 g_quark_to_string(process
->type
),
718 process
->creation_time
.tv_sec
,
719 process
->creation_time
.tv_nsec
,
720 process
->insertion_time
.tv_sec
,
721 process
->insertion_time
.tv_nsec
,
722 g_quark_to_string(process
->name
),
723 g_quark_to_string(process
->brand
),
727 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
728 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
731 //fprintf(fp, "%s", g_quark_to_string(es->t));
733 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
734 //fprintf(fp, "%s", g_quark_to_string(es->n));
736 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
737 //fprintf(fp, "%s", g_quark_to_string(es->s));
739 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
740 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
741 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
742 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
744 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
745 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
746 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
747 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
748 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
752 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
753 address
= g_array_index(process
->user_stack
, guint64
, i
);
754 fputc(HDR_USER_STACK
, fp
);
755 fwrite(&address
, sizeof(address
), 1, fp
);
757 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
762 if(process
->usertrace
) {
763 fputc(HDR_USERTRACE
, fp
);
764 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
766 fwrite(&process
->usertrace
->tracefile_name
,
767 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
768 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
770 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
771 g_quark_to_string(process
->usertrace
->tracefile_name
),
772 process
->usertrace
->cpu
);
779 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
781 guint i
, nb_tracefile
, nb_block
, offset
;
784 LttvTracefileState
*tfcs
;
788 LttEventPosition
*ep
;
792 ep
= ltt_event_position_new();
794 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
795 fputc(HDR_PROCESS_STATE
, fp
);
796 fwrite(&t
, sizeof(t
), 1, fp
);
798 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
800 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
801 for(i
=0;i
<nb_cpus
;i
++) {
803 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
804 fwrite(&self
->running_process
[i
]->pid
,
805 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
806 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
807 // i, self->running_process[i]->pid);
810 nb_tracefile
= self
->parent
.tracefiles
->len
;
812 for(i
= 0 ; i
< nb_tracefile
; i
++) {
814 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
815 LttvTracefileContext
*, i
));
816 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
817 // tfcs->parent.timestamp.tv_sec,
818 // tfcs->parent.timestamp.tv_nsec);
819 fputc(HDR_TRACEFILE
, fp
);
820 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
821 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
822 * position following : end of trace */
823 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
825 ltt_event_position(e
, ep
);
826 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
827 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
829 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
830 fwrite(&offset
, sizeof(offset
), 1, fp
);
831 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
838 /* Read process state from a file */
840 /* Called because a HDR_PROCESS was found */
841 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
842 GPtrArray
*quarktable
)
844 LttvExecutionState
*es
;
845 LttvProcessState
*process
, *parent_process
;
846 LttvProcessState tmp
;
851 /* TODO : check return value */
852 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
853 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
854 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
855 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
856 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
857 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
858 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
859 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
860 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
863 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
865 /* We must link to the parent */
866 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
868 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
869 if(process
== NULL
) {
870 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
872 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
876 process
->insertion_time
= tmp
.insertion_time
;
877 process
->creation_time
= tmp
.creation_time
;
878 process
->type
= g_quark_from_string(
879 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
880 process
->tgid
= tmp
.tgid
;
881 process
->ppid
= tmp
.ppid
;
882 process
->brand
= g_quark_from_string(
883 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
885 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
889 if(feof(fp
) || ferror(fp
)) goto end_loop
;
891 gint hdr
= fgetc(fp
);
892 if(hdr
== EOF
) goto end_loop
;
896 process
->execution_stack
=
897 g_array_set_size(process
->execution_stack
,
898 process
->execution_stack
->len
+ 1);
899 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
900 process
->execution_stack
->len
-1);
903 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
904 es
->t
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
906 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
907 es
->n
= g_quark_from_string(
908 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
909 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
910 es
->s
= g_quark_from_string(
911 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
912 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
913 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
914 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
917 process
->user_stack
= g_array_set_size(process
->user_stack
,
918 process
->user_stack
->len
+ 1);
919 address
= &g_array_index(process
->user_stack
, guint64
,
920 process
->user_stack
->len
-1);
921 fread(address
, sizeof(address
), 1, fp
);
922 process
->current_function
= *address
;
925 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
926 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
938 /* Called because a HDR_PROCESS_STATE was found */
939 /* Append a saved state to the trace states */
940 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
942 guint i
, nb_tracefile
, nb_block
, offset
;
944 LttvTracefileState
*tfcs
;
946 LttEventPosition
*ep
;
954 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
956 LttvAttributeValue value
;
957 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
958 ep
= ltt_event_position_new();
960 restore_init_state(self
);
962 fread(&t
, sizeof(t
), 1, fp
);
965 if(feof(fp
) || ferror(fp
)) goto end_loop
;
967 if(hdr
== EOF
) goto end_loop
;
971 /* Call read_process_state_raw */
972 read_process_state_raw(self
, fp
, quarktable
);
982 case HDR_PROCESS_STATE
:
988 g_error("Error while parsing saved state file : unknown data header %d",
994 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
995 for(i
=0;i
<nb_cpus
;i
++) {
998 g_assert(hdr
== HDR_CPU
);
999 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1000 g_assert(i
== cpu_num
);
1001 fread(&self
->running_process
[i
]->pid
,
1002 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1005 nb_tracefile
= self
->parent
.tracefiles
->len
;
1007 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1009 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1010 LttvTracefileContext
*, i
));
1011 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1012 // tfcs->parent.timestamp.tv_sec,
1013 // tfcs->parent.timestamp.tv_nsec);
1014 g_tree_remove(pqueue
, &tfcs
->parent
);
1016 g_assert(hdr
== HDR_TRACEFILE
);
1017 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1018 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1019 * position following : end of trace */
1020 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1021 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1022 fread(&offset
, sizeof(offset
), 1, fp
);
1023 fread(&tsc
, sizeof(tsc
), 1, fp
);
1024 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1025 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1027 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1032 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1033 LTTV_STATE_SAVED_STATES
);
1034 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1035 value
= lttv_attribute_add(saved_states_tree
,
1036 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1037 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1038 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1039 *(value
.v_time
) = t
;
1040 lttv_state_save(self
, saved_state_tree
);
1041 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1044 *(self
->max_time_state_recomputed_in_seek
) = t
;
1048 /* Called when a HDR_TRACE is found */
1049 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1050 GPtrArray
*quarktable
)
1055 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1057 if(hdr
== EOF
) goto end_loop
;
1060 case HDR_PROCESS_STATE
:
1061 /* Call read_process_state_raw */
1062 lttv_state_read_raw(tcs
, fp
, quarktable
);
1070 case HDR_USER_STACK
:
1074 g_error("Error while parsing saved state file :"
1075 " unexpected data header %d",
1079 g_error("Error while parsing saved state file : unknown data header %d",
1084 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1085 restore_init_state(tcs
);
1086 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1092 /* Copy each process from an existing hash table to a new one */
1094 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1096 LttvProcessState
*process
, *new_process
;
1098 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1102 process
= (LttvProcessState
*)value
;
1103 new_process
= g_new(LttvProcessState
, 1);
1104 *new_process
= *process
;
1105 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1106 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1107 new_process
->execution_stack
=
1108 g_array_set_size(new_process
->execution_stack
,
1109 process
->execution_stack
->len
);
1110 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1111 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1112 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1114 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1115 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1116 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1117 sizeof(guint64
), 0);
1118 new_process
->user_stack
=
1119 g_array_set_size(new_process
->user_stack
,
1120 process
->user_stack
->len
);
1121 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1122 g_array_index(new_process
->user_stack
, guint64
, i
) =
1123 g_array_index(process
->user_stack
, guint64
, i
);
1125 new_process
->current_function
= process
->current_function
;
1126 g_hash_table_insert(new_processes
, new_process
, new_process
);
1130 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1132 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1134 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1135 return new_processes
;
1138 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1141 LttvCPUState
*retval
;
1143 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1145 for(i
=0; i
<n
; i
++) {
1146 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1147 retval
[i
].last_irq
= states
[i
].last_irq
;
1148 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1149 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1150 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1157 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1161 for(i
=0; i
<n
; i
++) {
1162 g_array_free(states
[i
].mode_stack
, TRUE
);
1168 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1171 LttvIRQState
*retval
;
1173 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1175 for(i
=0; i
<n
; i
++) {
1176 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1177 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1178 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1179 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1186 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1190 for(i
=0; i
<n
; i
++) {
1191 g_array_free(states
[i
].mode_stack
, TRUE
);
1197 /* bdevstate stuff */
1199 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1201 gint devcode_gint
= devcode
;
1202 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1204 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1205 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1207 gint
* key
= g_malloc(sizeof(gint
));
1209 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1217 static LttvBdevState
*bdevstate_new(void)
1219 LttvBdevState
*retval
;
1220 retval
= g_malloc(sizeof(LttvBdevState
));
1221 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1226 static void bdevstate_free(LttvBdevState
*bds
)
1228 g_array_free(bds
->mode_stack
, TRUE
);
1232 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1234 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1236 bdevstate_free(bds
);
1239 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1241 LttvBdevState
*retval
;
1243 retval
= bdevstate_new();
1244 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1249 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1251 //GHashTable *ht = (GHashTable *)u;
1252 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1253 LttvBdevState
*newbds
;
1255 newbds
= bdevstate_copy(bds
);
1257 g_hash_table_insert(u
, k
, newbds
);
1260 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1264 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1266 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1271 /* Free a hashtable and the LttvBdevState structures its values
1274 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1276 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1277 g_hash_table_destroy(ht
);
1280 /* The saved state for each trace contains a member "processes", which
1281 stores a copy of the process table, and a member "tracefiles" with
1282 one entry per tracefile. Each tracefile has a "process" member pointing
1283 to the current process and a "position" member storing the tracefile
1284 position (needed to seek to the current "next" event. */
1286 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1288 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1290 LttvTracefileState
*tfcs
;
1292 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1294 guint
*running_process
;
1296 LttvAttributeValue value
;
1298 LttEventPosition
*ep
;
1300 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1301 LTTV_STATE_TRACEFILES
);
1303 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1305 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1307 /* Add the currently running processes array */
1308 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1309 running_process
= g_new(guint
, nb_cpus
);
1310 for(i
=0;i
<nb_cpus
;i
++) {
1311 running_process
[i
] = self
->running_process
[i
]->pid
;
1313 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1315 *(value
.v_pointer
) = running_process
;
1317 g_info("State save");
1319 nb_tracefile
= self
->parent
.tracefiles
->len
;
1321 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1323 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1324 LttvTracefileContext
*, i
));
1325 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1326 value
= lttv_attribute_add(tracefiles_tree
, i
,
1328 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1330 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1332 *(value
.v_uint
) = tfcs
->process
->pid
;
1334 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1336 /* Only save the position if the tfs has not infinite time. */
1337 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1338 // && current_tfcs != tfcs) {
1339 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1340 *(value
.v_pointer
) = NULL
;
1342 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1343 ep
= ltt_event_position_new();
1344 ltt_event_position(e
, ep
);
1345 *(value
.v_pointer
) = ep
;
1347 guint nb_block
, offset
;
1350 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1351 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1353 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1357 /* save the cpu state */
1359 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1361 *(value
.v_uint
) = nb_cpus
;
1363 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1365 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1368 /* save the irq state */
1369 nb_irqs
= self
->nb_irqs
;
1371 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1373 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1376 /* save the blkdev states */
1377 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1379 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1383 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1385 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1387 LttvTracefileState
*tfcs
;
1389 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1391 guint
*running_process
;
1393 LttvAttributeType type
;
1395 LttvAttributeValue value
;
1397 LttvAttributeName name
;
1401 LttEventPosition
*ep
;
1403 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1405 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1406 LTTV_STATE_TRACEFILES
);
1408 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1410 g_assert(type
== LTTV_POINTER
);
1411 lttv_state_free_process_table(self
->processes
);
1412 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1414 /* Add the currently running processes array */
1415 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1416 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1418 g_assert(type
== LTTV_POINTER
);
1419 running_process
= *(value
.v_pointer
);
1420 for(i
=0;i
<nb_cpus
;i
++) {
1421 pid
= running_process
[i
];
1422 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1423 g_assert(self
->running_process
[i
] != NULL
);
1426 nb_tracefile
= self
->parent
.tracefiles
->len
;
1428 //g_tree_destroy(tsc->pqueue);
1429 //tsc->pqueue = g_tree_new(compare_tracefile);
1431 /* restore cpu resource states */
1432 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1433 g_assert(type
== LTTV_POINTER
);
1434 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1435 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1437 /* restore irq resource states */
1438 nb_irqs
= self
->nb_irqs
;
1439 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1440 g_assert(type
== LTTV_POINTER
);
1441 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1442 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1444 /* restore the blkdev states */
1445 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1446 g_assert(type
== LTTV_POINTER
);
1447 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1448 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1450 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1452 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1453 LttvTracefileContext
*, i
));
1454 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1455 g_assert(type
== LTTV_GOBJECT
);
1456 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1458 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1460 g_assert(type
== LTTV_UINT
);
1461 pid
= *(value
.v_uint
);
1462 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1464 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1466 g_assert(type
== LTTV_POINTER
);
1467 //g_assert(*(value.v_pointer) != NULL);
1468 ep
= *(value
.v_pointer
);
1469 g_assert(tfcs
->parent
.t_context
!= NULL
);
1471 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1473 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1474 g_tree_remove(tsc
->pqueue
, tfc
);
1477 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1478 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1479 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1480 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1481 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1483 tfc
->timestamp
= ltt_time_infinite
;
1489 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1491 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1493 LttvTracefileState
*tfcs
;
1495 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1497 guint
*running_process
;
1499 LttvAttributeType type
;
1501 LttvAttributeValue value
;
1503 LttvAttributeName name
;
1507 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1508 LTTV_STATE_TRACEFILES
);
1509 g_object_ref(G_OBJECT(tracefiles_tree
));
1510 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1512 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1514 g_assert(type
== LTTV_POINTER
);
1515 lttv_state_free_process_table(*(value
.v_pointer
));
1516 *(value
.v_pointer
) = NULL
;
1517 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1519 /* Free running processes array */
1520 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1522 g_assert(type
== LTTV_POINTER
);
1523 running_process
= *(value
.v_pointer
);
1524 g_free(running_process
);
1526 /* free cpu resource states */
1527 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1528 g_assert(type
== LTTV_UINT
);
1529 nb_cpus
= *value
.v_uint
;
1530 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1531 g_assert(type
== LTTV_POINTER
);
1532 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1534 /* free irq resource states */
1535 nb_irqs
= self
->nb_irqs
;
1536 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1537 g_assert(type
== LTTV_POINTER
);
1538 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1540 /* free the blkdev states */
1541 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1542 g_assert(type
== LTTV_POINTER
);
1543 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1545 nb_tracefile
= self
->parent
.tracefiles
->len
;
1547 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1549 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1550 LttvTracefileContext
*, i
));
1551 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1552 g_assert(type
== LTTV_GOBJECT
);
1553 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1555 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1557 g_assert(type
== LTTV_POINTER
);
1558 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1560 g_object_unref(G_OBJECT(tracefiles_tree
));
1564 static void free_saved_state(LttvTraceState
*self
)
1568 LttvAttributeType type
;
1570 LttvAttributeValue value
;
1572 LttvAttributeName name
;
1576 LttvAttribute
*saved_states
;
1578 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1579 LTTV_STATE_SAVED_STATES
);
1581 nb
= lttv_attribute_get_number(saved_states
);
1582 for(i
= 0 ; i
< nb
; i
++) {
1583 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1584 g_assert(type
== LTTV_GOBJECT
);
1585 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1588 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1593 create_max_time(LttvTraceState
*tcs
)
1595 LttvAttributeValue v
;
1597 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1599 g_assert(*(v
.v_pointer
) == NULL
);
1600 *(v
.v_pointer
) = g_new(LttTime
,1);
1601 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1606 get_max_time(LttvTraceState
*tcs
)
1608 LttvAttributeValue v
;
1610 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1612 g_assert(*(v
.v_pointer
) != NULL
);
1613 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1618 free_max_time(LttvTraceState
*tcs
)
1620 LttvAttributeValue v
;
1622 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1624 g_free(*(v
.v_pointer
));
1625 *(v
.v_pointer
) = NULL
;
1629 typedef struct _LttvNameTables
{
1630 // FIXME GQuark *eventtype_names;
1631 GQuark
*syscall_names
;
1637 GQuark
*soft_irq_names
;
1643 create_name_tables(LttvTraceState
*tcs
)
1647 GString
*fe_name
= g_string_new("");
1649 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1651 LttvAttributeValue v
;
1655 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1657 g_assert(*(v
.v_pointer
) == NULL
);
1658 *(v
.v_pointer
) = name_tables
;
1660 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1662 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1663 LTT_FACILITY_KERNEL_ARCH
,
1664 LTT_EVENT_SYSCALL_ENTRY
,
1665 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1666 NULL
, NULL
, &hooks
)) {
1668 // th = lttv_trace_hook_get_first(&th);
1670 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1671 // nb = ltt_type_element_number(t);
1673 // name_tables->syscall_names = g_new(GQuark, nb);
1674 // name_tables->nb_syscalls = nb;
1676 // for(i = 0 ; i < nb ; i++) {
1677 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1678 // if(!name_tables->syscall_names[i]) {
1679 // GString *string = g_string_new("");
1680 // g_string_printf(string, "syscall %u", i);
1681 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1682 // g_string_free(string, TRUE);
1686 name_tables
->nb_syscalls
= 256;
1687 name_tables
->syscall_names
= g_new(GQuark
, 256);
1688 for(i
= 0 ; i
< 256 ; i
++) {
1689 g_string_printf(fe_name
, "syscall %d", i
);
1690 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1693 name_tables
->syscall_names
= NULL
;
1694 name_tables
->nb_syscalls
= 0;
1696 lttv_trace_hook_remove_all(&hooks
);
1698 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1699 LTT_FACILITY_KERNEL_ARCH
,
1700 LTT_EVENT_TRAP_ENTRY
,
1701 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1702 NULL
, NULL
, &hooks
)) {
1704 // th = lttv_trace_hook_get_first(&th);
1706 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1707 // //nb = ltt_type_element_number(t);
1709 // name_tables->trap_names = g_new(GQuark, nb);
1710 // for(i = 0 ; i < nb ; i++) {
1711 // name_tables->trap_names[i] = g_quark_from_string(
1712 // ltt_enum_string_get(t, i));
1715 name_tables
->nb_traps
= 256;
1716 name_tables
->trap_names
= g_new(GQuark
, 256);
1717 for(i
= 0 ; i
< 256 ; i
++) {
1718 g_string_printf(fe_name
, "trap %d", i
);
1719 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1722 name_tables
->trap_names
= NULL
;
1723 name_tables
->nb_traps
= 0;
1725 lttv_trace_hook_remove_all(&hooks
);
1727 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1728 LTT_FACILITY_KERNEL
,
1729 LTT_EVENT_IRQ_ENTRY
,
1730 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1731 NULL
, NULL
, &hooks
)) {
1734 name_tables->irq_names = g_new(GQuark, nb);
1735 for(i = 0 ; i < nb ; i++) {
1736 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1740 name_tables
->nb_irqs
= 256;
1741 name_tables
->irq_names
= g_new(GQuark
, 256);
1742 for(i
= 0 ; i
< 256 ; i
++) {
1743 g_string_printf(fe_name
, "irq %d", i
);
1744 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1747 name_tables
->nb_irqs
= 0;
1748 name_tables
->irq_names
= NULL
;
1750 lttv_trace_hook_remove_all(&hooks
);
1752 name_tables->soft_irq_names = g_new(GQuark, nb);
1753 for(i = 0 ; i < nb ; i++) {
1754 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1758 name_tables
->nb_softirqs
= 256;
1759 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1760 for(i
= 0 ; i
< 256 ; i
++) {
1761 g_string_printf(fe_name
, "softirq %d", i
);
1762 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1764 g_array_free(hooks
, TRUE
);
1766 g_string_free(fe_name
, TRUE
);
1771 get_name_tables(LttvTraceState
*tcs
)
1773 LttvNameTables
*name_tables
;
1775 LttvAttributeValue v
;
1777 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1779 g_assert(*(v
.v_pointer
) != NULL
);
1780 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1781 //tcs->eventtype_names = name_tables->eventtype_names;
1782 tcs
->syscall_names
= name_tables
->syscall_names
;
1783 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1784 tcs
->trap_names
= name_tables
->trap_names
;
1785 tcs
->nb_traps
= name_tables
->nb_traps
;
1786 tcs
->irq_names
= name_tables
->irq_names
;
1787 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1788 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1789 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1794 free_name_tables(LttvTraceState
*tcs
)
1796 LttvNameTables
*name_tables
;
1798 LttvAttributeValue v
;
1800 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1802 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1803 *(v
.v_pointer
) = NULL
;
1805 // g_free(name_tables->eventtype_names);
1806 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1807 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1808 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1809 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1810 if(name_tables
) g_free(name_tables
);
1813 #ifdef HASH_TABLE_DEBUG
1815 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1817 LttvProcessState
*process
= (LttvProcessState
*)value
;
1819 /* Test for process corruption */
1820 guint stack_len
= process
->execution_stack
->len
;
1823 static void hash_table_check(GHashTable
*table
)
1825 g_hash_table_foreach(table
, test_process
, NULL
);
1831 /* clears the stack and sets the state passed as argument */
1832 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1834 g_array_set_size(cpust
->mode_stack
, 1);
1835 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1838 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1840 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1841 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1844 static void cpu_pop_mode(LttvCPUState
*cpust
)
1846 if(cpust
->mode_stack
->len
<= 1)
1847 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1849 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1852 /* clears the stack and sets the state passed as argument */
1853 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1855 g_array_set_size(bdevst
->mode_stack
, 1);
1856 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1859 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1861 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1862 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1865 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1867 if(bdevst
->mode_stack
->len
<= 1)
1868 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1870 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1873 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1875 g_array_set_size(irqst
->mode_stack
, 1);
1876 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1879 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1881 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1882 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1885 static void irq_pop_mode(LttvIRQState
*irqst
)
1887 if(irqst
->mode_stack
->len
<= 1)
1888 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1890 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1893 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1896 LttvExecutionState
*es
;
1898 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1899 guint cpu
= tfs
->cpu
;
1901 #ifdef HASH_TABLE_DEBUG
1902 hash_table_check(ts
->processes
);
1904 LttvProcessState
*process
= ts
->running_process
[cpu
];
1906 guint depth
= process
->execution_stack
->len
;
1908 process
->execution_stack
=
1909 g_array_set_size(process
->execution_stack
, depth
+ 1);
1912 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1914 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1917 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1918 es
->cum_cpu_time
= ltt_time_zero
;
1919 es
->s
= process
->state
->s
;
1920 process
->state
= es
;
1924 * return 1 when empty, else 0 */
1925 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1926 LttvTracefileState
*tfs
)
1928 guint depth
= process
->execution_stack
->len
;
1934 process
->execution_stack
=
1935 g_array_set_size(process
->execution_stack
, depth
- 1);
1936 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1938 process
->state
->change
= tfs
->parent
.timestamp
;
1943 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1945 guint cpu
= tfs
->cpu
;
1946 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1947 LttvProcessState
*process
= ts
->running_process
[cpu
];
1949 guint depth
= process
->execution_stack
->len
;
1951 if(process
->state
->t
!= t
){
1952 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1953 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1954 g_info("process state has %s when pop_int is %s\n",
1955 g_quark_to_string(process
->state
->t
),
1956 g_quark_to_string(t
));
1957 g_info("{ %u, %u, %s, %s, %s }\n",
1960 g_quark_to_string(process
->name
),
1961 g_quark_to_string(process
->brand
),
1962 g_quark_to_string(process
->state
->s
));
1967 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1968 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1972 process
->execution_stack
=
1973 g_array_set_size(process
->execution_stack
, depth
- 1);
1974 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1976 process
->state
->change
= tfs
->parent
.timestamp
;
1979 struct search_result
{
1980 const LttTime
*time
; /* Requested time */
1981 LttTime
*best
; /* Best result */
1984 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1986 const LttTime
*elem_time
= (const LttTime
*)a
;
1987 /* Explicit non const cast */
1988 struct search_result
*res
= (struct search_result
*)b
;
1990 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1991 /* The usertrace was created before the schedchange */
1992 /* Get larger keys */
1994 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1995 /* The usertrace was created after the schedchange time */
1996 /* Get smaller keys */
1998 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1999 res
->best
= (LttTime
*)elem_time
;
2002 res
->best
= (LttTime
*)elem_time
;
2009 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2010 guint pid
, const LttTime
*timestamp
)
2012 LttvTracefileState
*tfs
= NULL
;
2013 struct search_result res
;
2014 /* Find the usertrace associated with a pid and time interval.
2015 * Search in the usertraces by PID (within a hash) and then, for each
2016 * corresponding element of the array, find the first one with creation
2017 * timestamp the lowest, but higher or equal to "timestamp". */
2018 res
.time
= timestamp
;
2020 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2021 if(usertrace_tree
) {
2022 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2024 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2032 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2033 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2035 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2037 LttvExecutionState
*es
;
2042 process
->tgid
= tgid
;
2044 process
->name
= name
;
2045 process
->brand
= LTTV_STATE_UNBRANDED
;
2046 //process->last_cpu = tfs->cpu_name;
2047 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2048 process
->type
= LTTV_STATE_USER_THREAD
;
2049 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2050 process
->current_function
= 0; //function 0x0 by default.
2052 g_info("Process %u, core %p", process
->pid
, process
);
2053 g_hash_table_insert(tcs
->processes
, process
, process
);
2056 process
->ppid
= parent
->pid
;
2057 process
->creation_time
= *timestamp
;
2060 /* No parent. This process exists but we are missing all information about
2061 its creation. The birth time is set to zero but we remember the time of
2066 process
->creation_time
= ltt_time_zero
;
2069 process
->insertion_time
= *timestamp
;
2070 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2071 process
->creation_time
.tv_nsec
);
2072 process
->pid_time
= g_quark_from_string(buffer
);
2074 //process->last_cpu = tfs->cpu_name;
2075 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2076 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2077 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2078 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2079 es
= process
->state
= &g_array_index(process
->execution_stack
,
2080 LttvExecutionState
, 0);
2081 es
->t
= LTTV_STATE_USER_MODE
;
2082 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2083 es
->entry
= *timestamp
;
2084 //g_assert(timestamp->tv_sec != 0);
2085 es
->change
= *timestamp
;
2086 es
->cum_cpu_time
= ltt_time_zero
;
2087 es
->s
= LTTV_STATE_RUN
;
2089 es
= process
->state
= &g_array_index(process
->execution_stack
,
2090 LttvExecutionState
, 1);
2091 es
->t
= LTTV_STATE_SYSCALL
;
2092 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2093 es
->entry
= *timestamp
;
2094 //g_assert(timestamp->tv_sec != 0);
2095 es
->change
= *timestamp
;
2096 es
->cum_cpu_time
= ltt_time_zero
;
2097 es
->s
= LTTV_STATE_WAIT_FORK
;
2099 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2100 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2101 sizeof(guint64
), 0);
2106 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2109 LttvProcessState key
;
2110 LttvProcessState
*process
;
2114 process
= g_hash_table_lookup(ts
->processes
, &key
);
2119 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2120 const LttTime
*timestamp
)
2122 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2123 LttvExecutionState
*es
;
2125 /* Put ltt_time_zero creation time for unexisting processes */
2126 if(unlikely(process
== NULL
)) {
2127 process
= lttv_state_create_process(ts
,
2128 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2129 /* We are not sure is it's a kernel thread or normal thread, put the
2130 * bottom stack state to unknown */
2131 process
->execution_stack
=
2132 g_array_set_size(process
->execution_stack
, 1);
2133 process
->state
= es
=
2134 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2135 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2136 es
->s
= LTTV_STATE_UNNAMED
;
2141 /* FIXME : this function should be called when we receive an event telling that
2142 * release_task has been called in the kernel. In happens generally when
2143 * the parent waits for its child terminaison, but may also happen in special
2144 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2145 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2146 * of a killed thread group, but isn't the leader.
2148 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2150 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2151 LttvProcessState key
;
2153 key
.pid
= process
->pid
;
2154 key
.cpu
= process
->cpu
;
2155 g_hash_table_remove(ts
->processes
, &key
);
2156 g_array_free(process
->execution_stack
, TRUE
);
2157 g_array_free(process
->user_stack
, TRUE
);
2162 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2164 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2165 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2170 static void lttv_state_free_process_table(GHashTable
*processes
)
2172 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2173 g_hash_table_destroy(processes
);
2177 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2179 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2181 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2182 LttvProcessState
*process
= ts
->running_process
[cpu
];
2183 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2184 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2185 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2187 LttvExecutionSubmode submode
;
2189 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2190 guint syscall
= ltt_event_get_unsigned(e
, f
);
2192 if(syscall
< nb_syscalls
) {
2193 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2196 /* Fixup an incomplete syscall table */
2197 GString
*string
= g_string_new("");
2198 g_string_printf(string
, "syscall %u", syscall
);
2199 submode
= g_quark_from_string(string
->str
);
2200 g_string_free(string
, TRUE
);
2202 /* There can be no system call from PID 0 : unknown state */
2203 if(process
->pid
!= 0)
2204 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2209 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2211 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2213 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2214 LttvProcessState
*process
= ts
->running_process
[cpu
];
2216 /* There can be no system call from PID 0 : unknown state */
2217 if(process
->pid
!= 0)
2218 pop_state(s
, LTTV_STATE_SYSCALL
);
2223 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2225 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2226 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2227 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2228 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2230 LttvExecutionSubmode submode
;
2232 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2233 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2235 if(trap
< nb_traps
) {
2236 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2238 /* Fixup an incomplete trap table */
2239 GString
*string
= g_string_new("");
2240 g_string_printf(string
, "trap %llu", trap
);
2241 submode
= g_quark_from_string(string
->str
);
2242 g_string_free(string
, TRUE
);
2245 push_state(s
, LTTV_STATE_TRAP
, submode
);
2247 /* update cpu status */
2248 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2253 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2255 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2257 pop_state(s
, LTTV_STATE_TRAP
);
2259 /* update cpu status */
2260 cpu_pop_mode(s
->cpu_state
);
2265 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2267 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2268 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2269 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2270 //guint8 ev_id = ltt_event_eventtype_id(e);
2271 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2272 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2274 LttvExecutionSubmode submode
;
2275 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2276 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2279 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2281 /* Fixup an incomplete irq table */
2282 GString
*string
= g_string_new("");
2283 g_string_printf(string
, "irq %llu", irq
);
2284 submode
= g_quark_from_string(string
->str
);
2285 g_string_free(string
, TRUE
);
2288 /* Do something with the info about being in user or system mode when int? */
2289 push_state(s
, LTTV_STATE_IRQ
, submode
);
2291 /* update cpu status */
2292 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2294 /* update irq status */
2295 s
->cpu_state
->last_irq
= irq
;
2296 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2301 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2303 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2305 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2311 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2313 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2314 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2316 pop_state(s
, LTTV_STATE_IRQ
);
2318 /* update cpu status */
2319 cpu_pop_mode(s
->cpu_state
);
2321 /* update irq status */
2322 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2327 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2329 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2330 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2331 //guint8 ev_id = ltt_event_eventtype_id(e);
2332 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2333 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2335 LttvExecutionSubmode submode
;
2336 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2337 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2339 if(softirq
< nb_softirqs
) {
2340 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2342 /* Fixup an incomplete irq table */
2343 GString
*string
= g_string_new("");
2344 g_string_printf(string
, "softirq %llu", softirq
);
2345 submode
= g_quark_from_string(string
->str
);
2346 g_string_free(string
, TRUE
);
2349 /* Do something with the info about being in user or system mode when int? */
2350 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2354 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2356 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2357 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2358 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2359 //guint8 ev_id = ltt_event_eventtype_id(e);
2360 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2362 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2363 lttv_trace_get_hook_field(th
, 0)));
2364 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2366 ts
->irq_names
[irq
] = action
;
2372 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2374 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2375 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2376 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2377 //guint8 ev_id = ltt_event_eventtype_id(e);
2378 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2380 guint major
= ltt_event_get_long_unsigned(e
,
2381 lttv_trace_get_hook_field(th
, 0));
2382 guint minor
= ltt_event_get_long_unsigned(e
,
2383 lttv_trace_get_hook_field(th
, 1));
2384 guint oper
= ltt_event_get_long_unsigned(e
,
2385 lttv_trace_get_hook_field(th
, 2));
2386 guint16 devcode
= MKDEV(major
,minor
);
2388 /* have we seen this block device before? */
2389 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2392 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2394 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2399 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2401 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2402 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2403 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2404 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2406 guint major
= ltt_event_get_long_unsigned(e
,
2407 lttv_trace_get_hook_field(th
, 0));
2408 guint minor
= ltt_event_get_long_unsigned(e
,
2409 lttv_trace_get_hook_field(th
, 1));
2410 //guint oper = ltt_event_get_long_unsigned(e,
2411 // lttv_trace_get_hook_field(th, 2));
2412 guint16 devcode
= MKDEV(major
,minor
);
2414 /* have we seen this block device before? */
2415 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2417 /* update block device */
2418 bdev_pop_mode(bdev
);
2423 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2427 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2428 guint cpu
= tfs
->cpu
;
2429 LttvProcessState
*process
= ts
->running_process
[cpu
];
2431 guint depth
= process
->user_stack
->len
;
2433 process
->user_stack
=
2434 g_array_set_size(process
->user_stack
, depth
+ 1);
2436 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2437 *new_func
= funcptr
;
2438 process
->current_function
= funcptr
;
2441 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2443 guint cpu
= tfs
->cpu
;
2444 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2445 LttvProcessState
*process
= ts
->running_process
[cpu
];
2447 if(process
->current_function
!= funcptr
){
2448 g_info("Different functions (%lu.%09lu): ignore it\n",
2449 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2450 g_info("process state has %llu when pop_function is %llu\n",
2451 process
->current_function
, funcptr
);
2452 g_info("{ %u, %u, %s, %s, %s }\n",
2455 g_quark_to_string(process
->name
),
2456 g_quark_to_string(process
->brand
),
2457 g_quark_to_string(process
->state
->s
));
2460 guint depth
= process
->user_stack
->len
;
2463 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2464 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2468 process
->user_stack
=
2469 g_array_set_size(process
->user_stack
, depth
- 1);
2470 process
->current_function
=
2471 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2475 static gboolean
function_entry(void *hook_data
, void *call_data
)
2477 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2478 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2479 //guint8 ev_id = ltt_event_eventtype_id(e);
2480 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2481 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2482 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2484 push_function(s
, funcptr
);
2488 static gboolean
function_exit(void *hook_data
, void *call_data
)
2490 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2491 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2492 //guint8 ev_id = ltt_event_eventtype_id(e);
2493 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2494 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2495 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2497 pop_function(s
, funcptr
);
2501 static gboolean
schedchange(void *hook_data
, void *call_data
)
2503 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2505 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2506 LttvProcessState
*process
= ts
->running_process
[cpu
];
2507 //LttvProcessState *old_process = ts->running_process[cpu];
2509 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2510 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2511 guint pid_in
, pid_out
;
2514 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2515 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2516 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2518 if(likely(process
!= NULL
)) {
2520 /* We could not know but it was not the idle process executing.
2521 This should only happen at the beginning, before the first schedule
2522 event, and when the initial information (current process for each CPU)
2523 is missing. It is not obvious how we could, after the fact, compensate
2524 the wrongly attributed statistics. */
2526 //This test only makes sense once the state is known and if there is no
2527 //missing events. We need to silently ignore schedchange coming after a
2528 //process_free, or it causes glitches. (FIXME)
2529 //if(unlikely(process->pid != pid_out)) {
2530 // g_assert(process->pid == 0);
2532 if(process
->pid
== 0
2533 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2535 /* Scheduling out of pid 0 at beginning of the trace :
2536 * we know for sure it is in syscall mode at this point. */
2537 g_assert(process
->execution_stack
->len
== 1);
2538 process
->state
->t
= LTTV_STATE_SYSCALL
;
2539 process
->state
->s
= LTTV_STATE_WAIT
;
2540 process
->state
->change
= s
->parent
.timestamp
;
2541 process
->state
->entry
= s
->parent
.timestamp
;
2544 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2545 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2546 process
->state
->change
= s
->parent
.timestamp
;
2548 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2549 else process
->state
->s
= LTTV_STATE_WAIT
;
2550 process
->state
->change
= s
->parent
.timestamp
;
2553 if(state_out
== 32 || state_out
== 64)
2554 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2555 /* see sched.h for states */
2558 process
= ts
->running_process
[cpu
] =
2559 lttv_state_find_process_or_create(
2560 (LttvTraceState
*)s
->parent
.t_context
,
2562 &s
->parent
.timestamp
);
2563 process
->state
->s
= LTTV_STATE_RUN
;
2565 if(process
->usertrace
)
2566 process
->usertrace
->cpu
= cpu
;
2567 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2568 process
->state
->change
= s
->parent
.timestamp
;
2570 /* update cpu status */
2572 /* going to idle task */
2573 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2575 /* scheduling a real task.
2576 * we must be careful here:
2577 * if we just schedule()'ed to a process that is
2578 * in a trap, we must put the cpu in trap mode
2580 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2581 if(process
->state
->t
== LTTV_STATE_TRAP
)
2582 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2588 static gboolean
process_fork(void *hook_data
, void *call_data
)
2590 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2591 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2592 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2594 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2595 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2596 //LttvProcessState *zombie_process;
2598 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2599 LttvProcessState
*process
= ts
->running_process
[cpu
];
2600 LttvProcessState
*child_process
;
2601 struct marker_field
*f
;
2604 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2607 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2608 s
->parent
.target_pid
= child_pid
;
2611 f
= lttv_trace_get_hook_field(th
, 2);
2613 child_tgid
= ltt_event_get_unsigned(e
, f
);
2617 /* Mathieu : it seems like the process might have been scheduled in before the
2618 * fork, and, in a rare case, might be the current process. This might happen
2619 * in a SMP case where we don't have enough precision on the clocks.
2621 * Test reenabled after precision fixes on time. (Mathieu) */
2623 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2625 if(unlikely(zombie_process
!= NULL
)) {
2626 /* Reutilisation of PID. Only now we are sure that the old PID
2627 * has been released. FIXME : should know when release_task happens instead.
2629 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2631 for(i
=0; i
< num_cpus
; i
++) {
2632 g_assert(zombie_process
!= ts
->running_process
[i
]);
2635 exit_process(s
, zombie_process
);
2638 g_assert(process
->pid
!= child_pid
);
2639 // FIXME : Add this test in the "known state" section
2640 // g_assert(process->pid == parent_pid);
2641 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2642 if(child_process
== NULL
) {
2643 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2644 child_pid
, child_tgid
,
2645 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2647 /* The process has already been created : due to time imprecision between
2648 * multiple CPUs : it has been scheduled in before creation. Note that we
2649 * shouldn't have this kind of imprecision.
2651 * Simply put a correct parent.
2653 g_assert(0); /* This is a problematic case : the process has been created
2654 before the fork event */
2655 child_process
->ppid
= process
->pid
;
2656 child_process
->tgid
= child_tgid
;
2658 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2659 child_process
->name
= process
->name
;
2660 child_process
->brand
= process
->brand
;
2665 /* We stamp a newly created process as kernel_thread.
2666 * The thread should not be running yet. */
2667 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2669 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2670 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2671 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2673 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2674 LttvProcessState
*process
;
2675 LttvExecutionState
*es
;
2678 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2679 s
->parent
.target_pid
= pid
;
2681 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2683 process
->execution_stack
=
2684 g_array_set_size(process
->execution_stack
, 1);
2685 es
= process
->state
=
2686 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2687 es
->t
= LTTV_STATE_SYSCALL
;
2688 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2693 static gboolean
process_exit(void *hook_data
, void *call_data
)
2695 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2696 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2697 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2699 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2700 LttvProcessState
*process
; // = ts->running_process[cpu];
2702 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2703 s
->parent
.target_pid
= pid
;
2705 // FIXME : Add this test in the "known state" section
2706 // g_assert(process->pid == pid);
2708 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2709 if(likely(process
!= NULL
)) {
2710 process
->state
->s
= LTTV_STATE_EXIT
;
2715 static gboolean
process_free(void *hook_data
, void *call_data
)
2717 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2718 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2719 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2720 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2722 LttvProcessState
*process
;
2724 /* PID of the process to release */
2725 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2726 s
->parent
.target_pid
= release_pid
;
2728 g_assert(release_pid
!= 0);
2730 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2732 if(likely(process
!= NULL
)) {
2733 /* release_task is happening at kernel level : we can now safely release
2734 * the data structure of the process */
2735 //This test is fun, though, as it may happen that
2736 //at time t : CPU 0 : process_free
2737 //at time t+150ns : CPU 1 : schedule out
2738 //Clearly due to time imprecision, we disable it. (Mathieu)
2739 //If this weird case happen, we have no choice but to put the
2740 //Currently running process on the cpu to 0.
2741 //I re-enable it following time precision fixes. (Mathieu)
2742 //Well, in the case where an process is freed by a process on another CPU
2743 //and still scheduled, it happens that this is the schedchange that will
2744 //drop the last reference count. Do not free it here!
2745 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2747 for(i
=0; i
< num_cpus
; i
++) {
2748 //g_assert(process != ts->running_process[i]);
2749 if(process
== ts
->running_process
[i
]) {
2750 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2754 if(i
== num_cpus
) /* process is not scheduled */
2755 exit_process(s
, process
);
2762 static gboolean
process_exec(void *hook_data
, void *call_data
)
2764 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2765 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2767 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2770 LttvProcessState
*process
= ts
->running_process
[cpu
];
2772 #if 0//how to use a sequence that must be transformed in a string
2773 /* PID of the process to release */
2774 guint64 name_len
= ltt_event_field_element_number(e
,
2775 lttv_trace_get_hook_field(th
, 0));
2776 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2777 LttField
*child
= ltt_event_field_element_select(e
,
2778 lttv_trace_get_hook_field(th
, 0), 0);
2780 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2781 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2782 memcpy(null_term_name
, name_begin
, name_len
);
2783 null_term_name
[name_len
] = '\0';
2784 process
->name
= g_quark_from_string(null_term_name
);
2787 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2788 lttv_trace_get_hook_field(th
, 0)));
2789 process
->brand
= LTTV_STATE_UNBRANDED
;
2790 //g_free(null_term_name);
2794 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2796 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2797 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2798 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2799 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2802 LttvProcessState
*process
= ts
->running_process
[cpu
];
2804 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2805 process
->brand
= g_quark_from_string(name
);
2810 static void fix_process(gpointer key
, gpointer value
,
2813 LttvProcessState
*process
;
2814 LttvExecutionState
*es
;
2815 process
= (LttvProcessState
*)value
;
2816 LttTime
*timestamp
= (LttTime
*)user_data
;
2818 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2819 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2820 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2821 es
->t
= LTTV_STATE_SYSCALL
;
2822 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2823 es
->entry
= *timestamp
;
2824 es
->change
= *timestamp
;
2825 es
->cum_cpu_time
= ltt_time_zero
;
2826 if(es
->s
== LTTV_STATE_UNNAMED
)
2827 es
->s
= LTTV_STATE_WAIT
;
2830 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2831 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2832 es
->t
= LTTV_STATE_USER_MODE
;
2833 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2834 es
->entry
= *timestamp
;
2835 //g_assert(timestamp->tv_sec != 0);
2836 es
->change
= *timestamp
;
2837 es
->cum_cpu_time
= ltt_time_zero
;
2838 if(es
->s
== LTTV_STATE_UNNAMED
)
2839 es
->s
= LTTV_STATE_RUN
;
2841 if(process
->execution_stack
->len
== 1) {
2842 /* Still in bottom unknown mode, means never did a system call
2843 * May be either in user mode, syscall mode, running or waiting.*/
2844 /* FIXME : we may be tagging syscall mode when being user mode */
2845 process
->execution_stack
=
2846 g_array_set_size(process
->execution_stack
, 2);
2847 es
= process
->state
= &g_array_index(process
->execution_stack
,
2848 LttvExecutionState
, 1);
2849 es
->t
= LTTV_STATE_SYSCALL
;
2850 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2851 es
->entry
= *timestamp
;
2852 //g_assert(timestamp->tv_sec != 0);
2853 es
->change
= *timestamp
;
2854 es
->cum_cpu_time
= ltt_time_zero
;
2855 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2856 es
->s
= LTTV_STATE_WAIT
;
2862 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2864 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2865 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2866 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2867 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2868 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2870 /* For all processes */
2871 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2872 /* else, if stack[0] is unknown, set to user mode, running */
2874 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2879 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2881 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2882 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2883 //It's slow : optimise later by doing this before reading trace.
2884 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2890 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2891 LttvProcessState
*process
= ts
->running_process
[cpu
];
2892 LttvProcessState
*parent_process
;
2893 struct marker_field
*f
;
2894 GQuark type
, mode
, submode
, status
;
2895 LttvExecutionState
*es
;
2899 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2900 s
->parent
.target_pid
= pid
;
2903 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2906 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2909 f
= lttv_trace_get_hook_field(th
, 3);
2910 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2912 //FIXME: type is rarely used, enum must match possible types.
2915 f
= lttv_trace_get_hook_field(th
, 4);
2916 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2919 f
= lttv_trace_get_hook_field(th
, 5);
2920 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2923 f
= lttv_trace_get_hook_field(th
, 6);
2924 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2927 f
= lttv_trace_get_hook_field(th
, 7);
2929 tgid
= ltt_event_get_unsigned(e
, f
);
2934 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2935 for(i
=0; i
<nb_cpus
; i
++) {
2936 process
= lttv_state_find_process(ts
, i
, pid
);
2937 g_assert(process
!= NULL
);
2939 process
->ppid
= parent_pid
;
2940 process
->tgid
= tgid
;
2941 process
->name
= g_quark_from_string(command
);
2943 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2944 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2948 /* The process might exist if a process was forked while performing the
2950 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2951 if(process
== NULL
) {
2952 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2953 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2954 pid
, tgid
, g_quark_from_string(command
),
2955 &s
->parent
.timestamp
);
2957 /* Keep the stack bottom : a running user mode */
2958 /* Disabled because of inconsistencies in the current statedump states. */
2959 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2960 /* Only keep the bottom
2961 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2962 /* Will cause expected trap when in fact being syscall (even after end of
2964 * Will cause expected interrupt when being syscall. (only before end of
2965 * statedump event) */
2966 // This will cause a "popping last state on stack, ignoring it."
2967 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2968 es
= process
->state
= &g_array_index(process
->execution_stack
,
2969 LttvExecutionState
, 0);
2970 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2971 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2972 es
->s
= LTTV_STATE_UNNAMED
;
2973 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2975 es
->t
= LTTV_STATE_SYSCALL
;
2980 /* User space process :
2981 * bottom : user mode
2982 * either currently running or scheduled out.
2983 * can be scheduled out because interrupted in (user mode or in syscall)
2984 * or because of an explicit call to the scheduler in syscall. Note that
2985 * the scheduler call comes after the irq_exit, so never in interrupt
2987 // temp workaround : set size to 1 : only have user mode bottom of stack.
2988 // will cause g_info message of expected syscall mode when in fact being
2989 // in user mode. Can also cause expected trap when in fact being user
2990 // mode in the event of a page fault reenabling interrupts in the handler.
2991 // Expected syscall and trap can also happen after the end of statedump
2992 // This will cause a "popping last state on stack, ignoring it."
2993 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2994 es
= process
->state
= &g_array_index(process
->execution_stack
,
2995 LttvExecutionState
, 0);
2996 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2997 es
->s
= LTTV_STATE_UNNAMED
;
2998 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3000 es
->t
= LTTV_STATE_USER_MODE
;
3008 es
= process
->state
= &g_array_index(process
->execution_stack
,
3009 LttvExecutionState
, 1);
3010 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3011 es
->s
= LTTV_STATE_UNNAMED
;
3012 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3016 /* The process has already been created :
3017 * Probably was forked while dumping the process state or
3018 * was simply scheduled in prior to get the state dump event.
3020 process
->ppid
= parent_pid
;
3021 process
->tgid
= tgid
;
3022 process
->name
= g_quark_from_string(command
);
3023 process
->type
= type
;
3025 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3027 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3028 if(type
== LTTV_STATE_KERNEL_THREAD
)
3029 es
->t
= LTTV_STATE_SYSCALL
;
3031 es
->t
= LTTV_STATE_USER_MODE
;
3034 /* Don't mess around with the stack, it will eventually become
3035 * ok after the end of state dump. */
3042 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3044 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3046 lttv_state_add_event_hooks(tss
);
3051 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3053 LttvTraceset
*traceset
= self
->parent
.ts
;
3055 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3059 LttvTracefileState
*tfs
;
3065 LttvAttributeValue val
;
3067 nb_trace
= lttv_traceset_number(traceset
);
3068 for(i
= 0 ; i
< nb_trace
; i
++) {
3069 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3071 /* Find the eventtype id for the following events and register the
3072 associated by id hooks. */
3074 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3075 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3078 lttv_trace_find_hook(ts
->parent
.t
,
3079 LTT_FACILITY_KERNEL_ARCH
,
3080 LTT_EVENT_SYSCALL_ENTRY
,
3081 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3082 syscall_entry
, NULL
, &hooks
);
3084 lttv_trace_find_hook(ts
->parent
.t
,
3085 LTT_FACILITY_KERNEL_ARCH
,
3086 LTT_EVENT_SYSCALL_EXIT
,
3088 syscall_exit
, NULL
, &hooks
);
3090 lttv_trace_find_hook(ts
->parent
.t
,
3091 LTT_FACILITY_KERNEL_ARCH
,
3092 LTT_EVENT_TRAP_ENTRY
,
3093 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3094 trap_entry
, NULL
, &hooks
);
3096 lttv_trace_find_hook(ts
->parent
.t
,
3097 LTT_FACILITY_KERNEL_ARCH
,
3098 LTT_EVENT_TRAP_EXIT
,
3100 trap_exit
, NULL
, &hooks
);
3102 lttv_trace_find_hook(ts
->parent
.t
,
3103 LTT_FACILITY_KERNEL
,
3104 LTT_EVENT_IRQ_ENTRY
,
3105 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3106 irq_entry
, NULL
, &hooks
);
3108 lttv_trace_find_hook(ts
->parent
.t
,
3109 LTT_FACILITY_KERNEL
,
3112 irq_exit
, NULL
, &hooks
);
3114 lttv_trace_find_hook(ts
->parent
.t
,
3115 LTT_FACILITY_KERNEL
,
3116 LTT_EVENT_SOFT_IRQ_ENTRY
,
3117 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3118 soft_irq_entry
, NULL
, &hooks
);
3120 lttv_trace_find_hook(ts
->parent
.t
,
3121 LTT_FACILITY_KERNEL
,
3122 LTT_EVENT_SOFT_IRQ_EXIT
,
3124 soft_irq_exit
, NULL
, &hooks
);
3126 lttv_trace_find_hook(ts
->parent
.t
,
3127 LTT_FACILITY_KERNEL
,
3128 LTT_EVENT_SCHED_SCHEDULE
,
3129 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3130 LTT_FIELD_PREV_STATE
),
3131 schedchange
, NULL
, &hooks
);
3133 lttv_trace_find_hook(ts
->parent
.t
,
3134 LTT_FACILITY_KERNEL
,
3135 LTT_EVENT_PROCESS_FORK
,
3136 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3137 LTT_FIELD_CHILD_TGID
),
3138 process_fork
, NULL
, &hooks
);
3140 lttv_trace_find_hook(ts
->parent
.t
,
3141 LTT_FACILITY_KERNEL_ARCH
,
3142 LTT_EVENT_KTHREAD_CREATE
,
3143 FIELD_ARRAY(LTT_FIELD_PID
),
3144 process_kernel_thread
, NULL
, &hooks
);
3146 lttv_trace_find_hook(ts
->parent
.t
,
3147 LTT_FACILITY_KERNEL
,
3148 LTT_EVENT_PROCESS_EXIT
,
3149 FIELD_ARRAY(LTT_FIELD_PID
),
3150 process_exit
, NULL
, &hooks
);
3152 lttv_trace_find_hook(ts
->parent
.t
,
3153 LTT_FACILITY_KERNEL
,
3154 LTT_EVENT_PROCESS_FREE
,
3155 FIELD_ARRAY(LTT_FIELD_PID
),
3156 process_free
, NULL
, &hooks
);
3158 lttv_trace_find_hook(ts
->parent
.t
,
3161 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3162 process_exec
, NULL
, &hooks
);
3164 lttv_trace_find_hook(ts
->parent
.t
,
3165 LTT_FACILITY_USER_GENERIC
,
3166 LTT_EVENT_THREAD_BRAND
,
3167 FIELD_ARRAY(LTT_FIELD_NAME
),
3168 thread_brand
, NULL
, &hooks
);
3170 /* statedump-related hooks */
3171 lttv_trace_find_hook(ts
->parent
.t
,
3173 LTT_EVENT_PROCESS_STATE
,
3174 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3175 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3176 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3177 enum_process_state
, NULL
, &hooks
);
3179 lttv_trace_find_hook(ts
->parent
.t
,
3181 LTT_EVENT_STATEDUMP_END
,
3183 statedump_end
, NULL
, &hooks
);
3185 lttv_trace_find_hook(ts
->parent
.t
,
3187 LTT_EVENT_LIST_INTERRUPT
,
3188 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3189 enum_interrupt
, NULL
, &hooks
);
3191 lttv_trace_find_hook(ts
->parent
.t
,
3193 LTT_EVENT_REQUEST_ISSUE
,
3194 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3195 bdev_request_issue
, NULL
, &hooks
);
3197 lttv_trace_find_hook(ts
->parent
.t
,
3199 LTT_EVENT_REQUEST_COMPLETE
,
3200 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3201 bdev_request_complete
, NULL
, &hooks
);
3203 lttv_trace_find_hook(ts
->parent
.t
,
3204 LTT_FACILITY_USER_GENERIC
,
3205 LTT_EVENT_FUNCTION_ENTRY
,
3206 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3207 function_entry
, NULL
, &hooks
);
3209 lttv_trace_find_hook(ts
->parent
.t
,
3210 LTT_FACILITY_USER_GENERIC
,
3211 LTT_EVENT_FUNCTION_EXIT
,
3212 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3213 function_exit
, NULL
, &hooks
);
3215 /* Add these hooks to each event_by_id hooks list */
3217 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3219 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3221 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3222 LttvTracefileContext
*, j
));
3224 for(k
= 0 ; k
< hooks
->len
; k
++) {
3225 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3227 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3233 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3234 *(val
.v_pointer
) = hooks
;
3238 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3240 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3242 lttv_state_remove_event_hooks(tss
);
3247 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3249 LttvTraceset
*traceset
= self
->parent
.ts
;
3251 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3255 LttvTracefileState
*tfs
;
3261 LttvAttributeValue val
;
3263 nb_trace
= lttv_traceset_number(traceset
);
3264 for(i
= 0 ; i
< nb_trace
; i
++) {
3265 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3267 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3268 hooks
= *(val
.v_pointer
);
3270 /* Remove these hooks from each event_by_id hooks list */
3272 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3274 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3276 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3277 LttvTracefileContext
*, j
));
3279 for(k
= 0 ; k
< hooks
->len
; k
++) {
3280 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3281 lttv_hooks_remove_data(
3282 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3287 lttv_trace_hook_remove_all(&hooks
);
3288 g_array_free(hooks
, TRUE
);
3292 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3294 guint
*event_count
= (guint
*)hook_data
;
3296 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3297 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3302 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3304 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3306 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3308 LttvAttributeValue value
;
3310 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3311 LTTV_STATE_SAVED_STATES
);
3312 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3313 value
= lttv_attribute_add(saved_states_tree
,
3314 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3315 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3316 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3317 *(value
.v_time
) = self
->parent
.timestamp
;
3318 lttv_state_save(tcs
, saved_state_tree
);
3319 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3320 self
->parent
.timestamp
.tv_nsec
);
3322 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3327 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3329 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3331 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3336 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3344 static gboolean
block_start(void *hook_data
, void *call_data
)
3346 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3348 LttvTracefileState
*tfcs
;
3350 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3352 LttEventPosition
*ep
;
3354 guint i
, nb_block
, nb_event
, nb_tracefile
;
3358 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3360 LttvAttributeValue value
;
3362 ep
= ltt_event_position_new();
3364 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3366 /* Count the number of events added since the last block end in any
3369 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3371 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3372 LttvTracefileContext
, i
));
3373 ltt_event_position(tfcs
->parent
.e
, ep
);
3374 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3375 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3376 tfcs
->saved_position
= nb_event
;
3380 if(tcs
->nb_event
>= tcs
->save_interval
) {
3381 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3382 LTTV_STATE_SAVED_STATES
);
3383 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3384 value
= lttv_attribute_add(saved_states_tree
,
3385 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3386 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3387 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3388 *(value
.v_time
) = self
->parent
.timestamp
;
3389 lttv_state_save(tcs
, saved_state_tree
);
3391 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3392 self
->parent
.timestamp
.tv_nsec
);
3394 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3400 static gboolean
block_end(void *hook_data
, void *call_data
)
3402 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3404 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3408 LttEventPosition
*ep
;
3410 guint nb_block
, nb_event
;
3412 ep
= ltt_event_position_new();
3413 ltt_event_position(self
->parent
.e
, ep
);
3414 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3415 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3416 self
->saved_position
= 0;
3417 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3424 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3426 LttvTraceset
*traceset
= self
->parent
.ts
;
3428 guint i
, j
, nb_trace
, nb_tracefile
;
3432 LttvTracefileState
*tfs
;
3434 LttvTraceHook hook_start
, hook_end
;
3436 nb_trace
= lttv_traceset_number(traceset
);
3437 for(i
= 0 ; i
< nb_trace
; i
++) {
3438 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3440 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3441 NULL
, NULL
, block_start
, &hook_start
);
3442 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3443 NULL
, NULL
, block_end
, &hook_end
);
3445 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3447 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3449 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3450 LttvTracefileContext
, j
));
3451 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3452 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3453 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3454 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3460 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3462 LttvTraceset
*traceset
= self
->parent
.ts
;
3464 guint i
, j
, nb_trace
, nb_tracefile
;
3468 LttvTracefileState
*tfs
;
3471 nb_trace
= lttv_traceset_number(traceset
);
3472 for(i
= 0 ; i
< nb_trace
; i
++) {
3474 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3475 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3477 if(ts
->has_precomputed_states
) continue;
3479 guint
*event_count
= g_new(guint
, 1);
3482 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3484 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3485 LttvTracefileContext
*, j
));
3486 lttv_hooks_add(tfs
->parent
.event
,
3487 state_save_event_hook
,
3494 lttv_process_traceset_begin(&self
->parent
,
3495 NULL
, NULL
, NULL
, NULL
, NULL
);
3499 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3501 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3503 lttv_state_save_add_event_hooks(tss
);
3510 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3512 LttvTraceset
*traceset
= self
->parent
.ts
;
3514 guint i
, j
, nb_trace
, nb_tracefile
;
3518 LttvTracefileState
*tfs
;
3520 LttvTraceHook hook_start
, hook_end
;
3522 nb_trace
= lttv_traceset_number(traceset
);
3523 for(i
= 0 ; i
< nb_trace
; i
++) {
3524 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3526 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3527 NULL
, NULL
, block_start
, &hook_start
);
3529 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3530 NULL
, NULL
, block_end
, &hook_end
);
3532 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3534 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3536 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3537 LttvTracefileContext
, j
));
3538 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3539 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3540 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3541 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3547 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3549 LttvTraceset
*traceset
= self
->parent
.ts
;
3551 guint i
, j
, nb_trace
, nb_tracefile
;
3555 LttvTracefileState
*tfs
;
3557 LttvHooks
*after_trace
= lttv_hooks_new();
3559 lttv_hooks_add(after_trace
,
3560 state_save_after_trace_hook
,
3565 lttv_process_traceset_end(&self
->parent
,
3566 NULL
, after_trace
, NULL
, NULL
, NULL
);
3568 lttv_hooks_destroy(after_trace
);
3570 nb_trace
= lttv_traceset_number(traceset
);
3571 for(i
= 0 ; i
< nb_trace
; i
++) {
3573 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3574 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3576 if(ts
->has_precomputed_states
) continue;
3578 guint
*event_count
= NULL
;
3580 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3582 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3583 LttvTracefileContext
*, j
));
3584 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3585 state_save_event_hook
);
3587 if(event_count
) g_free(event_count
);
3591 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3593 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3595 lttv_state_save_remove_event_hooks(tss
);
3600 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3602 LttvTraceset
*traceset
= self
->parent
.ts
;
3606 int min_pos
, mid_pos
, max_pos
;
3608 guint call_rest
= 0;
3610 LttvTraceState
*tcs
;
3612 LttvAttributeValue value
;
3614 LttvAttributeType type
;
3616 LttvAttributeName name
;
3620 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3622 //g_tree_destroy(self->parent.pqueue);
3623 //self->parent.pqueue = g_tree_new(compare_tracefile);
3625 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3627 nb_trace
= lttv_traceset_number(traceset
);
3628 for(i
= 0 ; i
< nb_trace
; i
++) {
3629 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3631 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3632 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3633 LTTV_STATE_SAVED_STATES
);
3636 if(saved_states_tree
) {
3637 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3638 mid_pos
= max_pos
/ 2;
3639 while(min_pos
< max_pos
) {
3640 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3642 g_assert(type
== LTTV_GOBJECT
);
3643 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3644 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3646 g_assert(type
== LTTV_TIME
);
3647 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3649 closest_tree
= saved_state_tree
;
3651 else max_pos
= mid_pos
- 1;
3653 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3657 /* restore the closest earlier saved state */
3659 lttv_state_restore(tcs
, closest_tree
);
3663 /* There is no saved state, yet we want to have it. Restart at T0 */
3665 restore_init_state(tcs
);
3666 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3669 /* We want to seek quickly without restoring/updating the state */
3671 restore_init_state(tcs
);
3672 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3675 if(!call_rest
) g_info("NOT Calling restore");
3680 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3686 traceset_state_finalize (LttvTracesetState
*self
)
3688 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3689 finalize(G_OBJECT(self
));
3694 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3696 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3698 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3699 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3700 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3701 klass
->new_traceset_context
= new_traceset_context
;
3702 klass
->new_trace_context
= new_trace_context
;
3703 klass
->new_tracefile_context
= new_tracefile_context
;
3708 lttv_traceset_state_get_type(void)
3710 static GType type
= 0;
3712 static const GTypeInfo info
= {
3713 sizeof (LttvTracesetStateClass
),
3714 NULL
, /* base_init */
3715 NULL
, /* base_finalize */
3716 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3717 NULL
, /* class_finalize */
3718 NULL
, /* class_data */
3719 sizeof (LttvTracesetState
),
3720 0, /* n_preallocs */
3721 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3722 NULL
/* value handling */
3725 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3733 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3739 trace_state_finalize (LttvTraceState
*self
)
3741 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3742 finalize(G_OBJECT(self
));
3747 trace_state_class_init (LttvTraceStateClass
*klass
)
3749 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3751 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3752 klass
->state_save
= state_save
;
3753 klass
->state_restore
= state_restore
;
3754 klass
->state_saved_free
= state_saved_free
;
3759 lttv_trace_state_get_type(void)
3761 static GType type
= 0;
3763 static const GTypeInfo info
= {
3764 sizeof (LttvTraceStateClass
),
3765 NULL
, /* base_init */
3766 NULL
, /* base_finalize */
3767 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3768 NULL
, /* class_finalize */
3769 NULL
, /* class_data */
3770 sizeof (LttvTraceState
),
3771 0, /* n_preallocs */
3772 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3773 NULL
/* value handling */
3776 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3777 "LttvTraceStateType", &info
, 0);
3784 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3790 tracefile_state_finalize (LttvTracefileState
*self
)
3792 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3793 finalize(G_OBJECT(self
));
3798 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3800 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3802 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3807 lttv_tracefile_state_get_type(void)
3809 static GType type
= 0;
3811 static const GTypeInfo info
= {
3812 sizeof (LttvTracefileStateClass
),
3813 NULL
, /* base_init */
3814 NULL
, /* base_finalize */
3815 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3816 NULL
, /* class_finalize */
3817 NULL
, /* class_data */
3818 sizeof (LttvTracefileState
),
3819 0, /* n_preallocs */
3820 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3821 NULL
/* value handling */
3824 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3825 "LttvTracefileStateType", &info
, 0);
3831 static void module_init()
3833 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3834 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3835 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3836 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3837 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3838 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3839 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3840 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3841 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3842 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3843 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3844 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3845 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3846 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3847 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3848 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3849 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3850 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3851 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3852 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3853 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3854 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3855 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3856 LTTV_STATE_EVENT
= g_quark_from_string("event");
3857 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3858 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3859 LTTV_STATE_TIME
= g_quark_from_string("time");
3860 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3861 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3862 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3863 g_quark_from_string("trace_state_use_count");
3864 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3865 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
3866 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3867 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3870 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3871 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3872 LTT_FACILITY_FS
= g_quark_from_string("fs");
3873 LTT_FACILITY_LIST
= g_quark_from_string("list");
3874 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3875 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3878 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3879 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3880 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3881 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3882 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3883 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3884 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3885 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3886 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3887 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3888 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3889 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3890 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3891 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3892 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3893 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3894 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3895 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3896 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3897 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3898 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3899 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3902 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3903 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3904 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3905 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3906 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3907 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3908 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3909 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3910 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3911 LTT_FIELD_PID
= g_quark_from_string("pid");
3912 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3913 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3914 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3915 LTT_FIELD_NAME
= g_quark_from_string("name");
3916 LTT_FIELD_TYPE
= g_quark_from_string("type");
3917 LTT_FIELD_MODE
= g_quark_from_string("mode");
3918 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3919 LTT_FIELD_STATUS
= g_quark_from_string("status");
3920 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3921 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3922 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3923 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3924 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3925 LTT_FIELD_ACTION
= g_quark_from_string("action");
3927 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3928 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3929 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3930 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3931 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3933 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3934 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3935 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3937 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3938 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3939 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3940 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3943 static void module_destroy()
3948 LTTV_MODULE("state", "State computation", \
3949 "Update the system state, possibly saving it at intervals", \
3950 module_init
, module_destroy
)