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_IRQS
,
172 LTTV_STATE_RESOURCE_BLKDEVS
;
174 static void create_max_time(LttvTraceState
*tcs
);
176 static void get_max_time(LttvTraceState
*tcs
);
178 static void free_max_time(LttvTraceState
*tcs
);
180 static void create_name_tables(LttvTraceState
*tcs
);
182 static void get_name_tables(LttvTraceState
*tcs
);
184 static void free_name_tables(LttvTraceState
*tcs
);
186 static void free_saved_state(LttvTraceState
*tcs
);
188 static void lttv_state_free_process_table(GHashTable
*processes
);
190 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
191 GPtrArray
*quarktable
);
193 /* Resource function prototypes */
194 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
195 static LttvBdevState
*bdevstate_new(void);
196 static void bdevstate_free(LttvBdevState
*);
197 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
198 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
201 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
203 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
207 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
209 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
213 void lttv_state_state_saved_free(LttvTraceState
*self
,
214 LttvAttribute
*container
)
216 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
220 guint
process_hash(gconstpointer key
)
222 guint pid
= ((const LttvProcessState
*)key
)->pid
;
223 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
227 /* If the hash table hash function is well distributed,
228 * the process_equal should compare different pid */
229 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
231 const LttvProcessState
*process_a
, *process_b
;
234 process_a
= (const LttvProcessState
*)a
;
235 process_b
= (const LttvProcessState
*)b
;
237 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
238 else if(likely(process_a
->pid
== 0 &&
239 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
244 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
246 g_tree_destroy((GTree
*)value
);
249 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
251 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
252 g_hash_table_destroy(usertraces
);
258 restore_init_state(LttvTraceState
*self
)
260 guint i
, nb_cpus
, nb_irqs
;
262 //LttvTracefileState *tfcs;
264 LttTime start_time
, end_time
;
266 /* Free the process tables */
267 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
268 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
269 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
270 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
273 /* Seek time to beginning */
274 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
275 // closest. It's the tracecontext job to seek the trace to the beginning
276 // anyway : the init state might be used at the middle of the trace as well...
277 //g_tree_destroy(self->parent.ts_context->pqueue);
278 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
280 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
282 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
284 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
285 nb_irqs
= self
->nb_irqs
;
287 /* Put the per cpu running_process to beginning state : process 0. */
288 for(i
=0; i
< nb_cpus
; i
++) {
289 LttvExecutionState
*es
;
290 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
291 LTTV_STATE_UNNAMED
, &start_time
);
292 /* We are not sure is it's a kernel thread or normal thread, put the
293 * bottom stack state to unknown */
294 self
->running_process
[i
]->execution_stack
=
295 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
296 es
= self
->running_process
[i
]->state
=
297 &g_array_index(self
->running_process
[i
]->execution_stack
,
298 LttvExecutionState
, 0);
299 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
300 es
->s
= LTTV_STATE_UNNAMED
;
302 //self->running_process[i]->state->s = LTTV_STATE_RUN;
303 self
->running_process
[i
]->cpu
= i
;
305 /* reset cpu states */
306 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
307 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
310 /* reset irq states */
311 for(i
=0; i
<nb_irqs
; i
++) {
312 if(self
->irq_states
[i
].mode_stack
->len
> 0)
313 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
316 /* reset bdev states */
317 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
318 g_hash_table_steal_all(self
->bdev_states
);
321 nb_tracefile
= self
->parent
.tracefiles
->len
;
323 for(i
= 0 ; i
< nb_tracefile
; i
++) {
325 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
326 LttvTracefileContext
*, i
));
327 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
328 // tfcs->saved_position = 0;
329 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
330 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
331 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
332 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
337 //static LttTime time_zero = {0,0};
339 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
342 const LttTime
*t1
= (const LttTime
*)a
;
343 const LttTime
*t2
= (const LttTime
*)b
;
345 return ltt_time_compare(*t1
, *t2
);
348 static void free_usertrace_key(gpointer data
)
353 #define MAX_STRING_LEN 4096
356 state_load_saved_states(LttvTraceState
*tcs
)
359 GPtrArray
*quarktable
;
360 const char *trace_path
;
364 tcs
->has_precomputed_states
= FALSE
;
368 gchar buf
[MAX_STRING_LEN
];
371 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
372 strncpy(path
, trace_path
, PATH_MAX
-1);
373 count
= strnlen(trace_path
, PATH_MAX
-1);
374 // quarktable : open, test
375 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
376 fp
= fopen(path
, "r");
378 quarktable
= g_ptr_array_sized_new(4096);
380 /* Index 0 is null */
382 if(hdr
== EOF
) return;
383 g_assert(hdr
== HDR_QUARKS
);
387 if(hdr
== EOF
) break;
388 g_assert(hdr
== HDR_QUARK
);
389 g_ptr_array_set_size(quarktable
, q
+1);
392 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
393 if(buf
[i
] == '\0' || feof(fp
)) break;
396 len
= strnlen(buf
, MAX_STRING_LEN
-1);
397 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
398 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
404 // saved_states : open, test
405 strncpy(path
, trace_path
, PATH_MAX
-1);
406 count
= strnlen(trace_path
, PATH_MAX
-1);
407 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
408 fp
= fopen(path
, "r");
412 if(hdr
!= HDR_TRACE
) goto end
;
414 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
416 tcs
->has_precomputed_states
= TRUE
;
421 /* Free the quarktable */
422 for(i
=0; i
<quarktable
->len
; i
++) {
423 string
= g_ptr_array_index (quarktable
, i
);
426 g_ptr_array_free(quarktable
, TRUE
);
431 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
433 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
436 LttvTraceContext
*tc
;
440 LttvTracefileState
*tfcs
;
442 LttvAttributeValue v
;
444 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
445 init((LttvTracesetContext
*)self
, ts
);
447 nb_trace
= lttv_traceset_number(ts
);
448 for(i
= 0 ; i
< nb_trace
; i
++) {
449 tc
= self
->parent
.traces
[i
];
450 tcs
= LTTV_TRACE_STATE(tc
);
451 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
452 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
456 if(*(v
.v_uint
) == 1) {
457 create_name_tables(tcs
);
458 create_max_time(tcs
);
460 get_name_tables(tcs
);
463 nb_tracefile
= tc
->tracefiles
->len
;
464 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
465 nb_irq
= tcs
->nb_irqs
;
466 tcs
->processes
= NULL
;
467 tcs
->usertraces
= NULL
;
468 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
470 /* init cpu resource stuff */
471 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
472 for(j
= 0; j
<nb_cpu
; j
++) {
473 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
474 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
477 /* init irq resource stuff */
478 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
479 for(j
= 0; j
<nb_irq
; j
++) {
480 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
481 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
484 /* init bdev resource stuff */
485 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
487 restore_init_state(tcs
);
488 for(j
= 0 ; j
< nb_tracefile
; j
++) {
490 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
491 LttvTracefileContext
*, j
));
492 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
493 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
494 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
495 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
496 /* It's a Usertrace */
497 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
498 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
500 if(!usertrace_tree
) {
501 usertrace_tree
= g_tree_new_full(compare_usertraces
,
502 NULL
, free_usertrace_key
, NULL
);
503 g_hash_table_insert(tcs
->usertraces
,
504 (gpointer
)tid
, usertrace_tree
);
506 LttTime
*timestamp
= g_new(LttTime
, 1);
507 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
508 ltt_tracefile_creation(tfcs
->parent
.tf
));
509 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
513 /* See if the trace has saved states */
514 state_load_saved_states(tcs
);
519 fini(LttvTracesetState
*self
)
525 //LttvTracefileState *tfcs;
527 LttvAttributeValue v
;
529 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
530 for(i
= 0 ; i
< nb_trace
; i
++) {
531 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
532 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
535 g_assert(*(v
.v_uint
) != 0);
538 if(*(v
.v_uint
) == 0) {
539 free_name_tables(tcs
);
541 free_saved_state(tcs
);
543 g_free(tcs
->running_process
);
544 tcs
->running_process
= NULL
;
545 lttv_state_free_process_table(tcs
->processes
);
546 lttv_state_free_usertraces(tcs
->usertraces
);
547 tcs
->processes
= NULL
;
548 tcs
->usertraces
= NULL
;
550 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
551 fini((LttvTracesetContext
*)self
);
555 static LttvTracesetContext
*
556 new_traceset_context(LttvTracesetContext
*self
)
558 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
562 static LttvTraceContext
*
563 new_trace_context(LttvTracesetContext
*self
)
565 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
569 static LttvTracefileContext
*
570 new_tracefile_context(LttvTracesetContext
*self
)
572 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
576 /* Write the process state of the trace */
578 static void write_process_state(gpointer key
, gpointer value
,
581 LttvProcessState
*process
;
583 LttvExecutionState
*es
;
585 FILE *fp
= (FILE *)user_data
;
590 process
= (LttvProcessState
*)value
;
592 " <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",
593 process
, process
->pid
, process
->tgid
, process
->ppid
,
594 g_quark_to_string(process
->type
),
595 process
->creation_time
.tv_sec
,
596 process
->creation_time
.tv_nsec
,
597 process
->insertion_time
.tv_sec
,
598 process
->insertion_time
.tv_nsec
,
599 g_quark_to_string(process
->name
),
600 g_quark_to_string(process
->brand
),
603 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
604 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
605 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
606 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
607 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
608 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
609 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
612 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
613 address
= g_array_index(process
->user_stack
, guint64
, i
);
614 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
618 if(process
->usertrace
) {
619 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
620 g_quark_to_string(process
->usertrace
->tracefile_name
),
621 process
->usertrace
->cpu
);
625 fprintf(fp
, " </PROCESS>\n");
629 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
631 guint i
, nb_tracefile
, nb_block
, offset
;
634 LttvTracefileState
*tfcs
;
638 LttEventPosition
*ep
;
642 ep
= ltt_event_position_new();
644 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
646 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
648 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
649 for(i
=0;i
<nb_cpus
;i
++) {
650 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
651 i
, self
->running_process
[i
]->pid
);
654 nb_tracefile
= self
->parent
.tracefiles
->len
;
656 for(i
= 0 ; i
< nb_tracefile
; i
++) {
658 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
659 LttvTracefileContext
*, i
));
660 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
661 tfcs
->parent
.timestamp
.tv_sec
,
662 tfcs
->parent
.timestamp
.tv_nsec
);
663 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
664 if(e
== NULL
) fprintf(fp
,"/>\n");
666 ltt_event_position(e
, ep
);
667 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
668 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
673 fprintf(fp
,"</PROCESS_STATE>\n");
677 static void write_process_state_raw(gpointer key
, gpointer value
,
680 LttvProcessState
*process
;
682 LttvExecutionState
*es
;
684 FILE *fp
= (FILE *)user_data
;
689 process
= (LttvProcessState
*)value
;
690 fputc(HDR_PROCESS
, fp
);
691 //fwrite(&header, sizeof(header), 1, fp);
692 //fprintf(fp, "%s", g_quark_to_string(process->type));
694 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
695 //fprintf(fp, "%s", g_quark_to_string(process->name));
697 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
698 //fprintf(fp, "%s", g_quark_to_string(process->brand));
700 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
701 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
702 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
703 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
704 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
705 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
706 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
710 " <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",
711 process
, process
->pid
, process
->tgid
, process
->ppid
,
712 g_quark_to_string(process
->type
),
713 process
->creation_time
.tv_sec
,
714 process
->creation_time
.tv_nsec
,
715 process
->insertion_time
.tv_sec
,
716 process
->insertion_time
.tv_nsec
,
717 g_quark_to_string(process
->name
),
718 g_quark_to_string(process
->brand
),
722 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
723 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
726 //fprintf(fp, "%s", g_quark_to_string(es->t));
728 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
729 //fprintf(fp, "%s", g_quark_to_string(es->n));
731 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
732 //fprintf(fp, "%s", g_quark_to_string(es->s));
734 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
735 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
736 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
737 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
739 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
740 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
741 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
742 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
743 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
747 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
748 address
= g_array_index(process
->user_stack
, guint64
, i
);
749 fputc(HDR_USER_STACK
, fp
);
750 fwrite(&address
, sizeof(address
), 1, fp
);
752 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
757 if(process
->usertrace
) {
758 fputc(HDR_USERTRACE
, fp
);
759 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
761 fwrite(&process
->usertrace
->tracefile_name
,
762 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
763 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
765 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
766 g_quark_to_string(process
->usertrace
->tracefile_name
),
767 process
->usertrace
->cpu
);
774 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
776 guint i
, nb_tracefile
, nb_block
, offset
;
779 LttvTracefileState
*tfcs
;
783 LttEventPosition
*ep
;
787 ep
= ltt_event_position_new();
789 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
790 fputc(HDR_PROCESS_STATE
, fp
);
791 fwrite(&t
, sizeof(t
), 1, fp
);
793 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
795 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
796 for(i
=0;i
<nb_cpus
;i
++) {
798 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
799 fwrite(&self
->running_process
[i
]->pid
,
800 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
801 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
802 // i, self->running_process[i]->pid);
805 nb_tracefile
= self
->parent
.tracefiles
->len
;
807 for(i
= 0 ; i
< nb_tracefile
; i
++) {
809 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
810 LttvTracefileContext
*, i
));
811 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
812 // tfcs->parent.timestamp.tv_sec,
813 // tfcs->parent.timestamp.tv_nsec);
814 fputc(HDR_TRACEFILE
, fp
);
815 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
816 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
817 * position following : end of trace */
818 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
820 ltt_event_position(e
, ep
);
821 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
822 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
824 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
825 fwrite(&offset
, sizeof(offset
), 1, fp
);
826 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
833 /* Read process state from a file */
835 /* Called because a HDR_PROCESS was found */
836 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
837 GPtrArray
*quarktable
)
839 LttvExecutionState
*es
;
840 LttvProcessState
*process
, *parent_process
;
841 LttvProcessState tmp
;
846 /* TODO : check return value */
847 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
848 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
849 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
850 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
851 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
852 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
853 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
854 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
855 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
858 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
860 /* We must link to the parent */
861 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
863 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
864 if(process
== NULL
) {
865 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
867 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
871 process
->insertion_time
= tmp
.insertion_time
;
872 process
->creation_time
= tmp
.creation_time
;
873 process
->type
= g_quark_from_string(
874 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
875 process
->tgid
= tmp
.tgid
;
876 process
->ppid
= tmp
.ppid
;
877 process
->brand
= g_quark_from_string(
878 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
880 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
884 if(feof(fp
) || ferror(fp
)) goto end_loop
;
886 gint hdr
= fgetc(fp
);
887 if(hdr
== EOF
) goto end_loop
;
891 process
->execution_stack
=
892 g_array_set_size(process
->execution_stack
,
893 process
->execution_stack
->len
+ 1);
894 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
895 process
->execution_stack
->len
-1);
898 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
899 es
->t
= g_quark_from_string(
900 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
901 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
902 es
->n
= g_quark_from_string(
903 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
904 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
905 es
->s
= g_quark_from_string(
906 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
907 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
908 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
909 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
912 process
->user_stack
= g_array_set_size(process
->user_stack
,
913 process
->user_stack
->len
+ 1);
914 address
= &g_array_index(process
->user_stack
, guint64
,
915 process
->user_stack
->len
-1);
916 fread(address
, sizeof(address
), 1, fp
);
917 process
->current_function
= *address
;
920 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
921 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
933 /* Called because a HDR_PROCESS_STATE was found */
934 /* Append a saved state to the trace states */
935 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
937 guint i
, nb_tracefile
, nb_block
, offset
;
939 LttvTracefileState
*tfcs
;
941 LttEventPosition
*ep
;
949 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
951 LttvAttributeValue value
;
952 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
953 ep
= ltt_event_position_new();
955 restore_init_state(self
);
957 fread(&t
, sizeof(t
), 1, fp
);
960 if(feof(fp
) || ferror(fp
)) goto end_loop
;
962 if(hdr
== EOF
) goto end_loop
;
966 /* Call read_process_state_raw */
967 read_process_state_raw(self
, fp
, quarktable
);
977 case HDR_PROCESS_STATE
:
983 g_error("Error while parsing saved state file : unknown data header %d",
989 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
990 for(i
=0;i
<nb_cpus
;i
++) {
993 g_assert(hdr
== HDR_CPU
);
994 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
995 g_assert(i
== cpu_num
);
996 fread(&self
->running_process
[i
]->pid
,
997 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1000 nb_tracefile
= self
->parent
.tracefiles
->len
;
1002 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1004 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1005 LttvTracefileContext
*, i
));
1006 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1007 // tfcs->parent.timestamp.tv_sec,
1008 // tfcs->parent.timestamp.tv_nsec);
1009 g_tree_remove(pqueue
, &tfcs
->parent
);
1011 g_assert(hdr
== HDR_TRACEFILE
);
1012 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1013 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1014 * position following : end of trace */
1015 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1016 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1017 fread(&offset
, sizeof(offset
), 1, fp
);
1018 fread(&tsc
, sizeof(tsc
), 1, fp
);
1019 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1020 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1022 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1027 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1028 LTTV_STATE_SAVED_STATES
);
1029 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1030 value
= lttv_attribute_add(saved_states_tree
,
1031 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1032 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1033 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1034 *(value
.v_time
) = t
;
1035 lttv_state_save(self
, saved_state_tree
);
1036 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1039 *(self
->max_time_state_recomputed_in_seek
) = t
;
1043 /* Called when a HDR_TRACE is found */
1044 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1045 GPtrArray
*quarktable
)
1050 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1052 if(hdr
== EOF
) goto end_loop
;
1055 case HDR_PROCESS_STATE
:
1056 /* Call read_process_state_raw */
1057 lttv_state_read_raw(tcs
, fp
, quarktable
);
1065 case HDR_USER_STACK
:
1069 g_error("Error while parsing saved state file :"
1070 " unexpected data header %d",
1074 g_error("Error while parsing saved state file : unknown data header %d",
1079 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1080 restore_init_state(tcs
);
1081 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1087 /* Copy each process from an existing hash table to a new one */
1089 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1091 LttvProcessState
*process
, *new_process
;
1093 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1097 process
= (LttvProcessState
*)value
;
1098 new_process
= g_new(LttvProcessState
, 1);
1099 *new_process
= *process
;
1100 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1101 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1102 new_process
->execution_stack
=
1103 g_array_set_size(new_process
->execution_stack
,
1104 process
->execution_stack
->len
);
1105 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1106 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1107 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1109 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1110 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1111 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1112 sizeof(guint64
), 0);
1113 new_process
->user_stack
=
1114 g_array_set_size(new_process
->user_stack
,
1115 process
->user_stack
->len
);
1116 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1117 g_array_index(new_process
->user_stack
, guint64
, i
) =
1118 g_array_index(process
->user_stack
, guint64
, i
);
1120 new_process
->current_function
= process
->current_function
;
1121 g_hash_table_insert(new_processes
, new_process
, new_process
);
1125 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1127 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1129 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1130 return new_processes
;
1133 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1136 LttvCPUState
*retval
;
1138 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1140 for(i
=0; i
<n
; i
++) {
1141 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1142 retval
[i
].last_irq
= states
[i
].last_irq
;
1143 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1144 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1145 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1152 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1156 for(i
=0; i
<n
; i
++) {
1157 g_array_free(states
[i
].mode_stack
, FALSE
);
1163 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1166 LttvIRQState
*retval
;
1168 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1170 for(i
=0; i
<n
; i
++) {
1171 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1172 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1173 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1174 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1181 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1185 for(i
=0; i
<n
; i
++) {
1186 g_array_free(states
[i
].mode_stack
, FALSE
);
1192 /* bdevstate stuff */
1194 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1196 gint devcode_gint
= devcode
;
1197 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1199 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1200 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1202 gint
* key
= g_malloc(sizeof(gint
));
1204 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1212 static LttvBdevState
*bdevstate_new(void)
1214 LttvBdevState
*retval
;
1215 retval
= g_malloc(sizeof(LttvBdevState
));
1216 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1221 static void bdevstate_free(LttvBdevState
*bds
)
1223 g_array_free(bds
->mode_stack
, FALSE
);
1227 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1229 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1231 bdevstate_free(bds
);
1234 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1236 LttvBdevState
*retval
;
1238 retval
= bdevstate_new();
1239 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1244 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1246 //GHashTable *ht = (GHashTable *)u;
1247 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1248 LttvBdevState
*newbds
;
1250 newbds
= bdevstate_copy(bds
);
1252 g_hash_table_insert(u
, k
, newbds
);
1255 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1259 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1261 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1266 /* Free a hashtable and the LttvBdevState structures its values
1269 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1271 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1272 g_hash_table_destroy(ht
);
1275 /* The saved state for each trace contains a member "processes", which
1276 stores a copy of the process table, and a member "tracefiles" with
1277 one entry per tracefile. Each tracefile has a "process" member pointing
1278 to the current process and a "position" member storing the tracefile
1279 position (needed to seek to the current "next" event. */
1281 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1283 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1285 LttvTracefileState
*tfcs
;
1287 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1289 guint
*running_process
;
1291 LttvAttributeValue value
;
1293 LttEventPosition
*ep
;
1295 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1296 LTTV_STATE_TRACEFILES
);
1298 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1300 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1302 /* Add the currently running processes array */
1303 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1304 running_process
= g_new(guint
, nb_cpus
);
1305 for(i
=0;i
<nb_cpus
;i
++) {
1306 running_process
[i
] = self
->running_process
[i
]->pid
;
1308 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1310 *(value
.v_pointer
) = running_process
;
1312 g_info("State save");
1314 nb_tracefile
= self
->parent
.tracefiles
->len
;
1316 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1318 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1319 LttvTracefileContext
*, i
));
1320 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1321 value
= lttv_attribute_add(tracefiles_tree
, i
,
1323 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1325 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1327 *(value
.v_uint
) = tfcs
->process
->pid
;
1329 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1331 /* Only save the position if the tfs has not infinite time. */
1332 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1333 // && current_tfcs != tfcs) {
1334 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1335 *(value
.v_pointer
) = NULL
;
1337 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1338 ep
= ltt_event_position_new();
1339 ltt_event_position(e
, ep
);
1340 *(value
.v_pointer
) = ep
;
1342 guint nb_block
, offset
;
1345 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1346 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1348 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1352 /* save the cpu state */
1354 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1356 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1359 /* save the irq state */
1360 nb_irqs
= self
->nb_irqs
;
1362 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1364 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1367 /* save the blkdev states */
1368 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1370 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1374 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1376 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1378 LttvTracefileState
*tfcs
;
1380 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1382 guint
*running_process
;
1384 LttvAttributeType type
;
1386 LttvAttributeValue value
;
1388 LttvAttributeName name
;
1392 LttEventPosition
*ep
;
1394 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1396 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1397 LTTV_STATE_TRACEFILES
);
1399 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1401 g_assert(type
== LTTV_POINTER
);
1402 lttv_state_free_process_table(self
->processes
);
1403 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1405 /* Add the currently running processes array */
1406 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1407 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1409 g_assert(type
== LTTV_POINTER
);
1410 running_process
= *(value
.v_pointer
);
1411 for(i
=0;i
<nb_cpus
;i
++) {
1412 pid
= running_process
[i
];
1413 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1414 g_assert(self
->running_process
[i
] != NULL
);
1417 nb_tracefile
= self
->parent
.tracefiles
->len
;
1419 //g_tree_destroy(tsc->pqueue);
1420 //tsc->pqueue = g_tree_new(compare_tracefile);
1422 /* restore cpu resource states */
1423 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1424 g_assert(type
== LTTV_POINTER
);
1425 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1426 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1428 /* restore irq resource states */
1429 nb_irqs
= self
->nb_irqs
;
1430 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1431 g_assert(type
== LTTV_POINTER
);
1432 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1433 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1435 /* restore the blkdev states */
1436 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1437 g_assert(type
== LTTV_POINTER
);
1438 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1439 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1441 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1443 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1444 LttvTracefileContext
*, i
));
1445 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1446 g_assert(type
== LTTV_GOBJECT
);
1447 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1449 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1451 g_assert(type
== LTTV_UINT
);
1452 pid
= *(value
.v_uint
);
1453 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1455 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1457 g_assert(type
== LTTV_POINTER
);
1458 //g_assert(*(value.v_pointer) != NULL);
1459 ep
= *(value
.v_pointer
);
1460 g_assert(tfcs
->parent
.t_context
!= NULL
);
1462 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1464 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1465 g_tree_remove(tsc
->pqueue
, tfc
);
1468 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1469 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1470 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1471 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1472 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1474 tfc
->timestamp
= ltt_time_infinite
;
1480 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1482 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1484 LttvTracefileState
*tfcs
;
1486 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1488 guint
*running_process
;
1490 LttvAttributeType type
;
1492 LttvAttributeValue value
;
1494 LttvAttributeName name
;
1498 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1499 LTTV_STATE_TRACEFILES
);
1500 g_object_ref(G_OBJECT(tracefiles_tree
));
1501 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1503 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1505 g_assert(type
== LTTV_POINTER
);
1506 lttv_state_free_process_table(*(value
.v_pointer
));
1507 *(value
.v_pointer
) = NULL
;
1508 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1510 /* Free running processes array */
1511 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1512 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1514 g_assert(type
== LTTV_POINTER
);
1515 running_process
= *(value
.v_pointer
);
1516 g_free(running_process
);
1518 /* free cpu resource states */
1519 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1520 g_assert(type
== LTTV_POINTER
);
1521 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1523 /* free irq resource states */
1524 nb_irqs
= self
->nb_irqs
;
1525 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1526 g_assert(type
== LTTV_POINTER
);
1527 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1529 /* free the blkdev states */
1530 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1531 g_assert(type
== LTTV_POINTER
);
1532 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1534 nb_tracefile
= self
->parent
.tracefiles
->len
;
1536 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1538 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1539 LttvTracefileContext
*, i
));
1540 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1541 g_assert(type
== LTTV_GOBJECT
);
1542 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1544 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1546 g_assert(type
== LTTV_POINTER
);
1547 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1549 g_object_unref(G_OBJECT(tracefiles_tree
));
1553 static void free_saved_state(LttvTraceState
*self
)
1557 LttvAttributeType type
;
1559 LttvAttributeValue value
;
1561 LttvAttributeName name
;
1565 LttvAttribute
*saved_states
;
1567 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1568 LTTV_STATE_SAVED_STATES
);
1570 nb
= lttv_attribute_get_number(saved_states
);
1571 for(i
= 0 ; i
< nb
; i
++) {
1572 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1573 g_assert(type
== LTTV_GOBJECT
);
1574 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1577 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1582 create_max_time(LttvTraceState
*tcs
)
1584 LttvAttributeValue v
;
1586 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1588 g_assert(*(v
.v_pointer
) == NULL
);
1589 *(v
.v_pointer
) = g_new(LttTime
,1);
1590 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1595 get_max_time(LttvTraceState
*tcs
)
1597 LttvAttributeValue v
;
1599 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1601 g_assert(*(v
.v_pointer
) != NULL
);
1602 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1607 free_max_time(LttvTraceState
*tcs
)
1609 LttvAttributeValue v
;
1611 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1613 g_free(*(v
.v_pointer
));
1614 *(v
.v_pointer
) = NULL
;
1618 typedef struct _LttvNameTables
{
1619 // FIXME GQuark *eventtype_names;
1620 GQuark
*syscall_names
;
1626 GQuark
*soft_irq_names
;
1632 create_name_tables(LttvTraceState
*tcs
)
1636 GString
*fe_name
= g_string_new("");
1638 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1640 LttvAttributeValue v
;
1644 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1646 g_assert(*(v
.v_pointer
) == NULL
);
1647 *(v
.v_pointer
) = name_tables
;
1649 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1651 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1652 LTT_FACILITY_KERNEL_ARCH
,
1653 LTT_EVENT_SYSCALL_ENTRY
,
1654 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1655 NULL
, NULL
, &hooks
)) {
1657 // th = lttv_trace_hook_get_first(&th);
1659 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1660 // nb = ltt_type_element_number(t);
1662 // name_tables->syscall_names = g_new(GQuark, nb);
1663 // name_tables->nb_syscalls = nb;
1665 // for(i = 0 ; i < nb ; i++) {
1666 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1667 // if(!name_tables->syscall_names[i]) {
1668 // GString *string = g_string_new("");
1669 // g_string_printf(string, "syscall %u", i);
1670 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1671 // g_string_free(string, TRUE);
1675 name_tables
->nb_syscalls
= 256;
1676 name_tables
->syscall_names
= g_new(GQuark
, 256);
1677 for(i
= 0 ; i
< 256 ; i
++) {
1678 g_string_printf(fe_name
, "syscall %d", i
);
1679 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1682 name_tables
->syscall_names
= NULL
;
1683 name_tables
->nb_syscalls
= 0;
1685 lttv_trace_hook_remove_all(&hooks
);
1687 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1688 LTT_FACILITY_KERNEL_ARCH
,
1689 LTT_EVENT_TRAP_ENTRY
,
1690 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1691 NULL
, NULL
, &hooks
)) {
1693 // th = lttv_trace_hook_get_first(&th);
1695 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1696 // //nb = ltt_type_element_number(t);
1698 // name_tables->trap_names = g_new(GQuark, nb);
1699 // for(i = 0 ; i < nb ; i++) {
1700 // name_tables->trap_names[i] = g_quark_from_string(
1701 // ltt_enum_string_get(t, i));
1704 name_tables
->nb_traps
= 256;
1705 name_tables
->trap_names
= g_new(GQuark
, 256);
1706 for(i
= 0 ; i
< 256 ; i
++) {
1707 g_string_printf(fe_name
, "trap %d", i
);
1708 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1711 name_tables
->trap_names
= NULL
;
1712 name_tables
->nb_traps
= 0;
1714 lttv_trace_hook_remove_all(&hooks
);
1716 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1717 LTT_FACILITY_KERNEL
,
1718 LTT_EVENT_IRQ_ENTRY
,
1719 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1720 NULL
, NULL
, &hooks
)) {
1723 name_tables->irq_names = g_new(GQuark, nb);
1724 for(i = 0 ; i < nb ; i++) {
1725 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1729 name_tables
->nb_irqs
= 256;
1730 name_tables
->irq_names
= g_new(GQuark
, 256);
1731 for(i
= 0 ; i
< 256 ; i
++) {
1732 g_string_printf(fe_name
, "irq %d", i
);
1733 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1736 name_tables
->nb_irqs
= 0;
1737 name_tables
->irq_names
= NULL
;
1739 lttv_trace_hook_remove_all(&hooks
);
1741 name_tables->soft_irq_names = g_new(GQuark, nb);
1742 for(i = 0 ; i < nb ; i++) {
1743 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1747 name_tables
->nb_softirqs
= 256;
1748 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1749 for(i
= 0 ; i
< 256 ; i
++) {
1750 g_string_printf(fe_name
, "softirq %d", i
);
1751 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1753 g_array_free(hooks
, TRUE
);
1755 g_string_free(fe_name
, TRUE
);
1760 get_name_tables(LttvTraceState
*tcs
)
1762 LttvNameTables
*name_tables
;
1764 LttvAttributeValue v
;
1766 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1768 g_assert(*(v
.v_pointer
) != NULL
);
1769 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1770 //tcs->eventtype_names = name_tables->eventtype_names;
1771 tcs
->syscall_names
= name_tables
->syscall_names
;
1772 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1773 tcs
->trap_names
= name_tables
->trap_names
;
1774 tcs
->nb_traps
= name_tables
->nb_traps
;
1775 tcs
->irq_names
= name_tables
->irq_names
;
1776 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1777 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1778 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1783 free_name_tables(LttvTraceState
*tcs
)
1785 LttvNameTables
*name_tables
;
1787 LttvAttributeValue v
;
1789 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1791 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1792 *(v
.v_pointer
) = NULL
;
1794 // g_free(name_tables->eventtype_names);
1795 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1796 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1797 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1798 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1799 if(name_tables
) g_free(name_tables
);
1802 #ifdef HASH_TABLE_DEBUG
1804 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1806 LttvProcessState
*process
= (LttvProcessState
*)value
;
1808 /* Test for process corruption */
1809 guint stack_len
= process
->execution_stack
->len
;
1812 static void hash_table_check(GHashTable
*table
)
1814 g_hash_table_foreach(table
, test_process
, NULL
);
1820 /* clears the stack and sets the state passed as argument */
1821 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1823 g_array_set_size(cpust
->mode_stack
, 1);
1824 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1827 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1829 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1830 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1833 static void cpu_pop_mode(LttvCPUState
*cpust
)
1835 if(cpust
->mode_stack
->len
<= 1)
1836 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1838 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1841 /* clears the stack and sets the state passed as argument */
1842 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1844 g_array_set_size(bdevst
->mode_stack
, 1);
1845 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1848 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1850 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1851 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1854 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1856 if(bdevst
->mode_stack
->len
<= 1)
1857 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1859 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1862 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1864 g_array_set_size(irqst
->mode_stack
, 1);
1865 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1868 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1870 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1871 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1874 static void irq_pop_mode(LttvIRQState
*irqst
)
1876 if(irqst
->mode_stack
->len
<= 1)
1877 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1879 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1882 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1885 LttvExecutionState
*es
;
1887 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1888 guint cpu
= tfs
->cpu
;
1890 #ifdef HASH_TABLE_DEBUG
1891 hash_table_check(ts
->processes
);
1893 LttvProcessState
*process
= ts
->running_process
[cpu
];
1895 guint depth
= process
->execution_stack
->len
;
1897 process
->execution_stack
=
1898 g_array_set_size(process
->execution_stack
, depth
+ 1);
1901 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1903 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1906 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1907 es
->cum_cpu_time
= ltt_time_zero
;
1908 es
->s
= process
->state
->s
;
1909 process
->state
= es
;
1913 * return 1 when empty, else 0 */
1914 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1915 LttvTracefileState
*tfs
)
1917 guint depth
= process
->execution_stack
->len
;
1923 process
->execution_stack
=
1924 g_array_set_size(process
->execution_stack
, depth
- 1);
1925 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1927 process
->state
->change
= tfs
->parent
.timestamp
;
1932 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1934 guint cpu
= tfs
->cpu
;
1935 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1936 LttvProcessState
*process
= ts
->running_process
[cpu
];
1938 guint depth
= process
->execution_stack
->len
;
1940 if(process
->state
->t
!= t
){
1941 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1942 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1943 g_info("process state has %s when pop_int is %s\n",
1944 g_quark_to_string(process
->state
->t
),
1945 g_quark_to_string(t
));
1946 g_info("{ %u, %u, %s, %s, %s }\n",
1949 g_quark_to_string(process
->name
),
1950 g_quark_to_string(process
->brand
),
1951 g_quark_to_string(process
->state
->s
));
1956 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1957 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1961 process
->execution_stack
=
1962 g_array_set_size(process
->execution_stack
, depth
- 1);
1963 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1965 process
->state
->change
= tfs
->parent
.timestamp
;
1968 struct search_result
{
1969 const LttTime
*time
; /* Requested time */
1970 LttTime
*best
; /* Best result */
1973 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1975 const LttTime
*elem_time
= (const LttTime
*)a
;
1976 /* Explicit non const cast */
1977 struct search_result
*res
= (struct search_result
*)b
;
1979 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1980 /* The usertrace was created before the schedchange */
1981 /* Get larger keys */
1983 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1984 /* The usertrace was created after the schedchange time */
1985 /* Get smaller keys */
1987 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1988 res
->best
= (LttTime
*)elem_time
;
1991 res
->best
= (LttTime
*)elem_time
;
1998 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1999 guint pid
, const LttTime
*timestamp
)
2001 LttvTracefileState
*tfs
= NULL
;
2002 struct search_result res
;
2003 /* Find the usertrace associated with a pid and time interval.
2004 * Search in the usertraces by PID (within a hash) and then, for each
2005 * corresponding element of the array, find the first one with creation
2006 * timestamp the lowest, but higher or equal to "timestamp". */
2007 res
.time
= timestamp
;
2009 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2010 if(usertrace_tree
) {
2011 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2013 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2021 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2022 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2024 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2026 LttvExecutionState
*es
;
2031 process
->tgid
= tgid
;
2033 process
->name
= name
;
2034 process
->brand
= LTTV_STATE_UNBRANDED
;
2035 //process->last_cpu = tfs->cpu_name;
2036 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2037 process
->type
= LTTV_STATE_USER_THREAD
;
2038 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2039 process
->current_function
= 0; //function 0x0 by default.
2041 g_info("Process %u, core %p", process
->pid
, process
);
2042 g_hash_table_insert(tcs
->processes
, process
, process
);
2045 process
->ppid
= parent
->pid
;
2046 process
->creation_time
= *timestamp
;
2049 /* No parent. This process exists but we are missing all information about
2050 its creation. The birth time is set to zero but we remember the time of
2055 process
->creation_time
= ltt_time_zero
;
2058 process
->insertion_time
= *timestamp
;
2059 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2060 process
->creation_time
.tv_nsec
);
2061 process
->pid_time
= g_quark_from_string(buffer
);
2063 //process->last_cpu = tfs->cpu_name;
2064 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2065 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2066 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2067 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2068 es
= process
->state
= &g_array_index(process
->execution_stack
,
2069 LttvExecutionState
, 0);
2070 es
->t
= LTTV_STATE_USER_MODE
;
2071 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2072 es
->entry
= *timestamp
;
2073 //g_assert(timestamp->tv_sec != 0);
2074 es
->change
= *timestamp
;
2075 es
->cum_cpu_time
= ltt_time_zero
;
2076 es
->s
= LTTV_STATE_RUN
;
2078 es
= process
->state
= &g_array_index(process
->execution_stack
,
2079 LttvExecutionState
, 1);
2080 es
->t
= LTTV_STATE_SYSCALL
;
2081 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2082 es
->entry
= *timestamp
;
2083 //g_assert(timestamp->tv_sec != 0);
2084 es
->change
= *timestamp
;
2085 es
->cum_cpu_time
= ltt_time_zero
;
2086 es
->s
= LTTV_STATE_WAIT_FORK
;
2088 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2089 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2090 sizeof(guint64
), 0);
2095 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2098 LttvProcessState key
;
2099 LttvProcessState
*process
;
2103 process
= g_hash_table_lookup(ts
->processes
, &key
);
2108 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2109 const LttTime
*timestamp
)
2111 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2112 LttvExecutionState
*es
;
2114 /* Put ltt_time_zero creation time for unexisting processes */
2115 if(unlikely(process
== NULL
)) {
2116 process
= lttv_state_create_process(ts
,
2117 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2118 /* We are not sure is it's a kernel thread or normal thread, put the
2119 * bottom stack state to unknown */
2120 process
->execution_stack
=
2121 g_array_set_size(process
->execution_stack
, 1);
2122 process
->state
= es
=
2123 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2124 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2125 es
->s
= LTTV_STATE_UNNAMED
;
2130 /* FIXME : this function should be called when we receive an event telling that
2131 * release_task has been called in the kernel. In happens generally when
2132 * the parent waits for its child terminaison, but may also happen in special
2133 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2134 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2135 * of a killed thread ground, but isn't the leader.
2137 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2139 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2140 LttvProcessState key
;
2142 key
.pid
= process
->pid
;
2143 key
.cpu
= process
->cpu
;
2144 g_hash_table_remove(ts
->processes
, &key
);
2145 g_array_free(process
->execution_stack
, TRUE
);
2146 g_array_free(process
->user_stack
, TRUE
);
2151 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2153 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2154 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2159 static void lttv_state_free_process_table(GHashTable
*processes
)
2161 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2162 g_hash_table_destroy(processes
);
2166 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2168 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2170 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2171 LttvProcessState
*process
= ts
->running_process
[cpu
];
2172 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2173 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2174 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2176 LttvExecutionSubmode submode
;
2178 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2179 guint syscall
= ltt_event_get_unsigned(e
, f
);
2181 if(syscall
< nb_syscalls
) {
2182 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2185 /* Fixup an incomplete syscall table */
2186 GString
*string
= g_string_new("");
2187 g_string_printf(string
, "syscall %u", syscall
);
2188 submode
= g_quark_from_string(string
->str
);
2189 g_string_free(string
, TRUE
);
2191 /* There can be no system call from PID 0 : unknown state */
2192 if(process
->pid
!= 0)
2193 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2198 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2200 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2202 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2203 LttvProcessState
*process
= ts
->running_process
[cpu
];
2205 /* There can be no system call from PID 0 : unknown state */
2206 if(process
->pid
!= 0)
2207 pop_state(s
, LTTV_STATE_SYSCALL
);
2212 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2214 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2215 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2216 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2217 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2219 LttvExecutionSubmode submode
;
2221 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2222 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2224 if(trap
< nb_traps
) {
2225 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2227 /* Fixup an incomplete trap table */
2228 GString
*string
= g_string_new("");
2229 g_string_printf(string
, "trap %llu", trap
);
2230 submode
= g_quark_from_string(string
->str
);
2231 g_string_free(string
, TRUE
);
2234 push_state(s
, LTTV_STATE_TRAP
, submode
);
2236 /* update cpu status */
2237 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2242 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2244 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2246 pop_state(s
, LTTV_STATE_TRAP
);
2248 /* update cpu status */
2249 cpu_pop_mode(s
->cpu_state
);
2254 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2256 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2257 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2258 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2259 //guint8 ev_id = ltt_event_eventtype_id(e);
2260 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2261 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2263 LttvExecutionSubmode submode
;
2264 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2265 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2268 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2270 /* Fixup an incomplete irq table */
2271 GString
*string
= g_string_new("");
2272 g_string_printf(string
, "irq %llu", irq
);
2273 submode
= g_quark_from_string(string
->str
);
2274 g_string_free(string
, TRUE
);
2277 /* Do something with the info about being in user or system mode when int? */
2278 push_state(s
, LTTV_STATE_IRQ
, submode
);
2280 /* update cpu status */
2281 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2283 /* update irq status */
2284 s
->cpu_state
->last_irq
= irq
;
2285 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2290 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2292 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2294 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2300 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2302 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2303 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2305 pop_state(s
, LTTV_STATE_IRQ
);
2307 /* update cpu status */
2308 cpu_pop_mode(s
->cpu_state
);
2310 /* update irq status */
2311 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2316 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2318 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2319 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2320 //guint8 ev_id = ltt_event_eventtype_id(e);
2321 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2322 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2324 LttvExecutionSubmode submode
;
2325 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2326 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2328 if(softirq
< nb_softirqs
) {
2329 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2331 /* Fixup an incomplete irq table */
2332 GString
*string
= g_string_new("");
2333 g_string_printf(string
, "softirq %llu", softirq
);
2334 submode
= g_quark_from_string(string
->str
);
2335 g_string_free(string
, TRUE
);
2338 /* Do something with the info about being in user or system mode when int? */
2339 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2343 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2345 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2346 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2347 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2348 //guint8 ev_id = ltt_event_eventtype_id(e);
2349 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2351 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2352 lttv_trace_get_hook_field(th
, 0)));
2353 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2355 ts
->irq_names
[irq
] = action
;
2361 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2363 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2364 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2365 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2366 //guint8 ev_id = ltt_event_eventtype_id(e);
2367 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2369 guint major
= ltt_event_get_long_unsigned(e
,
2370 lttv_trace_get_hook_field(th
, 0));
2371 guint minor
= ltt_event_get_long_unsigned(e
,
2372 lttv_trace_get_hook_field(th
, 1));
2373 guint oper
= ltt_event_get_long_unsigned(e
,
2374 lttv_trace_get_hook_field(th
, 2));
2375 guint16 devcode
= MKDEV(major
,minor
);
2377 /* have we seen this block device before? */
2378 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2381 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2383 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2388 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2390 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2391 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2392 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2393 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2395 guint major
= ltt_event_get_long_unsigned(e
,
2396 lttv_trace_get_hook_field(th
, 0));
2397 guint minor
= ltt_event_get_long_unsigned(e
,
2398 lttv_trace_get_hook_field(th
, 1));
2399 //guint oper = ltt_event_get_long_unsigned(e,
2400 // lttv_trace_get_hook_field(th, 2));
2401 guint16 devcode
= MKDEV(major
,minor
);
2403 /* have we seen this block device before? */
2404 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2406 /* update block device */
2407 bdev_pop_mode(bdev
);
2412 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2416 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2417 guint cpu
= tfs
->cpu
;
2418 LttvProcessState
*process
= ts
->running_process
[cpu
];
2420 guint depth
= process
->user_stack
->len
;
2422 process
->user_stack
=
2423 g_array_set_size(process
->user_stack
, depth
+ 1);
2425 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2426 *new_func
= funcptr
;
2427 process
->current_function
= funcptr
;
2430 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2432 guint cpu
= tfs
->cpu
;
2433 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2434 LttvProcessState
*process
= ts
->running_process
[cpu
];
2436 if(process
->current_function
!= funcptr
){
2437 g_info("Different functions (%lu.%09lu): ignore it\n",
2438 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2439 g_info("process state has %llu when pop_function is %llu\n",
2440 process
->current_function
, funcptr
);
2441 g_info("{ %u, %u, %s, %s, %s }\n",
2444 g_quark_to_string(process
->name
),
2445 g_quark_to_string(process
->brand
),
2446 g_quark_to_string(process
->state
->s
));
2449 guint depth
= process
->user_stack
->len
;
2452 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2453 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2457 process
->user_stack
=
2458 g_array_set_size(process
->user_stack
, depth
- 1);
2459 process
->current_function
=
2460 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2464 static gboolean
function_entry(void *hook_data
, void *call_data
)
2466 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2467 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2468 //guint8 ev_id = ltt_event_eventtype_id(e);
2469 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2470 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2471 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2473 push_function(s
, funcptr
);
2477 static gboolean
function_exit(void *hook_data
, void *call_data
)
2479 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2480 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2481 //guint8 ev_id = ltt_event_eventtype_id(e);
2482 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2483 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2484 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2486 pop_function(s
, funcptr
);
2490 static gboolean
schedchange(void *hook_data
, void *call_data
)
2492 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2494 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2495 LttvProcessState
*process
= ts
->running_process
[cpu
];
2496 //LttvProcessState *old_process = ts->running_process[cpu];
2498 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2499 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2500 guint pid_in
, pid_out
;
2503 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2504 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2505 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2507 if(likely(process
!= NULL
)) {
2509 /* We could not know but it was not the idle process executing.
2510 This should only happen at the beginning, before the first schedule
2511 event, and when the initial information (current process for each CPU)
2512 is missing. It is not obvious how we could, after the fact, compensate
2513 the wrongly attributed statistics. */
2515 //This test only makes sense once the state is known and if there is no
2516 //missing events. We need to silently ignore schedchange coming after a
2517 //process_free, or it causes glitches. (FIXME)
2518 //if(unlikely(process->pid != pid_out)) {
2519 // g_assert(process->pid == 0);
2521 if(process
->pid
== 0
2522 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2524 /* Scheduling out of pid 0 at beginning of the trace :
2525 * we know for sure it is in syscall mode at this point. */
2526 g_assert(process
->execution_stack
->len
== 1);
2527 process
->state
->t
= LTTV_STATE_SYSCALL
;
2528 process
->state
->s
= LTTV_STATE_WAIT
;
2529 process
->state
->change
= s
->parent
.timestamp
;
2530 process
->state
->entry
= s
->parent
.timestamp
;
2533 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2534 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2535 process
->state
->change
= s
->parent
.timestamp
;
2537 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2538 else process
->state
->s
= LTTV_STATE_WAIT
;
2539 process
->state
->change
= s
->parent
.timestamp
;
2542 if(state_out
== 32 || state_out
== 128)
2543 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2544 /* see sched.h for states */
2547 process
= ts
->running_process
[cpu
] =
2548 lttv_state_find_process_or_create(
2549 (LttvTraceState
*)s
->parent
.t_context
,
2551 &s
->parent
.timestamp
);
2552 process
->state
->s
= LTTV_STATE_RUN
;
2554 if(process
->usertrace
)
2555 process
->usertrace
->cpu
= cpu
;
2556 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2557 process
->state
->change
= s
->parent
.timestamp
;
2559 /* update cpu status */
2561 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2563 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2568 static gboolean
process_fork(void *hook_data
, void *call_data
)
2570 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2571 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2572 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2574 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2575 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2576 //LttvProcessState *zombie_process;
2578 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2579 LttvProcessState
*process
= ts
->running_process
[cpu
];
2580 LttvProcessState
*child_process
;
2581 struct marker_field
*f
;
2584 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2587 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2588 s
->parent
.target_pid
= child_pid
;
2591 f
= lttv_trace_get_hook_field(th
, 2);
2593 child_tgid
= ltt_event_get_unsigned(e
, f
);
2597 /* Mathieu : it seems like the process might have been scheduled in before the
2598 * fork, and, in a rare case, might be the current process. This might happen
2599 * in a SMP case where we don't have enough precision on the clocks.
2601 * Test reenabled after precision fixes on time. (Mathieu) */
2603 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2605 if(unlikely(zombie_process
!= NULL
)) {
2606 /* Reutilisation of PID. Only now we are sure that the old PID
2607 * has been released. FIXME : should know when release_task happens instead.
2609 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2611 for(i
=0; i
< num_cpus
; i
++) {
2612 g_assert(zombie_process
!= ts
->running_process
[i
]);
2615 exit_process(s
, zombie_process
);
2618 g_assert(process
->pid
!= child_pid
);
2619 // FIXME : Add this test in the "known state" section
2620 // g_assert(process->pid == parent_pid);
2621 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2622 if(child_process
== NULL
) {
2623 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2624 child_pid
, child_tgid
,
2625 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2627 /* The process has already been created : due to time imprecision between
2628 * multiple CPUs : it has been scheduled in before creation. Note that we
2629 * shouldn't have this kind of imprecision.
2631 * Simply put a correct parent.
2633 g_assert(0); /* This is a problematic case : the process has been created
2634 before the fork event */
2635 child_process
->ppid
= process
->pid
;
2636 child_process
->tgid
= child_tgid
;
2638 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2639 child_process
->name
= process
->name
;
2640 child_process
->brand
= process
->brand
;
2645 /* We stamp a newly created process as kernel_thread.
2646 * The thread should not be running yet. */
2647 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2649 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2650 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2651 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2653 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2654 LttvProcessState
*process
;
2655 LttvExecutionState
*es
;
2658 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2659 s
->parent
.target_pid
= pid
;
2661 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2663 process
->execution_stack
=
2664 g_array_set_size(process
->execution_stack
, 1);
2665 es
= process
->state
=
2666 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2667 es
->t
= LTTV_STATE_SYSCALL
;
2668 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2673 static gboolean
process_exit(void *hook_data
, void *call_data
)
2675 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2676 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2677 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2679 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2680 LttvProcessState
*process
; // = ts->running_process[cpu];
2682 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2683 s
->parent
.target_pid
= pid
;
2685 // FIXME : Add this test in the "known state" section
2686 // g_assert(process->pid == pid);
2688 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2689 if(likely(process
!= NULL
)) {
2690 process
->state
->s
= LTTV_STATE_EXIT
;
2695 static gboolean
process_free(void *hook_data
, void *call_data
)
2697 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2698 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2699 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2700 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2702 LttvProcessState
*process
;
2704 /* PID of the process to release */
2705 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2706 s
->parent
.target_pid
= release_pid
;
2708 g_assert(release_pid
!= 0);
2710 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2712 if(likely(process
!= NULL
)) {
2713 /* release_task is happening at kernel level : we can now safely release
2714 * the data structure of the process */
2715 //This test is fun, though, as it may happen that
2716 //at time t : CPU 0 : process_free
2717 //at time t+150ns : CPU 1 : schedule out
2718 //Clearly due to time imprecision, we disable it. (Mathieu)
2719 //If this weird case happen, we have no choice but to put the
2720 //Currently running process on the cpu to 0.
2721 //I re-enable it following time precision fixes. (Mathieu)
2722 //Well, in the case where an process is freed by a process on another CPU
2723 //and still scheduled, it happens that this is the schedchange that will
2724 //drop the last reference count. Do not free it here!
2725 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2727 for(i
=0; i
< num_cpus
; i
++) {
2728 //g_assert(process != ts->running_process[i]);
2729 if(process
== ts
->running_process
[i
]) {
2730 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2734 if(i
== num_cpus
) /* process is not scheduled */
2735 exit_process(s
, process
);
2742 static gboolean
process_exec(void *hook_data
, void *call_data
)
2744 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2745 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2746 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2747 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2750 LttvProcessState
*process
= ts
->running_process
[cpu
];
2752 #if 0//how to use a sequence that must be transformed in a string
2753 /* PID of the process to release */
2754 guint64 name_len
= ltt_event_field_element_number(e
,
2755 lttv_trace_get_hook_field(th
, 0));
2756 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2757 LttField
*child
= ltt_event_field_element_select(e
,
2758 lttv_trace_get_hook_field(th
, 0), 0);
2760 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2761 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2762 memcpy(null_term_name
, name_begin
, name_len
);
2763 null_term_name
[name_len
] = '\0';
2764 process
->name
= g_quark_from_string(null_term_name
);
2767 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2768 lttv_trace_get_hook_field(th
, 0)));
2769 process
->brand
= LTTV_STATE_UNBRANDED
;
2770 //g_free(null_term_name);
2774 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2776 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2777 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2778 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2779 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2782 LttvProcessState
*process
= ts
->running_process
[cpu
];
2784 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2785 process
->brand
= g_quark_from_string(name
);
2790 static void fix_process(gpointer key
, gpointer value
,
2793 LttvProcessState
*process
;
2794 LttvExecutionState
*es
;
2795 process
= (LttvProcessState
*)value
;
2796 LttTime
*timestamp
= (LttTime
*)user_data
;
2798 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2799 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2800 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2801 es
->t
= LTTV_STATE_SYSCALL
;
2802 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2803 es
->entry
= *timestamp
;
2804 es
->change
= *timestamp
;
2805 es
->cum_cpu_time
= ltt_time_zero
;
2806 if(es
->s
== LTTV_STATE_UNNAMED
)
2807 es
->s
= LTTV_STATE_WAIT
;
2810 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2811 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2812 es
->t
= LTTV_STATE_USER_MODE
;
2813 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2814 es
->entry
= *timestamp
;
2815 //g_assert(timestamp->tv_sec != 0);
2816 es
->change
= *timestamp
;
2817 es
->cum_cpu_time
= ltt_time_zero
;
2818 if(es
->s
== LTTV_STATE_UNNAMED
)
2819 es
->s
= LTTV_STATE_RUN
;
2821 if(process
->execution_stack
->len
== 1) {
2822 /* Still in bottom unknown mode, means never did a system call
2823 * May be either in user mode, syscall mode, running or waiting.*/
2824 /* FIXME : we may be tagging syscall mode when being user mode */
2825 process
->execution_stack
=
2826 g_array_set_size(process
->execution_stack
, 2);
2827 es
= process
->state
= &g_array_index(process
->execution_stack
,
2828 LttvExecutionState
, 1);
2829 es
->t
= LTTV_STATE_SYSCALL
;
2830 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2831 es
->entry
= *timestamp
;
2832 //g_assert(timestamp->tv_sec != 0);
2833 es
->change
= *timestamp
;
2834 es
->cum_cpu_time
= ltt_time_zero
;
2835 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2836 es
->s
= LTTV_STATE_WAIT
;
2842 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2844 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2845 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2846 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2847 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2848 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2850 /* For all processes */
2851 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2852 /* else, if stack[0] is unknown, set to user mode, running */
2854 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2859 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2861 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2862 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2863 //It's slow : optimise later by doing this before reading trace.
2864 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2870 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2871 LttvProcessState
*process
= ts
->running_process
[cpu
];
2872 LttvProcessState
*parent_process
;
2873 struct marker_field
*f
;
2874 GQuark type
, mode
, submode
, status
;
2875 LttvExecutionState
*es
;
2879 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2880 s
->parent
.target_pid
= pid
;
2883 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2886 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2889 f
= lttv_trace_get_hook_field(th
, 3);
2890 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2892 //FIXME: type is rarely used, enum must match possible types.
2895 f
= lttv_trace_get_hook_field(th
, 4);
2896 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2899 f
= lttv_trace_get_hook_field(th
, 5);
2900 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2903 f
= lttv_trace_get_hook_field(th
, 6);
2904 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2907 f
= lttv_trace_get_hook_field(th
, 7);
2909 tgid
= ltt_event_get_unsigned(e
, f
);
2914 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2915 for(i
=0; i
<nb_cpus
; i
++) {
2916 process
= lttv_state_find_process(ts
, i
, pid
);
2917 g_assert(process
!= NULL
);
2919 process
->ppid
= parent_pid
;
2920 process
->tgid
= tgid
;
2921 process
->name
= g_quark_from_string(command
);
2923 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2924 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2928 /* The process might exist if a process was forked while performing the
2930 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2931 if(process
== NULL
) {
2932 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2933 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2934 pid
, tgid
, g_quark_from_string(command
),
2935 &s
->parent
.timestamp
);
2937 /* Keep the stack bottom : a running user mode */
2938 /* Disabled because of inconsistencies in the current statedump states. */
2939 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2940 /* Only keep the bottom
2941 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2942 /* Will cause expected trap when in fact being syscall (even after end of
2944 * Will cause expected interrupt when being syscall. (only before end of
2945 * statedump event) */
2946 // This will cause a "popping last state on stack, ignoring it."
2947 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2948 es
= process
->state
= &g_array_index(process
->execution_stack
,
2949 LttvExecutionState
, 0);
2950 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2951 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2952 es
->s
= LTTV_STATE_UNNAMED
;
2953 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2955 es
->t
= LTTV_STATE_SYSCALL
;
2960 /* User space process :
2961 * bottom : user mode
2962 * either currently running or scheduled out.
2963 * can be scheduled out because interrupted in (user mode or in syscall)
2964 * or because of an explicit call to the scheduler in syscall. Note that
2965 * the scheduler call comes after the irq_exit, so never in interrupt
2967 // temp workaround : set size to 1 : only have user mode bottom of stack.
2968 // will cause g_info message of expected syscall mode when in fact being
2969 // in user mode. Can also cause expected trap when in fact being user
2970 // mode in the event of a page fault reenabling interrupts in the handler.
2971 // Expected syscall and trap can also happen after the end of statedump
2972 // This will cause a "popping last state on stack, ignoring it."
2973 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2974 es
= process
->state
= &g_array_index(process
->execution_stack
,
2975 LttvExecutionState
, 0);
2976 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2977 es
->s
= LTTV_STATE_UNNAMED
;
2978 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2980 es
->t
= LTTV_STATE_USER_MODE
;
2988 es
= process
->state
= &g_array_index(process
->execution_stack
,
2989 LttvExecutionState
, 1);
2990 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2991 es
->s
= LTTV_STATE_UNNAMED
;
2992 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2996 /* The process has already been created :
2997 * Probably was forked while dumping the process state or
2998 * was simply scheduled in prior to get the state dump event.
3000 process
->ppid
= parent_pid
;
3001 process
->tgid
= tgid
;
3002 process
->name
= g_quark_from_string(command
);
3003 process
->type
= type
;
3005 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3007 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3008 if(type
== LTTV_STATE_KERNEL_THREAD
)
3009 es
->t
= LTTV_STATE_SYSCALL
;
3011 es
->t
= LTTV_STATE_USER_MODE
;
3014 /* Don't mess around with the stack, it will eventually become
3015 * ok after the end of state dump. */
3022 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3024 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3026 lttv_state_add_event_hooks(tss
);
3031 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3033 LttvTraceset
*traceset
= self
->parent
.ts
;
3035 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3039 LttvTracefileState
*tfs
;
3045 LttvAttributeValue val
;
3047 nb_trace
= lttv_traceset_number(traceset
);
3048 for(i
= 0 ; i
< nb_trace
; i
++) {
3049 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3051 /* Find the eventtype id for the following events and register the
3052 associated by id hooks. */
3054 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3055 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3058 lttv_trace_find_hook(ts
->parent
.t
,
3059 LTT_FACILITY_KERNEL_ARCH
,
3060 LTT_EVENT_SYSCALL_ENTRY
,
3061 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3062 syscall_entry
, NULL
, &hooks
);
3064 lttv_trace_find_hook(ts
->parent
.t
,
3065 LTT_FACILITY_KERNEL_ARCH
,
3066 LTT_EVENT_SYSCALL_EXIT
,
3068 syscall_exit
, NULL
, &hooks
);
3070 lttv_trace_find_hook(ts
->parent
.t
,
3071 LTT_FACILITY_KERNEL_ARCH
,
3072 LTT_EVENT_TRAP_ENTRY
,
3073 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3074 trap_entry
, NULL
, &hooks
);
3076 lttv_trace_find_hook(ts
->parent
.t
,
3077 LTT_FACILITY_KERNEL_ARCH
,
3078 LTT_EVENT_TRAP_EXIT
,
3080 trap_exit
, NULL
, &hooks
);
3082 lttv_trace_find_hook(ts
->parent
.t
,
3083 LTT_FACILITY_KERNEL
,
3084 LTT_EVENT_IRQ_ENTRY
,
3085 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3086 irq_entry
, NULL
, &hooks
);
3088 lttv_trace_find_hook(ts
->parent
.t
,
3089 LTT_FACILITY_KERNEL
,
3092 irq_exit
, NULL
, &hooks
);
3094 lttv_trace_find_hook(ts
->parent
.t
,
3095 LTT_FACILITY_KERNEL
,
3096 LTT_EVENT_SOFT_IRQ_ENTRY
,
3097 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3098 soft_irq_entry
, NULL
, &hooks
);
3100 lttv_trace_find_hook(ts
->parent
.t
,
3101 LTT_FACILITY_KERNEL
,
3102 LTT_EVENT_SOFT_IRQ_EXIT
,
3104 soft_irq_exit
, NULL
, &hooks
);
3106 lttv_trace_find_hook(ts
->parent
.t
,
3107 LTT_FACILITY_KERNEL
,
3108 LTT_EVENT_SCHED_SCHEDULE
,
3109 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3110 LTT_FIELD_PREV_STATE
),
3111 schedchange
, NULL
, &hooks
);
3113 lttv_trace_find_hook(ts
->parent
.t
,
3114 LTT_FACILITY_KERNEL
,
3115 LTT_EVENT_PROCESS_FORK
,
3116 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3117 LTT_FIELD_CHILD_TGID
),
3118 process_fork
, NULL
, &hooks
);
3120 lttv_trace_find_hook(ts
->parent
.t
,
3121 LTT_FACILITY_KERNEL_ARCH
,
3122 LTT_EVENT_KTHREAD_CREATE
,
3123 FIELD_ARRAY(LTT_FIELD_PID
),
3124 process_kernel_thread
, NULL
, &hooks
);
3126 lttv_trace_find_hook(ts
->parent
.t
,
3127 LTT_FACILITY_KERNEL
,
3128 LTT_EVENT_PROCESS_EXIT
,
3129 FIELD_ARRAY(LTT_FIELD_PID
),
3130 process_exit
, NULL
, &hooks
);
3132 lttv_trace_find_hook(ts
->parent
.t
,
3133 LTT_FACILITY_KERNEL
,
3134 LTT_EVENT_PROCESS_FREE
,
3135 FIELD_ARRAY(LTT_FIELD_PID
),
3136 process_free
, NULL
, &hooks
);
3138 lttv_trace_find_hook(ts
->parent
.t
,
3141 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3142 process_exec
, NULL
, &hooks
);
3144 lttv_trace_find_hook(ts
->parent
.t
,
3145 LTT_FACILITY_USER_GENERIC
,
3146 LTT_EVENT_THREAD_BRAND
,
3147 FIELD_ARRAY(LTT_FIELD_NAME
),
3148 thread_brand
, NULL
, &hooks
);
3150 /* statedump-related hooks */
3151 lttv_trace_find_hook(ts
->parent
.t
,
3153 LTT_EVENT_PROCESS_STATE
,
3154 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3155 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3156 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3157 enum_process_state
, NULL
, &hooks
);
3159 lttv_trace_find_hook(ts
->parent
.t
,
3161 LTT_EVENT_STATEDUMP_END
,
3163 statedump_end
, NULL
, &hooks
);
3165 lttv_trace_find_hook(ts
->parent
.t
,
3167 LTT_EVENT_LIST_INTERRUPT
,
3168 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_IRQ_ID
),
3169 enum_interrupt
, NULL
, &hooks
);
3171 lttv_trace_find_hook(ts
->parent
.t
,
3173 LTT_EVENT_REQUEST_ISSUE
,
3174 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3175 bdev_request_issue
, NULL
, &hooks
);
3177 lttv_trace_find_hook(ts
->parent
.t
,
3179 LTT_EVENT_REQUEST_COMPLETE
,
3180 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3181 bdev_request_complete
, NULL
, &hooks
);
3183 lttv_trace_find_hook(ts
->parent
.t
,
3184 LTT_FACILITY_USER_GENERIC
,
3185 LTT_EVENT_FUNCTION_ENTRY
,
3186 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3187 function_entry
, NULL
, &hooks
);
3189 lttv_trace_find_hook(ts
->parent
.t
,
3190 LTT_FACILITY_USER_GENERIC
,
3191 LTT_EVENT_FUNCTION_EXIT
,
3192 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3193 function_exit
, NULL
, &hooks
);
3195 /* Add these hooks to each event_by_id hooks list */
3197 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3199 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3201 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3202 LttvTracefileContext
*, j
));
3204 for(k
= 0 ; k
< hooks
->len
; k
++) {
3205 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3207 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3213 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3214 *(val
.v_pointer
) = hooks
;
3218 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3220 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3222 lttv_state_remove_event_hooks(tss
);
3227 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3229 LttvTraceset
*traceset
= self
->parent
.ts
;
3231 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3235 LttvTracefileState
*tfs
;
3241 LttvAttributeValue val
;
3243 nb_trace
= lttv_traceset_number(traceset
);
3244 for(i
= 0 ; i
< nb_trace
; i
++) {
3245 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3247 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3248 hooks
= *(val
.v_pointer
);
3250 /* Remove these hooks from each event_by_id hooks list */
3252 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3254 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3256 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3257 LttvTracefileContext
*, j
));
3259 for(k
= 0 ; k
< hooks
->len
; k
++) {
3260 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3261 lttv_hooks_remove_data(
3262 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3267 lttv_trace_hook_remove_all(&hooks
);
3268 g_array_free(hooks
, TRUE
);
3272 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3274 guint
*event_count
= (guint
*)hook_data
;
3276 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3277 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3282 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3284 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3286 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3288 LttvAttributeValue value
;
3290 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3291 LTTV_STATE_SAVED_STATES
);
3292 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3293 value
= lttv_attribute_add(saved_states_tree
,
3294 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3295 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3296 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3297 *(value
.v_time
) = self
->parent
.timestamp
;
3298 lttv_state_save(tcs
, saved_state_tree
);
3299 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3300 self
->parent
.timestamp
.tv_nsec
);
3302 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3307 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3309 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3311 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3316 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3324 static gboolean
block_start(void *hook_data
, void *call_data
)
3326 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3328 LttvTracefileState
*tfcs
;
3330 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3332 LttEventPosition
*ep
;
3334 guint i
, nb_block
, nb_event
, nb_tracefile
;
3338 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3340 LttvAttributeValue value
;
3342 ep
= ltt_event_position_new();
3344 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3346 /* Count the number of events added since the last block end in any
3349 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3351 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3352 LttvTracefileContext
, i
));
3353 ltt_event_position(tfcs
->parent
.e
, ep
);
3354 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3355 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3356 tfcs
->saved_position
= nb_event
;
3360 if(tcs
->nb_event
>= tcs
->save_interval
) {
3361 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3362 LTTV_STATE_SAVED_STATES
);
3363 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3364 value
= lttv_attribute_add(saved_states_tree
,
3365 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3366 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3367 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3368 *(value
.v_time
) = self
->parent
.timestamp
;
3369 lttv_state_save(tcs
, saved_state_tree
);
3371 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3372 self
->parent
.timestamp
.tv_nsec
);
3374 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3380 static gboolean
block_end(void *hook_data
, void *call_data
)
3382 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3384 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3388 LttEventPosition
*ep
;
3390 guint nb_block
, nb_event
;
3392 ep
= ltt_event_position_new();
3393 ltt_event_position(self
->parent
.e
, ep
);
3394 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3395 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3396 self
->saved_position
= 0;
3397 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3404 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3406 LttvTraceset
*traceset
= self
->parent
.ts
;
3408 guint i
, j
, nb_trace
, nb_tracefile
;
3412 LttvTracefileState
*tfs
;
3414 LttvTraceHook hook_start
, hook_end
;
3416 nb_trace
= lttv_traceset_number(traceset
);
3417 for(i
= 0 ; i
< nb_trace
; i
++) {
3418 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3420 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3421 NULL
, NULL
, block_start
, &hook_start
);
3422 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3423 NULL
, NULL
, block_end
, &hook_end
);
3425 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3427 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3429 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3430 LttvTracefileContext
, j
));
3431 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3432 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3433 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3434 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3440 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3442 LttvTraceset
*traceset
= self
->parent
.ts
;
3444 guint i
, j
, nb_trace
, nb_tracefile
;
3448 LttvTracefileState
*tfs
;
3451 nb_trace
= lttv_traceset_number(traceset
);
3452 for(i
= 0 ; i
< nb_trace
; i
++) {
3454 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3455 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3457 if(ts
->has_precomputed_states
) continue;
3459 guint
*event_count
= g_new(guint
, 1);
3462 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3464 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3465 LttvTracefileContext
*, j
));
3466 lttv_hooks_add(tfs
->parent
.event
,
3467 state_save_event_hook
,
3474 lttv_process_traceset_begin(&self
->parent
,
3475 NULL
, NULL
, NULL
, NULL
, NULL
);
3479 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3481 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3483 lttv_state_save_add_event_hooks(tss
);
3490 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3492 LttvTraceset
*traceset
= self
->parent
.ts
;
3494 guint i
, j
, nb_trace
, nb_tracefile
;
3498 LttvTracefileState
*tfs
;
3500 LttvTraceHook hook_start
, hook_end
;
3502 nb_trace
= lttv_traceset_number(traceset
);
3503 for(i
= 0 ; i
< nb_trace
; i
++) {
3504 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3506 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3507 NULL
, NULL
, block_start
, &hook_start
);
3509 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3510 NULL
, NULL
, block_end
, &hook_end
);
3512 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3514 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3516 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3517 LttvTracefileContext
, j
));
3518 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3519 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3520 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3521 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3527 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3529 LttvTraceset
*traceset
= self
->parent
.ts
;
3531 guint i
, j
, nb_trace
, nb_tracefile
;
3535 LttvTracefileState
*tfs
;
3537 LttvHooks
*after_trace
= lttv_hooks_new();
3539 lttv_hooks_add(after_trace
,
3540 state_save_after_trace_hook
,
3545 lttv_process_traceset_end(&self
->parent
,
3546 NULL
, after_trace
, NULL
, NULL
, NULL
);
3548 lttv_hooks_destroy(after_trace
);
3550 nb_trace
= lttv_traceset_number(traceset
);
3551 for(i
= 0 ; i
< nb_trace
; i
++) {
3553 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3554 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3556 if(ts
->has_precomputed_states
) continue;
3558 guint
*event_count
= NULL
;
3560 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3562 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3563 LttvTracefileContext
*, j
));
3564 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3565 state_save_event_hook
);
3567 if(event_count
) g_free(event_count
);
3571 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3573 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3575 lttv_state_save_remove_event_hooks(tss
);
3580 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3582 LttvTraceset
*traceset
= self
->parent
.ts
;
3586 int min_pos
, mid_pos
, max_pos
;
3588 guint call_rest
= 0;
3590 LttvTraceState
*tcs
;
3592 LttvAttributeValue value
;
3594 LttvAttributeType type
;
3596 LttvAttributeName name
;
3600 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3602 //g_tree_destroy(self->parent.pqueue);
3603 //self->parent.pqueue = g_tree_new(compare_tracefile);
3605 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3607 nb_trace
= lttv_traceset_number(traceset
);
3608 for(i
= 0 ; i
< nb_trace
; i
++) {
3609 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3611 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3612 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3613 LTTV_STATE_SAVED_STATES
);
3616 if(saved_states_tree
) {
3617 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3618 mid_pos
= max_pos
/ 2;
3619 while(min_pos
< max_pos
) {
3620 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3622 g_assert(type
== LTTV_GOBJECT
);
3623 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3624 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3626 g_assert(type
== LTTV_TIME
);
3627 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3629 closest_tree
= saved_state_tree
;
3631 else max_pos
= mid_pos
- 1;
3633 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3637 /* restore the closest earlier saved state */
3639 lttv_state_restore(tcs
, closest_tree
);
3643 /* There is no saved state, yet we want to have it. Restart at T0 */
3645 restore_init_state(tcs
);
3646 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3649 /* We want to seek quickly without restoring/updating the state */
3651 restore_init_state(tcs
);
3652 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3655 if(!call_rest
) g_info("NOT Calling restore");
3660 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3666 traceset_state_finalize (LttvTracesetState
*self
)
3668 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3669 finalize(G_OBJECT(self
));
3674 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3676 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3678 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3679 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3680 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3681 klass
->new_traceset_context
= new_traceset_context
;
3682 klass
->new_trace_context
= new_trace_context
;
3683 klass
->new_tracefile_context
= new_tracefile_context
;
3688 lttv_traceset_state_get_type(void)
3690 static GType type
= 0;
3692 static const GTypeInfo info
= {
3693 sizeof (LttvTracesetStateClass
),
3694 NULL
, /* base_init */
3695 NULL
, /* base_finalize */
3696 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3697 NULL
, /* class_finalize */
3698 NULL
, /* class_data */
3699 sizeof (LttvTracesetState
),
3700 0, /* n_preallocs */
3701 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3702 NULL
/* value handling */
3705 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3713 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3719 trace_state_finalize (LttvTraceState
*self
)
3721 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3722 finalize(G_OBJECT(self
));
3727 trace_state_class_init (LttvTraceStateClass
*klass
)
3729 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3731 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3732 klass
->state_save
= state_save
;
3733 klass
->state_restore
= state_restore
;
3734 klass
->state_saved_free
= state_saved_free
;
3739 lttv_trace_state_get_type(void)
3741 static GType type
= 0;
3743 static const GTypeInfo info
= {
3744 sizeof (LttvTraceStateClass
),
3745 NULL
, /* base_init */
3746 NULL
, /* base_finalize */
3747 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3748 NULL
, /* class_finalize */
3749 NULL
, /* class_data */
3750 sizeof (LttvTraceState
),
3751 0, /* n_preallocs */
3752 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3753 NULL
/* value handling */
3756 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3757 "LttvTraceStateType", &info
, 0);
3764 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3770 tracefile_state_finalize (LttvTracefileState
*self
)
3772 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3773 finalize(G_OBJECT(self
));
3778 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3780 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3782 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3787 lttv_tracefile_state_get_type(void)
3789 static GType type
= 0;
3791 static const GTypeInfo info
= {
3792 sizeof (LttvTracefileStateClass
),
3793 NULL
, /* base_init */
3794 NULL
, /* base_finalize */
3795 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3796 NULL
, /* class_finalize */
3797 NULL
, /* class_data */
3798 sizeof (LttvTracefileState
),
3799 0, /* n_preallocs */
3800 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3801 NULL
/* value handling */
3804 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3805 "LttvTracefileStateType", &info
, 0);
3811 static void module_init()
3813 LTTV_STATE_UNNAMED
= g_quark_from_string("");
3814 LTTV_STATE_UNBRANDED
= g_quark_from_string("");
3815 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3816 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3817 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3818 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3819 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3820 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3821 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3822 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3823 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3824 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3825 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3826 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3827 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3828 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3829 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3830 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3831 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3832 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3833 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3834 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3835 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3836 LTTV_STATE_EVENT
= g_quark_from_string("event");
3837 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3838 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3839 LTTV_STATE_TIME
= g_quark_from_string("time");
3840 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3841 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3842 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3843 g_quark_from_string("trace_state_use_count");
3844 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3845 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3846 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3849 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3850 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3851 LTT_FACILITY_FS
= g_quark_from_string("fs");
3852 LTT_FACILITY_LIST
= g_quark_from_string("list");
3853 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3854 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3857 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3858 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3859 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3860 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3861 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3862 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3863 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("softirq_entry");
3864 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("softirq_exit");
3865 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3866 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3867 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3868 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3869 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3870 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3871 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3872 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3873 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3874 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3875 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3876 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3877 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3878 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3881 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3882 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3883 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3884 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3885 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3886 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3887 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3888 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3889 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3890 LTT_FIELD_PID
= g_quark_from_string("pid");
3891 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3892 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3893 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3894 LTT_FIELD_NAME
= g_quark_from_string("name");
3895 LTT_FIELD_TYPE
= g_quark_from_string("type");
3896 LTT_FIELD_MODE
= g_quark_from_string("mode");
3897 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3898 LTT_FIELD_STATUS
= g_quark_from_string("status");
3899 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3900 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3901 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3902 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3903 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3904 LTT_FIELD_ACTION
= g_quark_from_string("action");
3906 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3907 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3908 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3909 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3910 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3912 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3913 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3914 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3916 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3917 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3918 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3919 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3922 static void module_destroy()
3927 LTTV_MODULE("state", "State computation", \
3928 "Update the system state, possibly saving it at intervals", \
3929 module_init
, module_destroy
)