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>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_USER_GENERIC
,
58 LTT_EVENT_SYSCALL_ENTRY
,
59 LTT_EVENT_SYSCALL_EXIT
,
64 LTT_EVENT_SOFT_IRQ_ENTRY
,
65 LTT_EVENT_SOFT_IRQ_EXIT
,
66 LTT_EVENT_SCHED_SCHEDULE
,
67 LTT_EVENT_PROCESS_FORK
,
68 LTT_EVENT_KTHREAD_CREATE
,
69 LTT_EVENT_PROCESS_EXIT
,
70 LTT_EVENT_PROCESS_FREE
,
72 LTT_EVENT_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
,
77 LTT_EVENT_REQUEST_ISSUE
,
78 LTT_EVENT_REQUEST_COMPLETE
,
79 LTT_EVENT_LIST_INTERRUPT
;
87 LTT_FIELD_SOFT_IRQ_ID
,
111 LTTV_STATE_MODE_UNKNOWN
,
112 LTTV_STATE_USER_MODE
,
119 LTTV_STATE_SUBMODE_UNKNOWN
,
120 LTTV_STATE_SUBMODE_NONE
;
124 LTTV_STATE_WAIT_FORK
,
133 LTTV_STATE_UNBRANDED
;
136 LTTV_STATE_USER_THREAD
,
137 LTTV_STATE_KERNEL_THREAD
;
154 LTTV_BDEV_BUSY_READING
,
155 LTTV_BDEV_BUSY_WRITING
;
158 LTTV_STATE_TRACEFILES
,
159 LTTV_STATE_PROCESSES
,
161 LTTV_STATE_RUNNING_PROCESS
,
163 LTTV_STATE_SAVED_STATES
,
164 LTTV_STATE_SAVED_STATES_TIME
,
167 LTTV_STATE_NAME_TABLES
,
168 LTTV_STATE_TRACE_STATE_USE_COUNT
,
169 LTTV_STATE_RESOURCE_CPUS
,
170 LTTV_STATE_RESOURCE_IRQS
,
171 LTTV_STATE_RESOURCE_BLKDEVS
;
173 static void create_max_time(LttvTraceState
*tcs
);
175 static void get_max_time(LttvTraceState
*tcs
);
177 static void free_max_time(LttvTraceState
*tcs
);
179 static void create_name_tables(LttvTraceState
*tcs
);
181 static void get_name_tables(LttvTraceState
*tcs
);
183 static void free_name_tables(LttvTraceState
*tcs
);
185 static void free_saved_state(LttvTraceState
*tcs
);
187 static void lttv_state_free_process_table(GHashTable
*processes
);
189 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
190 GPtrArray
*quarktable
);
192 /* Resource function prototypes */
193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
194 static LttvBdevState
*bdevstate_new(void);
195 static void bdevstate_free(LttvBdevState
*);
196 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
197 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
198 static LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
);
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
)
1624 GString
*fe_name
= g_string_new("");
1626 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1628 LttvAttributeValue v
;
1630 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1632 g_assert(*(v
.v_pointer
) == NULL
);
1633 *(v
.v_pointer
) = name_tables
;
1635 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1636 LTT_EVENT_SYSCALL_ENTRY
,
1637 LTT_FIELD_SYSCALL_ID
, 0, 0,
1640 thf
= lttv_trace_hook_get_first(&h
);
1642 t
= ltt_field_type(thf
->f1
);
1643 nb
= ltt_type_element_number(t
);
1645 lttv_trace_hook_destroy(&h
);
1647 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1648 name_tables
->nb_syscalls
= nb
;
1650 for(i
= 0 ; i
< nb
; i
++) {
1651 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1652 if(!name_tables
->syscall_names
[i
]) {
1653 GString
*string
= g_string_new("");
1654 g_string_printf(string
, "syscall %u", i
);
1655 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1656 g_string_free(string
, TRUE
);
1660 //name_tables->syscall_names = g_new(GQuark, 256);
1661 //for(i = 0 ; i < 256 ; i++) {
1662 // g_string_printf(fe_name, "syscall %d", i);
1663 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1666 name_tables
->syscall_names
= NULL
;
1667 name_tables
->nb_syscalls
= 0;
1670 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1671 LTT_EVENT_TRAP_ENTRY
,
1672 LTT_FIELD_TRAP_ID
, 0, 0,
1675 thf
= lttv_trace_hook_get_first(&h
);
1677 t
= ltt_field_type(thf
->f1
);
1678 //nb = ltt_type_element_number(t);
1680 lttv_trace_hook_destroy(&h
);
1683 name_tables->trap_names = g_new(GQuark, nb);
1684 for(i = 0 ; i < nb ; i++) {
1685 name_tables->trap_names[i] = g_quark_from_string(
1686 ltt_enum_string_get(t, i));
1689 name_tables
->nb_traps
= 256;
1690 name_tables
->trap_names
= g_new(GQuark
, 256);
1691 for(i
= 0 ; i
< 256 ; i
++) {
1692 g_string_printf(fe_name
, "trap %d", i
);
1693 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1696 name_tables
->trap_names
= NULL
;
1697 name_tables
->nb_traps
= 0;
1700 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1701 LTT_EVENT_IRQ_ENTRY
,
1702 LTT_FIELD_IRQ_ID
, 0, 0,
1705 thf
= lttv_trace_hook_get_first(&h
);
1707 t
= ltt_field_type(thf
->f1
);
1708 //nb = ltt_type_element_number(t);
1710 lttv_trace_hook_destroy(&h
);
1713 name_tables->irq_names = g_new(GQuark, nb);
1714 for(i = 0 ; i < nb ; i++) {
1715 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1719 name_tables
->nb_irqs
= 256;
1720 name_tables
->irq_names
= g_new(GQuark
, 256);
1721 for(i
= 0 ; i
< 256 ; i
++) {
1722 g_string_printf(fe_name
, "irq %d", i
);
1723 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1726 name_tables
->nb_irqs
= 0;
1727 name_tables
->irq_names
= NULL
;
1730 name_tables->soft_irq_names = g_new(GQuark, nb);
1731 for(i = 0 ; i < nb ; i++) {
1732 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1736 name_tables
->nb_softirqs
= 256;
1737 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1738 for(i
= 0 ; i
< 256 ; i
++) {
1739 g_string_printf(fe_name
, "softirq %d", i
);
1740 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1744 g_string_free(fe_name
, TRUE
);
1749 get_name_tables(LttvTraceState
*tcs
)
1751 LttvNameTables
*name_tables
;
1753 LttvAttributeValue v
;
1755 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1757 g_assert(*(v
.v_pointer
) != NULL
);
1758 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1759 //tcs->eventtype_names = name_tables->eventtype_names;
1760 tcs
->syscall_names
= name_tables
->syscall_names
;
1761 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1762 tcs
->trap_names
= name_tables
->trap_names
;
1763 tcs
->nb_traps
= name_tables
->nb_traps
;
1764 tcs
->irq_names
= name_tables
->irq_names
;
1765 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1766 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1767 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1772 free_name_tables(LttvTraceState
*tcs
)
1774 LttvNameTables
*name_tables
;
1776 LttvAttributeValue v
;
1778 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1780 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1781 *(v
.v_pointer
) = NULL
;
1783 // g_free(name_tables->eventtype_names);
1784 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1785 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1786 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1787 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1788 if(name_tables
) g_free(name_tables
);
1791 #ifdef HASH_TABLE_DEBUG
1793 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1795 LttvProcessState
*process
= (LttvProcessState
*)value
;
1797 /* Test for process corruption */
1798 guint stack_len
= process
->execution_stack
->len
;
1801 static void hash_table_check(GHashTable
*table
)
1803 g_hash_table_foreach(table
, test_process
, NULL
);
1809 /* clears the stack and sets the state passed as argument */
1810 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1812 g_array_set_size(cpust
->mode_stack
, 1);
1813 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1816 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1818 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1819 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1822 static void cpu_pop_mode(LttvCPUState
*cpust
)
1824 if(cpust
->mode_stack
->len
<= 1)
1825 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1827 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1830 /* clears the stack and sets the state passed as argument */
1831 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1833 g_array_set_size(bdevst
->mode_stack
, 1);
1834 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1837 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1839 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1840 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1843 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1845 if(bdevst
->mode_stack
->len
<= 1)
1846 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1848 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1851 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1853 g_array_set_size(irqst
->mode_stack
, 1);
1854 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1857 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1859 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1860 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1863 static void irq_pop_mode(LttvIRQState
*irqst
)
1865 if(irqst
->mode_stack
->len
<= 1)
1866 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1868 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1871 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1874 LttvExecutionState
*es
;
1876 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1877 guint cpu
= tfs
->cpu
;
1879 #ifdef HASH_TABLE_DEBUG
1880 hash_table_check(ts
->processes
);
1882 LttvProcessState
*process
= ts
->running_process
[cpu
];
1884 guint depth
= process
->execution_stack
->len
;
1886 process
->execution_stack
=
1887 g_array_set_size(process
->execution_stack
, depth
+ 1);
1890 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1892 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1895 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1896 es
->cum_cpu_time
= ltt_time_zero
;
1897 es
->s
= process
->state
->s
;
1898 process
->state
= es
;
1902 * return 1 when empty, else 0 */
1903 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1904 LttvTracefileState
*tfs
)
1906 guint depth
= process
->execution_stack
->len
;
1912 process
->execution_stack
=
1913 g_array_set_size(process
->execution_stack
, depth
- 1);
1914 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1916 process
->state
->change
= tfs
->parent
.timestamp
;
1921 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1923 guint cpu
= tfs
->cpu
;
1924 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1925 LttvProcessState
*process
= ts
->running_process
[cpu
];
1927 guint depth
= process
->execution_stack
->len
;
1929 if(process
->state
->t
!= t
){
1930 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1931 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1932 g_info("process state has %s when pop_int is %s\n",
1933 g_quark_to_string(process
->state
->t
),
1934 g_quark_to_string(t
));
1935 g_info("{ %u, %u, %s, %s, %s }\n",
1938 g_quark_to_string(process
->name
),
1939 g_quark_to_string(process
->brand
),
1940 g_quark_to_string(process
->state
->s
));
1945 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1946 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1950 process
->execution_stack
=
1951 g_array_set_size(process
->execution_stack
, depth
- 1);
1952 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1954 process
->state
->change
= tfs
->parent
.timestamp
;
1957 struct search_result
{
1958 const LttTime
*time
; /* Requested time */
1959 LttTime
*best
; /* Best result */
1962 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1964 const LttTime
*elem_time
= (const LttTime
*)a
;
1965 /* Explicit non const cast */
1966 struct search_result
*res
= (struct search_result
*)b
;
1968 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1969 /* The usertrace was created before the schedchange */
1970 /* Get larger keys */
1972 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1973 /* The usertrace was created after the schedchange time */
1974 /* Get smaller keys */
1976 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1977 res
->best
= (LttTime
*)elem_time
;
1980 res
->best
= (LttTime
*)elem_time
;
1987 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1988 guint pid
, const LttTime
*timestamp
)
1990 LttvTracefileState
*tfs
= NULL
;
1991 struct search_result res
;
1992 /* Find the usertrace associated with a pid and time interval.
1993 * Search in the usertraces by PID (within a hash) and then, for each
1994 * corresponding element of the array, find the first one with creation
1995 * timestamp the lowest, but higher or equal to "timestamp". */
1996 res
.time
= timestamp
;
1998 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1999 if(usertrace_tree
) {
2000 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2002 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2010 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2011 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2013 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2015 LttvExecutionState
*es
;
2020 process
->tgid
= tgid
;
2022 process
->name
= name
;
2023 process
->brand
= LTTV_STATE_UNBRANDED
;
2024 //process->last_cpu = tfs->cpu_name;
2025 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2026 process
->type
= LTTV_STATE_USER_THREAD
;
2027 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2028 process
->current_function
= 0; //function 0x0 by default.
2030 g_info("Process %u, core %p", process
->pid
, process
);
2031 g_hash_table_insert(tcs
->processes
, process
, process
);
2034 process
->ppid
= parent
->pid
;
2035 process
->creation_time
= *timestamp
;
2038 /* No parent. This process exists but we are missing all information about
2039 its creation. The birth time is set to zero but we remember the time of
2044 process
->creation_time
= ltt_time_zero
;
2047 process
->insertion_time
= *timestamp
;
2048 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2049 process
->creation_time
.tv_nsec
);
2050 process
->pid_time
= g_quark_from_string(buffer
);
2052 //process->last_cpu = tfs->cpu_name;
2053 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2054 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2055 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2056 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2057 es
= process
->state
= &g_array_index(process
->execution_stack
,
2058 LttvExecutionState
, 0);
2059 es
->t
= LTTV_STATE_USER_MODE
;
2060 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2061 es
->entry
= *timestamp
;
2062 //g_assert(timestamp->tv_sec != 0);
2063 es
->change
= *timestamp
;
2064 es
->cum_cpu_time
= ltt_time_zero
;
2065 es
->s
= LTTV_STATE_RUN
;
2067 es
= process
->state
= &g_array_index(process
->execution_stack
,
2068 LttvExecutionState
, 1);
2069 es
->t
= LTTV_STATE_SYSCALL
;
2070 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2071 es
->entry
= *timestamp
;
2072 //g_assert(timestamp->tv_sec != 0);
2073 es
->change
= *timestamp
;
2074 es
->cum_cpu_time
= ltt_time_zero
;
2075 es
->s
= LTTV_STATE_WAIT_FORK
;
2077 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2078 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2079 sizeof(guint64
), 0);
2084 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2087 LttvProcessState key
;
2088 LttvProcessState
*process
;
2092 process
= g_hash_table_lookup(ts
->processes
, &key
);
2097 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2098 const LttTime
*timestamp
)
2100 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2101 LttvExecutionState
*es
;
2103 /* Put ltt_time_zero creation time for unexisting processes */
2104 if(unlikely(process
== NULL
)) {
2105 process
= lttv_state_create_process(ts
,
2106 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2107 /* We are not sure is it's a kernel thread or normal thread, put the
2108 * bottom stack state to unknown */
2109 process
->execution_stack
=
2110 g_array_set_size(process
->execution_stack
, 1);
2111 process
->state
= es
=
2112 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2113 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2114 es
->s
= LTTV_STATE_UNNAMED
;
2119 /* FIXME : this function should be called when we receive an event telling that
2120 * release_task has been called in the kernel. In happens generally when
2121 * the parent waits for its child terminaison, but may also happen in special
2122 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2123 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2124 * of a killed thread ground, but isn't the leader.
2126 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2128 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2129 LttvProcessState key
;
2131 key
.pid
= process
->pid
;
2132 key
.cpu
= process
->cpu
;
2133 g_hash_table_remove(ts
->processes
, &key
);
2134 g_array_free(process
->execution_stack
, TRUE
);
2135 g_array_free(process
->user_stack
, TRUE
);
2140 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2142 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2143 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2148 static void lttv_state_free_process_table(GHashTable
*processes
)
2150 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2151 g_hash_table_destroy(processes
);
2155 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2157 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2159 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2160 LttvProcessState
*process
= ts
->running_process
[cpu
];
2161 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2162 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2163 LttField
*f
= thf
->f1
;
2165 LttvExecutionSubmode submode
;
2167 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2168 guint syscall
= ltt_event_get_unsigned(e
, f
);
2170 if(syscall
< nb_syscalls
) {
2171 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2174 /* Fixup an incomplete syscall table */
2175 GString
*string
= g_string_new("");
2176 g_string_printf(string
, "syscall %u", syscall
);
2177 submode
= g_quark_from_string(string
->str
);
2178 g_string_free(string
, TRUE
);
2180 /* There can be no system call from PID 0 : unknown state */
2181 if(process
->pid
!= 0)
2182 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2187 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2189 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2191 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2192 LttvProcessState
*process
= ts
->running_process
[cpu
];
2194 /* There can be no system call from PID 0 : unknown state */
2195 if(process
->pid
!= 0)
2196 pop_state(s
, LTTV_STATE_SYSCALL
);
2201 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2203 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2204 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2205 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2206 LttField
*f
= thf
->f1
;
2208 LttvExecutionSubmode submode
;
2210 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2211 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2213 if(trap
< nb_traps
) {
2214 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2216 /* Fixup an incomplete trap table */
2217 GString
*string
= g_string_new("");
2218 g_string_printf(string
, "trap %llu", trap
);
2219 submode
= g_quark_from_string(string
->str
);
2220 g_string_free(string
, TRUE
);
2223 push_state(s
, LTTV_STATE_TRAP
, submode
);
2225 /* update cpu status */
2226 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2231 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2233 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2235 pop_state(s
, LTTV_STATE_TRAP
);
2237 /* update cpu status */
2238 cpu_pop_mode(s
->cpu_state
);
2243 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2245 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2246 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2247 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2248 guint8 fac_id
= ltt_event_facility_id(e
);
2249 guint8 ev_id
= ltt_event_eventtype_id(e
);
2250 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2251 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2252 g_assert(thf
->f1
!= NULL
);
2253 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2254 LttField
*f
= thf
->f1
;
2256 LttvExecutionSubmode submode
;
2257 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2258 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2262 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2264 /* Fixup an incomplete irq table */
2265 GString
*string
= g_string_new("");
2266 g_string_printf(string
, "irq %llu", irq
);
2267 submode
= g_quark_from_string(string
->str
);
2268 g_string_free(string
, TRUE
);
2271 /* Do something with the info about being in user or system mode when int? */
2272 push_state(s
, LTTV_STATE_IRQ
, submode
);
2274 /* update cpu status */
2275 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2277 /* update irq status */
2278 s
->cpu_state
->last_irq
= irq
;
2279 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2284 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2286 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2288 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2294 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2296 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2297 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2299 pop_state(s
, LTTV_STATE_IRQ
);
2301 /* update cpu status */
2302 cpu_pop_mode(s
->cpu_state
);
2304 /* update irq status */
2305 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2310 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2312 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2313 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2314 guint8 fac_id
= ltt_event_facility_id(e
);
2315 guint8 ev_id
= ltt_event_eventtype_id(e
);
2316 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2317 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2318 g_assert(thf
->f1
!= NULL
);
2319 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2320 LttField
*f
= thf
->f1
;
2322 LttvExecutionSubmode submode
;
2323 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2324 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2327 if(softirq
< nb_softirqs
) {
2328 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2330 /* Fixup an incomplete irq table */
2331 GString
*string
= g_string_new("");
2332 g_string_printf(string
, "softirq %llu", softirq
);
2333 submode
= g_quark_from_string(string
->str
);
2334 g_string_free(string
, TRUE
);
2337 /* Do something with the info about being in user or system mode when int? */
2338 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2342 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2344 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2345 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2346 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2347 guint8 fac_id
= ltt_event_facility_id(e
);
2348 guint8 ev_id
= ltt_event_eventtype_id(e
);
2349 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2351 GQuark action
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2352 guint irq
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2354 ts
->irq_names
[irq
] = action
;
2360 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2362 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2363 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2364 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2365 guint8 fac_id
= ltt_event_facility_id(e
);
2366 guint8 ev_id
= ltt_event_eventtype_id(e
);
2367 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2369 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2370 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2371 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2372 guint16 devcode
= MKDEV(major
,minor
);
2374 /* have we seen this block device before? */
2375 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2378 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2380 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2385 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2387 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2388 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2389 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2390 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2392 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2393 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2394 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2395 guint16 devcode
= MKDEV(major
,minor
);
2397 /* have we seen this block device before? */
2398 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2400 /* update block device */
2401 bdev_pop_mode(bdev
);
2406 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2410 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2411 guint cpu
= tfs
->cpu
;
2412 LttvProcessState
*process
= ts
->running_process
[cpu
];
2414 guint depth
= process
->user_stack
->len
;
2416 process
->user_stack
=
2417 g_array_set_size(process
->user_stack
, depth
+ 1);
2419 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2420 *new_func
= funcptr
;
2421 process
->current_function
= funcptr
;
2424 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2426 guint cpu
= tfs
->cpu
;
2427 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2428 LttvProcessState
*process
= ts
->running_process
[cpu
];
2430 if(process
->current_function
!= funcptr
){
2431 g_info("Different functions (%lu.%09lu): ignore it\n",
2432 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2433 g_info("process state has %llu when pop_function is %llu\n",
2434 process
->current_function
, funcptr
);
2435 g_info("{ %u, %u, %s, %s, %s }\n",
2438 g_quark_to_string(process
->name
),
2439 g_quark_to_string(process
->brand
),
2440 g_quark_to_string(process
->state
->s
));
2443 guint depth
= process
->user_stack
->len
;
2446 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2447 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2451 process
->user_stack
=
2452 g_array_set_size(process
->user_stack
, depth
- 1);
2453 process
->current_function
=
2454 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2458 static gboolean
function_entry(void *hook_data
, void *call_data
)
2460 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2461 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2462 guint8 fac_id
= ltt_event_facility_id(e
);
2463 guint8 ev_id
= ltt_event_eventtype_id(e
);
2464 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2465 g_assert(thf
->f1
!= NULL
);
2466 LttField
*f
= thf
->f1
;
2467 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2469 push_function(s
, funcptr
);
2473 static gboolean
function_exit(void *hook_data
, void *call_data
)
2475 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2476 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2477 guint8 fac_id
= ltt_event_facility_id(e
);
2478 guint8 ev_id
= ltt_event_eventtype_id(e
);
2479 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2480 g_assert(thf
->f1
!= NULL
);
2481 LttField
*f
= thf
->f1
;
2482 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2484 LttvExecutionSubmode submode
;
2486 pop_function(s
, funcptr
);
2490 static gboolean
schedchange(void *hook_data
, void *call_data
)
2492 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2494 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2495 LttvProcessState
*process
= ts
->running_process
[cpu
];
2496 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2498 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2499 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2500 guint pid_in
, pid_out
;
2503 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2504 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2505 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2507 if(likely(process
!= NULL
)) {
2509 /* We could not know but it was not the idle process executing.
2510 This should only happen at the beginning, before the first schedule
2511 event, and when the initial information (current process for each CPU)
2512 is missing. It is not obvious how we could, after the fact, compensate
2513 the wrongly attributed statistics. */
2515 //This test only makes sense once the state is known and if there is no
2516 //missing events. We need to silently ignore schedchange coming after a
2517 //process_free, or it causes glitches. (FIXME)
2518 //if(unlikely(process->pid != pid_out)) {
2519 // g_assert(process->pid == 0);
2521 if(process
->pid
== 0
2522 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2524 /* Scheduling out of pid 0 at beginning of the trace :
2525 * we know for sure it is in syscall mode at this point. */
2526 g_assert(process
->execution_stack
->len
== 1);
2527 process
->state
->t
= LTTV_STATE_SYSCALL
;
2528 process
->state
->s
= LTTV_STATE_WAIT
;
2529 process
->state
->change
= s
->parent
.timestamp
;
2530 process
->state
->entry
= s
->parent
.timestamp
;
2533 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2534 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2535 process
->state
->change
= s
->parent
.timestamp
;
2537 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2538 else process
->state
->s
= LTTV_STATE_WAIT
;
2539 process
->state
->change
= s
->parent
.timestamp
;
2542 if(state_out
== 32 || state_out
== 128)
2543 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2544 /* see sched.h for states */
2547 process
= ts
->running_process
[cpu
] =
2548 lttv_state_find_process_or_create(
2549 (LttvTraceState
*)s
->parent
.t_context
,
2551 &s
->parent
.timestamp
);
2552 process
->state
->s
= LTTV_STATE_RUN
;
2554 if(process
->usertrace
)
2555 process
->usertrace
->cpu
= cpu
;
2556 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2557 process
->state
->change
= s
->parent
.timestamp
;
2559 /* update cpu status */
2561 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2563 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2568 static gboolean
process_fork(void *hook_data
, void *call_data
)
2570 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2571 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2572 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2574 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2575 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2576 LttvProcessState
*zombie_process
;
2578 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2579 LttvProcessState
*process
= ts
->running_process
[cpu
];
2580 LttvProcessState
*child_process
;
2583 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2586 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2587 s
->parent
.target_pid
= child_pid
;
2590 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2591 else child_tgid
= 0;
2593 /* Mathieu : it seems like the process might have been scheduled in before the
2594 * fork, and, in a rare case, might be the current process. This might happen
2595 * in a SMP case where we don't have enough precision on the clocks.
2597 * Test reenabled after precision fixes on time. (Mathieu) */
2599 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2601 if(unlikely(zombie_process
!= NULL
)) {
2602 /* Reutilisation of PID. Only now we are sure that the old PID
2603 * has been released. FIXME : should know when release_task happens instead.
2605 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2607 for(i
=0; i
< num_cpus
; i
++) {
2608 g_assert(zombie_process
!= ts
->running_process
[i
]);
2611 exit_process(s
, zombie_process
);
2614 g_assert(process
->pid
!= child_pid
);
2615 // FIXME : Add this test in the "known state" section
2616 // g_assert(process->pid == parent_pid);
2617 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2618 if(child_process
== NULL
) {
2619 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2620 child_pid
, child_tgid
,
2621 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2623 /* The process has already been created : due to time imprecision between
2624 * multiple CPUs : it has been scheduled in before creation. Note that we
2625 * shouldn't have this kind of imprecision.
2627 * Simply put a correct parent.
2629 g_assert(0); /* This is a problematic case : the process has been created
2630 before the fork event */
2631 child_process
->ppid
= process
->pid
;
2632 child_process
->tgid
= child_tgid
;
2634 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2635 child_process
->name
= process
->name
;
2636 child_process
->brand
= process
->brand
;
2641 /* We stamp a newly created process as kernel_thread.
2642 * The thread should not be running yet. */
2643 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2645 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2646 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2647 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2650 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2651 LttvProcessState
*process
;
2652 LttvExecutionState
*es
;
2655 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2656 s
->parent
.target_pid
= pid
;
2658 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2660 process
->execution_stack
=
2661 g_array_set_size(process
->execution_stack
, 1);
2662 es
= process
->state
=
2663 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2664 es
->t
= LTTV_STATE_SYSCALL
;
2665 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2670 static gboolean
process_exit(void *hook_data
, void *call_data
)
2672 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2673 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2674 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2678 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2679 LttvProcessState
*process
; // = ts->running_process[cpu];
2681 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2682 s
->parent
.target_pid
= pid
;
2684 // FIXME : Add this test in the "known state" section
2685 // g_assert(process->pid == pid);
2687 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2688 if(likely(process
!= NULL
)) {
2689 process
->state
->s
= LTTV_STATE_EXIT
;
2694 static gboolean
process_free(void *hook_data
, void *call_data
)
2696 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2697 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2698 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2699 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2701 LttvProcessState
*process
;
2703 /* PID of the process to release */
2704 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2705 s
->parent
.target_pid
= release_pid
;
2707 g_assert(release_pid
!= 0);
2709 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2711 if(likely(process
!= NULL
)) {
2712 /* release_task is happening at kernel level : we can now safely release
2713 * the data structure of the process */
2714 //This test is fun, though, as it may happen that
2715 //at time t : CPU 0 : process_free
2716 //at time t+150ns : CPU 1 : schedule out
2717 //Clearly due to time imprecision, we disable it. (Mathieu)
2718 //If this weird case happen, we have no choice but to put the
2719 //Currently running process on the cpu to 0.
2720 //I re-enable it following time precision fixes. (Mathieu)
2721 //Well, in the case where an process is freed by a process on another CPU
2722 //and still scheduled, it happens that this is the schedchange that will
2723 //drop the last reference count. Do not free it here!
2724 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2726 for(i
=0; i
< num_cpus
; i
++) {
2727 //g_assert(process != ts->running_process[i]);
2728 if(process
== ts
->running_process
[i
]) {
2729 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2733 if(i
== num_cpus
) /* process is not scheduled */
2734 exit_process(s
, process
);
2741 static gboolean
process_exec(void *hook_data
, void *call_data
)
2743 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2744 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2745 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2746 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2749 LttvProcessState
*process
= ts
->running_process
[cpu
];
2751 #if 0//how to use a sequence that must be transformed in a string
2752 /* PID of the process to release */
2753 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2754 //name = ltt_event_get_string(e, thf->f1);
2755 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2757 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2758 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2759 memcpy(null_term_name
, name_begin
, name_len
);
2760 null_term_name
[name_len
] = '\0';
2761 process
->name
= g_quark_from_string(null_term_name
);
2764 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2765 process
->brand
= LTTV_STATE_UNBRANDED
;
2766 //g_free(null_term_name);
2770 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2772 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2773 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2774 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2775 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2778 LttvProcessState
*process
= ts
->running_process
[cpu
];
2780 name
= ltt_event_get_string(e
, thf
->f1
);
2781 process
->brand
= g_quark_from_string(name
);
2786 static void fix_process(gpointer key
, gpointer value
,
2789 LttvProcessState
*process
;
2790 LttvExecutionState
*es
;
2791 process
= (LttvProcessState
*)value
;
2792 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2793 LttTime
*timestamp
= (LttTime
*)user_data
;
2795 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2796 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2797 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2798 es
->t
= LTTV_STATE_SYSCALL
;
2799 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2800 es
->entry
= *timestamp
;
2801 es
->change
= *timestamp
;
2802 es
->cum_cpu_time
= ltt_time_zero
;
2803 if(es
->s
== LTTV_STATE_UNNAMED
)
2804 es
->s
= LTTV_STATE_WAIT
;
2807 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2808 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2809 es
->t
= LTTV_STATE_USER_MODE
;
2810 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2811 es
->entry
= *timestamp
;
2812 //g_assert(timestamp->tv_sec != 0);
2813 es
->change
= *timestamp
;
2814 es
->cum_cpu_time
= ltt_time_zero
;
2815 if(es
->s
== LTTV_STATE_UNNAMED
)
2816 es
->s
= LTTV_STATE_RUN
;
2818 if(process
->execution_stack
->len
== 1) {
2819 /* Still in bottom unknown mode, means never did a system call
2820 * May be either in user mode, syscall mode, running or waiting.*/
2821 /* FIXME : we may be tagging syscall mode when being user mode */
2822 process
->execution_stack
=
2823 g_array_set_size(process
->execution_stack
, 2);
2824 es
= process
->state
= &g_array_index(process
->execution_stack
,
2825 LttvExecutionState
, 1);
2826 es
->t
= LTTV_STATE_SYSCALL
;
2827 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2828 es
->entry
= *timestamp
;
2829 //g_assert(timestamp->tv_sec != 0);
2830 es
->change
= *timestamp
;
2831 es
->cum_cpu_time
= ltt_time_zero
;
2832 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2833 es
->s
= LTTV_STATE_WAIT
;
2839 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2841 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2842 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2843 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2844 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2845 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2847 /* For all processes */
2848 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2849 /* else, if stack[0] is unknown, set to user mode, running */
2851 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2854 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2856 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2857 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2858 //It's slow : optimise later by doing this before reading trace.
2859 LttEventType
*et
= ltt_event_eventtype(e
);
2861 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2867 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2868 LttvProcessState
*process
= ts
->running_process
[cpu
];
2869 LttvProcessState
*parent_process
;
2870 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2871 GQuark type
, mode
, submode
, status
;
2872 LttvExecutionState
*es
;
2876 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2877 s
->parent
.target_pid
= pid
;
2880 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2883 command
= ltt_event_get_string(e
, thf
->f3
);
2886 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2887 type
= ltt_enum_string_get(ltt_field_type(f4
),
2888 ltt_event_get_unsigned(e
, f4
));
2891 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2892 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2893 ltt_event_get_unsigned(e
, f5
));
2896 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2897 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2898 ltt_event_get_unsigned(e
, f6
));
2901 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2902 status
= ltt_enum_string_get(ltt_field_type(f7
),
2903 ltt_event_get_unsigned(e
, f7
));
2906 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2907 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2912 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2913 for(i
=0; i
<nb_cpus
; i
++) {
2914 process
= lttv_state_find_process(ts
, i
, pid
);
2915 g_assert(process
!= NULL
);
2917 process
->ppid
= parent_pid
;
2918 process
->tgid
= tgid
;
2919 process
->name
= g_quark_from_string(command
);
2921 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2922 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2926 /* The process might exist if a process was forked while performing the
2928 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2929 if(process
== NULL
) {
2930 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2931 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2932 pid
, tgid
, g_quark_from_string(command
),
2933 &s
->parent
.timestamp
);
2935 /* Keep the stack bottom : a running user mode */
2936 /* Disabled because of inconsistencies in the current statedump states. */
2937 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2938 /* Only keep the bottom
2939 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2940 /* Will cause expected trap when in fact being syscall (even after end of
2942 * Will cause expected interrupt when being syscall. (only before end of
2943 * statedump event) */
2944 // This will cause a "popping last state on stack, ignoring it."
2945 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2946 es
= process
->state
= &g_array_index(process
->execution_stack
,
2947 LttvExecutionState
, 0);
2948 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2949 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2950 es
->s
= LTTV_STATE_UNNAMED
;
2951 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2953 es
->t
= LTTV_STATE_SYSCALL
;
2958 /* User space process :
2959 * bottom : user mode
2960 * either currently running or scheduled out.
2961 * can be scheduled out because interrupted in (user mode or in syscall)
2962 * or because of an explicit call to the scheduler in syscall. Note that
2963 * the scheduler call comes after the irq_exit, so never in interrupt
2965 // temp workaround : set size to 1 : only have user mode bottom of stack.
2966 // will cause g_info message of expected syscall mode when in fact being
2967 // in user mode. Can also cause expected trap when in fact being user
2968 // mode in the event of a page fault reenabling interrupts in the handler.
2969 // Expected syscall and trap can also happen after the end of statedump
2970 // This will cause a "popping last state on stack, ignoring it."
2971 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2972 es
= process
->state
= &g_array_index(process
->execution_stack
,
2973 LttvExecutionState
, 0);
2974 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2975 es
->s
= LTTV_STATE_UNNAMED
;
2976 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2978 es
->t
= LTTV_STATE_USER_MODE
;
2986 es
= process
->state
= &g_array_index(process
->execution_stack
,
2987 LttvExecutionState
, 1);
2988 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2989 es
->s
= LTTV_STATE_UNNAMED
;
2990 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2994 /* The process has already been created :
2995 * Probably was forked while dumping the process state or
2996 * was simply scheduled in prior to get the state dump event.
2998 process
->ppid
= parent_pid
;
2999 process
->tgid
= tgid
;
3000 process
->name
= g_quark_from_string(command
);
3001 process
->type
= type
;
3003 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3005 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3006 if(type
== LTTV_STATE_KERNEL_THREAD
)
3007 es
->t
= LTTV_STATE_SYSCALL
;
3009 es
->t
= LTTV_STATE_USER_MODE
;
3012 /* Don't mess around with the stack, it will eventually become
3013 * ok after the end of state dump. */
3020 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3022 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3024 lttv_state_add_event_hooks(tss
);
3029 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3031 LttvTraceset
*traceset
= self
->parent
.ts
;
3033 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3037 LttvTracefileState
*tfs
;
3041 LttvTraceHookByFacility
*thf
;
3043 LttvTraceHook
*hook
;
3045 LttvAttributeValue val
;
3050 nb_trace
= lttv_traceset_number(traceset
);
3051 for(i
= 0 ; i
< nb_trace
; i
++) {
3052 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3054 /* Find the eventtype id for the following events and register the
3055 associated by id hooks. */
3057 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3058 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
3061 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3062 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3063 LTT_FIELD_SYSCALL_ID
, 0, 0,
3064 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3067 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3068 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3070 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3073 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3074 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
3075 LTT_FIELD_TRAP_ID
, 0, 0,
3076 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3079 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3080 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3082 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3085 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3086 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3087 LTT_FIELD_IRQ_ID
, 0, 0,
3088 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3091 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3092 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3094 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3097 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3098 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3099 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3100 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3103 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3104 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3106 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3109 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3110 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3111 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3112 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3115 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3116 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3117 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3118 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3121 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3122 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3123 LTT_FIELD_PID
, 0, 0,
3124 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3128 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3129 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3130 LTT_FIELD_PID
, 0, 0,
3131 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3134 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3135 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3136 LTT_FIELD_PID
, 0, 0,
3137 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3140 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3141 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3142 LTT_FIELD_FILENAME
, 0, 0,
3143 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3146 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3147 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3148 LTT_FIELD_NAME
, 0, 0,
3149 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3152 /* statedump-related hooks */
3153 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3154 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3155 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3156 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3159 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3160 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3162 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3165 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3166 LTT_FACILITY_LIST
, LTT_EVENT_LIST_INTERRUPT
,
3167 LTT_FIELD_ACTION
, LTT_FIELD_NUM
, 0,
3168 enum_interrupt
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3171 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3172 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3173 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3174 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3177 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3178 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3179 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3180 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3183 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3184 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3185 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3186 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3189 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3190 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3191 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3192 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3195 hooks
= g_array_set_size(hooks
, hn
);
3197 /* Add these hooks to each event_by_id hooks list */
3199 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3201 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3203 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3204 LttvTracefileContext
*, j
));
3206 for(k
= 0 ; k
< hooks
->len
; k
++) {
3207 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3208 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3209 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3211 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3218 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3219 *(val
.v_pointer
) = hooks
;
3223 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3225 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3227 lttv_state_remove_event_hooks(tss
);
3232 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3234 LttvTraceset
*traceset
= self
->parent
.ts
;
3236 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3240 LttvTracefileState
*tfs
;
3244 LttvTraceHook
*hook
;
3246 LttvTraceHookByFacility
*thf
;
3248 LttvAttributeValue val
;
3250 nb_trace
= lttv_traceset_number(traceset
);
3251 for(i
= 0 ; i
< nb_trace
; i
++) {
3252 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3254 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3255 hooks
= *(val
.v_pointer
);
3257 /* Remove these hooks from each event_by_id hooks list */
3259 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3261 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3263 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3264 LttvTracefileContext
*, j
));
3266 for(k
= 0 ; k
< hooks
->len
; k
++) {
3267 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3268 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3269 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3271 lttv_hooks_remove_data(
3272 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3278 for(k
= 0 ; k
< hooks
->len
; k
++)
3279 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3280 g_array_free(hooks
, TRUE
);
3284 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3286 guint
*event_count
= (guint
*)hook_data
;
3288 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3289 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3294 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3296 LttvTracefileState
*tfcs
;
3298 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3300 LttEventPosition
*ep
;
3306 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3308 LttvAttributeValue value
;
3310 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3311 LTTV_STATE_SAVED_STATES
);
3312 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3313 value
= lttv_attribute_add(saved_states_tree
,
3314 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3315 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3316 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3317 *(value
.v_time
) = self
->parent
.timestamp
;
3318 lttv_state_save(tcs
, saved_state_tree
);
3319 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3320 self
->parent
.timestamp
.tv_nsec
);
3322 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3327 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3329 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3331 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3336 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3344 static gboolean
block_start(void *hook_data
, void *call_data
)
3346 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3348 LttvTracefileState
*tfcs
;
3350 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3352 LttEventPosition
*ep
;
3354 guint i
, nb_block
, nb_event
, nb_tracefile
;
3358 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3360 LttvAttributeValue value
;
3362 ep
= ltt_event_position_new();
3364 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3366 /* Count the number of events added since the last block end in any
3369 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3371 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3372 LttvTracefileContext
, i
));
3373 ltt_event_position(tfcs
->parent
.e
, ep
);
3374 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3375 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3376 tfcs
->saved_position
= nb_event
;
3380 if(tcs
->nb_event
>= tcs
->save_interval
) {
3381 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3382 LTTV_STATE_SAVED_STATES
);
3383 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3384 value
= lttv_attribute_add(saved_states_tree
,
3385 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3386 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3387 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3388 *(value
.v_time
) = self
->parent
.timestamp
;
3389 lttv_state_save(tcs
, saved_state_tree
);
3391 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3392 self
->parent
.timestamp
.tv_nsec
);
3394 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3400 static gboolean
block_end(void *hook_data
, void *call_data
)
3402 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3404 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3408 LttEventPosition
*ep
;
3410 guint nb_block
, nb_event
;
3412 ep
= ltt_event_position_new();
3413 ltt_event_position(self
->parent
.e
, ep
);
3414 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3415 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3416 self
->saved_position
= 0;
3417 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3424 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3426 LttvTraceset
*traceset
= self
->parent
.ts
;
3428 guint i
, j
, nb_trace
, nb_tracefile
;
3432 LttvTracefileState
*tfs
;
3434 LttvTraceHook hook_start
, hook_end
;
3436 nb_trace
= lttv_traceset_number(traceset
);
3437 for(i
= 0 ; i
< nb_trace
; i
++) {
3438 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3440 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3441 NULL
, NULL
, block_start
, &hook_start
);
3442 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3443 NULL
, NULL
, block_end
, &hook_end
);
3445 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3447 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3449 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3450 LttvTracefileContext
, j
));
3451 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3452 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3453 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3454 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3460 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3462 LttvTraceset
*traceset
= self
->parent
.ts
;
3464 guint i
, j
, nb_trace
, nb_tracefile
;
3468 LttvTracefileState
*tfs
;
3471 nb_trace
= lttv_traceset_number(traceset
);
3472 for(i
= 0 ; i
< nb_trace
; i
++) {
3474 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3475 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3477 if(ts
->has_precomputed_states
) continue;
3479 guint
*event_count
= g_new(guint
, 1);
3482 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3484 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3485 LttvTracefileContext
*, j
));
3486 lttv_hooks_add(tfs
->parent
.event
,
3487 state_save_event_hook
,
3494 lttv_process_traceset_begin(&self
->parent
,
3495 NULL
, NULL
, NULL
, NULL
, NULL
);
3499 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3501 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3503 lttv_state_save_add_event_hooks(tss
);
3510 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3512 LttvTraceset
*traceset
= self
->parent
.ts
;
3514 guint i
, j
, nb_trace
, nb_tracefile
;
3518 LttvTracefileState
*tfs
;
3520 LttvTraceHook hook_start
, hook_end
;
3522 nb_trace
= lttv_traceset_number(traceset
);
3523 for(i
= 0 ; i
< nb_trace
; i
++) {
3524 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3526 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3527 NULL
, NULL
, block_start
, &hook_start
);
3529 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3530 NULL
, NULL
, block_end
, &hook_end
);
3532 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3534 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3536 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3537 LttvTracefileContext
, j
));
3538 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3539 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3540 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3541 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3547 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3549 LttvTraceset
*traceset
= self
->parent
.ts
;
3551 guint i
, j
, nb_trace
, nb_tracefile
;
3555 LttvTracefileState
*tfs
;
3557 LttvHooks
*after_trace
= lttv_hooks_new();
3559 lttv_hooks_add(after_trace
,
3560 state_save_after_trace_hook
,
3565 lttv_process_traceset_end(&self
->parent
,
3566 NULL
, after_trace
, NULL
, NULL
, NULL
);
3568 lttv_hooks_destroy(after_trace
);
3570 nb_trace
= lttv_traceset_number(traceset
);
3571 for(i
= 0 ; i
< nb_trace
; i
++) {
3573 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3574 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3576 if(ts
->has_precomputed_states
) continue;
3578 guint
*event_count
= NULL
;
3580 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3582 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3583 LttvTracefileContext
*, j
));
3584 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3585 state_save_event_hook
);
3587 if(event_count
) g_free(event_count
);
3591 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3593 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3595 lttv_state_save_remove_event_hooks(tss
);
3600 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3602 LttvTraceset
*traceset
= self
->parent
.ts
;
3606 int min_pos
, mid_pos
, max_pos
;
3608 guint call_rest
= 0;
3610 LttvTraceState
*tcs
;
3612 LttvAttributeValue value
;
3614 LttvAttributeType type
;
3616 LttvAttributeName name
;
3620 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3622 //g_tree_destroy(self->parent.pqueue);
3623 //self->parent.pqueue = g_tree_new(compare_tracefile);
3625 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3627 nb_trace
= lttv_traceset_number(traceset
);
3628 for(i
= 0 ; i
< nb_trace
; i
++) {
3629 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3631 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3632 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3633 LTTV_STATE_SAVED_STATES
);
3636 if(saved_states_tree
) {
3637 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3638 mid_pos
= max_pos
/ 2;
3639 while(min_pos
< max_pos
) {
3640 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3642 g_assert(type
== LTTV_GOBJECT
);
3643 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3644 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3646 g_assert(type
== LTTV_TIME
);
3647 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3649 closest_tree
= saved_state_tree
;
3651 else max_pos
= mid_pos
- 1;
3653 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3657 /* restore the closest earlier saved state */
3659 lttv_state_restore(tcs
, closest_tree
);
3663 /* There is no saved state, yet we want to have it. Restart at T0 */
3665 restore_init_state(tcs
);
3666 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3669 /* We want to seek quickly without restoring/updating the state */
3671 restore_init_state(tcs
);
3672 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3675 if(!call_rest
) g_info("NOT Calling restore");
3680 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3686 traceset_state_finalize (LttvTracesetState
*self
)
3688 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3689 finalize(G_OBJECT(self
));
3694 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3696 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3698 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3699 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3700 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3701 klass
->new_traceset_context
= new_traceset_context
;
3702 klass
->new_trace_context
= new_trace_context
;
3703 klass
->new_tracefile_context
= new_tracefile_context
;
3708 lttv_traceset_state_get_type(void)
3710 static GType type
= 0;
3712 static const GTypeInfo info
= {
3713 sizeof (LttvTracesetStateClass
),
3714 NULL
, /* base_init */
3715 NULL
, /* base_finalize */
3716 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3717 NULL
, /* class_finalize */
3718 NULL
, /* class_data */
3719 sizeof (LttvTracesetState
),
3720 0, /* n_preallocs */
3721 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3722 NULL
/* value handling */
3725 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3733 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3739 trace_state_finalize (LttvTraceState
*self
)
3741 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3742 finalize(G_OBJECT(self
));
3747 trace_state_class_init (LttvTraceStateClass
*klass
)
3749 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3751 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3752 klass
->state_save
= state_save
;
3753 klass
->state_restore
= state_restore
;
3754 klass
->state_saved_free
= state_saved_free
;
3759 lttv_trace_state_get_type(void)
3761 static GType type
= 0;
3763 static const GTypeInfo info
= {
3764 sizeof (LttvTraceStateClass
),
3765 NULL
, /* base_init */
3766 NULL
, /* base_finalize */
3767 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3768 NULL
, /* class_finalize */
3769 NULL
, /* class_data */
3770 sizeof (LttvTraceState
),
3771 0, /* n_preallocs */
3772 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3773 NULL
/* value handling */
3776 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3777 "LttvTraceStateType", &info
, 0);
3784 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3790 tracefile_state_finalize (LttvTracefileState
*self
)
3792 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3793 finalize(G_OBJECT(self
));
3798 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3800 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3802 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3807 lttv_tracefile_state_get_type(void)
3809 static GType type
= 0;
3811 static const GTypeInfo info
= {
3812 sizeof (LttvTracefileStateClass
),
3813 NULL
, /* base_init */
3814 NULL
, /* base_finalize */
3815 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3816 NULL
, /* class_finalize */
3817 NULL
, /* class_data */
3818 sizeof (LttvTracefileState
),
3819 0, /* n_preallocs */
3820 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3821 NULL
/* value handling */
3824 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3825 "LttvTracefileStateType", &info
, 0);
3831 static void module_init()
3833 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3834 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3835 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3836 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3837 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3838 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3839 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3840 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3841 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3842 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3843 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3844 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3845 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3846 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3847 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3848 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3849 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3850 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3851 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3852 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3853 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3854 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3855 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3856 LTTV_STATE_EVENT
= g_quark_from_string("event");
3857 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3858 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3859 LTTV_STATE_TIME
= g_quark_from_string("time");
3860 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3861 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3862 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3863 g_quark_from_string("trace_state_use_count");
3864 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3865 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3866 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3869 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3870 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3871 LTT_FACILITY_FS
= g_quark_from_string("fs");
3872 LTT_FACILITY_LIST
= g_quark_from_string("list");
3873 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3874 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3877 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3878 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3879 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3880 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3881 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3882 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3883 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3884 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3885 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3886 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3887 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3888 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3889 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3890 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3891 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3892 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3893 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3894 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3895 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3896 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3897 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3898 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3901 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3902 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3903 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3904 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3905 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3906 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3907 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3908 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3909 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3910 LTT_FIELD_PID
= g_quark_from_string("pid");
3911 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3912 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3913 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3914 LTT_FIELD_NAME
= g_quark_from_string("name");
3915 LTT_FIELD_TYPE
= g_quark_from_string("type");
3916 LTT_FIELD_MODE
= g_quark_from_string("mode");
3917 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3918 LTT_FIELD_STATUS
= g_quark_from_string("status");
3919 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3920 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3921 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3922 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3923 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3924 LTT_FIELD_ACTION
= g_quark_from_string("action");
3925 LTT_FIELD_NUM
= g_quark_from_string("num");
3927 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3928 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3929 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3930 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3931 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3933 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3934 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3935 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3937 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3938 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3939 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3940 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3943 static void module_destroy()
3948 LTTV_MODULE("state", "State computation", \
3949 "Update the system state, possibly saving it at intervals", \
3950 module_init
, module_destroy
)