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_FACILITY_KERNEL_ARCH
,
1637 LTT_EVENT_SYSCALL_ENTRY
,
1638 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1639 NULL
, NULL
, &hooks
)) {
1641 // th = lttv_trace_hook_get_first(&th);
1643 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1644 // nb = ltt_type_element_number(t);
1646 // name_tables->syscall_names = g_new(GQuark, nb);
1647 // name_tables->nb_syscalls = nb;
1649 // for(i = 0 ; i < nb ; i++) {
1650 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1651 // if(!name_tables->syscall_names[i]) {
1652 // GString *string = g_string_new("");
1653 // g_string_printf(string, "syscall %u", i);
1654 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1655 // g_string_free(string, TRUE);
1659 name_tables
->syscall_names
= g_new(GQuark
, 256);
1660 for(i
= 0 ; i
< 256 ; i
++) {
1661 g_string_printf(fe_name
, "syscall %d", i
);
1662 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1665 name_tables
->syscall_names
= NULL
;
1666 name_tables
->nb_syscalls
= 0;
1668 lttv_trace_hook_remove_all(&hooks
);
1670 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1671 LTT_FACILITY_KERNEL_ARCH
,
1672 LTT_EVENT_TRAP_ENTRY
,
1673 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1674 NULL
, NULL
, &hooks
)) {
1676 // th = lttv_trace_hook_get_first(&th);
1678 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1679 // //nb = ltt_type_element_number(t);
1681 // name_tables->trap_names = g_new(GQuark, nb);
1682 // for(i = 0 ; i < nb ; i++) {
1683 // name_tables->trap_names[i] = g_quark_from_string(
1684 // ltt_enum_string_get(t, i));
1687 name_tables
->nb_traps
= 256;
1688 name_tables
->trap_names
= g_new(GQuark
, 256);
1689 for(i
= 0 ; i
< 256 ; i
++) {
1690 g_string_printf(fe_name
, "trap %d", i
);
1691 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1694 name_tables
->trap_names
= NULL
;
1695 name_tables
->nb_traps
= 0;
1697 lttv_trace_hook_remove_all(&hooks
);
1699 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1700 LTT_FACILITY_KERNEL
,
1701 LTT_EVENT_IRQ_ENTRY
,
1702 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1703 NULL
, NULL
, &hooks
)) {
1706 name_tables->irq_names = g_new(GQuark, nb);
1707 for(i = 0 ; i < nb ; i++) {
1708 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1712 name_tables
->nb_irqs
= 256;
1713 name_tables
->irq_names
= g_new(GQuark
, 256);
1714 for(i
= 0 ; i
< 256 ; i
++) {
1715 g_string_printf(fe_name
, "irq %d", i
);
1716 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1719 name_tables
->nb_irqs
= 0;
1720 name_tables
->irq_names
= NULL
;
1722 lttv_trace_hook_remove_all(&hooks
);
1724 name_tables->soft_irq_names = g_new(GQuark, nb);
1725 for(i = 0 ; i < nb ; i++) {
1726 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1730 name_tables
->nb_softirqs
= 256;
1731 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1732 for(i
= 0 ; i
< 256 ; i
++) {
1733 g_string_printf(fe_name
, "softirq %d", i
);
1734 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1736 g_array_free(hooks
, TRUE
);
1738 g_string_free(fe_name
, TRUE
);
1743 get_name_tables(LttvTraceState
*tcs
)
1745 LttvNameTables
*name_tables
;
1747 LttvAttributeValue v
;
1749 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1751 g_assert(*(v
.v_pointer
) != NULL
);
1752 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1753 //tcs->eventtype_names = name_tables->eventtype_names;
1754 tcs
->syscall_names
= name_tables
->syscall_names
;
1755 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1756 tcs
->trap_names
= name_tables
->trap_names
;
1757 tcs
->nb_traps
= name_tables
->nb_traps
;
1758 tcs
->irq_names
= name_tables
->irq_names
;
1759 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1760 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1761 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1766 free_name_tables(LttvTraceState
*tcs
)
1768 LttvNameTables
*name_tables
;
1770 LttvAttributeValue v
;
1772 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1774 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1775 *(v
.v_pointer
) = NULL
;
1777 // g_free(name_tables->eventtype_names);
1778 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1779 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1780 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1781 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1782 if(name_tables
) g_free(name_tables
);
1785 #ifdef HASH_TABLE_DEBUG
1787 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1789 LttvProcessState
*process
= (LttvProcessState
*)value
;
1791 /* Test for process corruption */
1792 guint stack_len
= process
->execution_stack
->len
;
1795 static void hash_table_check(GHashTable
*table
)
1797 g_hash_table_foreach(table
, test_process
, NULL
);
1803 /* clears the stack and sets the state passed as argument */
1804 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1806 g_array_set_size(cpust
->mode_stack
, 1);
1807 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1810 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1812 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1813 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1816 static void cpu_pop_mode(LttvCPUState
*cpust
)
1818 if(cpust
->mode_stack
->len
<= 1)
1819 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1821 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1824 /* clears the stack and sets the state passed as argument */
1825 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1827 g_array_set_size(bdevst
->mode_stack
, 1);
1828 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1831 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1833 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1834 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1837 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1839 if(bdevst
->mode_stack
->len
<= 1)
1840 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1842 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1845 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1847 g_array_set_size(irqst
->mode_stack
, 1);
1848 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1851 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1853 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1854 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1857 static void irq_pop_mode(LttvIRQState
*irqst
)
1859 if(irqst
->mode_stack
->len
<= 1)
1860 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1862 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1865 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1868 LttvExecutionState
*es
;
1870 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1871 guint cpu
= tfs
->cpu
;
1873 #ifdef HASH_TABLE_DEBUG
1874 hash_table_check(ts
->processes
);
1876 LttvProcessState
*process
= ts
->running_process
[cpu
];
1878 guint depth
= process
->execution_stack
->len
;
1880 process
->execution_stack
=
1881 g_array_set_size(process
->execution_stack
, depth
+ 1);
1884 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1886 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1889 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1890 es
->cum_cpu_time
= ltt_time_zero
;
1891 es
->s
= process
->state
->s
;
1892 process
->state
= es
;
1896 * return 1 when empty, else 0 */
1897 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1898 LttvTracefileState
*tfs
)
1900 guint depth
= process
->execution_stack
->len
;
1906 process
->execution_stack
=
1907 g_array_set_size(process
->execution_stack
, depth
- 1);
1908 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1910 process
->state
->change
= tfs
->parent
.timestamp
;
1915 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1917 guint cpu
= tfs
->cpu
;
1918 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1919 LttvProcessState
*process
= ts
->running_process
[cpu
];
1921 guint depth
= process
->execution_stack
->len
;
1923 if(process
->state
->t
!= t
){
1924 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1925 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1926 g_info("process state has %s when pop_int is %s\n",
1927 g_quark_to_string(process
->state
->t
),
1928 g_quark_to_string(t
));
1929 g_info("{ %u, %u, %s, %s, %s }\n",
1932 g_quark_to_string(process
->name
),
1933 g_quark_to_string(process
->brand
),
1934 g_quark_to_string(process
->state
->s
));
1939 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1940 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1944 process
->execution_stack
=
1945 g_array_set_size(process
->execution_stack
, depth
- 1);
1946 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1948 process
->state
->change
= tfs
->parent
.timestamp
;
1951 struct search_result
{
1952 const LttTime
*time
; /* Requested time */
1953 LttTime
*best
; /* Best result */
1956 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1958 const LttTime
*elem_time
= (const LttTime
*)a
;
1959 /* Explicit non const cast */
1960 struct search_result
*res
= (struct search_result
*)b
;
1962 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1963 /* The usertrace was created before the schedchange */
1964 /* Get larger keys */
1966 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1967 /* The usertrace was created after the schedchange time */
1968 /* Get smaller keys */
1970 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1971 res
->best
= (LttTime
*)elem_time
;
1974 res
->best
= (LttTime
*)elem_time
;
1981 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1982 guint pid
, const LttTime
*timestamp
)
1984 LttvTracefileState
*tfs
= NULL
;
1985 struct search_result res
;
1986 /* Find the usertrace associated with a pid and time interval.
1987 * Search in the usertraces by PID (within a hash) and then, for each
1988 * corresponding element of the array, find the first one with creation
1989 * timestamp the lowest, but higher or equal to "timestamp". */
1990 res
.time
= timestamp
;
1992 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1993 if(usertrace_tree
) {
1994 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1996 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2004 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2005 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2007 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2009 LttvExecutionState
*es
;
2014 process
->tgid
= tgid
;
2016 process
->name
= name
;
2017 process
->brand
= LTTV_STATE_UNBRANDED
;
2018 //process->last_cpu = tfs->cpu_name;
2019 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2020 process
->type
= LTTV_STATE_USER_THREAD
;
2021 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2022 process
->current_function
= 0; //function 0x0 by default.
2024 g_info("Process %u, core %p", process
->pid
, process
);
2025 g_hash_table_insert(tcs
->processes
, process
, process
);
2028 process
->ppid
= parent
->pid
;
2029 process
->creation_time
= *timestamp
;
2032 /* No parent. This process exists but we are missing all information about
2033 its creation. The birth time is set to zero but we remember the time of
2038 process
->creation_time
= ltt_time_zero
;
2041 process
->insertion_time
= *timestamp
;
2042 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2043 process
->creation_time
.tv_nsec
);
2044 process
->pid_time
= g_quark_from_string(buffer
);
2046 //process->last_cpu = tfs->cpu_name;
2047 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2048 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2049 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2050 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2051 es
= process
->state
= &g_array_index(process
->execution_stack
,
2052 LttvExecutionState
, 0);
2053 es
->t
= LTTV_STATE_USER_MODE
;
2054 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2055 es
->entry
= *timestamp
;
2056 //g_assert(timestamp->tv_sec != 0);
2057 es
->change
= *timestamp
;
2058 es
->cum_cpu_time
= ltt_time_zero
;
2059 es
->s
= LTTV_STATE_RUN
;
2061 es
= process
->state
= &g_array_index(process
->execution_stack
,
2062 LttvExecutionState
, 1);
2063 es
->t
= LTTV_STATE_SYSCALL
;
2064 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2065 es
->entry
= *timestamp
;
2066 //g_assert(timestamp->tv_sec != 0);
2067 es
->change
= *timestamp
;
2068 es
->cum_cpu_time
= ltt_time_zero
;
2069 es
->s
= LTTV_STATE_WAIT_FORK
;
2071 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2072 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2073 sizeof(guint64
), 0);
2078 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2081 LttvProcessState key
;
2082 LttvProcessState
*process
;
2086 process
= g_hash_table_lookup(ts
->processes
, &key
);
2091 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2092 const LttTime
*timestamp
)
2094 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2095 LttvExecutionState
*es
;
2097 /* Put ltt_time_zero creation time for unexisting processes */
2098 if(unlikely(process
== NULL
)) {
2099 process
= lttv_state_create_process(ts
,
2100 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2101 /* We are not sure is it's a kernel thread or normal thread, put the
2102 * bottom stack state to unknown */
2103 process
->execution_stack
=
2104 g_array_set_size(process
->execution_stack
, 1);
2105 process
->state
= es
=
2106 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2107 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2108 es
->s
= LTTV_STATE_UNNAMED
;
2113 /* FIXME : this function should be called when we receive an event telling that
2114 * release_task has been called in the kernel. In happens generally when
2115 * the parent waits for its child terminaison, but may also happen in special
2116 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2117 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2118 * of a killed thread ground, but isn't the leader.
2120 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2122 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2123 LttvProcessState key
;
2125 key
.pid
= process
->pid
;
2126 key
.cpu
= process
->cpu
;
2127 g_hash_table_remove(ts
->processes
, &key
);
2128 g_array_free(process
->execution_stack
, TRUE
);
2129 g_array_free(process
->user_stack
, TRUE
);
2134 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2136 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2137 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2142 static void lttv_state_free_process_table(GHashTable
*processes
)
2144 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2145 g_hash_table_destroy(processes
);
2149 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2151 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2153 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2154 LttvProcessState
*process
= ts
->running_process
[cpu
];
2155 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2156 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2157 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2159 LttvExecutionSubmode submode
;
2161 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2162 guint syscall
= ltt_event_get_unsigned(e
, f
);
2164 if(syscall
< nb_syscalls
) {
2165 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2168 /* Fixup an incomplete syscall table */
2169 GString
*string
= g_string_new("");
2170 g_string_printf(string
, "syscall %u", syscall
);
2171 submode
= g_quark_from_string(string
->str
);
2172 g_string_free(string
, TRUE
);
2174 /* There can be no system call from PID 0 : unknown state */
2175 if(process
->pid
!= 0)
2176 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2181 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2183 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2185 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2186 LttvProcessState
*process
= ts
->running_process
[cpu
];
2188 /* There can be no system call from PID 0 : unknown state */
2189 if(process
->pid
!= 0)
2190 pop_state(s
, LTTV_STATE_SYSCALL
);
2195 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2197 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2198 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2199 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2200 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2202 LttvExecutionSubmode submode
;
2204 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2205 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2207 if(trap
< nb_traps
) {
2208 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2210 /* Fixup an incomplete trap table */
2211 GString
*string
= g_string_new("");
2212 g_string_printf(string
, "trap %llu", trap
);
2213 submode
= g_quark_from_string(string
->str
);
2214 g_string_free(string
, TRUE
);
2217 push_state(s
, LTTV_STATE_TRAP
, submode
);
2219 /* update cpu status */
2220 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2225 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2227 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2229 pop_state(s
, LTTV_STATE_TRAP
);
2231 /* update cpu status */
2232 cpu_pop_mode(s
->cpu_state
);
2237 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2239 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2240 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2241 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2242 //guint8 ev_id = ltt_event_eventtype_id(e);
2243 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2244 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2246 LttvExecutionSubmode submode
;
2247 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2248 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2251 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2253 /* Fixup an incomplete irq table */
2254 GString
*string
= g_string_new("");
2255 g_string_printf(string
, "irq %llu", irq
);
2256 submode
= g_quark_from_string(string
->str
);
2257 g_string_free(string
, TRUE
);
2260 /* Do something with the info about being in user or system mode when int? */
2261 push_state(s
, LTTV_STATE_IRQ
, submode
);
2263 /* update cpu status */
2264 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2266 /* update irq status */
2267 s
->cpu_state
->last_irq
= irq
;
2268 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2273 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2275 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2277 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2283 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2285 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2286 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2288 pop_state(s
, LTTV_STATE_IRQ
);
2290 /* update cpu status */
2291 cpu_pop_mode(s
->cpu_state
);
2293 /* update irq status */
2294 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2299 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2301 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2302 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2303 //guint8 ev_id = ltt_event_eventtype_id(e);
2304 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2305 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2307 LttvExecutionSubmode submode
;
2308 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2309 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2311 if(softirq
< nb_softirqs
) {
2312 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2314 /* Fixup an incomplete irq table */
2315 GString
*string
= g_string_new("");
2316 g_string_printf(string
, "softirq %llu", softirq
);
2317 submode
= g_quark_from_string(string
->str
);
2318 g_string_free(string
, TRUE
);
2321 /* Do something with the info about being in user or system mode when int? */
2322 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2326 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2328 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2329 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2330 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2331 //guint8 ev_id = ltt_event_eventtype_id(e);
2332 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2334 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2335 lttv_trace_get_hook_field(th
, 0)));
2336 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2338 ts
->irq_names
[irq
] = action
;
2344 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2346 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2347 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2348 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2349 //guint8 ev_id = ltt_event_eventtype_id(e);
2350 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2352 guint major
= ltt_event_get_long_unsigned(e
,
2353 lttv_trace_get_hook_field(th
, 0));
2354 guint minor
= ltt_event_get_long_unsigned(e
,
2355 lttv_trace_get_hook_field(th
, 1));
2356 guint oper
= ltt_event_get_long_unsigned(e
,
2357 lttv_trace_get_hook_field(th
, 2));
2358 guint16 devcode
= MKDEV(major
,minor
);
2360 /* have we seen this block device before? */
2361 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2364 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2366 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2371 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2373 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2374 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2375 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2376 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2378 guint major
= ltt_event_get_long_unsigned(e
,
2379 lttv_trace_get_hook_field(th
, 0));
2380 guint minor
= ltt_event_get_long_unsigned(e
,
2381 lttv_trace_get_hook_field(th
, 1));
2382 //guint oper = ltt_event_get_long_unsigned(e,
2383 // lttv_trace_get_hook_field(th, 2));
2384 guint16 devcode
= MKDEV(major
,minor
);
2386 /* have we seen this block device before? */
2387 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2389 /* update block device */
2390 bdev_pop_mode(bdev
);
2395 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2399 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2400 guint cpu
= tfs
->cpu
;
2401 LttvProcessState
*process
= ts
->running_process
[cpu
];
2403 guint depth
= process
->user_stack
->len
;
2405 process
->user_stack
=
2406 g_array_set_size(process
->user_stack
, depth
+ 1);
2408 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2409 *new_func
= funcptr
;
2410 process
->current_function
= funcptr
;
2413 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2415 guint cpu
= tfs
->cpu
;
2416 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2417 LttvProcessState
*process
= ts
->running_process
[cpu
];
2419 if(process
->current_function
!= funcptr
){
2420 g_info("Different functions (%lu.%09lu): ignore it\n",
2421 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2422 g_info("process state has %llu when pop_function is %llu\n",
2423 process
->current_function
, funcptr
);
2424 g_info("{ %u, %u, %s, %s, %s }\n",
2427 g_quark_to_string(process
->name
),
2428 g_quark_to_string(process
->brand
),
2429 g_quark_to_string(process
->state
->s
));
2432 guint depth
= process
->user_stack
->len
;
2435 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2436 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2440 process
->user_stack
=
2441 g_array_set_size(process
->user_stack
, depth
- 1);
2442 process
->current_function
=
2443 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2447 static gboolean
function_entry(void *hook_data
, void *call_data
)
2449 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2450 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2451 //guint8 ev_id = ltt_event_eventtype_id(e);
2452 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2453 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2454 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2456 push_function(s
, funcptr
);
2460 static gboolean
function_exit(void *hook_data
, void *call_data
)
2462 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2463 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2464 //guint8 ev_id = ltt_event_eventtype_id(e);
2465 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2466 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2467 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2469 pop_function(s
, funcptr
);
2473 static gboolean
schedchange(void *hook_data
, void *call_data
)
2475 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2477 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2478 LttvProcessState
*process
= ts
->running_process
[cpu
];
2479 //LttvProcessState *old_process = ts->running_process[cpu];
2481 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2482 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2483 guint pid_in
, pid_out
;
2486 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2487 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2488 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2490 if(likely(process
!= NULL
)) {
2492 /* We could not know but it was not the idle process executing.
2493 This should only happen at the beginning, before the first schedule
2494 event, and when the initial information (current process for each CPU)
2495 is missing. It is not obvious how we could, after the fact, compensate
2496 the wrongly attributed statistics. */
2498 //This test only makes sense once the state is known and if there is no
2499 //missing events. We need to silently ignore schedchange coming after a
2500 //process_free, or it causes glitches. (FIXME)
2501 //if(unlikely(process->pid != pid_out)) {
2502 // g_assert(process->pid == 0);
2504 if(process
->pid
== 0
2505 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2507 /* Scheduling out of pid 0 at beginning of the trace :
2508 * we know for sure it is in syscall mode at this point. */
2509 g_assert(process
->execution_stack
->len
== 1);
2510 process
->state
->t
= LTTV_STATE_SYSCALL
;
2511 process
->state
->s
= LTTV_STATE_WAIT
;
2512 process
->state
->change
= s
->parent
.timestamp
;
2513 process
->state
->entry
= s
->parent
.timestamp
;
2516 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2517 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2518 process
->state
->change
= s
->parent
.timestamp
;
2520 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2521 else process
->state
->s
= LTTV_STATE_WAIT
;
2522 process
->state
->change
= s
->parent
.timestamp
;
2525 if(state_out
== 32 || state_out
== 128)
2526 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2527 /* see sched.h for states */
2530 process
= ts
->running_process
[cpu
] =
2531 lttv_state_find_process_or_create(
2532 (LttvTraceState
*)s
->parent
.t_context
,
2534 &s
->parent
.timestamp
);
2535 process
->state
->s
= LTTV_STATE_RUN
;
2537 if(process
->usertrace
)
2538 process
->usertrace
->cpu
= cpu
;
2539 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2540 process
->state
->change
= s
->parent
.timestamp
;
2542 /* update cpu status */
2544 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2546 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2551 static gboolean
process_fork(void *hook_data
, void *call_data
)
2553 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2554 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2555 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2557 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2558 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2559 //LttvProcessState *zombie_process;
2561 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2562 LttvProcessState
*process
= ts
->running_process
[cpu
];
2563 LttvProcessState
*child_process
;
2564 struct marker_field
*f
;
2567 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2570 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2571 s
->parent
.target_pid
= child_pid
;
2574 f
= lttv_trace_get_hook_field(th
, 2);
2576 child_tgid
= ltt_event_get_unsigned(e
, f
);
2580 /* Mathieu : it seems like the process might have been scheduled in before the
2581 * fork, and, in a rare case, might be the current process. This might happen
2582 * in a SMP case where we don't have enough precision on the clocks.
2584 * Test reenabled after precision fixes on time. (Mathieu) */
2586 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2588 if(unlikely(zombie_process
!= NULL
)) {
2589 /* Reutilisation of PID. Only now we are sure that the old PID
2590 * has been released. FIXME : should know when release_task happens instead.
2592 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2594 for(i
=0; i
< num_cpus
; i
++) {
2595 g_assert(zombie_process
!= ts
->running_process
[i
]);
2598 exit_process(s
, zombie_process
);
2601 g_assert(process
->pid
!= child_pid
);
2602 // FIXME : Add this test in the "known state" section
2603 // g_assert(process->pid == parent_pid);
2604 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2605 if(child_process
== NULL
) {
2606 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2607 child_pid
, child_tgid
,
2608 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2610 /* The process has already been created : due to time imprecision between
2611 * multiple CPUs : it has been scheduled in before creation. Note that we
2612 * shouldn't have this kind of imprecision.
2614 * Simply put a correct parent.
2616 g_assert(0); /* This is a problematic case : the process has been created
2617 before the fork event */
2618 child_process
->ppid
= process
->pid
;
2619 child_process
->tgid
= child_tgid
;
2621 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2622 child_process
->name
= process
->name
;
2623 child_process
->brand
= process
->brand
;
2628 /* We stamp a newly created process as kernel_thread.
2629 * The thread should not be running yet. */
2630 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2632 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2633 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2634 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2636 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2637 LttvProcessState
*process
;
2638 LttvExecutionState
*es
;
2641 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2642 s
->parent
.target_pid
= pid
;
2644 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2646 process
->execution_stack
=
2647 g_array_set_size(process
->execution_stack
, 1);
2648 es
= process
->state
=
2649 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2650 es
->t
= LTTV_STATE_SYSCALL
;
2651 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2656 static gboolean
process_exit(void *hook_data
, void *call_data
)
2658 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2659 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2660 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2662 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2663 LttvProcessState
*process
; // = ts->running_process[cpu];
2665 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2666 s
->parent
.target_pid
= pid
;
2668 // FIXME : Add this test in the "known state" section
2669 // g_assert(process->pid == pid);
2671 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2672 if(likely(process
!= NULL
)) {
2673 process
->state
->s
= LTTV_STATE_EXIT
;
2678 static gboolean
process_free(void *hook_data
, void *call_data
)
2680 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2681 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2682 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2683 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2685 LttvProcessState
*process
;
2687 /* PID of the process to release */
2688 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2689 s
->parent
.target_pid
= release_pid
;
2691 g_assert(release_pid
!= 0);
2693 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2695 if(likely(process
!= NULL
)) {
2696 /* release_task is happening at kernel level : we can now safely release
2697 * the data structure of the process */
2698 //This test is fun, though, as it may happen that
2699 //at time t : CPU 0 : process_free
2700 //at time t+150ns : CPU 1 : schedule out
2701 //Clearly due to time imprecision, we disable it. (Mathieu)
2702 //If this weird case happen, we have no choice but to put the
2703 //Currently running process on the cpu to 0.
2704 //I re-enable it following time precision fixes. (Mathieu)
2705 //Well, in the case where an process is freed by a process on another CPU
2706 //and still scheduled, it happens that this is the schedchange that will
2707 //drop the last reference count. Do not free it here!
2708 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2710 for(i
=0; i
< num_cpus
; i
++) {
2711 //g_assert(process != ts->running_process[i]);
2712 if(process
== ts
->running_process
[i
]) {
2713 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2717 if(i
== num_cpus
) /* process is not scheduled */
2718 exit_process(s
, process
);
2725 static gboolean
process_exec(void *hook_data
, void *call_data
)
2727 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2728 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2729 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2730 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2733 LttvProcessState
*process
= ts
->running_process
[cpu
];
2735 #if 0//how to use a sequence that must be transformed in a string
2736 /* PID of the process to release */
2737 guint64 name_len
= ltt_event_field_element_number(e
,
2738 lttv_trace_get_hook_field(th
, 0));
2739 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2740 LttField
*child
= ltt_event_field_element_select(e
,
2741 lttv_trace_get_hook_field(th
, 0), 0);
2743 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2744 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2745 memcpy(null_term_name
, name_begin
, name_len
);
2746 null_term_name
[name_len
] = '\0';
2747 process
->name
= g_quark_from_string(null_term_name
);
2750 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2751 lttv_trace_get_hook_field(th
, 0)));
2752 process
->brand
= LTTV_STATE_UNBRANDED
;
2753 //g_free(null_term_name);
2757 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2759 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2760 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2761 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2762 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2765 LttvProcessState
*process
= ts
->running_process
[cpu
];
2767 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2768 process
->brand
= g_quark_from_string(name
);
2773 static void fix_process(gpointer key
, gpointer value
,
2776 LttvProcessState
*process
;
2777 LttvExecutionState
*es
;
2778 process
= (LttvProcessState
*)value
;
2779 LttTime
*timestamp
= (LttTime
*)user_data
;
2781 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2782 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2783 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2784 es
->t
= LTTV_STATE_SYSCALL
;
2785 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2786 es
->entry
= *timestamp
;
2787 es
->change
= *timestamp
;
2788 es
->cum_cpu_time
= ltt_time_zero
;
2789 if(es
->s
== LTTV_STATE_UNNAMED
)
2790 es
->s
= LTTV_STATE_WAIT
;
2793 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2794 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2795 es
->t
= LTTV_STATE_USER_MODE
;
2796 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2797 es
->entry
= *timestamp
;
2798 //g_assert(timestamp->tv_sec != 0);
2799 es
->change
= *timestamp
;
2800 es
->cum_cpu_time
= ltt_time_zero
;
2801 if(es
->s
== LTTV_STATE_UNNAMED
)
2802 es
->s
= LTTV_STATE_RUN
;
2804 if(process
->execution_stack
->len
== 1) {
2805 /* Still in bottom unknown mode, means never did a system call
2806 * May be either in user mode, syscall mode, running or waiting.*/
2807 /* FIXME : we may be tagging syscall mode when being user mode */
2808 process
->execution_stack
=
2809 g_array_set_size(process
->execution_stack
, 2);
2810 es
= process
->state
= &g_array_index(process
->execution_stack
,
2811 LttvExecutionState
, 1);
2812 es
->t
= LTTV_STATE_SYSCALL
;
2813 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2814 es
->entry
= *timestamp
;
2815 //g_assert(timestamp->tv_sec != 0);
2816 es
->change
= *timestamp
;
2817 es
->cum_cpu_time
= ltt_time_zero
;
2818 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2819 es
->s
= LTTV_STATE_WAIT
;
2825 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2827 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2828 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2829 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2830 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2831 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2833 /* For all processes */
2834 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2835 /* else, if stack[0] is unknown, set to user mode, running */
2837 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2842 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2844 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2845 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2846 //It's slow : optimise later by doing this before reading trace.
2847 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2853 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2854 LttvProcessState
*process
= ts
->running_process
[cpu
];
2855 LttvProcessState
*parent_process
;
2856 struct marker_field
*f
;
2857 GQuark type
, mode
, submode
, status
;
2858 LttvExecutionState
*es
;
2862 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2863 s
->parent
.target_pid
= pid
;
2866 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2869 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2872 f
= lttv_trace_get_hook_field(th
, 3);
2873 type
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2876 f
= lttv_trace_get_hook_field(th
, 4);
2877 mode
= ltt_enum_string_get(f
,ltt_event_get_unsigned(e
, f
));
2880 f
= lttv_trace_get_hook_field(th
, 5);
2881 submode
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2884 f
= lttv_trace_get_hook_field(th
, 6);
2885 status
= ltt_enum_string_get(f
, ltt_event_get_unsigned(e
, f
));
2888 f
= lttv_trace_get_hook_field(th
, 7);
2890 tgid
= ltt_event_get_unsigned(e
, f
);
2895 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2896 for(i
=0; i
<nb_cpus
; i
++) {
2897 process
= lttv_state_find_process(ts
, i
, pid
);
2898 g_assert(process
!= NULL
);
2900 process
->ppid
= parent_pid
;
2901 process
->tgid
= tgid
;
2902 process
->name
= g_quark_from_string(command
);
2904 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2905 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2909 /* The process might exist if a process was forked while performing the
2911 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2912 if(process
== NULL
) {
2913 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2914 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2915 pid
, tgid
, g_quark_from_string(command
),
2916 &s
->parent
.timestamp
);
2918 /* Keep the stack bottom : a running user mode */
2919 /* Disabled because of inconsistencies in the current statedump states. */
2920 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2921 /* Only keep the bottom
2922 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2923 /* Will cause expected trap when in fact being syscall (even after end of
2925 * Will cause expected interrupt when being syscall. (only before end of
2926 * statedump event) */
2927 // This will cause a "popping last state on stack, ignoring it."
2928 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2929 es
= process
->state
= &g_array_index(process
->execution_stack
,
2930 LttvExecutionState
, 0);
2931 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2932 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2933 es
->s
= LTTV_STATE_UNNAMED
;
2934 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2936 es
->t
= LTTV_STATE_SYSCALL
;
2941 /* User space process :
2942 * bottom : user mode
2943 * either currently running or scheduled out.
2944 * can be scheduled out because interrupted in (user mode or in syscall)
2945 * or because of an explicit call to the scheduler in syscall. Note that
2946 * the scheduler call comes after the irq_exit, so never in interrupt
2948 // temp workaround : set size to 1 : only have user mode bottom of stack.
2949 // will cause g_info message of expected syscall mode when in fact being
2950 // in user mode. Can also cause expected trap when in fact being user
2951 // mode in the event of a page fault reenabling interrupts in the handler.
2952 // Expected syscall and trap can also happen after the end of statedump
2953 // This will cause a "popping last state on stack, ignoring it."
2954 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2955 es
= process
->state
= &g_array_index(process
->execution_stack
,
2956 LttvExecutionState
, 0);
2957 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2958 es
->s
= LTTV_STATE_UNNAMED
;
2959 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2961 es
->t
= LTTV_STATE_USER_MODE
;
2969 es
= process
->state
= &g_array_index(process
->execution_stack
,
2970 LttvExecutionState
, 1);
2971 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2972 es
->s
= LTTV_STATE_UNNAMED
;
2973 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2977 /* The process has already been created :
2978 * Probably was forked while dumping the process state or
2979 * was simply scheduled in prior to get the state dump event.
2981 process
->ppid
= parent_pid
;
2982 process
->tgid
= tgid
;
2983 process
->name
= g_quark_from_string(command
);
2984 process
->type
= type
;
2986 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2988 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2989 if(type
== LTTV_STATE_KERNEL_THREAD
)
2990 es
->t
= LTTV_STATE_SYSCALL
;
2992 es
->t
= LTTV_STATE_USER_MODE
;
2995 /* Don't mess around with the stack, it will eventually become
2996 * ok after the end of state dump. */
3003 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3005 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3007 lttv_state_add_event_hooks(tss
);
3012 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3014 LttvTraceset
*traceset
= self
->parent
.ts
;
3016 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3020 LttvTracefileState
*tfs
;
3026 LttvAttributeValue val
;
3028 nb_trace
= lttv_traceset_number(traceset
);
3029 for(i
= 0 ; i
< nb_trace
; i
++) {
3030 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3032 /* Find the eventtype id for the following events and register the
3033 associated by id hooks. */
3035 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3036 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3039 lttv_trace_find_hook(ts
->parent
.t
,
3040 LTT_FACILITY_KERNEL_ARCH
,
3041 LTT_EVENT_SYSCALL_ENTRY
,
3042 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3043 syscall_entry
, NULL
, &hooks
);
3045 lttv_trace_find_hook(ts
->parent
.t
,
3046 LTT_FACILITY_KERNEL_ARCH
,
3047 LTT_EVENT_SYSCALL_EXIT
,
3049 syscall_exit
, NULL
, &hooks
);
3051 lttv_trace_find_hook(ts
->parent
.t
,
3052 LTT_FACILITY_KERNEL_ARCH
,
3053 LTT_EVENT_TRAP_ENTRY
,
3054 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3055 trap_entry
, NULL
, &hooks
);
3057 lttv_trace_find_hook(ts
->parent
.t
,
3058 LTT_FACILITY_KERNEL_ARCH
,
3059 LTT_EVENT_TRAP_EXIT
,
3061 trap_exit
, NULL
, &hooks
);
3063 lttv_trace_find_hook(ts
->parent
.t
,
3064 LTT_FACILITY_KERNEL
,
3065 LTT_EVENT_IRQ_ENTRY
,
3066 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3067 irq_entry
, NULL
, &hooks
);
3069 lttv_trace_find_hook(ts
->parent
.t
,
3070 LTT_FACILITY_KERNEL
,
3073 irq_exit
, NULL
, &hooks
);
3075 lttv_trace_find_hook(ts
->parent
.t
,
3076 LTT_FACILITY_KERNEL
,
3077 LTT_EVENT_SOFT_IRQ_ENTRY
,
3078 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3079 soft_irq_entry
, NULL
, &hooks
);
3081 lttv_trace_find_hook(ts
->parent
.t
,
3082 LTT_FACILITY_KERNEL
,
3083 LTT_EVENT_SOFT_IRQ_EXIT
,
3085 soft_irq_exit
, NULL
, &hooks
);
3087 lttv_trace_find_hook(ts
->parent
.t
,
3088 LTT_FACILITY_KERNEL
,
3089 LTT_EVENT_SCHED_SCHEDULE
,
3090 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3091 LTT_FIELD_PREV_STATE
),
3092 schedchange
, NULL
, &hooks
);
3094 lttv_trace_find_hook(ts
->parent
.t
,
3095 LTT_FACILITY_KERNEL
,
3096 LTT_EVENT_PROCESS_FORK
,
3097 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3098 LTT_FIELD_CHILD_TGID
),
3099 process_fork
, NULL
, &hooks
);
3101 lttv_trace_find_hook(ts
->parent
.t
,
3102 LTT_FACILITY_KERNEL_ARCH
,
3103 LTT_EVENT_KTHREAD_CREATE
,
3104 FIELD_ARRAY(LTT_FIELD_PID
),
3105 process_kernel_thread
, NULL
, &hooks
);
3107 lttv_trace_find_hook(ts
->parent
.t
,
3108 LTT_FACILITY_KERNEL
,
3109 LTT_EVENT_PROCESS_EXIT
,
3110 FIELD_ARRAY(LTT_FIELD_PID
),
3111 process_exit
, NULL
, &hooks
);
3113 lttv_trace_find_hook(ts
->parent
.t
,
3114 LTT_FACILITY_KERNEL
,
3115 LTT_EVENT_PROCESS_FREE
,
3116 FIELD_ARRAY(LTT_FIELD_PID
),
3117 process_free
, NULL
, &hooks
);
3119 lttv_trace_find_hook(ts
->parent
.t
,
3120 LTT_FACILITY_KERNEL
,
3122 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3123 process_exec
, NULL
, &hooks
);
3125 lttv_trace_find_hook(ts
->parent
.t
,
3126 LTT_FACILITY_USER_GENERIC
,
3127 LTT_EVENT_THREAD_BRAND
,
3128 FIELD_ARRAY(LTT_FIELD_NAME
),
3129 thread_brand
, NULL
, &hooks
);
3131 /* statedump-related hooks */
3132 lttv_trace_find_hook(ts
->parent
.t
,
3134 LTT_EVENT_PROCESS_STATE
,
3135 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3136 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3137 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3138 enum_process_state
, NULL
, &hooks
);
3140 lttv_trace_find_hook(ts
->parent
.t
,
3142 LTT_EVENT_STATEDUMP_END
,
3144 statedump_end
, NULL
, &hooks
);
3146 lttv_trace_find_hook(ts
->parent
.t
,
3148 LTT_EVENT_LIST_INTERRUPT
,
3149 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_NUM
),
3150 enum_interrupt
, NULL
, &hooks
);
3152 lttv_trace_find_hook(ts
->parent
.t
,
3154 LTT_EVENT_REQUEST_ISSUE
,
3155 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3156 bdev_request_issue
, NULL
, &hooks
);
3158 lttv_trace_find_hook(ts
->parent
.t
,
3160 LTT_EVENT_REQUEST_COMPLETE
,
3161 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3162 bdev_request_complete
, NULL
, &hooks
);
3164 lttv_trace_find_hook(ts
->parent
.t
,
3165 LTT_FACILITY_USER_GENERIC
,
3166 LTT_EVENT_FUNCTION_ENTRY
,
3167 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3168 function_entry
, NULL
, &hooks
);
3170 lttv_trace_find_hook(ts
->parent
.t
,
3171 LTT_FACILITY_USER_GENERIC
,
3172 LTT_EVENT_FUNCTION_EXIT
,
3173 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3174 function_exit
, NULL
, &hooks
);
3176 /* Add these hooks to each event_by_id hooks list */
3178 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3180 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3182 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3183 LttvTracefileContext
*, j
));
3185 for(k
= 0 ; k
< hooks
->len
; k
++) {
3186 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3188 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3194 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3195 *(val
.v_pointer
) = hooks
;
3199 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3201 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3203 lttv_state_remove_event_hooks(tss
);
3208 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3210 LttvTraceset
*traceset
= self
->parent
.ts
;
3212 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3216 LttvTracefileState
*tfs
;
3222 LttvAttributeValue val
;
3224 nb_trace
= lttv_traceset_number(traceset
);
3225 for(i
= 0 ; i
< nb_trace
; i
++) {
3226 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3228 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3229 hooks
= *(val
.v_pointer
);
3231 /* Remove these hooks from each event_by_id hooks list */
3233 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3235 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3237 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3238 LttvTracefileContext
*, j
));
3240 for(k
= 0 ; k
< hooks
->len
; k
++) {
3241 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3242 lttv_hooks_remove_data(
3243 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3248 lttv_trace_hook_remove_all(&hooks
);
3249 g_array_free(hooks
, TRUE
);
3253 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3255 guint
*event_count
= (guint
*)hook_data
;
3257 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3258 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3263 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3265 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3267 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3269 LttvAttributeValue value
;
3271 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3272 LTTV_STATE_SAVED_STATES
);
3273 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3274 value
= lttv_attribute_add(saved_states_tree
,
3275 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3276 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3277 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3278 *(value
.v_time
) = self
->parent
.timestamp
;
3279 lttv_state_save(tcs
, saved_state_tree
);
3280 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3281 self
->parent
.timestamp
.tv_nsec
);
3283 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3288 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3290 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3292 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3297 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3305 static gboolean
block_start(void *hook_data
, void *call_data
)
3307 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3309 LttvTracefileState
*tfcs
;
3311 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3313 LttEventPosition
*ep
;
3315 guint i
, nb_block
, nb_event
, nb_tracefile
;
3319 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3321 LttvAttributeValue value
;
3323 ep
= ltt_event_position_new();
3325 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3327 /* Count the number of events added since the last block end in any
3330 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3332 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3333 LttvTracefileContext
, i
));
3334 ltt_event_position(tfcs
->parent
.e
, ep
);
3335 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3336 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3337 tfcs
->saved_position
= nb_event
;
3341 if(tcs
->nb_event
>= tcs
->save_interval
) {
3342 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3343 LTTV_STATE_SAVED_STATES
);
3344 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3345 value
= lttv_attribute_add(saved_states_tree
,
3346 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3347 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3348 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3349 *(value
.v_time
) = self
->parent
.timestamp
;
3350 lttv_state_save(tcs
, saved_state_tree
);
3352 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3353 self
->parent
.timestamp
.tv_nsec
);
3355 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3361 static gboolean
block_end(void *hook_data
, void *call_data
)
3363 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3365 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3369 LttEventPosition
*ep
;
3371 guint nb_block
, nb_event
;
3373 ep
= ltt_event_position_new();
3374 ltt_event_position(self
->parent
.e
, ep
);
3375 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3376 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3377 self
->saved_position
= 0;
3378 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3385 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3387 LttvTraceset
*traceset
= self
->parent
.ts
;
3389 guint i
, j
, nb_trace
, nb_tracefile
;
3393 LttvTracefileState
*tfs
;
3395 LttvTraceHook hook_start
, hook_end
;
3397 nb_trace
= lttv_traceset_number(traceset
);
3398 for(i
= 0 ; i
< nb_trace
; i
++) {
3399 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3401 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3402 NULL
, NULL
, block_start
, &hook_start
);
3403 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3404 NULL
, NULL
, block_end
, &hook_end
);
3406 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3408 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3410 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3411 LttvTracefileContext
, j
));
3412 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3413 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3414 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3415 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3421 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3423 LttvTraceset
*traceset
= self
->parent
.ts
;
3425 guint i
, j
, nb_trace
, nb_tracefile
;
3429 LttvTracefileState
*tfs
;
3432 nb_trace
= lttv_traceset_number(traceset
);
3433 for(i
= 0 ; i
< nb_trace
; i
++) {
3435 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3436 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3438 if(ts
->has_precomputed_states
) continue;
3440 guint
*event_count
= g_new(guint
, 1);
3443 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3445 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3446 LttvTracefileContext
*, j
));
3447 lttv_hooks_add(tfs
->parent
.event
,
3448 state_save_event_hook
,
3455 lttv_process_traceset_begin(&self
->parent
,
3456 NULL
, NULL
, NULL
, NULL
, NULL
);
3460 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3462 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3464 lttv_state_save_add_event_hooks(tss
);
3471 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3473 LttvTraceset
*traceset
= self
->parent
.ts
;
3475 guint i
, j
, nb_trace
, nb_tracefile
;
3479 LttvTracefileState
*tfs
;
3481 LttvTraceHook hook_start
, hook_end
;
3483 nb_trace
= lttv_traceset_number(traceset
);
3484 for(i
= 0 ; i
< nb_trace
; i
++) {
3485 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3487 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3488 NULL
, NULL
, block_start
, &hook_start
);
3490 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3491 NULL
, NULL
, block_end
, &hook_end
);
3493 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3495 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3497 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3498 LttvTracefileContext
, j
));
3499 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3500 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3501 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3502 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3508 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3510 LttvTraceset
*traceset
= self
->parent
.ts
;
3512 guint i
, j
, nb_trace
, nb_tracefile
;
3516 LttvTracefileState
*tfs
;
3518 LttvHooks
*after_trace
= lttv_hooks_new();
3520 lttv_hooks_add(after_trace
,
3521 state_save_after_trace_hook
,
3526 lttv_process_traceset_end(&self
->parent
,
3527 NULL
, after_trace
, NULL
, NULL
, NULL
);
3529 lttv_hooks_destroy(after_trace
);
3531 nb_trace
= lttv_traceset_number(traceset
);
3532 for(i
= 0 ; i
< nb_trace
; i
++) {
3534 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3535 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3537 if(ts
->has_precomputed_states
) continue;
3539 guint
*event_count
= NULL
;
3541 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3543 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3544 LttvTracefileContext
*, j
));
3545 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3546 state_save_event_hook
);
3548 if(event_count
) g_free(event_count
);
3552 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3554 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3556 lttv_state_save_remove_event_hooks(tss
);
3561 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3563 LttvTraceset
*traceset
= self
->parent
.ts
;
3567 int min_pos
, mid_pos
, max_pos
;
3569 guint call_rest
= 0;
3571 LttvTraceState
*tcs
;
3573 LttvAttributeValue value
;
3575 LttvAttributeType type
;
3577 LttvAttributeName name
;
3581 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3583 //g_tree_destroy(self->parent.pqueue);
3584 //self->parent.pqueue = g_tree_new(compare_tracefile);
3586 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3588 nb_trace
= lttv_traceset_number(traceset
);
3589 for(i
= 0 ; i
< nb_trace
; i
++) {
3590 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3592 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3593 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3594 LTTV_STATE_SAVED_STATES
);
3597 if(saved_states_tree
) {
3598 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3599 mid_pos
= max_pos
/ 2;
3600 while(min_pos
< max_pos
) {
3601 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3603 g_assert(type
== LTTV_GOBJECT
);
3604 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3605 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3607 g_assert(type
== LTTV_TIME
);
3608 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3610 closest_tree
= saved_state_tree
;
3612 else max_pos
= mid_pos
- 1;
3614 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3618 /* restore the closest earlier saved state */
3620 lttv_state_restore(tcs
, closest_tree
);
3624 /* There is no saved state, yet we want to have it. Restart at T0 */
3626 restore_init_state(tcs
);
3627 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3630 /* We want to seek quickly without restoring/updating the state */
3632 restore_init_state(tcs
);
3633 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3636 if(!call_rest
) g_info("NOT Calling restore");
3641 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3647 traceset_state_finalize (LttvTracesetState
*self
)
3649 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3650 finalize(G_OBJECT(self
));
3655 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3657 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3659 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3660 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3661 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3662 klass
->new_traceset_context
= new_traceset_context
;
3663 klass
->new_trace_context
= new_trace_context
;
3664 klass
->new_tracefile_context
= new_tracefile_context
;
3669 lttv_traceset_state_get_type(void)
3671 static GType type
= 0;
3673 static const GTypeInfo info
= {
3674 sizeof (LttvTracesetStateClass
),
3675 NULL
, /* base_init */
3676 NULL
, /* base_finalize */
3677 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3678 NULL
, /* class_finalize */
3679 NULL
, /* class_data */
3680 sizeof (LttvTracesetState
),
3681 0, /* n_preallocs */
3682 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3683 NULL
/* value handling */
3686 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3694 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3700 trace_state_finalize (LttvTraceState
*self
)
3702 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3703 finalize(G_OBJECT(self
));
3708 trace_state_class_init (LttvTraceStateClass
*klass
)
3710 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3712 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3713 klass
->state_save
= state_save
;
3714 klass
->state_restore
= state_restore
;
3715 klass
->state_saved_free
= state_saved_free
;
3720 lttv_trace_state_get_type(void)
3722 static GType type
= 0;
3724 static const GTypeInfo info
= {
3725 sizeof (LttvTraceStateClass
),
3726 NULL
, /* base_init */
3727 NULL
, /* base_finalize */
3728 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3729 NULL
, /* class_finalize */
3730 NULL
, /* class_data */
3731 sizeof (LttvTraceState
),
3732 0, /* n_preallocs */
3733 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3734 NULL
/* value handling */
3737 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3738 "LttvTraceStateType", &info
, 0);
3745 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3751 tracefile_state_finalize (LttvTracefileState
*self
)
3753 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3754 finalize(G_OBJECT(self
));
3759 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3761 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3763 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3768 lttv_tracefile_state_get_type(void)
3770 static GType type
= 0;
3772 static const GTypeInfo info
= {
3773 sizeof (LttvTracefileStateClass
),
3774 NULL
, /* base_init */
3775 NULL
, /* base_finalize */
3776 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3777 NULL
, /* class_finalize */
3778 NULL
, /* class_data */
3779 sizeof (LttvTracefileState
),
3780 0, /* n_preallocs */
3781 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3782 NULL
/* value handling */
3785 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3786 "LttvTracefileStateType", &info
, 0);
3792 static void module_init()
3794 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3795 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3796 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3797 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3798 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3799 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3800 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3801 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3802 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3803 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3804 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3805 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3806 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3807 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3808 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3809 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3810 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3811 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3812 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3813 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3814 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3815 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3816 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3817 LTTV_STATE_EVENT
= g_quark_from_string("event");
3818 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3819 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3820 LTTV_STATE_TIME
= g_quark_from_string("time");
3821 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3822 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3823 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3824 g_quark_from_string("trace_state_use_count");
3825 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3826 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3827 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3830 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3831 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3832 LTT_FACILITY_FS
= g_quark_from_string("fs");
3833 LTT_FACILITY_LIST
= g_quark_from_string("list");
3834 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3835 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3838 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3839 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3840 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3841 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3842 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3843 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3844 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3845 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3846 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3847 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3848 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3849 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3850 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3851 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3852 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3853 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3854 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3855 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3856 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3857 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3858 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3859 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3862 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3863 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3864 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3865 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3866 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3867 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3868 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3869 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3870 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3871 LTT_FIELD_PID
= g_quark_from_string("pid");
3872 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3873 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3874 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3875 LTT_FIELD_NAME
= g_quark_from_string("name");
3876 LTT_FIELD_TYPE
= g_quark_from_string("type");
3877 LTT_FIELD_MODE
= g_quark_from_string("mode");
3878 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3879 LTT_FIELD_STATUS
= g_quark_from_string("status");
3880 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3881 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3882 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3883 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3884 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3885 LTT_FIELD_ACTION
= g_quark_from_string("action");
3886 LTT_FIELD_NUM
= g_quark_from_string("num");
3888 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3889 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3890 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3891 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3892 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3894 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3895 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3896 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3898 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3899 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3900 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3901 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3904 static void module_destroy()
3909 LTTV_MODULE("state", "State computation", \
3910 "Update the system state, possibly saving it at intervals", \
3911 module_init
, module_destroy
)