1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <lttv/lttv.h>
25 #include <lttv/module.h>
26 #include <lttv/state.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
30 #include <ltt/marker-desc.h>
36 * usertrace is there only to be able to update the current CPU of the
37 * usertraces when there is a schedchange. it is a way to link the ProcessState
38 * to the associated usertrace. Link only created upon thread creation.
40 * The cpu id is necessary : it gives us back the current ProcessState when we
41 * are considering data from the usertrace.
44 #define PREALLOCATED_EXECUTION_STACK 10
46 /* Facilities Quarks */
50 LTT_FACILITY_KERNEL_ARCH
,
53 LTT_FACILITY_USER_GENERIC
,
59 LTT_EVENT_SYSCALL_ENTRY
,
60 LTT_EVENT_SYSCALL_EXIT
,
65 LTT_EVENT_SOFT_IRQ_ENTRY
,
66 LTT_EVENT_SOFT_IRQ_EXIT
,
67 LTT_EVENT_SCHED_SCHEDULE
,
68 LTT_EVENT_PROCESS_FORK
,
69 LTT_EVENT_KTHREAD_CREATE
,
70 LTT_EVENT_PROCESS_EXIT
,
71 LTT_EVENT_PROCESS_FREE
,
73 LTT_EVENT_PROCESS_STATE
,
74 LTT_EVENT_STATEDUMP_END
,
75 LTT_EVENT_FUNCTION_ENTRY
,
76 LTT_EVENT_FUNCTION_EXIT
,
77 LTT_EVENT_THREAD_BRAND
,
78 LTT_EVENT_REQUEST_ISSUE
,
79 LTT_EVENT_REQUEST_COMPLETE
,
80 LTT_EVENT_LIST_INTERRUPT
;
88 LTT_FIELD_SOFT_IRQ_ID
,
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
;
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 nb_tracefile
= self
->parent
.tracefiles
->len
;
1520 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1522 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1523 LttvTracefileContext
*, i
));
1524 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1525 g_assert(type
== LTTV_GOBJECT
);
1526 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1528 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1530 g_assert(type
== LTTV_POINTER
);
1531 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1533 g_object_unref(G_OBJECT(tracefiles_tree
));
1537 static void free_saved_state(LttvTraceState
*self
)
1541 LttvAttributeType type
;
1543 LttvAttributeValue value
;
1545 LttvAttributeName name
;
1549 LttvAttribute
*saved_states
;
1551 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1552 LTTV_STATE_SAVED_STATES
);
1554 nb
= lttv_attribute_get_number(saved_states
);
1555 for(i
= 0 ; i
< nb
; i
++) {
1556 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1557 g_assert(type
== LTTV_GOBJECT
);
1558 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1561 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1566 create_max_time(LttvTraceState
*tcs
)
1568 LttvAttributeValue v
;
1570 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1572 g_assert(*(v
.v_pointer
) == NULL
);
1573 *(v
.v_pointer
) = g_new(LttTime
,1);
1574 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1579 get_max_time(LttvTraceState
*tcs
)
1581 LttvAttributeValue v
;
1583 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1585 g_assert(*(v
.v_pointer
) != NULL
);
1586 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1591 free_max_time(LttvTraceState
*tcs
)
1593 LttvAttributeValue v
;
1595 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1597 g_free(*(v
.v_pointer
));
1598 *(v
.v_pointer
) = NULL
;
1602 typedef struct _LttvNameTables
{
1603 // FIXME GQuark *eventtype_names;
1604 GQuark
*syscall_names
;
1610 GQuark
*soft_irq_names
;
1616 create_name_tables(LttvTraceState
*tcs
)
1620 GString
*fe_name
= g_string_new("");
1622 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1624 LttvAttributeValue v
;
1628 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1630 g_assert(*(v
.v_pointer
) == NULL
);
1631 *(v
.v_pointer
) = name_tables
;
1633 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1635 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1636 LTT_EVENT_SYSCALL_ENTRY
,
1637 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1638 NULL
, NULL
, &hooks
)) {
1640 // th = lttv_trace_hook_get_first(&th);
1642 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1643 // nb = ltt_type_element_number(t);
1645 // name_tables->syscall_names = g_new(GQuark, nb);
1646 // name_tables->nb_syscalls = nb;
1648 // for(i = 0 ; i < nb ; i++) {
1649 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1650 // if(!name_tables->syscall_names[i]) {
1651 // GString *string = g_string_new("");
1652 // g_string_printf(string, "syscall %u", i);
1653 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1654 // g_string_free(string, TRUE);
1658 name_tables
->syscall_names
= g_new(GQuark
, 256);
1659 for(i
= 0 ; i
< 256 ; i
++) {
1660 g_string_printf(fe_name
, "syscall %d", i
);
1661 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1664 name_tables
->syscall_names
= NULL
;
1665 name_tables
->nb_syscalls
= 0;
1667 lttv_trace_hook_remove_all(&hooks
);
1669 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1670 LTT_EVENT_TRAP_ENTRY
,
1671 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1672 NULL
, NULL
, &hooks
)) {
1674 // th = lttv_trace_hook_get_first(&th);
1676 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1677 // //nb = ltt_type_element_number(t);
1679 // name_tables->trap_names = g_new(GQuark, nb);
1680 // for(i = 0 ; i < nb ; i++) {
1681 // name_tables->trap_names[i] = g_quark_from_string(
1682 // ltt_enum_string_get(t, i));
1685 name_tables
->nb_traps
= 256;
1686 name_tables
->trap_names
= g_new(GQuark
, 256);
1687 for(i
= 0 ; i
< 256 ; i
++) {
1688 g_string_printf(fe_name
, "trap %d", i
);
1689 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1692 name_tables
->trap_names
= NULL
;
1693 name_tables
->nb_traps
= 0;
1695 lttv_trace_hook_remove_all(&hooks
);
1697 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1698 LTT_EVENT_IRQ_ENTRY
,
1699 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1700 NULL
, NULL
, &hooks
)) {
1703 name_tables->irq_names = g_new(GQuark, nb);
1704 for(i = 0 ; i < nb ; i++) {
1705 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1709 name_tables
->nb_irqs
= 256;
1710 name_tables
->irq_names
= g_new(GQuark
, 256);
1711 for(i
= 0 ; i
< 256 ; i
++) {
1712 g_string_printf(fe_name
, "irq %d", i
);
1713 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1716 name_tables
->nb_irqs
= 0;
1717 name_tables
->irq_names
= NULL
;
1719 lttv_trace_hook_remove_all(&hooks
);
1721 name_tables->soft_irq_names = g_new(GQuark, nb);
1722 for(i = 0 ; i < nb ; i++) {
1723 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1727 name_tables
->nb_softirqs
= 256;
1728 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1729 for(i
= 0 ; i
< 256 ; i
++) {
1730 g_string_printf(fe_name
, "softirq %d", i
);
1731 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1733 g_array_free(hooks
, TRUE
);
1735 g_string_free(fe_name
, TRUE
);
1740 get_name_tables(LttvTraceState
*tcs
)
1742 LttvNameTables
*name_tables
;
1744 LttvAttributeValue v
;
1746 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1748 g_assert(*(v
.v_pointer
) != NULL
);
1749 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1750 //tcs->eventtype_names = name_tables->eventtype_names;
1751 tcs
->syscall_names
= name_tables
->syscall_names
;
1752 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1753 tcs
->trap_names
= name_tables
->trap_names
;
1754 tcs
->nb_traps
= name_tables
->nb_traps
;
1755 tcs
->irq_names
= name_tables
->irq_names
;
1756 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1757 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1758 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1763 free_name_tables(LttvTraceState
*tcs
)
1765 LttvNameTables
*name_tables
;
1767 LttvAttributeValue v
;
1769 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1771 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1772 *(v
.v_pointer
) = NULL
;
1774 // g_free(name_tables->eventtype_names);
1775 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1776 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1777 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1778 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1779 if(name_tables
) g_free(name_tables
);
1782 #ifdef HASH_TABLE_DEBUG
1784 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1786 LttvProcessState
*process
= (LttvProcessState
*)value
;
1788 /* Test for process corruption */
1789 guint stack_len
= process
->execution_stack
->len
;
1792 static void hash_table_check(GHashTable
*table
)
1794 g_hash_table_foreach(table
, test_process
, NULL
);
1800 /* clears the stack and sets the state passed as argument */
1801 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1803 g_array_set_size(cpust
->mode_stack
, 1);
1804 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1807 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1809 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1810 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1813 static void cpu_pop_mode(LttvCPUState
*cpust
)
1815 if(cpust
->mode_stack
->len
<= 1)
1816 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1818 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1821 /* clears the stack and sets the state passed as argument */
1822 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1824 g_array_set_size(bdevst
->mode_stack
, 1);
1825 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1828 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1830 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1831 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1834 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1836 if(bdevst
->mode_stack
->len
<= 1)
1837 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1839 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1842 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1844 g_array_set_size(irqst
->mode_stack
, 1);
1845 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1848 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1850 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1851 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1854 static void irq_pop_mode(LttvIRQState
*irqst
)
1856 if(irqst
->mode_stack
->len
<= 1)
1857 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1859 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1862 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1865 LttvExecutionState
*es
;
1867 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1868 guint cpu
= tfs
->cpu
;
1870 #ifdef HASH_TABLE_DEBUG
1871 hash_table_check(ts
->processes
);
1873 LttvProcessState
*process
= ts
->running_process
[cpu
];
1875 guint depth
= process
->execution_stack
->len
;
1877 process
->execution_stack
=
1878 g_array_set_size(process
->execution_stack
, depth
+ 1);
1881 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1883 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1886 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1887 es
->cum_cpu_time
= ltt_time_zero
;
1888 es
->s
= process
->state
->s
;
1889 process
->state
= es
;
1893 * return 1 when empty, else 0 */
1894 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1895 LttvTracefileState
*tfs
)
1897 guint depth
= process
->execution_stack
->len
;
1903 process
->execution_stack
=
1904 g_array_set_size(process
->execution_stack
, depth
- 1);
1905 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1907 process
->state
->change
= tfs
->parent
.timestamp
;
1912 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1914 guint cpu
= tfs
->cpu
;
1915 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1916 LttvProcessState
*process
= ts
->running_process
[cpu
];
1918 guint depth
= process
->execution_stack
->len
;
1920 if(process
->state
->t
!= t
){
1921 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1922 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1923 g_info("process state has %s when pop_int is %s\n",
1924 g_quark_to_string(process
->state
->t
),
1925 g_quark_to_string(t
));
1926 g_info("{ %u, %u, %s, %s, %s }\n",
1929 g_quark_to_string(process
->name
),
1930 g_quark_to_string(process
->brand
),
1931 g_quark_to_string(process
->state
->s
));
1936 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1937 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1941 process
->execution_stack
=
1942 g_array_set_size(process
->execution_stack
, depth
- 1);
1943 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1945 process
->state
->change
= tfs
->parent
.timestamp
;
1948 struct search_result
{
1949 const LttTime
*time
; /* Requested time */
1950 LttTime
*best
; /* Best result */
1953 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1955 const LttTime
*elem_time
= (const LttTime
*)a
;
1956 /* Explicit non const cast */
1957 struct search_result
*res
= (struct search_result
*)b
;
1959 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1960 /* The usertrace was created before the schedchange */
1961 /* Get larger keys */
1963 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1964 /* The usertrace was created after the schedchange time */
1965 /* Get smaller keys */
1967 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1968 res
->best
= (LttTime
*)elem_time
;
1971 res
->best
= (LttTime
*)elem_time
;
1978 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1979 guint pid
, const LttTime
*timestamp
)
1981 LttvTracefileState
*tfs
= NULL
;
1982 struct search_result res
;
1983 /* Find the usertrace associated with a pid and time interval.
1984 * Search in the usertraces by PID (within a hash) and then, for each
1985 * corresponding element of the array, find the first one with creation
1986 * timestamp the lowest, but higher or equal to "timestamp". */
1987 res
.time
= timestamp
;
1989 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1990 if(usertrace_tree
) {
1991 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1993 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2001 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2002 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2004 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2006 LttvExecutionState
*es
;
2011 process
->tgid
= tgid
;
2013 process
->name
= name
;
2014 process
->brand
= LTTV_STATE_UNBRANDED
;
2015 //process->last_cpu = tfs->cpu_name;
2016 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2017 process
->type
= LTTV_STATE_USER_THREAD
;
2018 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2019 process
->current_function
= 0; //function 0x0 by default.
2021 g_info("Process %u, core %p", process
->pid
, process
);
2022 g_hash_table_insert(tcs
->processes
, process
, process
);
2025 process
->ppid
= parent
->pid
;
2026 process
->creation_time
= *timestamp
;
2029 /* No parent. This process exists but we are missing all information about
2030 its creation. The birth time is set to zero but we remember the time of
2035 process
->creation_time
= ltt_time_zero
;
2038 process
->insertion_time
= *timestamp
;
2039 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2040 process
->creation_time
.tv_nsec
);
2041 process
->pid_time
= g_quark_from_string(buffer
);
2043 //process->last_cpu = tfs->cpu_name;
2044 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2045 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2046 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2047 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2048 es
= process
->state
= &g_array_index(process
->execution_stack
,
2049 LttvExecutionState
, 0);
2050 es
->t
= LTTV_STATE_USER_MODE
;
2051 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2052 es
->entry
= *timestamp
;
2053 //g_assert(timestamp->tv_sec != 0);
2054 es
->change
= *timestamp
;
2055 es
->cum_cpu_time
= ltt_time_zero
;
2056 es
->s
= LTTV_STATE_RUN
;
2058 es
= process
->state
= &g_array_index(process
->execution_stack
,
2059 LttvExecutionState
, 1);
2060 es
->t
= LTTV_STATE_SYSCALL
;
2061 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2062 es
->entry
= *timestamp
;
2063 //g_assert(timestamp->tv_sec != 0);
2064 es
->change
= *timestamp
;
2065 es
->cum_cpu_time
= ltt_time_zero
;
2066 es
->s
= LTTV_STATE_WAIT_FORK
;
2068 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2069 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2070 sizeof(guint64
), 0);
2075 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2078 LttvProcessState key
;
2079 LttvProcessState
*process
;
2083 process
= g_hash_table_lookup(ts
->processes
, &key
);
2088 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2089 const LttTime
*timestamp
)
2091 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2092 LttvExecutionState
*es
;
2094 /* Put ltt_time_zero creation time for unexisting processes */
2095 if(unlikely(process
== NULL
)) {
2096 process
= lttv_state_create_process(ts
,
2097 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2098 /* We are not sure is it's a kernel thread or normal thread, put the
2099 * bottom stack state to unknown */
2100 process
->execution_stack
=
2101 g_array_set_size(process
->execution_stack
, 1);
2102 process
->state
= es
=
2103 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2104 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2105 es
->s
= LTTV_STATE_UNNAMED
;
2110 /* FIXME : this function should be called when we receive an event telling that
2111 * release_task has been called in the kernel. In happens generally when
2112 * the parent waits for its child terminaison, but may also happen in special
2113 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2114 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2115 * of a killed thread ground, but isn't the leader.
2117 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2119 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2120 LttvProcessState key
;
2122 key
.pid
= process
->pid
;
2123 key
.cpu
= process
->cpu
;
2124 g_hash_table_remove(ts
->processes
, &key
);
2125 g_array_free(process
->execution_stack
, TRUE
);
2126 g_array_free(process
->user_stack
, TRUE
);
2131 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2133 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2134 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2139 static void lttv_state_free_process_table(GHashTable
*processes
)
2141 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2142 g_hash_table_destroy(processes
);
2146 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2148 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2150 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2151 LttvProcessState
*process
= ts
->running_process
[cpu
];
2152 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2153 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2154 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2156 LttvExecutionSubmode submode
;
2158 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2159 guint syscall
= ltt_event_get_unsigned(e
, f
);
2161 if(syscall
< nb_syscalls
) {
2162 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2165 /* Fixup an incomplete syscall table */
2166 GString
*string
= g_string_new("");
2167 g_string_printf(string
, "syscall %u", syscall
);
2168 submode
= g_quark_from_string(string
->str
);
2169 g_string_free(string
, TRUE
);
2171 /* There can be no system call from PID 0 : unknown state */
2172 if(process
->pid
!= 0)
2173 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2178 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2180 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2182 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2183 LttvProcessState
*process
= ts
->running_process
[cpu
];
2185 /* There can be no system call from PID 0 : unknown state */
2186 if(process
->pid
!= 0)
2187 pop_state(s
, LTTV_STATE_SYSCALL
);
2192 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2194 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2195 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2196 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2197 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2199 LttvExecutionSubmode submode
;
2201 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2202 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2204 if(trap
< nb_traps
) {
2205 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2207 /* Fixup an incomplete trap table */
2208 GString
*string
= g_string_new("");
2209 g_string_printf(string
, "trap %llu", trap
);
2210 submode
= g_quark_from_string(string
->str
);
2211 g_string_free(string
, TRUE
);
2214 push_state(s
, LTTV_STATE_TRAP
, submode
);
2216 /* update cpu status */
2217 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2222 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2224 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2226 pop_state(s
, LTTV_STATE_TRAP
);
2228 /* update cpu status */
2229 cpu_pop_mode(s
->cpu_state
);
2234 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2236 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2237 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2238 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2239 //guint8 ev_id = ltt_event_eventtype_id(e);
2240 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2241 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2243 LttvExecutionSubmode submode
;
2244 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2245 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2248 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2250 /* Fixup an incomplete irq table */
2251 GString
*string
= g_string_new("");
2252 g_string_printf(string
, "irq %llu", irq
);
2253 submode
= g_quark_from_string(string
->str
);
2254 g_string_free(string
, TRUE
);
2257 /* Do something with the info about being in user or system mode when int? */
2258 push_state(s
, LTTV_STATE_IRQ
, submode
);
2260 /* update cpu status */
2261 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2263 /* update irq status */
2264 s
->cpu_state
->last_irq
= irq
;
2265 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2270 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2272 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2274 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2280 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2282 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2283 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2285 pop_state(s
, LTTV_STATE_IRQ
);
2287 /* update cpu status */
2288 cpu_pop_mode(s
->cpu_state
);
2290 /* update irq status */
2291 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2296 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2298 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2299 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2300 //guint8 ev_id = ltt_event_eventtype_id(e);
2301 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2302 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2304 LttvExecutionSubmode submode
;
2305 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2306 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2308 if(softirq
< nb_softirqs
) {
2309 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2311 /* Fixup an incomplete irq table */
2312 GString
*string
= g_string_new("");
2313 g_string_printf(string
, "softirq %llu", softirq
);
2314 submode
= g_quark_from_string(string
->str
);
2315 g_string_free(string
, TRUE
);
2318 /* Do something with the info about being in user or system mode when int? */
2319 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2323 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2325 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2326 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2327 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2328 //guint8 ev_id = ltt_event_eventtype_id(e);
2329 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2331 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2332 lttv_trace_get_hook_field(th
, 0)));
2333 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2335 ts
->irq_names
[irq
] = action
;
2341 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2343 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2344 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2345 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2346 //guint8 ev_id = ltt_event_eventtype_id(e);
2347 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2349 guint major
= ltt_event_get_long_unsigned(e
,
2350 lttv_trace_get_hook_field(th
, 0));
2351 guint minor
= ltt_event_get_long_unsigned(e
,
2352 lttv_trace_get_hook_field(th
, 1));
2353 guint oper
= ltt_event_get_long_unsigned(e
,
2354 lttv_trace_get_hook_field(th
, 2));
2355 guint16 devcode
= MKDEV(major
,minor
);
2357 /* have we seen this block device before? */
2358 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2361 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2363 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2368 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2370 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2371 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2372 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2373 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2375 guint major
= ltt_event_get_long_unsigned(e
,
2376 lttv_trace_get_hook_field(th
, 0));
2377 guint minor
= ltt_event_get_long_unsigned(e
,
2378 lttv_trace_get_hook_field(th
, 1));
2379 //guint oper = ltt_event_get_long_unsigned(e,
2380 // lttv_trace_get_hook_field(th, 2));
2381 guint16 devcode
= MKDEV(major
,minor
);
2383 /* have we seen this block device before? */
2384 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2386 /* update block device */
2387 bdev_pop_mode(bdev
);
2392 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2396 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2397 guint cpu
= tfs
->cpu
;
2398 LttvProcessState
*process
= ts
->running_process
[cpu
];
2400 guint depth
= process
->user_stack
->len
;
2402 process
->user_stack
=
2403 g_array_set_size(process
->user_stack
, depth
+ 1);
2405 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2406 *new_func
= funcptr
;
2407 process
->current_function
= funcptr
;
2410 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2412 guint cpu
= tfs
->cpu
;
2413 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2414 LttvProcessState
*process
= ts
->running_process
[cpu
];
2416 if(process
->current_function
!= funcptr
){
2417 g_info("Different functions (%lu.%09lu): ignore it\n",
2418 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2419 g_info("process state has %llu when pop_function is %llu\n",
2420 process
->current_function
, funcptr
);
2421 g_info("{ %u, %u, %s, %s, %s }\n",
2424 g_quark_to_string(process
->name
),
2425 g_quark_to_string(process
->brand
),
2426 g_quark_to_string(process
->state
->s
));
2429 guint depth
= process
->user_stack
->len
;
2432 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2433 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2437 process
->user_stack
=
2438 g_array_set_size(process
->user_stack
, depth
- 1);
2439 process
->current_function
=
2440 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2444 static gboolean
function_entry(void *hook_data
, void *call_data
)
2446 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2447 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2448 //guint8 ev_id = ltt_event_eventtype_id(e);
2449 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2450 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2451 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2453 push_function(s
, funcptr
);
2457 static gboolean
function_exit(void *hook_data
, void *call_data
)
2459 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2460 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2461 //guint8 ev_id = ltt_event_eventtype_id(e);
2462 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2463 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2464 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2466 pop_function(s
, funcptr
);
2470 static gboolean
schedchange(void *hook_data
, void *call_data
)
2472 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2474 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2475 LttvProcessState
*process
= ts
->running_process
[cpu
];
2476 //LttvProcessState *old_process = ts->running_process[cpu];
2478 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2479 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2480 guint pid_in
, pid_out
;
2483 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2484 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2485 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2487 if(likely(process
!= NULL
)) {
2489 /* We could not know but it was not the idle process executing.
2490 This should only happen at the beginning, before the first schedule
2491 event, and when the initial information (current process for each CPU)
2492 is missing. It is not obvious how we could, after the fact, compensate
2493 the wrongly attributed statistics. */
2495 //This test only makes sense once the state is known and if there is no
2496 //missing events. We need to silently ignore schedchange coming after a
2497 //process_free, or it causes glitches. (FIXME)
2498 //if(unlikely(process->pid != pid_out)) {
2499 // g_assert(process->pid == 0);
2501 if(process
->pid
== 0
2502 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2504 /* Scheduling out of pid 0 at beginning of the trace :
2505 * we know for sure it is in syscall mode at this point. */
2506 g_assert(process
->execution_stack
->len
== 1);
2507 process
->state
->t
= LTTV_STATE_SYSCALL
;
2508 process
->state
->s
= LTTV_STATE_WAIT
;
2509 process
->state
->change
= s
->parent
.timestamp
;
2510 process
->state
->entry
= s
->parent
.timestamp
;
2513 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2514 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2515 process
->state
->change
= s
->parent
.timestamp
;
2517 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2518 else process
->state
->s
= LTTV_STATE_WAIT
;
2519 process
->state
->change
= s
->parent
.timestamp
;
2522 if(state_out
== 32 || state_out
== 128)
2523 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2524 /* see sched.h for states */
2527 process
= ts
->running_process
[cpu
] =
2528 lttv_state_find_process_or_create(
2529 (LttvTraceState
*)s
->parent
.t_context
,
2531 &s
->parent
.timestamp
);
2532 process
->state
->s
= LTTV_STATE_RUN
;
2534 if(process
->usertrace
)
2535 process
->usertrace
->cpu
= cpu
;
2536 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2537 process
->state
->change
= s
->parent
.timestamp
;
2539 /* update cpu status */
2541 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2543 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2548 static gboolean
process_fork(void *hook_data
, void *call_data
)
2550 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2551 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2552 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2554 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2555 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2556 //LttvProcessState *zombie_process;
2558 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2559 LttvProcessState
*process
= ts
->running_process
[cpu
];
2560 LttvProcessState
*child_process
;
2561 struct marker_field
*f
;
2564 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2567 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2568 s
->parent
.target_pid
= child_pid
;
2571 f
= lttv_trace_get_hook_field(th
, 2);
2573 child_tgid
= ltt_event_get_unsigned(e
, f
);
2577 /* Mathieu : it seems like the process might have been scheduled in before the
2578 * fork, and, in a rare case, might be the current process. This might happen
2579 * in a SMP case where we don't have enough precision on the clocks.
2581 * Test reenabled after precision fixes on time. (Mathieu) */
2583 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2585 if(unlikely(zombie_process
!= NULL
)) {
2586 /* Reutilisation of PID. Only now we are sure that the old PID
2587 * has been released. FIXME : should know when release_task happens instead.
2589 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2591 for(i
=0; i
< num_cpus
; i
++) {
2592 g_assert(zombie_process
!= ts
->running_process
[i
]);
2595 exit_process(s
, zombie_process
);
2598 g_assert(process
->pid
!= child_pid
);
2599 // FIXME : Add this test in the "known state" section
2600 // g_assert(process->pid == parent_pid);
2601 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2602 if(child_process
== NULL
) {
2603 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2604 child_pid
, child_tgid
,
2605 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2607 /* The process has already been created : due to time imprecision between
2608 * multiple CPUs : it has been scheduled in before creation. Note that we
2609 * shouldn't have this kind of imprecision.
2611 * Simply put a correct parent.
2613 g_assert(0); /* This is a problematic case : the process has been created
2614 before the fork event */
2615 child_process
->ppid
= process
->pid
;
2616 child_process
->tgid
= child_tgid
;
2618 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2619 child_process
->name
= process
->name
;
2620 child_process
->brand
= process
->brand
;
2625 /* We stamp a newly created process as kernel_thread.
2626 * The thread should not be running yet. */
2627 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2629 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2630 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2631 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2633 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2634 LttvProcessState
*process
;
2635 LttvExecutionState
*es
;
2638 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2639 s
->parent
.target_pid
= pid
;
2641 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2643 process
->execution_stack
=
2644 g_array_set_size(process
->execution_stack
, 1);
2645 es
= process
->state
=
2646 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2647 es
->t
= LTTV_STATE_SYSCALL
;
2648 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2653 static gboolean
process_exit(void *hook_data
, void *call_data
)
2655 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2656 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2657 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2659 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2660 LttvProcessState
*process
; // = ts->running_process[cpu];
2662 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2663 s
->parent
.target_pid
= pid
;
2665 // FIXME : Add this test in the "known state" section
2666 // g_assert(process->pid == pid);
2668 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2669 if(likely(process
!= NULL
)) {
2670 process
->state
->s
= LTTV_STATE_EXIT
;
2675 static gboolean
process_free(void *hook_data
, void *call_data
)
2677 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2678 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2679 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2680 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2682 LttvProcessState
*process
;
2684 /* PID of the process to release */
2685 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2686 s
->parent
.target_pid
= release_pid
;
2688 g_assert(release_pid
!= 0);
2690 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2692 if(likely(process
!= NULL
)) {
2693 /* release_task is happening at kernel level : we can now safely release
2694 * the data structure of the process */
2695 //This test is fun, though, as it may happen that
2696 //at time t : CPU 0 : process_free
2697 //at time t+150ns : CPU 1 : schedule out
2698 //Clearly due to time imprecision, we disable it. (Mathieu)
2699 //If this weird case happen, we have no choice but to put the
2700 //Currently running process on the cpu to 0.
2701 //I re-enable it following time precision fixes. (Mathieu)
2702 //Well, in the case where an process is freed by a process on another CPU
2703 //and still scheduled, it happens that this is the schedchange that will
2704 //drop the last reference count. Do not free it here!
2705 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2707 for(i
=0; i
< num_cpus
; i
++) {
2708 //g_assert(process != ts->running_process[i]);
2709 if(process
== ts
->running_process
[i
]) {
2710 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2714 if(i
== num_cpus
) /* process is not scheduled */
2715 exit_process(s
, process
);
2722 static gboolean
process_exec(void *hook_data
, void *call_data
)
2724 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2725 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2726 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2727 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2730 LttvProcessState
*process
= ts
->running_process
[cpu
];
2732 #if 0//how to use a sequence that must be transformed in a string
2733 /* PID of the process to release */
2734 guint64 name_len
= ltt_event_field_element_number(e
,
2735 lttv_trace_get_hook_field(th
, 0));
2736 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2737 LttField
*child
= ltt_event_field_element_select(e
,
2738 lttv_trace_get_hook_field(th
, 0), 0);
2740 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2741 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2742 memcpy(null_term_name
, name_begin
, name_len
);
2743 null_term_name
[name_len
] = '\0';
2744 process
->name
= g_quark_from_string(null_term_name
);
2747 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2748 lttv_trace_get_hook_field(th
, 0)));
2749 process
->brand
= LTTV_STATE_UNBRANDED
;
2750 //g_free(null_term_name);
2754 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2756 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2757 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2758 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2759 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2762 LttvProcessState
*process
= ts
->running_process
[cpu
];
2764 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2765 process
->brand
= g_quark_from_string(name
);
2770 static void fix_process(gpointer key
, gpointer value
,
2773 LttvProcessState
*process
;
2774 LttvExecutionState
*es
;
2775 process
= (LttvProcessState
*)value
;
2776 LttTime
*timestamp
= (LttTime
*)user_data
;
2778 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2779 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2780 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2781 es
->t
= LTTV_STATE_SYSCALL
;
2782 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2783 es
->entry
= *timestamp
;
2784 es
->change
= *timestamp
;
2785 es
->cum_cpu_time
= ltt_time_zero
;
2786 if(es
->s
== LTTV_STATE_UNNAMED
)
2787 es
->s
= LTTV_STATE_WAIT
;
2790 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2791 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2792 es
->t
= LTTV_STATE_USER_MODE
;
2793 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2794 es
->entry
= *timestamp
;
2795 //g_assert(timestamp->tv_sec != 0);
2796 es
->change
= *timestamp
;
2797 es
->cum_cpu_time
= ltt_time_zero
;
2798 if(es
->s
== LTTV_STATE_UNNAMED
)
2799 es
->s
= LTTV_STATE_RUN
;
2801 if(process
->execution_stack
->len
== 1) {
2802 /* Still in bottom unknown mode, means never did a system call
2803 * May be either in user mode, syscall mode, running or waiting.*/
2804 /* FIXME : we may be tagging syscall mode when being user mode */
2805 process
->execution_stack
=
2806 g_array_set_size(process
->execution_stack
, 2);
2807 es
= process
->state
= &g_array_index(process
->execution_stack
,
2808 LttvExecutionState
, 1);
2809 es
->t
= LTTV_STATE_SYSCALL
;
2810 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2811 es
->entry
= *timestamp
;
2812 //g_assert(timestamp->tv_sec != 0);
2813 es
->change
= *timestamp
;
2814 es
->cum_cpu_time
= ltt_time_zero
;
2815 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2816 es
->s
= LTTV_STATE_WAIT
;
2822 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2824 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2825 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2826 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2827 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2828 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2830 /* For all processes */
2831 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2832 /* else, if stack[0] is unknown, set to user mode, running */
2834 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2839 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2841 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2842 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2843 //It's slow : optimise later by doing this before reading trace.
2844 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2850 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2851 LttvProcessState
*process
= ts
->running_process
[cpu
];
2852 LttvProcessState
*parent_process
;
2853 struct marker_field
*f
;
2854 GQuark type
, mode
, submode
, status
;
2855 LttvExecutionState
*es
;
2859 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2860 s
->parent
.target_pid
= pid
;
2863 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2866 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2869 f
= lttv_trace_get_hook_field(th
, 3);
2870 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2873 f
= lttv_trace_get_hook_field(th
, 4);
2874 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2877 f
= lttv_trace_get_hook_field(th
, 5);
2878 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2881 f
= lttv_trace_get_hook_field(th
, 6);
2882 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2885 f
= lttv_trace_get_hook_field(th
, 7);
2887 tgid
= ltt_event_get_unsigned(e
, f
);
2892 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2893 for(i
=0; i
<nb_cpus
; i
++) {
2894 process
= lttv_state_find_process(ts
, i
, pid
);
2895 g_assert(process
!= NULL
);
2897 process
->ppid
= parent_pid
;
2898 process
->tgid
= tgid
;
2899 process
->name
= g_quark_from_string(command
);
2901 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2902 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2906 /* The process might exist if a process was forked while performing the
2908 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2909 if(process
== NULL
) {
2910 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2911 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2912 pid
, tgid
, g_quark_from_string(command
),
2913 &s
->parent
.timestamp
);
2915 /* Keep the stack bottom : a running user mode */
2916 /* Disabled because of inconsistencies in the current statedump states. */
2917 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2918 /* Only keep the bottom
2919 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2920 /* Will cause expected trap when in fact being syscall (even after end of
2922 * Will cause expected interrupt when being syscall. (only before end of
2923 * statedump event) */
2924 // This will cause a "popping last state on stack, ignoring it."
2925 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2926 es
= process
->state
= &g_array_index(process
->execution_stack
,
2927 LttvExecutionState
, 0);
2928 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2929 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2930 es
->s
= LTTV_STATE_UNNAMED
;
2931 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2933 es
->t
= LTTV_STATE_SYSCALL
;
2938 /* User space process :
2939 * bottom : user mode
2940 * either currently running or scheduled out.
2941 * can be scheduled out because interrupted in (user mode or in syscall)
2942 * or because of an explicit call to the scheduler in syscall. Note that
2943 * the scheduler call comes after the irq_exit, so never in interrupt
2945 // temp workaround : set size to 1 : only have user mode bottom of stack.
2946 // will cause g_info message of expected syscall mode when in fact being
2947 // in user mode. Can also cause expected trap when in fact being user
2948 // mode in the event of a page fault reenabling interrupts in the handler.
2949 // Expected syscall and trap can also happen after the end of statedump
2950 // This will cause a "popping last state on stack, ignoring it."
2951 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2952 es
= process
->state
= &g_array_index(process
->execution_stack
,
2953 LttvExecutionState
, 0);
2954 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2955 es
->s
= LTTV_STATE_UNNAMED
;
2956 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2958 es
->t
= LTTV_STATE_USER_MODE
;
2966 es
= process
->state
= &g_array_index(process
->execution_stack
,
2967 LttvExecutionState
, 1);
2968 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2969 es
->s
= LTTV_STATE_UNNAMED
;
2970 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2974 /* The process has already been created :
2975 * Probably was forked while dumping the process state or
2976 * was simply scheduled in prior to get the state dump event.
2978 process
->ppid
= parent_pid
;
2979 process
->tgid
= tgid
;
2980 process
->name
= g_quark_from_string(command
);
2981 process
->type
= type
;
2983 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2985 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2986 if(type
== LTTV_STATE_KERNEL_THREAD
)
2987 es
->t
= LTTV_STATE_SYSCALL
;
2989 es
->t
= LTTV_STATE_USER_MODE
;
2992 /* Don't mess around with the stack, it will eventually become
2993 * ok after the end of state dump. */
3000 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3002 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3004 lttv_state_add_event_hooks(tss
);
3009 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3011 LttvTraceset
*traceset
= self
->parent
.ts
;
3013 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3017 LttvTracefileState
*tfs
;
3023 LttvAttributeValue val
;
3025 nb_trace
= lttv_traceset_number(traceset
);
3026 for(i
= 0 ; i
< nb_trace
; i
++) {
3027 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3029 /* Find the eventtype id for the following events and register the
3030 associated by id hooks. */
3032 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3033 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3036 lttv_trace_find_hook(ts
->parent
.t
,
3037 LTT_EVENT_SYSCALL_ENTRY
,
3038 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3039 syscall_entry
, NULL
, &hooks
);
3041 lttv_trace_find_hook(ts
->parent
.t
,
3042 LTT_EVENT_SYSCALL_EXIT
,
3044 syscall_exit
, NULL
, &hooks
);
3046 lttv_trace_find_hook(ts
->parent
.t
,
3047 LTT_EVENT_TRAP_ENTRY
,
3048 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3049 trap_entry
, NULL
, &hooks
);
3051 lttv_trace_find_hook(ts
->parent
.t
,
3052 LTT_EVENT_TRAP_EXIT
,
3054 trap_exit
, NULL
, &hooks
);
3056 lttv_trace_find_hook(ts
->parent
.t
,
3057 LTT_EVENT_IRQ_ENTRY
,
3058 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3059 irq_entry
, NULL
, &hooks
);
3061 lttv_trace_find_hook(ts
->parent
.t
,
3064 irq_exit
, NULL
, &hooks
);
3066 lttv_trace_find_hook(ts
->parent
.t
,
3067 LTT_EVENT_SOFT_IRQ_ENTRY
,
3068 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3069 soft_irq_entry
, NULL
, &hooks
);
3071 lttv_trace_find_hook(ts
->parent
.t
,
3072 LTT_EVENT_SOFT_IRQ_EXIT
,
3074 soft_irq_exit
, NULL
, &hooks
);
3076 lttv_trace_find_hook(ts
->parent
.t
,
3077 LTT_EVENT_SCHED_SCHEDULE
,
3078 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3079 LTT_FIELD_PREV_STATE
),
3080 schedchange
, NULL
, &hooks
);
3082 lttv_trace_find_hook(ts
->parent
.t
,
3083 LTT_EVENT_PROCESS_FORK
,
3084 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3085 LTT_FIELD_CHILD_TGID
),
3086 process_fork
, NULL
, &hooks
);
3088 lttv_trace_find_hook(ts
->parent
.t
,
3089 LTT_EVENT_KTHREAD_CREATE
,
3090 FIELD_ARRAY(LTT_FIELD_PID
),
3091 process_kernel_thread
, NULL
, &hooks
);
3093 lttv_trace_find_hook(ts
->parent
.t
,
3094 LTT_EVENT_PROCESS_EXIT
,
3095 FIELD_ARRAY(LTT_FIELD_PID
),
3096 process_exit
, NULL
, &hooks
);
3098 lttv_trace_find_hook(ts
->parent
.t
,
3099 LTT_EVENT_PROCESS_FREE
,
3100 FIELD_ARRAY(LTT_FIELD_PID
),
3101 process_free
, NULL
, &hooks
);
3103 lttv_trace_find_hook(ts
->parent
.t
,
3105 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3106 process_exec
, NULL
, &hooks
);
3108 lttv_trace_find_hook(ts
->parent
.t
,
3109 LTT_EVENT_THREAD_BRAND
,
3110 FIELD_ARRAY(LTT_FIELD_NAME
),
3111 thread_brand
, NULL
, &hooks
);
3113 /* statedump-related hooks */
3114 lttv_trace_find_hook(ts
->parent
.t
,
3115 LTT_EVENT_PROCESS_STATE
,
3116 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3117 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3118 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3119 enum_process_state
, NULL
, &hooks
);
3121 lttv_trace_find_hook(ts
->parent
.t
,
3122 LTT_EVENT_STATEDUMP_END
,
3124 statedump_end
, NULL
, &hooks
);
3126 lttv_trace_find_hook(ts
->parent
.t
,
3127 LTT_EVENT_LIST_INTERRUPT
,
3128 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_NUM
),
3129 enum_interrupt
, NULL
, &hooks
);
3131 lttv_trace_find_hook(ts
->parent
.t
,
3132 LTT_EVENT_REQUEST_ISSUE
,
3133 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3134 bdev_request_issue
, NULL
, &hooks
);
3136 lttv_trace_find_hook(ts
->parent
.t
,
3137 LTT_EVENT_REQUEST_COMPLETE
,
3138 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3139 bdev_request_complete
, NULL
, &hooks
);
3141 lttv_trace_find_hook(ts
->parent
.t
,
3142 LTT_EVENT_FUNCTION_ENTRY
,
3143 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3144 function_entry
, NULL
, &hooks
);
3146 lttv_trace_find_hook(ts
->parent
.t
,
3147 LTT_EVENT_FUNCTION_EXIT
,
3148 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3149 function_exit
, NULL
, &hooks
);
3151 /* Add these hooks to each event_by_id hooks list */
3153 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3155 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3157 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3158 LttvTracefileContext
*, j
));
3160 for(k
= 0 ; k
< hooks
->len
; k
++) {
3161 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3163 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3169 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3170 *(val
.v_pointer
) = hooks
;
3174 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3176 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3178 lttv_state_remove_event_hooks(tss
);
3183 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3185 LttvTraceset
*traceset
= self
->parent
.ts
;
3187 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3191 LttvTracefileState
*tfs
;
3197 LttvAttributeValue val
;
3199 nb_trace
= lttv_traceset_number(traceset
);
3200 for(i
= 0 ; i
< nb_trace
; i
++) {
3201 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3203 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3204 hooks
= *(val
.v_pointer
);
3206 /* Remove these hooks from each event_by_id hooks list */
3208 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3210 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3212 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3213 LttvTracefileContext
*, j
));
3215 for(k
= 0 ; k
< hooks
->len
; k
++) {
3216 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3217 lttv_hooks_remove_data(
3218 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3223 lttv_trace_hook_remove_all(&hooks
);
3224 g_array_free(hooks
, TRUE
);
3228 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3230 guint
*event_count
= (guint
*)hook_data
;
3232 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3233 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3238 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3240 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3242 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3244 LttvAttributeValue value
;
3246 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3247 LTTV_STATE_SAVED_STATES
);
3248 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3249 value
= lttv_attribute_add(saved_states_tree
,
3250 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3251 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3252 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3253 *(value
.v_time
) = self
->parent
.timestamp
;
3254 lttv_state_save(tcs
, saved_state_tree
);
3255 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3256 self
->parent
.timestamp
.tv_nsec
);
3258 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3263 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3265 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3267 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3272 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3280 static gboolean
block_start(void *hook_data
, void *call_data
)
3282 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3284 LttvTracefileState
*tfcs
;
3286 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3288 LttEventPosition
*ep
;
3290 guint i
, nb_block
, nb_event
, nb_tracefile
;
3294 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3296 LttvAttributeValue value
;
3298 ep
= ltt_event_position_new();
3300 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3302 /* Count the number of events added since the last block end in any
3305 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3307 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3308 LttvTracefileContext
, i
));
3309 ltt_event_position(tfcs
->parent
.e
, ep
);
3310 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3311 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3312 tfcs
->saved_position
= nb_event
;
3316 if(tcs
->nb_event
>= tcs
->save_interval
) {
3317 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3318 LTTV_STATE_SAVED_STATES
);
3319 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3320 value
= lttv_attribute_add(saved_states_tree
,
3321 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3322 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3323 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3324 *(value
.v_time
) = self
->parent
.timestamp
;
3325 lttv_state_save(tcs
, saved_state_tree
);
3327 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3328 self
->parent
.timestamp
.tv_nsec
);
3330 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3336 static gboolean
block_end(void *hook_data
, void *call_data
)
3338 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3340 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3344 LttEventPosition
*ep
;
3346 guint nb_block
, nb_event
;
3348 ep
= ltt_event_position_new();
3349 ltt_event_position(self
->parent
.e
, ep
);
3350 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3351 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3352 self
->saved_position
= 0;
3353 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3360 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3362 LttvTraceset
*traceset
= self
->parent
.ts
;
3364 guint i
, j
, nb_trace
, nb_tracefile
;
3368 LttvTracefileState
*tfs
;
3370 LttvTraceHook hook_start
, hook_end
;
3372 nb_trace
= lttv_traceset_number(traceset
);
3373 for(i
= 0 ; i
< nb_trace
; i
++) {
3374 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3376 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3377 NULL
, NULL
, block_start
, &hook_start
);
3378 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3379 NULL
, NULL
, block_end
, &hook_end
);
3381 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3383 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3385 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3386 LttvTracefileContext
, j
));
3387 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3388 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3389 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3390 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3396 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3398 LttvTraceset
*traceset
= self
->parent
.ts
;
3400 guint i
, j
, nb_trace
, nb_tracefile
;
3404 LttvTracefileState
*tfs
;
3407 nb_trace
= lttv_traceset_number(traceset
);
3408 for(i
= 0 ; i
< nb_trace
; i
++) {
3410 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3411 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3413 if(ts
->has_precomputed_states
) continue;
3415 guint
*event_count
= g_new(guint
, 1);
3418 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3420 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3421 LttvTracefileContext
*, j
));
3422 lttv_hooks_add(tfs
->parent
.event
,
3423 state_save_event_hook
,
3430 lttv_process_traceset_begin(&self
->parent
,
3431 NULL
, NULL
, NULL
, NULL
, NULL
);
3435 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3437 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3439 lttv_state_save_add_event_hooks(tss
);
3446 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3448 LttvTraceset
*traceset
= self
->parent
.ts
;
3450 guint i
, j
, nb_trace
, nb_tracefile
;
3454 LttvTracefileState
*tfs
;
3456 LttvTraceHook hook_start
, hook_end
;
3458 nb_trace
= lttv_traceset_number(traceset
);
3459 for(i
= 0 ; i
< nb_trace
; i
++) {
3460 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3462 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3463 NULL
, NULL
, block_start
, &hook_start
);
3465 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3466 NULL
, NULL
, block_end
, &hook_end
);
3468 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3470 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3472 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3473 LttvTracefileContext
, j
));
3474 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3475 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3476 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3477 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3483 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3485 LttvTraceset
*traceset
= self
->parent
.ts
;
3487 guint i
, j
, nb_trace
, nb_tracefile
;
3491 LttvTracefileState
*tfs
;
3493 LttvHooks
*after_trace
= lttv_hooks_new();
3495 lttv_hooks_add(after_trace
,
3496 state_save_after_trace_hook
,
3501 lttv_process_traceset_end(&self
->parent
,
3502 NULL
, after_trace
, NULL
, NULL
, NULL
);
3504 lttv_hooks_destroy(after_trace
);
3506 nb_trace
= lttv_traceset_number(traceset
);
3507 for(i
= 0 ; i
< nb_trace
; i
++) {
3509 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3510 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3512 if(ts
->has_precomputed_states
) continue;
3514 guint
*event_count
= NULL
;
3516 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3518 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3519 LttvTracefileContext
*, j
));
3520 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3521 state_save_event_hook
);
3523 if(event_count
) g_free(event_count
);
3527 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3529 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3531 lttv_state_save_remove_event_hooks(tss
);
3536 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3538 LttvTraceset
*traceset
= self
->parent
.ts
;
3542 int min_pos
, mid_pos
, max_pos
;
3544 guint call_rest
= 0;
3546 LttvTraceState
*tcs
;
3548 LttvAttributeValue value
;
3550 LttvAttributeType type
;
3552 LttvAttributeName name
;
3556 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3558 //g_tree_destroy(self->parent.pqueue);
3559 //self->parent.pqueue = g_tree_new(compare_tracefile);
3561 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3563 nb_trace
= lttv_traceset_number(traceset
);
3564 for(i
= 0 ; i
< nb_trace
; i
++) {
3565 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3567 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3568 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3569 LTTV_STATE_SAVED_STATES
);
3572 if(saved_states_tree
) {
3573 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3574 mid_pos
= max_pos
/ 2;
3575 while(min_pos
< max_pos
) {
3576 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3578 g_assert(type
== LTTV_GOBJECT
);
3579 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3580 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3582 g_assert(type
== LTTV_TIME
);
3583 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3585 closest_tree
= saved_state_tree
;
3587 else max_pos
= mid_pos
- 1;
3589 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3593 /* restore the closest earlier saved state */
3595 lttv_state_restore(tcs
, closest_tree
);
3599 /* There is no saved state, yet we want to have it. Restart at T0 */
3601 restore_init_state(tcs
);
3602 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3605 /* We want to seek quickly without restoring/updating the state */
3607 restore_init_state(tcs
);
3608 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3611 if(!call_rest
) g_info("NOT Calling restore");
3616 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3622 traceset_state_finalize (LttvTracesetState
*self
)
3624 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3625 finalize(G_OBJECT(self
));
3630 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3632 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3634 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3635 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3636 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3637 klass
->new_traceset_context
= new_traceset_context
;
3638 klass
->new_trace_context
= new_trace_context
;
3639 klass
->new_tracefile_context
= new_tracefile_context
;
3644 lttv_traceset_state_get_type(void)
3646 static GType type
= 0;
3648 static const GTypeInfo info
= {
3649 sizeof (LttvTracesetStateClass
),
3650 NULL
, /* base_init */
3651 NULL
, /* base_finalize */
3652 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3653 NULL
, /* class_finalize */
3654 NULL
, /* class_data */
3655 sizeof (LttvTracesetState
),
3656 0, /* n_preallocs */
3657 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3658 NULL
/* value handling */
3661 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3669 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3675 trace_state_finalize (LttvTraceState
*self
)
3677 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3678 finalize(G_OBJECT(self
));
3683 trace_state_class_init (LttvTraceStateClass
*klass
)
3685 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3687 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3688 klass
->state_save
= state_save
;
3689 klass
->state_restore
= state_restore
;
3690 klass
->state_saved_free
= state_saved_free
;
3695 lttv_trace_state_get_type(void)
3697 static GType type
= 0;
3699 static const GTypeInfo info
= {
3700 sizeof (LttvTraceStateClass
),
3701 NULL
, /* base_init */
3702 NULL
, /* base_finalize */
3703 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3704 NULL
, /* class_finalize */
3705 NULL
, /* class_data */
3706 sizeof (LttvTraceState
),
3707 0, /* n_preallocs */
3708 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3709 NULL
/* value handling */
3712 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3713 "LttvTraceStateType", &info
, 0);
3720 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3726 tracefile_state_finalize (LttvTracefileState
*self
)
3728 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3729 finalize(G_OBJECT(self
));
3734 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3736 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3738 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3743 lttv_tracefile_state_get_type(void)
3745 static GType type
= 0;
3747 static const GTypeInfo info
= {
3748 sizeof (LttvTracefileStateClass
),
3749 NULL
, /* base_init */
3750 NULL
, /* base_finalize */
3751 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3752 NULL
, /* class_finalize */
3753 NULL
, /* class_data */
3754 sizeof (LttvTracefileState
),
3755 0, /* n_preallocs */
3756 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3757 NULL
/* value handling */
3760 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3761 "LttvTracefileStateType", &info
, 0);
3767 static void module_init()
3769 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3770 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3771 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3772 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3773 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3774 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3775 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3776 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3777 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3778 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3779 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3780 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3781 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3782 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3783 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3784 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3785 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3786 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3787 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3788 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3789 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3790 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3791 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3792 LTTV_STATE_EVENT
= g_quark_from_string("event");
3793 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3794 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3795 LTTV_STATE_TIME
= g_quark_from_string("time");
3796 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3797 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3798 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3799 g_quark_from_string("trace_state_use_count");
3800 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3801 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3802 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3805 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3806 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3807 LTT_FACILITY_FS
= g_quark_from_string("fs");
3808 LTT_FACILITY_LIST
= g_quark_from_string("list");
3809 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3810 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3813 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3814 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3815 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3816 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3817 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3818 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3819 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3820 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3821 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3822 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3823 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3824 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3825 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3826 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3827 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3828 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3829 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3830 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3831 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3832 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3833 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3834 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3837 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3838 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3839 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3840 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3841 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3842 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3843 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3844 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3845 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3846 LTT_FIELD_PID
= g_quark_from_string("pid");
3847 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3848 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3849 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3850 LTT_FIELD_NAME
= g_quark_from_string("name");
3851 LTT_FIELD_TYPE
= g_quark_from_string("type");
3852 LTT_FIELD_MODE
= g_quark_from_string("mode");
3853 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3854 LTT_FIELD_STATUS
= g_quark_from_string("status");
3855 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3856 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3857 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3858 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3859 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3860 LTT_FIELD_ACTION
= g_quark_from_string("action");
3861 LTT_FIELD_NUM
= g_quark_from_string("num");
3863 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3864 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3865 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3866 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3867 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3869 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3870 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3871 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3873 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3874 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3875 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3876 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3879 static void module_destroy()
3884 LTTV_MODULE("state", "State computation", \
3885 "Update the system state, possibly saving it at intervals", \
3886 module_init
, module_destroy
)