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
);
259 restore_init_state(LttvTraceState
*self
)
261 guint i
, nb_cpus
, nb_irqs
;
263 //LttvTracefileState *tfcs;
265 LttTime start_time
, end_time
;
267 /* Free the process tables */
268 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
269 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
270 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
271 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
274 /* Seek time to beginning */
275 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
276 // closest. It's the tracecontext job to seek the trace to the beginning
277 // anyway : the init state might be used at the middle of the trace as well...
278 //g_tree_destroy(self->parent.ts_context->pqueue);
279 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
281 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
283 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
285 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
286 nb_irqs
= self
->nb_irqs
;
288 /* Put the per cpu running_process to beginning state : process 0. */
289 for(i
=0; i
< nb_cpus
; i
++) {
290 LttvExecutionState
*es
;
291 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
292 LTTV_STATE_UNNAMED
, &start_time
);
293 /* We are not sure is it's a kernel thread or normal thread, put the
294 * bottom stack state to unknown */
295 self
->running_process
[i
]->execution_stack
=
296 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
297 es
= self
->running_process
[i
]->state
=
298 &g_array_index(self
->running_process
[i
]->execution_stack
,
299 LttvExecutionState
, 0);
300 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
301 es
->s
= LTTV_STATE_UNNAMED
;
303 //self->running_process[i]->state->s = LTTV_STATE_RUN;
304 self
->running_process
[i
]->cpu
= i
;
306 /* reset cpu states */
307 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
308 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
311 /* reset irq states */
312 for(i
=0; i
<nb_irqs
; i
++) {
313 if(self
->irq_states
[i
].mode_stack
->len
> 0)
314 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
317 /* reset bdev states */
318 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
319 g_hash_table_steal_all(self
->bdev_states
);
322 nb_tracefile
= self
->parent
.tracefiles
->len
;
324 for(i
= 0 ; i
< nb_tracefile
; i
++) {
326 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
327 LttvTracefileContext
*, i
));
328 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
329 // tfcs->saved_position = 0;
330 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
331 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
332 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
333 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
338 //static LttTime time_zero = {0,0};
340 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
343 const LttTime
*t1
= (const LttTime
*)a
;
344 const LttTime
*t2
= (const LttTime
*)b
;
346 return ltt_time_compare(*t1
, *t2
);
349 static void free_usertrace_key(gpointer data
)
354 #define MAX_STRING_LEN 4096
357 state_load_saved_states(LttvTraceState
*tcs
)
360 GPtrArray
*quarktable
;
361 const char *trace_path
;
365 tcs
->has_precomputed_states
= FALSE
;
369 gchar buf
[MAX_STRING_LEN
];
372 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
373 strncpy(path
, trace_path
, PATH_MAX
-1);
374 count
= strnlen(trace_path
, PATH_MAX
-1);
375 // quarktable : open, test
376 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
377 fp
= fopen(path
, "r");
379 quarktable
= g_ptr_array_sized_new(4096);
381 /* Index 0 is null */
383 if(hdr
== EOF
) return;
384 g_assert(hdr
== HDR_QUARKS
);
388 if(hdr
== EOF
) break;
389 g_assert(hdr
== HDR_QUARK
);
390 g_ptr_array_set_size(quarktable
, q
+1);
393 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
394 if(buf
[i
] == '\0' || feof(fp
)) break;
397 len
= strnlen(buf
, MAX_STRING_LEN
-1);
398 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
399 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
405 // saved_states : open, test
406 strncpy(path
, trace_path
, PATH_MAX
-1);
407 count
= strnlen(trace_path
, PATH_MAX
-1);
408 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
409 fp
= fopen(path
, "r");
413 if(hdr
!= HDR_TRACE
) goto end
;
415 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
417 tcs
->has_precomputed_states
= TRUE
;
422 /* Free the quarktable */
423 for(i
=0; i
<quarktable
->len
; i
++) {
424 string
= g_ptr_array_index (quarktable
, i
);
427 g_ptr_array_free(quarktable
, TRUE
);
432 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
434 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
437 LttvTraceContext
*tc
;
441 LttvTracefileState
*tfcs
;
443 LttvAttributeValue v
;
445 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
446 init((LttvTracesetContext
*)self
, ts
);
448 nb_trace
= lttv_traceset_number(ts
);
449 for(i
= 0 ; i
< nb_trace
; i
++) {
450 tc
= self
->parent
.traces
[i
];
451 tcs
= LTTV_TRACE_STATE(tc
);
452 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
453 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
457 if(*(v
.v_uint
) == 1) {
458 create_name_tables(tcs
);
459 create_max_time(tcs
);
461 get_name_tables(tcs
);
464 nb_tracefile
= tc
->tracefiles
->len
;
465 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
466 nb_irq
= tcs
->nb_irqs
;
467 tcs
->processes
= NULL
;
468 tcs
->usertraces
= NULL
;
469 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
471 /* init cpu resource stuff */
472 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
473 for(j
= 0; j
<nb_cpu
; j
++) {
474 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
475 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
478 /* init irq resource stuff */
479 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
480 for(j
= 0; j
<nb_irq
; j
++) {
481 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
482 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
485 /* init bdev resource stuff */
486 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
488 restore_init_state(tcs
);
489 for(j
= 0 ; j
< nb_tracefile
; j
++) {
491 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
492 LttvTracefileContext
*, j
));
493 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
494 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
495 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
496 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
497 /* It's a Usertrace */
498 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
499 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
501 if(!usertrace_tree
) {
502 usertrace_tree
= g_tree_new_full(compare_usertraces
,
503 NULL
, free_usertrace_key
, NULL
);
504 g_hash_table_insert(tcs
->usertraces
,
505 (gpointer
)tid
, usertrace_tree
);
507 LttTime
*timestamp
= g_new(LttTime
, 1);
508 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
509 ltt_tracefile_creation(tfcs
->parent
.tf
));
510 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
514 /* See if the trace has saved states */
515 state_load_saved_states(tcs
);
520 fini(LttvTracesetState
*self
)
526 //LttvTracefileState *tfcs;
528 LttvAttributeValue v
;
530 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
531 for(i
= 0 ; i
< nb_trace
; i
++) {
532 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
533 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
536 g_assert(*(v
.v_uint
) != 0);
539 if(*(v
.v_uint
) == 0) {
540 free_name_tables(tcs
);
542 free_saved_state(tcs
);
544 g_free(tcs
->running_process
);
545 tcs
->running_process
= NULL
;
546 lttv_state_free_process_table(tcs
->processes
);
547 lttv_state_free_usertraces(tcs
->usertraces
);
548 tcs
->processes
= NULL
;
549 tcs
->usertraces
= NULL
;
551 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
552 fini((LttvTracesetContext
*)self
);
556 static LttvTracesetContext
*
557 new_traceset_context(LttvTracesetContext
*self
)
559 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
563 static LttvTraceContext
*
564 new_trace_context(LttvTracesetContext
*self
)
566 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
570 static LttvTracefileContext
*
571 new_tracefile_context(LttvTracesetContext
*self
)
573 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
577 /* Write the process state of the trace */
579 static void write_process_state(gpointer key
, gpointer value
,
582 LttvProcessState
*process
;
584 LttvExecutionState
*es
;
586 FILE *fp
= (FILE *)user_data
;
591 process
= (LttvProcessState
*)value
;
593 " <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",
594 process
, process
->pid
, process
->tgid
, process
->ppid
,
595 g_quark_to_string(process
->type
),
596 process
->creation_time
.tv_sec
,
597 process
->creation_time
.tv_nsec
,
598 process
->insertion_time
.tv_sec
,
599 process
->insertion_time
.tv_nsec
,
600 g_quark_to_string(process
->name
),
601 g_quark_to_string(process
->brand
),
604 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
605 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
606 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
607 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
608 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
609 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
610 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
613 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
614 address
= g_array_index(process
->user_stack
, guint64
, i
);
615 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
619 if(process
->usertrace
) {
620 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
621 g_quark_to_string(process
->usertrace
->tracefile_name
),
622 process
->usertrace
->cpu
);
626 fprintf(fp
, " </PROCESS>\n");
630 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
632 guint i
, nb_tracefile
, nb_block
, offset
;
635 LttvTracefileState
*tfcs
;
639 LttEventPosition
*ep
;
643 ep
= ltt_event_position_new();
645 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
647 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
649 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
650 for(i
=0;i
<nb_cpus
;i
++) {
651 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
652 i
, self
->running_process
[i
]->pid
);
655 nb_tracefile
= self
->parent
.tracefiles
->len
;
657 for(i
= 0 ; i
< nb_tracefile
; i
++) {
659 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
660 LttvTracefileContext
*, i
));
661 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
662 tfcs
->parent
.timestamp
.tv_sec
,
663 tfcs
->parent
.timestamp
.tv_nsec
);
664 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
665 if(e
== NULL
) fprintf(fp
,"/>\n");
667 ltt_event_position(e
, ep
);
668 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
669 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
674 fprintf(fp
,"</PROCESS_STATE>\n");
678 static void write_process_state_raw(gpointer key
, gpointer value
,
681 LttvProcessState
*process
;
683 LttvExecutionState
*es
;
685 FILE *fp
= (FILE *)user_data
;
690 process
= (LttvProcessState
*)value
;
691 fputc(HDR_PROCESS
, fp
);
692 //fwrite(&header, sizeof(header), 1, fp);
693 //fprintf(fp, "%s", g_quark_to_string(process->type));
695 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
696 //fprintf(fp, "%s", g_quark_to_string(process->name));
698 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
699 //fprintf(fp, "%s", g_quark_to_string(process->brand));
701 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
702 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
703 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
704 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
705 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
706 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
707 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
711 " <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",
712 process
, process
->pid
, process
->tgid
, process
->ppid
,
713 g_quark_to_string(process
->type
),
714 process
->creation_time
.tv_sec
,
715 process
->creation_time
.tv_nsec
,
716 process
->insertion_time
.tv_sec
,
717 process
->insertion_time
.tv_nsec
,
718 g_quark_to_string(process
->name
),
719 g_quark_to_string(process
->brand
),
723 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
724 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
727 //fprintf(fp, "%s", g_quark_to_string(es->t));
729 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
730 //fprintf(fp, "%s", g_quark_to_string(es->n));
732 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
733 //fprintf(fp, "%s", g_quark_to_string(es->s));
735 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
736 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
737 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
738 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
740 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
741 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
742 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
743 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
744 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
748 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
749 address
= g_array_index(process
->user_stack
, guint64
, i
);
750 fputc(HDR_USER_STACK
, fp
);
751 fwrite(&address
, sizeof(address
), 1, fp
);
753 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
758 if(process
->usertrace
) {
759 fputc(HDR_USERTRACE
, fp
);
760 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
762 fwrite(&process
->usertrace
->tracefile_name
,
763 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
764 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
766 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
767 g_quark_to_string(process
->usertrace
->tracefile_name
),
768 process
->usertrace
->cpu
);
775 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
777 guint i
, nb_tracefile
, nb_block
, offset
;
780 LttvTracefileState
*tfcs
;
784 LttEventPosition
*ep
;
788 ep
= ltt_event_position_new();
790 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
791 fputc(HDR_PROCESS_STATE
, fp
);
792 fwrite(&t
, sizeof(t
), 1, fp
);
794 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
796 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
797 for(i
=0;i
<nb_cpus
;i
++) {
799 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
800 fwrite(&self
->running_process
[i
]->pid
,
801 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
802 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
803 // i, self->running_process[i]->pid);
806 nb_tracefile
= self
->parent
.tracefiles
->len
;
808 for(i
= 0 ; i
< nb_tracefile
; i
++) {
810 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
811 LttvTracefileContext
*, i
));
812 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
813 // tfcs->parent.timestamp.tv_sec,
814 // tfcs->parent.timestamp.tv_nsec);
815 fputc(HDR_TRACEFILE
, fp
);
816 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
817 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
818 * position following : end of trace */
819 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
821 ltt_event_position(e
, ep
);
822 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
823 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
825 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
826 fwrite(&offset
, sizeof(offset
), 1, fp
);
827 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
834 /* Read process state from a file */
836 /* Called because a HDR_PROCESS was found */
837 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
838 GPtrArray
*quarktable
)
840 LttvExecutionState
*es
;
841 LttvProcessState
*process
, *parent_process
;
842 LttvProcessState tmp
;
847 /* TODO : check return value */
848 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
849 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
850 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
851 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
852 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
853 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
854 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
855 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
856 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
859 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
861 /* We must link to the parent */
862 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
864 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
865 if(process
== NULL
) {
866 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
868 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
872 process
->insertion_time
= tmp
.insertion_time
;
873 process
->creation_time
= tmp
.creation_time
;
874 process
->type
= g_quark_from_string(
875 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
876 process
->tgid
= tmp
.tgid
;
877 process
->ppid
= tmp
.ppid
;
878 process
->brand
= g_quark_from_string(
879 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
881 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
885 if(feof(fp
) || ferror(fp
)) goto end_loop
;
887 gint hdr
= fgetc(fp
);
888 if(hdr
== EOF
) goto end_loop
;
892 process
->execution_stack
=
893 g_array_set_size(process
->execution_stack
,
894 process
->execution_stack
->len
+ 1);
895 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
896 process
->execution_stack
->len
-1);
899 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
900 es
->t
= g_quark_from_string(
901 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
902 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
903 es
->n
= g_quark_from_string(
904 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
905 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
906 es
->s
= g_quark_from_string(
907 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
908 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
909 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
910 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
913 process
->user_stack
= g_array_set_size(process
->user_stack
,
914 process
->user_stack
->len
+ 1);
915 address
= &g_array_index(process
->user_stack
, guint64
,
916 process
->user_stack
->len
-1);
917 fread(address
, sizeof(address
), 1, fp
);
918 process
->current_function
= *address
;
921 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
922 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
934 /* Called because a HDR_PROCESS_STATE was found */
935 /* Append a saved state to the trace states */
936 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
938 guint i
, nb_tracefile
, nb_block
, offset
;
940 LttvTracefileState
*tfcs
;
942 LttEventPosition
*ep
;
950 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
952 LttvAttributeValue value
;
953 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
954 ep
= ltt_event_position_new();
956 restore_init_state(self
);
958 fread(&t
, sizeof(t
), 1, fp
);
961 if(feof(fp
) || ferror(fp
)) goto end_loop
;
963 if(hdr
== EOF
) goto end_loop
;
967 /* Call read_process_state_raw */
968 read_process_state_raw(self
, fp
, quarktable
);
978 case HDR_PROCESS_STATE
:
984 g_error("Error while parsing saved state file : unknown data header %d",
990 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
991 for(i
=0;i
<nb_cpus
;i
++) {
994 g_assert(hdr
== HDR_CPU
);
995 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
996 g_assert(i
== cpu_num
);
997 fread(&self
->running_process
[i
]->pid
,
998 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1001 nb_tracefile
= self
->parent
.tracefiles
->len
;
1003 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1005 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1006 LttvTracefileContext
*, i
));
1007 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1008 // tfcs->parent.timestamp.tv_sec,
1009 // tfcs->parent.timestamp.tv_nsec);
1010 g_tree_remove(pqueue
, &tfcs
->parent
);
1012 g_assert(hdr
== HDR_TRACEFILE
);
1013 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1014 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1015 * position following : end of trace */
1016 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1017 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1018 fread(&offset
, sizeof(offset
), 1, fp
);
1019 fread(&tsc
, sizeof(tsc
), 1, fp
);
1020 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1021 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1023 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1028 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1029 LTTV_STATE_SAVED_STATES
);
1030 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1031 value
= lttv_attribute_add(saved_states_tree
,
1032 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1033 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1034 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1035 *(value
.v_time
) = t
;
1036 lttv_state_save(self
, saved_state_tree
);
1037 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1040 *(self
->max_time_state_recomputed_in_seek
) = t
;
1044 /* Called when a HDR_TRACE is found */
1045 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1046 GPtrArray
*quarktable
)
1051 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1053 if(hdr
== EOF
) goto end_loop
;
1056 case HDR_PROCESS_STATE
:
1057 /* Call read_process_state_raw */
1058 lttv_state_read_raw(tcs
, fp
, quarktable
);
1066 case HDR_USER_STACK
:
1070 g_error("Error while parsing saved state file :"
1071 " unexpected data header %d",
1075 g_error("Error while parsing saved state file : unknown data header %d",
1080 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1081 restore_init_state(tcs
);
1082 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1088 /* Copy each process from an existing hash table to a new one */
1090 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1092 LttvProcessState
*process
, *new_process
;
1094 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1098 process
= (LttvProcessState
*)value
;
1099 new_process
= g_new(LttvProcessState
, 1);
1100 *new_process
= *process
;
1101 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1102 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1103 new_process
->execution_stack
=
1104 g_array_set_size(new_process
->execution_stack
,
1105 process
->execution_stack
->len
);
1106 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1107 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1108 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1110 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1111 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1112 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1113 sizeof(guint64
), 0);
1114 new_process
->user_stack
=
1115 g_array_set_size(new_process
->user_stack
,
1116 process
->user_stack
->len
);
1117 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1118 g_array_index(new_process
->user_stack
, guint64
, i
) =
1119 g_array_index(process
->user_stack
, guint64
, i
);
1121 new_process
->current_function
= process
->current_function
;
1122 g_hash_table_insert(new_processes
, new_process
, new_process
);
1126 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1128 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1130 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1131 return new_processes
;
1134 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1137 LttvCPUState
*retval
;
1139 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1141 for(i
=0; i
<n
; i
++) {
1142 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1143 retval
[i
].last_irq
= states
[i
].last_irq
;
1144 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1145 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1146 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1153 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1157 for(i
=0; i
<n
; i
++) {
1158 g_array_free(states
[i
].mode_stack
, TRUE
);
1164 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1167 LttvIRQState
*retval
;
1169 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1171 for(i
=0; i
<n
; i
++) {
1172 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1173 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1174 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1175 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1182 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1186 for(i
=0; i
<n
; i
++) {
1187 g_array_free(states
[i
].mode_stack
, TRUE
);
1193 /* bdevstate stuff */
1195 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1197 gint devcode_gint
= devcode
;
1198 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1200 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1201 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1203 gint
* key
= g_malloc(sizeof(gint
));
1205 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1213 static LttvBdevState
*bdevstate_new(void)
1215 LttvBdevState
*retval
;
1216 retval
= g_malloc(sizeof(LttvBdevState
));
1217 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1222 static void bdevstate_free(LttvBdevState
*bds
)
1224 g_array_free(bds
->mode_stack
, TRUE
);
1228 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1230 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1232 bdevstate_free(bds
);
1235 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1237 LttvBdevState
*retval
;
1239 retval
= bdevstate_new();
1240 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1245 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1247 //GHashTable *ht = (GHashTable *)u;
1248 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1249 LttvBdevState
*newbds
;
1251 newbds
= bdevstate_copy(bds
);
1253 g_hash_table_insert(u
, k
, newbds
);
1256 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1260 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1262 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1267 /* Free a hashtable and the LttvBdevState structures its values
1270 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1272 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1273 g_hash_table_destroy(ht
);
1276 /* The saved state for each trace contains a member "processes", which
1277 stores a copy of the process table, and a member "tracefiles" with
1278 one entry per tracefile. Each tracefile has a "process" member pointing
1279 to the current process and a "position" member storing the tracefile
1280 position (needed to seek to the current "next" event. */
1282 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1284 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1286 LttvTracefileState
*tfcs
;
1288 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1290 guint
*running_process
;
1292 LttvAttributeValue value
;
1294 LttEventPosition
*ep
;
1296 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1297 LTTV_STATE_TRACEFILES
);
1299 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1301 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1303 /* Add the currently running processes array */
1304 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1305 running_process
= g_new(guint
, nb_cpus
);
1306 for(i
=0;i
<nb_cpus
;i
++) {
1307 running_process
[i
] = self
->running_process
[i
]->pid
;
1309 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1311 *(value
.v_pointer
) = running_process
;
1313 g_info("State save");
1315 nb_tracefile
= self
->parent
.tracefiles
->len
;
1317 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1319 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1320 LttvTracefileContext
*, i
));
1321 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1322 value
= lttv_attribute_add(tracefiles_tree
, i
,
1324 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1326 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1328 *(value
.v_uint
) = tfcs
->process
->pid
;
1330 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1332 /* Only save the position if the tfs has not infinite time. */
1333 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1334 // && current_tfcs != tfcs) {
1335 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1336 *(value
.v_pointer
) = NULL
;
1338 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1339 ep
= ltt_event_position_new();
1340 ltt_event_position(e
, ep
);
1341 *(value
.v_pointer
) = ep
;
1343 guint nb_block
, offset
;
1346 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1347 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1349 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1353 /* save the cpu state */
1355 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
,
1357 *(value
.v_uint
) = nb_cpus
;
1359 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1361 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1364 /* save the irq state */
1365 nb_irqs
= self
->nb_irqs
;
1367 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1369 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1372 /* save the blkdev states */
1373 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1375 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1379 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1381 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1383 LttvTracefileState
*tfcs
;
1385 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1387 guint
*running_process
;
1389 LttvAttributeType type
;
1391 LttvAttributeValue value
;
1393 LttvAttributeName name
;
1397 LttEventPosition
*ep
;
1399 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1401 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1402 LTTV_STATE_TRACEFILES
);
1404 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1406 g_assert(type
== LTTV_POINTER
);
1407 lttv_state_free_process_table(self
->processes
);
1408 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1410 /* Add the currently running processes array */
1411 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1412 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1414 g_assert(type
== LTTV_POINTER
);
1415 running_process
= *(value
.v_pointer
);
1416 for(i
=0;i
<nb_cpus
;i
++) {
1417 pid
= running_process
[i
];
1418 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1419 g_assert(self
->running_process
[i
] != NULL
);
1422 nb_tracefile
= self
->parent
.tracefiles
->len
;
1424 //g_tree_destroy(tsc->pqueue);
1425 //tsc->pqueue = g_tree_new(compare_tracefile);
1427 /* restore cpu resource states */
1428 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1429 g_assert(type
== LTTV_POINTER
);
1430 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1431 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1433 /* restore irq resource states */
1434 nb_irqs
= self
->nb_irqs
;
1435 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1436 g_assert(type
== LTTV_POINTER
);
1437 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1438 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1440 /* restore the blkdev states */
1441 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1442 g_assert(type
== LTTV_POINTER
);
1443 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1444 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1446 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1448 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1449 LttvTracefileContext
*, i
));
1450 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1451 g_assert(type
== LTTV_GOBJECT
);
1452 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1454 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1456 g_assert(type
== LTTV_UINT
);
1457 pid
= *(value
.v_uint
);
1458 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1460 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1462 g_assert(type
== LTTV_POINTER
);
1463 //g_assert(*(value.v_pointer) != NULL);
1464 ep
= *(value
.v_pointer
);
1465 g_assert(tfcs
->parent
.t_context
!= NULL
);
1467 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1469 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1470 g_tree_remove(tsc
->pqueue
, tfc
);
1473 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1474 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1475 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1476 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1477 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1479 tfc
->timestamp
= ltt_time_infinite
;
1485 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1487 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1489 LttvTracefileState
*tfcs
;
1491 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1493 guint
*running_process
;
1495 LttvAttributeType type
;
1497 LttvAttributeValue value
;
1499 LttvAttributeName name
;
1503 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1504 LTTV_STATE_TRACEFILES
);
1505 g_object_ref(G_OBJECT(tracefiles_tree
));
1506 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1508 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1510 g_assert(type
== LTTV_POINTER
);
1511 lttv_state_free_process_table(*(value
.v_pointer
));
1512 *(value
.v_pointer
) = NULL
;
1513 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1515 /* Free running processes array */
1516 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1518 g_assert(type
== LTTV_POINTER
);
1519 running_process
= *(value
.v_pointer
);
1520 g_free(running_process
);
1522 /* free cpu resource states */
1523 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS_COUNT
, &value
);
1524 g_assert(type
== LTTV_UINT
);
1525 nb_cpus
= *value
.v_uint
;
1526 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1527 g_assert(type
== LTTV_POINTER
);
1528 lttv_state_free_cpu_states(*(value
.v_pointer
), nb_cpus
);
1530 /* free irq resource states */
1531 nb_irqs
= self
->nb_irqs
;
1532 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1533 g_assert(type
== LTTV_POINTER
);
1534 lttv_state_free_irq_states(*(value
.v_pointer
), nb_irqs
);
1536 /* free the blkdev states */
1537 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1538 g_assert(type
== LTTV_POINTER
);
1539 lttv_state_free_blkdev_hashtable(*(value
.v_pointer
));
1541 nb_tracefile
= self
->parent
.tracefiles
->len
;
1543 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1545 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1546 LttvTracefileContext
*, i
));
1547 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1548 g_assert(type
== LTTV_GOBJECT
);
1549 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1551 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1553 g_assert(type
== LTTV_POINTER
);
1554 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1556 g_object_unref(G_OBJECT(tracefiles_tree
));
1560 static void free_saved_state(LttvTraceState
*self
)
1564 LttvAttributeType type
;
1566 LttvAttributeValue value
;
1568 LttvAttributeName name
;
1572 LttvAttribute
*saved_states
;
1574 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1575 LTTV_STATE_SAVED_STATES
);
1577 nb
= lttv_attribute_get_number(saved_states
);
1578 for(i
= 0 ; i
< nb
; i
++) {
1579 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1580 g_assert(type
== LTTV_GOBJECT
);
1581 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1584 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1589 create_max_time(LttvTraceState
*tcs
)
1591 LttvAttributeValue v
;
1593 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1595 g_assert(*(v
.v_pointer
) == NULL
);
1596 *(v
.v_pointer
) = g_new(LttTime
,1);
1597 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1602 get_max_time(LttvTraceState
*tcs
)
1604 LttvAttributeValue v
;
1606 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1608 g_assert(*(v
.v_pointer
) != NULL
);
1609 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1614 free_max_time(LttvTraceState
*tcs
)
1616 LttvAttributeValue v
;
1618 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1620 g_free(*(v
.v_pointer
));
1621 *(v
.v_pointer
) = NULL
;
1625 typedef struct _LttvNameTables
{
1626 // FIXME GQuark *eventtype_names;
1627 GQuark
*syscall_names
;
1633 GQuark
*soft_irq_names
;
1639 create_name_tables(LttvTraceState
*tcs
)
1643 GString
*fe_name
= g_string_new("");
1645 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1647 LttvAttributeValue v
;
1651 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1653 g_assert(*(v
.v_pointer
) == NULL
);
1654 *(v
.v_pointer
) = name_tables
;
1656 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1658 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1659 LTT_FACILITY_KERNEL_ARCH
,
1660 LTT_EVENT_SYSCALL_ENTRY
,
1661 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1662 NULL
, NULL
, &hooks
)) {
1664 // th = lttv_trace_hook_get_first(&th);
1666 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1667 // nb = ltt_type_element_number(t);
1669 // name_tables->syscall_names = g_new(GQuark, nb);
1670 // name_tables->nb_syscalls = nb;
1672 // for(i = 0 ; i < nb ; i++) {
1673 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1674 // if(!name_tables->syscall_names[i]) {
1675 // GString *string = g_string_new("");
1676 // g_string_printf(string, "syscall %u", i);
1677 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1678 // g_string_free(string, TRUE);
1682 name_tables
->nb_syscalls
= 256;
1683 name_tables
->syscall_names
= g_new(GQuark
, 256);
1684 for(i
= 0 ; i
< 256 ; i
++) {
1685 g_string_printf(fe_name
, "syscall %d", i
);
1686 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1689 name_tables
->syscall_names
= NULL
;
1690 name_tables
->nb_syscalls
= 0;
1692 lttv_trace_hook_remove_all(&hooks
);
1694 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1695 LTT_FACILITY_KERNEL_ARCH
,
1696 LTT_EVENT_TRAP_ENTRY
,
1697 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1698 NULL
, NULL
, &hooks
)) {
1700 // th = lttv_trace_hook_get_first(&th);
1702 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1703 // //nb = ltt_type_element_number(t);
1705 // name_tables->trap_names = g_new(GQuark, nb);
1706 // for(i = 0 ; i < nb ; i++) {
1707 // name_tables->trap_names[i] = g_quark_from_string(
1708 // ltt_enum_string_get(t, i));
1711 name_tables
->nb_traps
= 256;
1712 name_tables
->trap_names
= g_new(GQuark
, 256);
1713 for(i
= 0 ; i
< 256 ; i
++) {
1714 g_string_printf(fe_name
, "trap %d", i
);
1715 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1718 name_tables
->trap_names
= NULL
;
1719 name_tables
->nb_traps
= 0;
1721 lttv_trace_hook_remove_all(&hooks
);
1723 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1724 LTT_FACILITY_KERNEL
,
1725 LTT_EVENT_IRQ_ENTRY
,
1726 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1727 NULL
, NULL
, &hooks
)) {
1730 name_tables->irq_names = g_new(GQuark, nb);
1731 for(i = 0 ; i < nb ; i++) {
1732 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1736 name_tables
->nb_irqs
= 256;
1737 name_tables
->irq_names
= g_new(GQuark
, 256);
1738 for(i
= 0 ; i
< 256 ; i
++) {
1739 g_string_printf(fe_name
, "irq %d", i
);
1740 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1743 name_tables
->nb_irqs
= 0;
1744 name_tables
->irq_names
= NULL
;
1746 lttv_trace_hook_remove_all(&hooks
);
1748 name_tables->soft_irq_names = g_new(GQuark, nb);
1749 for(i = 0 ; i < nb ; i++) {
1750 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1754 name_tables
->nb_softirqs
= 256;
1755 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1756 for(i
= 0 ; i
< 256 ; i
++) {
1757 g_string_printf(fe_name
, "softirq %d", i
);
1758 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1760 g_array_free(hooks
, TRUE
);
1762 g_string_free(fe_name
, TRUE
);
1767 get_name_tables(LttvTraceState
*tcs
)
1769 LttvNameTables
*name_tables
;
1771 LttvAttributeValue v
;
1773 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1775 g_assert(*(v
.v_pointer
) != NULL
);
1776 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1777 //tcs->eventtype_names = name_tables->eventtype_names;
1778 tcs
->syscall_names
= name_tables
->syscall_names
;
1779 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1780 tcs
->trap_names
= name_tables
->trap_names
;
1781 tcs
->nb_traps
= name_tables
->nb_traps
;
1782 tcs
->irq_names
= name_tables
->irq_names
;
1783 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1784 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1785 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1790 free_name_tables(LttvTraceState
*tcs
)
1792 LttvNameTables
*name_tables
;
1794 LttvAttributeValue v
;
1796 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1798 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1799 *(v
.v_pointer
) = NULL
;
1801 // g_free(name_tables->eventtype_names);
1802 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1803 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1804 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1805 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1806 if(name_tables
) g_free(name_tables
);
1809 #ifdef HASH_TABLE_DEBUG
1811 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1813 LttvProcessState
*process
= (LttvProcessState
*)value
;
1815 /* Test for process corruption */
1816 guint stack_len
= process
->execution_stack
->len
;
1819 static void hash_table_check(GHashTable
*table
)
1821 g_hash_table_foreach(table
, test_process
, NULL
);
1827 /* clears the stack and sets the state passed as argument */
1828 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1830 g_array_set_size(cpust
->mode_stack
, 1);
1831 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1834 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1836 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1837 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1840 static void cpu_pop_mode(LttvCPUState
*cpust
)
1842 if(cpust
->mode_stack
->len
<= 1)
1843 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1845 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1848 /* clears the stack and sets the state passed as argument */
1849 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1851 g_array_set_size(bdevst
->mode_stack
, 1);
1852 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1855 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1857 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1858 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1861 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1863 if(bdevst
->mode_stack
->len
<= 1)
1864 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1866 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1869 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1871 g_array_set_size(irqst
->mode_stack
, 1);
1872 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1875 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1877 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1878 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1881 static void irq_pop_mode(LttvIRQState
*irqst
)
1883 if(irqst
->mode_stack
->len
<= 1)
1884 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1886 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1889 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1892 LttvExecutionState
*es
;
1894 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1895 guint cpu
= tfs
->cpu
;
1897 #ifdef HASH_TABLE_DEBUG
1898 hash_table_check(ts
->processes
);
1900 LttvProcessState
*process
= ts
->running_process
[cpu
];
1902 guint depth
= process
->execution_stack
->len
;
1904 process
->execution_stack
=
1905 g_array_set_size(process
->execution_stack
, depth
+ 1);
1908 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1910 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1913 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1914 es
->cum_cpu_time
= ltt_time_zero
;
1915 es
->s
= process
->state
->s
;
1916 process
->state
= es
;
1920 * return 1 when empty, else 0 */
1921 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1922 LttvTracefileState
*tfs
)
1924 guint depth
= process
->execution_stack
->len
;
1930 process
->execution_stack
=
1931 g_array_set_size(process
->execution_stack
, depth
- 1);
1932 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1934 process
->state
->change
= tfs
->parent
.timestamp
;
1939 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1941 guint cpu
= tfs
->cpu
;
1942 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1943 LttvProcessState
*process
= ts
->running_process
[cpu
];
1945 guint depth
= process
->execution_stack
->len
;
1947 if(process
->state
->t
!= t
){
1948 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1949 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1950 g_info("process state has %s when pop_int is %s\n",
1951 g_quark_to_string(process
->state
->t
),
1952 g_quark_to_string(t
));
1953 g_info("{ %u, %u, %s, %s, %s }\n",
1956 g_quark_to_string(process
->name
),
1957 g_quark_to_string(process
->brand
),
1958 g_quark_to_string(process
->state
->s
));
1963 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1964 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1968 process
->execution_stack
=
1969 g_array_set_size(process
->execution_stack
, depth
- 1);
1970 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1972 process
->state
->change
= tfs
->parent
.timestamp
;
1975 struct search_result
{
1976 const LttTime
*time
; /* Requested time */
1977 LttTime
*best
; /* Best result */
1980 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1982 const LttTime
*elem_time
= (const LttTime
*)a
;
1983 /* Explicit non const cast */
1984 struct search_result
*res
= (struct search_result
*)b
;
1986 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1987 /* The usertrace was created before the schedchange */
1988 /* Get larger keys */
1990 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1991 /* The usertrace was created after the schedchange time */
1992 /* Get smaller keys */
1994 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1995 res
->best
= (LttTime
*)elem_time
;
1998 res
->best
= (LttTime
*)elem_time
;
2005 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2006 guint pid
, const LttTime
*timestamp
)
2008 LttvTracefileState
*tfs
= NULL
;
2009 struct search_result res
;
2010 /* Find the usertrace associated with a pid and time interval.
2011 * Search in the usertraces by PID (within a hash) and then, for each
2012 * corresponding element of the array, find the first one with creation
2013 * timestamp the lowest, but higher or equal to "timestamp". */
2014 res
.time
= timestamp
;
2016 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2017 if(usertrace_tree
) {
2018 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2020 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2028 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2029 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2031 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2033 LttvExecutionState
*es
;
2038 process
->tgid
= tgid
;
2040 process
->name
= name
;
2041 process
->brand
= LTTV_STATE_UNBRANDED
;
2042 //process->last_cpu = tfs->cpu_name;
2043 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2044 process
->type
= LTTV_STATE_USER_THREAD
;
2045 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2046 process
->current_function
= 0; //function 0x0 by default.
2048 g_info("Process %u, core %p", process
->pid
, process
);
2049 g_hash_table_insert(tcs
->processes
, process
, process
);
2052 process
->ppid
= parent
->pid
;
2053 process
->creation_time
= *timestamp
;
2056 /* No parent. This process exists but we are missing all information about
2057 its creation. The birth time is set to zero but we remember the time of
2062 process
->creation_time
= ltt_time_zero
;
2065 process
->insertion_time
= *timestamp
;
2066 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2067 process
->creation_time
.tv_nsec
);
2068 process
->pid_time
= g_quark_from_string(buffer
);
2070 //process->last_cpu = tfs->cpu_name;
2071 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2072 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2073 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2074 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2075 es
= process
->state
= &g_array_index(process
->execution_stack
,
2076 LttvExecutionState
, 0);
2077 es
->t
= LTTV_STATE_USER_MODE
;
2078 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2079 es
->entry
= *timestamp
;
2080 //g_assert(timestamp->tv_sec != 0);
2081 es
->change
= *timestamp
;
2082 es
->cum_cpu_time
= ltt_time_zero
;
2083 es
->s
= LTTV_STATE_RUN
;
2085 es
= process
->state
= &g_array_index(process
->execution_stack
,
2086 LttvExecutionState
, 1);
2087 es
->t
= LTTV_STATE_SYSCALL
;
2088 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2089 es
->entry
= *timestamp
;
2090 //g_assert(timestamp->tv_sec != 0);
2091 es
->change
= *timestamp
;
2092 es
->cum_cpu_time
= ltt_time_zero
;
2093 es
->s
= LTTV_STATE_WAIT_FORK
;
2095 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2096 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2097 sizeof(guint64
), 0);
2102 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2105 LttvProcessState key
;
2106 LttvProcessState
*process
;
2110 process
= g_hash_table_lookup(ts
->processes
, &key
);
2115 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2116 const LttTime
*timestamp
)
2118 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2119 LttvExecutionState
*es
;
2121 /* Put ltt_time_zero creation time for unexisting processes */
2122 if(unlikely(process
== NULL
)) {
2123 process
= lttv_state_create_process(ts
,
2124 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2125 /* We are not sure is it's a kernel thread or normal thread, put the
2126 * bottom stack state to unknown */
2127 process
->execution_stack
=
2128 g_array_set_size(process
->execution_stack
, 1);
2129 process
->state
= es
=
2130 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2131 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2132 es
->s
= LTTV_STATE_UNNAMED
;
2137 /* FIXME : this function should be called when we receive an event telling that
2138 * release_task has been called in the kernel. In happens generally when
2139 * the parent waits for its child terminaison, but may also happen in special
2140 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2141 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2142 * of a killed thread ground, but isn't the leader.
2144 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2146 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2147 LttvProcessState key
;
2149 key
.pid
= process
->pid
;
2150 key
.cpu
= process
->cpu
;
2151 g_hash_table_remove(ts
->processes
, &key
);
2152 g_array_free(process
->execution_stack
, TRUE
);
2153 g_array_free(process
->user_stack
, TRUE
);
2158 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2160 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2161 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2166 static void lttv_state_free_process_table(GHashTable
*processes
)
2168 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2169 g_hash_table_destroy(processes
);
2173 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2175 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2177 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2178 LttvProcessState
*process
= ts
->running_process
[cpu
];
2179 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2180 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2181 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2183 LttvExecutionSubmode submode
;
2185 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2186 guint syscall
= ltt_event_get_unsigned(e
, f
);
2188 if(syscall
< nb_syscalls
) {
2189 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2192 /* Fixup an incomplete syscall table */
2193 GString
*string
= g_string_new("");
2194 g_string_printf(string
, "syscall %u", syscall
);
2195 submode
= g_quark_from_string(string
->str
);
2196 g_string_free(string
, TRUE
);
2198 /* There can be no system call from PID 0 : unknown state */
2199 if(process
->pid
!= 0)
2200 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2205 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2207 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2209 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2210 LttvProcessState
*process
= ts
->running_process
[cpu
];
2212 /* There can be no system call from PID 0 : unknown state */
2213 if(process
->pid
!= 0)
2214 pop_state(s
, LTTV_STATE_SYSCALL
);
2219 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2221 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2222 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2223 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2224 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2226 LttvExecutionSubmode submode
;
2228 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2229 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2231 if(trap
< nb_traps
) {
2232 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2234 /* Fixup an incomplete trap table */
2235 GString
*string
= g_string_new("");
2236 g_string_printf(string
, "trap %llu", trap
);
2237 submode
= g_quark_from_string(string
->str
);
2238 g_string_free(string
, TRUE
);
2241 push_state(s
, LTTV_STATE_TRAP
, submode
);
2243 /* update cpu status */
2244 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2249 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2251 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2253 pop_state(s
, LTTV_STATE_TRAP
);
2255 /* update cpu status */
2256 cpu_pop_mode(s
->cpu_state
);
2261 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2263 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2264 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2265 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2266 //guint8 ev_id = ltt_event_eventtype_id(e);
2267 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2268 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2270 LttvExecutionSubmode submode
;
2271 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2272 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2275 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2277 /* Fixup an incomplete irq table */
2278 GString
*string
= g_string_new("");
2279 g_string_printf(string
, "irq %llu", irq
);
2280 submode
= g_quark_from_string(string
->str
);
2281 g_string_free(string
, TRUE
);
2284 /* Do something with the info about being in user or system mode when int? */
2285 push_state(s
, LTTV_STATE_IRQ
, submode
);
2287 /* update cpu status */
2288 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2290 /* update irq status */
2291 s
->cpu_state
->last_irq
= irq
;
2292 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2297 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2299 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2301 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2307 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2309 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2310 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2312 pop_state(s
, LTTV_STATE_IRQ
);
2314 /* update cpu status */
2315 cpu_pop_mode(s
->cpu_state
);
2317 /* update irq status */
2318 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2323 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2325 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2326 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2327 //guint8 ev_id = ltt_event_eventtype_id(e);
2328 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2329 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2331 LttvExecutionSubmode submode
;
2332 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2333 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2335 if(softirq
< nb_softirqs
) {
2336 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2338 /* Fixup an incomplete irq table */
2339 GString
*string
= g_string_new("");
2340 g_string_printf(string
, "softirq %llu", softirq
);
2341 submode
= g_quark_from_string(string
->str
);
2342 g_string_free(string
, TRUE
);
2345 /* Do something with the info about being in user or system mode when int? */
2346 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2350 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2352 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2353 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2354 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2355 //guint8 ev_id = ltt_event_eventtype_id(e);
2356 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2358 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2359 lttv_trace_get_hook_field(th
, 0)));
2360 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2362 ts
->irq_names
[irq
] = action
;
2368 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2370 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2371 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2372 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2373 //guint8 ev_id = ltt_event_eventtype_id(e);
2374 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2376 guint major
= ltt_event_get_long_unsigned(e
,
2377 lttv_trace_get_hook_field(th
, 0));
2378 guint minor
= ltt_event_get_long_unsigned(e
,
2379 lttv_trace_get_hook_field(th
, 1));
2380 guint oper
= ltt_event_get_long_unsigned(e
,
2381 lttv_trace_get_hook_field(th
, 2));
2382 guint16 devcode
= MKDEV(major
,minor
);
2384 /* have we seen this block device before? */
2385 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2388 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2390 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2395 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2397 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2398 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2399 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2400 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2402 guint major
= ltt_event_get_long_unsigned(e
,
2403 lttv_trace_get_hook_field(th
, 0));
2404 guint minor
= ltt_event_get_long_unsigned(e
,
2405 lttv_trace_get_hook_field(th
, 1));
2406 //guint oper = ltt_event_get_long_unsigned(e,
2407 // lttv_trace_get_hook_field(th, 2));
2408 guint16 devcode
= MKDEV(major
,minor
);
2410 /* have we seen this block device before? */
2411 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2413 /* update block device */
2414 bdev_pop_mode(bdev
);
2419 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2423 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2424 guint cpu
= tfs
->cpu
;
2425 LttvProcessState
*process
= ts
->running_process
[cpu
];
2427 guint depth
= process
->user_stack
->len
;
2429 process
->user_stack
=
2430 g_array_set_size(process
->user_stack
, depth
+ 1);
2432 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2433 *new_func
= funcptr
;
2434 process
->current_function
= funcptr
;
2437 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2439 guint cpu
= tfs
->cpu
;
2440 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2441 LttvProcessState
*process
= ts
->running_process
[cpu
];
2443 if(process
->current_function
!= funcptr
){
2444 g_info("Different functions (%lu.%09lu): ignore it\n",
2445 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2446 g_info("process state has %llu when pop_function is %llu\n",
2447 process
->current_function
, funcptr
);
2448 g_info("{ %u, %u, %s, %s, %s }\n",
2451 g_quark_to_string(process
->name
),
2452 g_quark_to_string(process
->brand
),
2453 g_quark_to_string(process
->state
->s
));
2456 guint depth
= process
->user_stack
->len
;
2459 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2460 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2464 process
->user_stack
=
2465 g_array_set_size(process
->user_stack
, depth
- 1);
2466 process
->current_function
=
2467 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2471 static gboolean
function_entry(void *hook_data
, void *call_data
)
2473 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2474 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2475 //guint8 ev_id = ltt_event_eventtype_id(e);
2476 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2477 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2478 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2480 push_function(s
, funcptr
);
2484 static gboolean
function_exit(void *hook_data
, void *call_data
)
2486 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2487 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2488 //guint8 ev_id = ltt_event_eventtype_id(e);
2489 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2490 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2491 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2493 pop_function(s
, funcptr
);
2497 static gboolean
schedchange(void *hook_data
, void *call_data
)
2499 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2501 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2502 LttvProcessState
*process
= ts
->running_process
[cpu
];
2503 //LttvProcessState *old_process = ts->running_process[cpu];
2505 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2506 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2507 guint pid_in
, pid_out
;
2510 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2511 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2512 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2514 if(likely(process
!= NULL
)) {
2516 /* We could not know but it was not the idle process executing.
2517 This should only happen at the beginning, before the first schedule
2518 event, and when the initial information (current process for each CPU)
2519 is missing. It is not obvious how we could, after the fact, compensate
2520 the wrongly attributed statistics. */
2522 //This test only makes sense once the state is known and if there is no
2523 //missing events. We need to silently ignore schedchange coming after a
2524 //process_free, or it causes glitches. (FIXME)
2525 //if(unlikely(process->pid != pid_out)) {
2526 // g_assert(process->pid == 0);
2528 if(process
->pid
== 0
2529 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2531 /* Scheduling out of pid 0 at beginning of the trace :
2532 * we know for sure it is in syscall mode at this point. */
2533 g_assert(process
->execution_stack
->len
== 1);
2534 process
->state
->t
= LTTV_STATE_SYSCALL
;
2535 process
->state
->s
= LTTV_STATE_WAIT
;
2536 process
->state
->change
= s
->parent
.timestamp
;
2537 process
->state
->entry
= s
->parent
.timestamp
;
2540 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2541 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2542 process
->state
->change
= s
->parent
.timestamp
;
2544 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2545 else process
->state
->s
= LTTV_STATE_WAIT
;
2546 process
->state
->change
= s
->parent
.timestamp
;
2549 if(state_out
== 32 || state_out
== 128)
2550 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2551 /* see sched.h for states */
2554 process
= ts
->running_process
[cpu
] =
2555 lttv_state_find_process_or_create(
2556 (LttvTraceState
*)s
->parent
.t_context
,
2558 &s
->parent
.timestamp
);
2559 process
->state
->s
= LTTV_STATE_RUN
;
2561 if(process
->usertrace
)
2562 process
->usertrace
->cpu
= cpu
;
2563 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2564 process
->state
->change
= s
->parent
.timestamp
;
2566 /* update cpu status */
2568 /* going to idle task */
2569 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2571 /* scheduling a real task.
2572 * we must be careful here:
2573 * if we just schedule()'ed to a process that is
2574 * in a trap, we must put the cpu in trap mode
2576 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2577 if(process
->state
->t
== LTTV_STATE_TRAP
)
2578 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2584 static gboolean
process_fork(void *hook_data
, void *call_data
)
2586 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2587 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2588 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2590 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2591 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2592 //LttvProcessState *zombie_process;
2594 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2595 LttvProcessState
*process
= ts
->running_process
[cpu
];
2596 LttvProcessState
*child_process
;
2597 struct marker_field
*f
;
2600 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2603 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2604 s
->parent
.target_pid
= child_pid
;
2607 f
= lttv_trace_get_hook_field(th
, 2);
2609 child_tgid
= ltt_event_get_unsigned(e
, f
);
2613 /* Mathieu : it seems like the process might have been scheduled in before the
2614 * fork, and, in a rare case, might be the current process. This might happen
2615 * in a SMP case where we don't have enough precision on the clocks.
2617 * Test reenabled after precision fixes on time. (Mathieu) */
2619 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2621 if(unlikely(zombie_process
!= NULL
)) {
2622 /* Reutilisation of PID. Only now we are sure that the old PID
2623 * has been released. FIXME : should know when release_task happens instead.
2625 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2627 for(i
=0; i
< num_cpus
; i
++) {
2628 g_assert(zombie_process
!= ts
->running_process
[i
]);
2631 exit_process(s
, zombie_process
);
2634 g_assert(process
->pid
!= child_pid
);
2635 // FIXME : Add this test in the "known state" section
2636 // g_assert(process->pid == parent_pid);
2637 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2638 if(child_process
== NULL
) {
2639 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2640 child_pid
, child_tgid
,
2641 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2643 /* The process has already been created : due to time imprecision between
2644 * multiple CPUs : it has been scheduled in before creation. Note that we
2645 * shouldn't have this kind of imprecision.
2647 * Simply put a correct parent.
2649 g_assert(0); /* This is a problematic case : the process has been created
2650 before the fork event */
2651 child_process
->ppid
= process
->pid
;
2652 child_process
->tgid
= child_tgid
;
2654 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2655 child_process
->name
= process
->name
;
2656 child_process
->brand
= process
->brand
;
2661 /* We stamp a newly created process as kernel_thread.
2662 * The thread should not be running yet. */
2663 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2665 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2666 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2667 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2669 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2670 LttvProcessState
*process
;
2671 LttvExecutionState
*es
;
2674 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2675 s
->parent
.target_pid
= pid
;
2677 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2679 process
->execution_stack
=
2680 g_array_set_size(process
->execution_stack
, 1);
2681 es
= process
->state
=
2682 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2683 es
->t
= LTTV_STATE_SYSCALL
;
2684 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2689 static gboolean
process_exit(void *hook_data
, void *call_data
)
2691 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2692 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2693 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2695 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2696 LttvProcessState
*process
; // = ts->running_process[cpu];
2698 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2699 s
->parent
.target_pid
= pid
;
2701 // FIXME : Add this test in the "known state" section
2702 // g_assert(process->pid == pid);
2704 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2705 if(likely(process
!= NULL
)) {
2706 process
->state
->s
= LTTV_STATE_EXIT
;
2711 static gboolean
process_free(void *hook_data
, void *call_data
)
2713 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2714 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2715 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2716 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2718 LttvProcessState
*process
;
2720 /* PID of the process to release */
2721 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2722 s
->parent
.target_pid
= release_pid
;
2724 g_assert(release_pid
!= 0);
2726 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2728 if(likely(process
!= NULL
)) {
2729 /* release_task is happening at kernel level : we can now safely release
2730 * the data structure of the process */
2731 //This test is fun, though, as it may happen that
2732 //at time t : CPU 0 : process_free
2733 //at time t+150ns : CPU 1 : schedule out
2734 //Clearly due to time imprecision, we disable it. (Mathieu)
2735 //If this weird case happen, we have no choice but to put the
2736 //Currently running process on the cpu to 0.
2737 //I re-enable it following time precision fixes. (Mathieu)
2738 //Well, in the case where an process is freed by a process on another CPU
2739 //and still scheduled, it happens that this is the schedchange that will
2740 //drop the last reference count. Do not free it here!
2741 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2743 for(i
=0; i
< num_cpus
; i
++) {
2744 //g_assert(process != ts->running_process[i]);
2745 if(process
== ts
->running_process
[i
]) {
2746 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2750 if(i
== num_cpus
) /* process is not scheduled */
2751 exit_process(s
, process
);
2758 static gboolean
process_exec(void *hook_data
, void *call_data
)
2760 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2761 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2762 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2763 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2766 LttvProcessState
*process
= ts
->running_process
[cpu
];
2768 #if 0//how to use a sequence that must be transformed in a string
2769 /* PID of the process to release */
2770 guint64 name_len
= ltt_event_field_element_number(e
,
2771 lttv_trace_get_hook_field(th
, 0));
2772 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2773 LttField
*child
= ltt_event_field_element_select(e
,
2774 lttv_trace_get_hook_field(th
, 0), 0);
2776 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2777 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2778 memcpy(null_term_name
, name_begin
, name_len
);
2779 null_term_name
[name_len
] = '\0';
2780 process
->name
= g_quark_from_string(null_term_name
);
2783 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2784 lttv_trace_get_hook_field(th
, 0)));
2785 process
->brand
= LTTV_STATE_UNBRANDED
;
2786 //g_free(null_term_name);
2790 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2792 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2793 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2794 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2795 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2798 LttvProcessState
*process
= ts
->running_process
[cpu
];
2800 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2801 process
->brand
= g_quark_from_string(name
);
2806 static void fix_process(gpointer key
, gpointer value
,
2809 LttvProcessState
*process
;
2810 LttvExecutionState
*es
;
2811 process
= (LttvProcessState
*)value
;
2812 LttTime
*timestamp
= (LttTime
*)user_data
;
2814 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2815 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2816 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2817 es
->t
= LTTV_STATE_SYSCALL
;
2818 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2819 es
->entry
= *timestamp
;
2820 es
->change
= *timestamp
;
2821 es
->cum_cpu_time
= ltt_time_zero
;
2822 if(es
->s
== LTTV_STATE_UNNAMED
)
2823 es
->s
= LTTV_STATE_WAIT
;
2826 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2827 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2828 es
->t
= LTTV_STATE_USER_MODE
;
2829 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2830 es
->entry
= *timestamp
;
2831 //g_assert(timestamp->tv_sec != 0);
2832 es
->change
= *timestamp
;
2833 es
->cum_cpu_time
= ltt_time_zero
;
2834 if(es
->s
== LTTV_STATE_UNNAMED
)
2835 es
->s
= LTTV_STATE_RUN
;
2837 if(process
->execution_stack
->len
== 1) {
2838 /* Still in bottom unknown mode, means never did a system call
2839 * May be either in user mode, syscall mode, running or waiting.*/
2840 /* FIXME : we may be tagging syscall mode when being user mode */
2841 process
->execution_stack
=
2842 g_array_set_size(process
->execution_stack
, 2);
2843 es
= process
->state
= &g_array_index(process
->execution_stack
,
2844 LttvExecutionState
, 1);
2845 es
->t
= LTTV_STATE_SYSCALL
;
2846 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2847 es
->entry
= *timestamp
;
2848 //g_assert(timestamp->tv_sec != 0);
2849 es
->change
= *timestamp
;
2850 es
->cum_cpu_time
= ltt_time_zero
;
2851 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2852 es
->s
= LTTV_STATE_WAIT
;
2858 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2860 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2861 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2862 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2863 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2864 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2866 /* For all processes */
2867 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2868 /* else, if stack[0] is unknown, set to user mode, running */
2870 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2875 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2877 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2878 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2879 //It's slow : optimise later by doing this before reading trace.
2880 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2886 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2887 LttvProcessState
*process
= ts
->running_process
[cpu
];
2888 LttvProcessState
*parent_process
;
2889 struct marker_field
*f
;
2890 GQuark type
, mode
, submode
, status
;
2891 LttvExecutionState
*es
;
2895 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2896 s
->parent
.target_pid
= pid
;
2899 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2902 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2905 f
= lttv_trace_get_hook_field(th
, 3);
2906 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2908 //FIXME: type is rarely used, enum must match possible types.
2911 f
= lttv_trace_get_hook_field(th
, 4);
2912 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2915 f
= lttv_trace_get_hook_field(th
, 5);
2916 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2919 f
= lttv_trace_get_hook_field(th
, 6);
2920 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2923 f
= lttv_trace_get_hook_field(th
, 7);
2925 tgid
= ltt_event_get_unsigned(e
, f
);
2930 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2931 for(i
=0; i
<nb_cpus
; i
++) {
2932 process
= lttv_state_find_process(ts
, i
, pid
);
2933 g_assert(process
!= NULL
);
2935 process
->ppid
= parent_pid
;
2936 process
->tgid
= tgid
;
2937 process
->name
= g_quark_from_string(command
);
2939 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2940 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2944 /* The process might exist if a process was forked while performing the
2946 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2947 if(process
== NULL
) {
2948 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2949 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2950 pid
, tgid
, g_quark_from_string(command
),
2951 &s
->parent
.timestamp
);
2953 /* Keep the stack bottom : a running user mode */
2954 /* Disabled because of inconsistencies in the current statedump states. */
2955 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2956 /* Only keep the bottom
2957 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2958 /* Will cause expected trap when in fact being syscall (even after end of
2960 * Will cause expected interrupt when being syscall. (only before end of
2961 * statedump event) */
2962 // This will cause a "popping last state on stack, ignoring it."
2963 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2964 es
= process
->state
= &g_array_index(process
->execution_stack
,
2965 LttvExecutionState
, 0);
2966 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2967 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2968 es
->s
= LTTV_STATE_UNNAMED
;
2969 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2971 es
->t
= LTTV_STATE_SYSCALL
;
2976 /* User space process :
2977 * bottom : user mode
2978 * either currently running or scheduled out.
2979 * can be scheduled out because interrupted in (user mode or in syscall)
2980 * or because of an explicit call to the scheduler in syscall. Note that
2981 * the scheduler call comes after the irq_exit, so never in interrupt
2983 // temp workaround : set size to 1 : only have user mode bottom of stack.
2984 // will cause g_info message of expected syscall mode when in fact being
2985 // in user mode. Can also cause expected trap when in fact being user
2986 // mode in the event of a page fault reenabling interrupts in the handler.
2987 // Expected syscall and trap can also happen after the end of statedump
2988 // This will cause a "popping last state on stack, ignoring it."
2989 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2990 es
= process
->state
= &g_array_index(process
->execution_stack
,
2991 LttvExecutionState
, 0);
2992 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2993 es
->s
= LTTV_STATE_UNNAMED
;
2994 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2996 es
->t
= LTTV_STATE_USER_MODE
;
3004 es
= process
->state
= &g_array_index(process
->execution_stack
,
3005 LttvExecutionState
, 1);
3006 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3007 es
->s
= LTTV_STATE_UNNAMED
;
3008 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3012 /* The process has already been created :
3013 * Probably was forked while dumping the process state or
3014 * was simply scheduled in prior to get the state dump event.
3016 process
->ppid
= parent_pid
;
3017 process
->tgid
= tgid
;
3018 process
->name
= g_quark_from_string(command
);
3019 process
->type
= type
;
3021 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3023 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3024 if(type
== LTTV_STATE_KERNEL_THREAD
)
3025 es
->t
= LTTV_STATE_SYSCALL
;
3027 es
->t
= LTTV_STATE_USER_MODE
;
3030 /* Don't mess around with the stack, it will eventually become
3031 * ok after the end of state dump. */
3038 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3040 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3042 lttv_state_add_event_hooks(tss
);
3047 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3049 LttvTraceset
*traceset
= self
->parent
.ts
;
3051 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3055 LttvTracefileState
*tfs
;
3061 LttvAttributeValue val
;
3063 nb_trace
= lttv_traceset_number(traceset
);
3064 for(i
= 0 ; i
< nb_trace
; i
++) {
3065 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3067 /* Find the eventtype id for the following events and register the
3068 associated by id hooks. */
3070 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3071 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3074 lttv_trace_find_hook(ts
->parent
.t
,
3075 LTT_FACILITY_KERNEL_ARCH
,
3076 LTT_EVENT_SYSCALL_ENTRY
,
3077 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3078 syscall_entry
, NULL
, &hooks
);
3080 lttv_trace_find_hook(ts
->parent
.t
,
3081 LTT_FACILITY_KERNEL_ARCH
,
3082 LTT_EVENT_SYSCALL_EXIT
,
3084 syscall_exit
, NULL
, &hooks
);
3086 lttv_trace_find_hook(ts
->parent
.t
,
3087 LTT_FACILITY_KERNEL_ARCH
,
3088 LTT_EVENT_TRAP_ENTRY
,
3089 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3090 trap_entry
, NULL
, &hooks
);
3092 lttv_trace_find_hook(ts
->parent
.t
,
3093 LTT_FACILITY_KERNEL_ARCH
,
3094 LTT_EVENT_TRAP_EXIT
,
3096 trap_exit
, NULL
, &hooks
);
3098 lttv_trace_find_hook(ts
->parent
.t
,
3099 LTT_FACILITY_KERNEL
,
3100 LTT_EVENT_IRQ_ENTRY
,
3101 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3102 irq_entry
, NULL
, &hooks
);
3104 lttv_trace_find_hook(ts
->parent
.t
,
3105 LTT_FACILITY_KERNEL
,
3108 irq_exit
, NULL
, &hooks
);
3110 lttv_trace_find_hook(ts
->parent
.t
,
3111 LTT_FACILITY_KERNEL
,
3112 LTT_EVENT_SOFT_IRQ_ENTRY
,
3113 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3114 soft_irq_entry
, NULL
, &hooks
);
3116 lttv_trace_find_hook(ts
->parent
.t
,
3117 LTT_FACILITY_KERNEL
,
3118 LTT_EVENT_SOFT_IRQ_EXIT
,
3120 soft_irq_exit
, NULL
, &hooks
);
3122 lttv_trace_find_hook(ts
->parent
.t
,
3123 LTT_FACILITY_KERNEL
,
3124 LTT_EVENT_SCHED_SCHEDULE
,
3125 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3126 LTT_FIELD_PREV_STATE
),
3127 schedchange
, NULL
, &hooks
);
3129 lttv_trace_find_hook(ts
->parent
.t
,
3130 LTT_FACILITY_KERNEL
,
3131 LTT_EVENT_PROCESS_FORK
,
3132 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3133 LTT_FIELD_CHILD_TGID
),
3134 process_fork
, NULL
, &hooks
);
3136 lttv_trace_find_hook(ts
->parent
.t
,
3137 LTT_FACILITY_KERNEL_ARCH
,
3138 LTT_EVENT_KTHREAD_CREATE
,
3139 FIELD_ARRAY(LTT_FIELD_PID
),
3140 process_kernel_thread
, NULL
, &hooks
);
3142 lttv_trace_find_hook(ts
->parent
.t
,
3143 LTT_FACILITY_KERNEL
,
3144 LTT_EVENT_PROCESS_EXIT
,
3145 FIELD_ARRAY(LTT_FIELD_PID
),
3146 process_exit
, NULL
, &hooks
);
3148 lttv_trace_find_hook(ts
->parent
.t
,
3149 LTT_FACILITY_KERNEL
,
3150 LTT_EVENT_PROCESS_FREE
,
3151 FIELD_ARRAY(LTT_FIELD_PID
),
3152 process_free
, NULL
, &hooks
);
3154 lttv_trace_find_hook(ts
->parent
.t
,
3157 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3158 process_exec
, NULL
, &hooks
);
3160 lttv_trace_find_hook(ts
->parent
.t
,
3161 LTT_FACILITY_USER_GENERIC
,
3162 LTT_EVENT_THREAD_BRAND
,
3163 FIELD_ARRAY(LTT_FIELD_NAME
),
3164 thread_brand
, NULL
, &hooks
);
3166 /* statedump-related hooks */
3167 lttv_trace_find_hook(ts
->parent
.t
,
3169 LTT_EVENT_PROCESS_STATE
,
3170 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3171 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3172 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3173 enum_process_state
, NULL
, &hooks
);
3175 lttv_trace_find_hook(ts
->parent
.t
,
3177 LTT_EVENT_STATEDUMP_END
,
3179 statedump_end
, NULL
, &hooks
);
3181 lttv_trace_find_hook(ts
->parent
.t
,
3183 LTT_EVENT_LIST_INTERRUPT
,
3184 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3185 enum_interrupt
, NULL
, &hooks
);
3187 lttv_trace_find_hook(ts
->parent
.t
,
3189 LTT_EVENT_REQUEST_ISSUE
,
3190 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3191 bdev_request_issue
, NULL
, &hooks
);
3193 lttv_trace_find_hook(ts
->parent
.t
,
3195 LTT_EVENT_REQUEST_COMPLETE
,
3196 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3197 bdev_request_complete
, NULL
, &hooks
);
3199 lttv_trace_find_hook(ts
->parent
.t
,
3200 LTT_FACILITY_USER_GENERIC
,
3201 LTT_EVENT_FUNCTION_ENTRY
,
3202 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3203 function_entry
, NULL
, &hooks
);
3205 lttv_trace_find_hook(ts
->parent
.t
,
3206 LTT_FACILITY_USER_GENERIC
,
3207 LTT_EVENT_FUNCTION_EXIT
,
3208 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3209 function_exit
, NULL
, &hooks
);
3211 /* Add these hooks to each event_by_id hooks list */
3213 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3215 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3217 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3218 LttvTracefileContext
*, j
));
3220 for(k
= 0 ; k
< hooks
->len
; k
++) {
3221 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3223 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3229 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3230 *(val
.v_pointer
) = hooks
;
3234 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3236 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3238 lttv_state_remove_event_hooks(tss
);
3243 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3245 LttvTraceset
*traceset
= self
->parent
.ts
;
3247 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3251 LttvTracefileState
*tfs
;
3257 LttvAttributeValue val
;
3259 nb_trace
= lttv_traceset_number(traceset
);
3260 for(i
= 0 ; i
< nb_trace
; i
++) {
3261 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3263 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3264 hooks
= *(val
.v_pointer
);
3266 /* Remove these hooks from each event_by_id hooks list */
3268 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3270 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3272 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3273 LttvTracefileContext
*, j
));
3275 for(k
= 0 ; k
< hooks
->len
; k
++) {
3276 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3277 lttv_hooks_remove_data(
3278 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3283 lttv_trace_hook_remove_all(&hooks
);
3284 g_array_free(hooks
, TRUE
);
3288 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3290 guint
*event_count
= (guint
*)hook_data
;
3292 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3293 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3298 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3300 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3302 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3304 LttvAttributeValue value
;
3306 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3307 LTTV_STATE_SAVED_STATES
);
3308 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3309 value
= lttv_attribute_add(saved_states_tree
,
3310 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3311 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3312 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3313 *(value
.v_time
) = self
->parent
.timestamp
;
3314 lttv_state_save(tcs
, saved_state_tree
);
3315 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3316 self
->parent
.timestamp
.tv_nsec
);
3318 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3323 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3325 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3327 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3332 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3340 static gboolean
block_start(void *hook_data
, void *call_data
)
3342 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3344 LttvTracefileState
*tfcs
;
3346 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3348 LttEventPosition
*ep
;
3350 guint i
, nb_block
, nb_event
, nb_tracefile
;
3354 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3356 LttvAttributeValue value
;
3358 ep
= ltt_event_position_new();
3360 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3362 /* Count the number of events added since the last block end in any
3365 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3367 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3368 LttvTracefileContext
, i
));
3369 ltt_event_position(tfcs
->parent
.e
, ep
);
3370 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3371 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3372 tfcs
->saved_position
= nb_event
;
3376 if(tcs
->nb_event
>= tcs
->save_interval
) {
3377 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3378 LTTV_STATE_SAVED_STATES
);
3379 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3380 value
= lttv_attribute_add(saved_states_tree
,
3381 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3382 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3383 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3384 *(value
.v_time
) = self
->parent
.timestamp
;
3385 lttv_state_save(tcs
, saved_state_tree
);
3387 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3388 self
->parent
.timestamp
.tv_nsec
);
3390 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3396 static gboolean
block_end(void *hook_data
, void *call_data
)
3398 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3400 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3404 LttEventPosition
*ep
;
3406 guint nb_block
, nb_event
;
3408 ep
= ltt_event_position_new();
3409 ltt_event_position(self
->parent
.e
, ep
);
3410 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3411 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3412 self
->saved_position
= 0;
3413 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3420 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3422 LttvTraceset
*traceset
= self
->parent
.ts
;
3424 guint i
, j
, nb_trace
, nb_tracefile
;
3428 LttvTracefileState
*tfs
;
3430 LttvTraceHook hook_start
, hook_end
;
3432 nb_trace
= lttv_traceset_number(traceset
);
3433 for(i
= 0 ; i
< nb_trace
; i
++) {
3434 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3436 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3437 NULL
, NULL
, block_start
, &hook_start
);
3438 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3439 NULL
, NULL
, block_end
, &hook_end
);
3441 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3443 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3445 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3446 LttvTracefileContext
, j
));
3447 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3448 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3449 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3450 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3456 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3458 LttvTraceset
*traceset
= self
->parent
.ts
;
3460 guint i
, j
, nb_trace
, nb_tracefile
;
3464 LttvTracefileState
*tfs
;
3467 nb_trace
= lttv_traceset_number(traceset
);
3468 for(i
= 0 ; i
< nb_trace
; i
++) {
3470 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3471 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3473 if(ts
->has_precomputed_states
) continue;
3475 guint
*event_count
= g_new(guint
, 1);
3478 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3480 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3481 LttvTracefileContext
*, j
));
3482 lttv_hooks_add(tfs
->parent
.event
,
3483 state_save_event_hook
,
3490 lttv_process_traceset_begin(&self
->parent
,
3491 NULL
, NULL
, NULL
, NULL
, NULL
);
3495 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3497 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3499 lttv_state_save_add_event_hooks(tss
);
3506 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3508 LttvTraceset
*traceset
= self
->parent
.ts
;
3510 guint i
, j
, nb_trace
, nb_tracefile
;
3514 LttvTracefileState
*tfs
;
3516 LttvTraceHook hook_start
, hook_end
;
3518 nb_trace
= lttv_traceset_number(traceset
);
3519 for(i
= 0 ; i
< nb_trace
; i
++) {
3520 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3522 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3523 NULL
, NULL
, block_start
, &hook_start
);
3525 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3526 NULL
, NULL
, block_end
, &hook_end
);
3528 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3530 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3532 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3533 LttvTracefileContext
, j
));
3534 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3535 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3536 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3537 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3543 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3545 LttvTraceset
*traceset
= self
->parent
.ts
;
3547 guint i
, j
, nb_trace
, nb_tracefile
;
3551 LttvTracefileState
*tfs
;
3553 LttvHooks
*after_trace
= lttv_hooks_new();
3555 lttv_hooks_add(after_trace
,
3556 state_save_after_trace_hook
,
3561 lttv_process_traceset_end(&self
->parent
,
3562 NULL
, after_trace
, NULL
, NULL
, NULL
);
3564 lttv_hooks_destroy(after_trace
);
3566 nb_trace
= lttv_traceset_number(traceset
);
3567 for(i
= 0 ; i
< nb_trace
; i
++) {
3569 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3570 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3572 if(ts
->has_precomputed_states
) continue;
3574 guint
*event_count
= NULL
;
3576 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3578 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3579 LttvTracefileContext
*, j
));
3580 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3581 state_save_event_hook
);
3583 if(event_count
) g_free(event_count
);
3587 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3589 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3591 lttv_state_save_remove_event_hooks(tss
);
3596 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3598 LttvTraceset
*traceset
= self
->parent
.ts
;
3602 int min_pos
, mid_pos
, max_pos
;
3604 guint call_rest
= 0;
3606 LttvTraceState
*tcs
;
3608 LttvAttributeValue value
;
3610 LttvAttributeType type
;
3612 LttvAttributeName name
;
3616 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3618 //g_tree_destroy(self->parent.pqueue);
3619 //self->parent.pqueue = g_tree_new(compare_tracefile);
3621 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3623 nb_trace
= lttv_traceset_number(traceset
);
3624 for(i
= 0 ; i
< nb_trace
; i
++) {
3625 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3627 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3628 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3629 LTTV_STATE_SAVED_STATES
);
3632 if(saved_states_tree
) {
3633 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3634 mid_pos
= max_pos
/ 2;
3635 while(min_pos
< max_pos
) {
3636 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3638 g_assert(type
== LTTV_GOBJECT
);
3639 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3640 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3642 g_assert(type
== LTTV_TIME
);
3643 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3645 closest_tree
= saved_state_tree
;
3647 else max_pos
= mid_pos
- 1;
3649 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3653 /* restore the closest earlier saved state */
3655 lttv_state_restore(tcs
, closest_tree
);
3659 /* There is no saved state, yet we want to have it. Restart at T0 */
3661 restore_init_state(tcs
);
3662 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3665 /* We want to seek quickly without restoring/updating the state */
3667 restore_init_state(tcs
);
3668 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3671 if(!call_rest
) g_info("NOT Calling restore");
3676 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3682 traceset_state_finalize (LttvTracesetState
*self
)
3684 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3685 finalize(G_OBJECT(self
));
3690 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3692 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3694 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3695 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3696 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3697 klass
->new_traceset_context
= new_traceset_context
;
3698 klass
->new_trace_context
= new_trace_context
;
3699 klass
->new_tracefile_context
= new_tracefile_context
;
3704 lttv_traceset_state_get_type(void)
3706 static GType type
= 0;
3708 static const GTypeInfo info
= {
3709 sizeof (LttvTracesetStateClass
),
3710 NULL
, /* base_init */
3711 NULL
, /* base_finalize */
3712 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3713 NULL
, /* class_finalize */
3714 NULL
, /* class_data */
3715 sizeof (LttvTracesetState
),
3716 0, /* n_preallocs */
3717 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3718 NULL
/* value handling */
3721 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3729 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3735 trace_state_finalize (LttvTraceState
*self
)
3737 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3738 finalize(G_OBJECT(self
));
3743 trace_state_class_init (LttvTraceStateClass
*klass
)
3745 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3747 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3748 klass
->state_save
= state_save
;
3749 klass
->state_restore
= state_restore
;
3750 klass
->state_saved_free
= state_saved_free
;
3755 lttv_trace_state_get_type(void)
3757 static GType type
= 0;
3759 static const GTypeInfo info
= {
3760 sizeof (LttvTraceStateClass
),
3761 NULL
, /* base_init */
3762 NULL
, /* base_finalize */
3763 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3764 NULL
, /* class_finalize */
3765 NULL
, /* class_data */
3766 sizeof (LttvTraceState
),
3767 0, /* n_preallocs */
3768 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3769 NULL
/* value handling */
3772 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3773 "LttvTraceStateType", &info
, 0);
3780 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3786 tracefile_state_finalize (LttvTracefileState
*self
)
3788 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3789 finalize(G_OBJECT(self
));
3794 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3796 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3798 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3803 lttv_tracefile_state_get_type(void)
3805 static GType type
= 0;
3807 static const GTypeInfo info
= {
3808 sizeof (LttvTracefileStateClass
),
3809 NULL
, /* base_init */
3810 NULL
, /* base_finalize */
3811 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3812 NULL
, /* class_finalize */
3813 NULL
, /* class_data */
3814 sizeof (LttvTracefileState
),
3815 0, /* n_preallocs */
3816 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3817 NULL
/* value handling */
3820 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3821 "LttvTracefileStateType", &info
, 0);
3827 static void module_init()
3829 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3830 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3831 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3832 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3833 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3834 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3835 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3836 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3837 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3838 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3839 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3840 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3841 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3842 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3843 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3844 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3845 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3846 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3847 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3848 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3849 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3850 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3851 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3852 LTTV_STATE_EVENT
= g_quark_from_string("event");
3853 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3854 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3855 LTTV_STATE_TIME
= g_quark_from_string("time");
3856 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3857 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3858 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3859 g_quark_from_string("trace_state_use_count");
3860 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3861 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu count");
3862 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3863 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3866 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3867 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3868 LTT_FACILITY_FS
= g_quark_from_string("fs");
3869 LTT_FACILITY_LIST
= g_quark_from_string("list");
3870 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3871 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3874 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3875 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3876 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3877 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3878 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3879 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3880 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3881 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3882 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3883 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3884 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3885 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3886 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3887 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3888 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3889 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3890 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3891 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3892 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3893 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3894 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3895 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3898 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3899 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3900 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3901 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3902 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3903 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3904 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3905 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3906 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3907 LTT_FIELD_PID
= g_quark_from_string("pid");
3908 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3909 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3910 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3911 LTT_FIELD_NAME
= g_quark_from_string("name");
3912 LTT_FIELD_TYPE
= g_quark_from_string("type");
3913 LTT_FIELD_MODE
= g_quark_from_string("mode");
3914 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3915 LTT_FIELD_STATUS
= g_quark_from_string("status");
3916 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3917 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3918 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3919 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3920 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3921 LTT_FIELD_ACTION
= g_quark_from_string("action");
3923 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3924 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3925 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3926 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3927 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3929 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3930 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3931 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3933 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3934 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3935 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3936 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3939 static void module_destroy()
3944 LTTV_MODULE("state", "State computation", \
3945 "Update the system state, possibly saving it at intervals", \
3946 module_init
, module_destroy
)