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,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.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
;
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
;
848 /* TODO : check return value */
849 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
850 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
851 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
852 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
853 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
854 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
855 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
856 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
857 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
860 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
862 /* We must link to the parent */
863 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
865 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
866 if(process
== NULL
) {
867 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
869 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
873 process
->insertion_time
= tmp
.insertion_time
;
874 process
->creation_time
= tmp
.creation_time
;
875 process
->type
= g_quark_from_string(
876 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
877 process
->tgid
= tmp
.tgid
;
878 process
->ppid
= tmp
.ppid
;
879 process
->brand
= g_quark_from_string(
880 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
882 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
886 if(feof(fp
) || ferror(fp
)) goto end_loop
;
888 gint hdr
= fgetc(fp
);
889 if(hdr
== EOF
) goto end_loop
;
893 process
->execution_stack
=
894 g_array_set_size(process
->execution_stack
,
895 process
->execution_stack
->len
+ 1);
896 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
897 process
->execution_stack
->len
-1);
900 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
901 es
->t
= g_quark_from_string(
902 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
903 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
904 es
->n
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
906 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
907 es
->s
= g_quark_from_string(
908 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
909 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
910 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
911 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
914 process
->user_stack
= g_array_set_size(process
->user_stack
,
915 process
->user_stack
->len
+ 1);
916 address
= &g_array_index(process
->user_stack
, guint64
,
917 process
->user_stack
->len
-1);
918 fread(address
, sizeof(address
), 1, fp
);
919 process
->current_function
= *address
;
922 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
923 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
935 /* Called because a HDR_PROCESS_STATE was found */
936 /* Append a saved state to the trace states */
937 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
939 guint i
, nb_tracefile
, nb_block
, offset
;
941 LttvTracefileState
*tfcs
;
943 LttEventPosition
*ep
;
951 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
953 LttvAttributeValue value
;
954 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
955 ep
= ltt_event_position_new();
957 restore_init_state(self
);
959 fread(&t
, sizeof(t
), 1, fp
);
962 if(feof(fp
) || ferror(fp
)) goto end_loop
;
964 if(hdr
== EOF
) goto end_loop
;
968 /* Call read_process_state_raw */
969 read_process_state_raw(self
, fp
, quarktable
);
979 case HDR_PROCESS_STATE
:
985 g_error("Error while parsing saved state file : unknown data header %d",
991 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
992 for(i
=0;i
<nb_cpus
;i
++) {
995 g_assert(hdr
== HDR_CPU
);
996 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
997 g_assert(i
== cpu_num
);
998 fread(&self
->running_process
[i
]->pid
,
999 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1002 nb_tracefile
= self
->parent
.tracefiles
->len
;
1004 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1006 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1007 LttvTracefileContext
*, i
));
1008 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1009 // tfcs->parent.timestamp.tv_sec,
1010 // tfcs->parent.timestamp.tv_nsec);
1011 g_tree_remove(pqueue
, &tfcs
->parent
);
1013 g_assert(hdr
== HDR_TRACEFILE
);
1014 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1015 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1016 * position following : end of trace */
1017 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1018 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1019 fread(&offset
, sizeof(offset
), 1, fp
);
1020 fread(&tsc
, sizeof(tsc
), 1, fp
);
1021 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1022 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1024 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1029 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1030 LTTV_STATE_SAVED_STATES
);
1031 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1032 value
= lttv_attribute_add(saved_states_tree
,
1033 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1034 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1035 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1036 *(value
.v_time
) = t
;
1037 lttv_state_save(self
, saved_state_tree
);
1038 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1041 *(self
->max_time_state_recomputed_in_seek
) = t
;
1045 /* Called when a HDR_TRACE is found */
1046 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1047 GPtrArray
*quarktable
)
1052 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1054 if(hdr
== EOF
) goto end_loop
;
1057 case HDR_PROCESS_STATE
:
1058 /* Call read_process_state_raw */
1059 lttv_state_read_raw(tcs
, fp
, quarktable
);
1067 case HDR_USER_STACK
:
1071 g_error("Error while parsing saved state file :"
1072 " unexpected data header %d",
1076 g_error("Error while parsing saved state file : unknown data header %d",
1081 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1082 restore_init_state(tcs
);
1083 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1089 /* Copy each process from an existing hash table to a new one */
1091 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1093 LttvProcessState
*process
, *new_process
;
1095 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1099 process
= (LttvProcessState
*)value
;
1100 new_process
= g_new(LttvProcessState
, 1);
1101 *new_process
= *process
;
1102 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1103 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1104 new_process
->execution_stack
=
1105 g_array_set_size(new_process
->execution_stack
,
1106 process
->execution_stack
->len
);
1107 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1108 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1109 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1111 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1112 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1113 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1114 sizeof(guint64
), 0);
1115 new_process
->user_stack
=
1116 g_array_set_size(new_process
->user_stack
,
1117 process
->user_stack
->len
);
1118 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1119 g_array_index(new_process
->user_stack
, guint64
, i
) =
1120 g_array_index(process
->user_stack
, guint64
, i
);
1122 new_process
->current_function
= process
->current_function
;
1123 g_hash_table_insert(new_processes
, new_process
, new_process
);
1127 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1129 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1131 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1132 return new_processes
;
1135 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1138 LttvCPUState
*retval
;
1140 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1142 for(i
=0; i
<n
; i
++) {
1143 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1144 retval
[i
].last_irq
= states
[i
].last_irq
;
1145 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1146 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1147 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1154 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1158 for(i
=0; i
<n
; i
++) {
1159 g_array_free(states
[i
].mode_stack
, FALSE
);
1165 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1168 LttvIRQState
*retval
;
1170 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1172 for(i
=0; i
<n
; i
++) {
1173 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1174 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1175 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1176 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1183 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1187 for(i
=0; i
<n
; i
++) {
1188 g_array_free(states
[i
].mode_stack
, FALSE
);
1194 /* bdevstate stuff */
1196 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1198 gint devcode_gint
= devcode
;
1199 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1201 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1202 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1204 gint
* key
= g_malloc(sizeof(gint
));
1206 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1214 static LttvBdevState
*bdevstate_new(void)
1216 LttvBdevState
*retval
;
1217 retval
= g_malloc(sizeof(LttvBdevState
));
1218 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1223 static void bdevstate_free(LttvBdevState
*bds
)
1225 g_array_free(bds
->mode_stack
, FALSE
);
1229 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1231 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1233 bdevstate_free(bds
);
1236 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1238 LttvBdevState
*retval
;
1240 retval
= bdevstate_new();
1241 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1246 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1248 GHashTable
*ht
= (GHashTable
*)u
;
1249 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1250 LttvBdevState
*newbds
;
1252 newbds
= bdevstate_copy(v
);
1254 g_hash_table_insert(u
, k
, newbds
);
1257 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1261 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1263 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1268 /* Free a hashtable and the LttvBdevState structures its values
1271 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1273 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1274 g_hash_table_destroy(ht
);
1277 /* The saved state for each trace contains a member "processes", which
1278 stores a copy of the process table, and a member "tracefiles" with
1279 one entry per tracefile. Each tracefile has a "process" member pointing
1280 to the current process and a "position" member storing the tracefile
1281 position (needed to seek to the current "next" event. */
1283 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1285 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1287 LttvTracefileState
*tfcs
;
1289 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1291 guint
*running_process
;
1293 LttvAttributeType type
;
1295 LttvAttributeValue value
;
1297 LttvAttributeName name
;
1299 LttEventPosition
*ep
;
1301 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1302 LTTV_STATE_TRACEFILES
);
1304 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1306 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1308 /* Add the currently running processes array */
1309 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1310 running_process
= g_new(guint
, nb_cpus
);
1311 for(i
=0;i
<nb_cpus
;i
++) {
1312 running_process
[i
] = self
->running_process
[i
]->pid
;
1314 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1316 *(value
.v_pointer
) = running_process
;
1318 g_info("State save");
1320 nb_tracefile
= self
->parent
.tracefiles
->len
;
1322 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1324 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1325 LttvTracefileContext
*, i
));
1326 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1327 value
= lttv_attribute_add(tracefiles_tree
, i
,
1329 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1331 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1333 *(value
.v_uint
) = tfcs
->process
->pid
;
1335 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1337 /* Only save the position if the tfs has not infinite time. */
1338 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1339 // && current_tfcs != tfcs) {
1340 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1341 *(value
.v_pointer
) = NULL
;
1343 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1344 ep
= ltt_event_position_new();
1345 ltt_event_position(e
, ep
);
1346 *(value
.v_pointer
) = ep
;
1348 guint nb_block
, offset
;
1351 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1352 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1354 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1358 /* save the cpu state */
1360 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1361 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1363 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1366 /* save the irq state */
1367 nb_irqs
= self
->nb_irqs
;
1369 guint size
= sizeof(LttvCPUState
)*nb_irqs
;
1370 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1372 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1375 /* save the blkdev states */
1376 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1378 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1382 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1384 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1386 LttvTracefileState
*tfcs
;
1388 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1390 guint
*running_process
;
1392 LttvAttributeType type
;
1394 LttvAttributeValue value
;
1396 LttvAttributeName name
;
1400 LttEventPosition
*ep
;
1402 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1404 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1405 LTTV_STATE_TRACEFILES
);
1407 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1409 g_assert(type
== LTTV_POINTER
);
1410 lttv_state_free_process_table(self
->processes
);
1411 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1413 /* Add the currently running processes array */
1414 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1415 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1417 g_assert(type
== LTTV_POINTER
);
1418 running_process
= *(value
.v_pointer
);
1419 for(i
=0;i
<nb_cpus
;i
++) {
1420 pid
= running_process
[i
];
1421 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1422 g_assert(self
->running_process
[i
] != NULL
);
1425 nb_tracefile
= self
->parent
.tracefiles
->len
;
1427 //g_tree_destroy(tsc->pqueue);
1428 //tsc->pqueue = g_tree_new(compare_tracefile);
1430 /* restore cpu resource states */
1431 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1432 g_assert(type
== LTTV_POINTER
);
1433 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1434 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1436 /* restore irq resource states */
1437 nb_irqs
= self
->nb_irqs
;
1438 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1439 g_assert(type
== LTTV_POINTER
);
1440 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1441 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1443 /* restore the blkdev states */
1444 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1445 g_assert(type
== LTTV_POINTER
);
1446 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1447 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1449 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1451 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1452 LttvTracefileContext
*, i
));
1453 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1454 g_assert(type
== LTTV_GOBJECT
);
1455 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1457 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1459 g_assert(type
== LTTV_UINT
);
1460 pid
= *(value
.v_uint
);
1461 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1463 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1465 g_assert(type
== LTTV_POINTER
);
1466 //g_assert(*(value.v_pointer) != NULL);
1467 ep
= *(value
.v_pointer
);
1468 g_assert(tfcs
->parent
.t_context
!= NULL
);
1470 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1472 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1473 g_tree_remove(tsc
->pqueue
, tfc
);
1476 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1477 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1478 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1479 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1480 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1482 tfc
->timestamp
= ltt_time_infinite
;
1488 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1490 guint i
, nb_tracefile
, nb_cpus
;
1492 LttvTracefileState
*tfcs
;
1494 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1496 guint
*running_process
;
1498 LttvAttributeType type
;
1500 LttvAttributeValue value
;
1502 LttvAttributeName name
;
1506 LttEventPosition
*ep
;
1508 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1509 LTTV_STATE_TRACEFILES
);
1510 g_object_ref(G_OBJECT(tracefiles_tree
));
1511 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1513 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1515 g_assert(type
== LTTV_POINTER
);
1516 lttv_state_free_process_table(*(value
.v_pointer
));
1517 *(value
.v_pointer
) = NULL
;
1518 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1520 /* Free running processes array */
1521 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1522 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1524 g_assert(type
== LTTV_POINTER
);
1525 running_process
= *(value
.v_pointer
);
1526 g_free(running_process
);
1528 nb_tracefile
= self
->parent
.tracefiles
->len
;
1530 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1532 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1533 LttvTracefileContext
*, i
));
1534 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1535 g_assert(type
== LTTV_GOBJECT
);
1536 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1538 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1540 g_assert(type
== LTTV_POINTER
);
1541 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1543 g_object_unref(G_OBJECT(tracefiles_tree
));
1547 static void free_saved_state(LttvTraceState
*self
)
1551 LttvAttributeType type
;
1553 LttvAttributeValue value
;
1555 LttvAttributeName name
;
1559 LttvAttribute
*saved_states
;
1561 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1562 LTTV_STATE_SAVED_STATES
);
1564 nb
= lttv_attribute_get_number(saved_states
);
1565 for(i
= 0 ; i
< nb
; i
++) {
1566 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1567 g_assert(type
== LTTV_GOBJECT
);
1568 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1571 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1576 create_max_time(LttvTraceState
*tcs
)
1578 LttvAttributeValue v
;
1580 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1582 g_assert(*(v
.v_pointer
) == NULL
);
1583 *(v
.v_pointer
) = g_new(LttTime
,1);
1584 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1589 get_max_time(LttvTraceState
*tcs
)
1591 LttvAttributeValue v
;
1593 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1595 g_assert(*(v
.v_pointer
) != NULL
);
1596 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1601 free_max_time(LttvTraceState
*tcs
)
1603 LttvAttributeValue v
;
1605 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1607 g_free(*(v
.v_pointer
));
1608 *(v
.v_pointer
) = NULL
;
1612 typedef struct _LttvNameTables
{
1613 // FIXME GQuark *eventtype_names;
1614 GQuark
*syscall_names
;
1620 GQuark
*soft_irq_names
;
1626 create_name_tables(LttvTraceState
*tcs
)
1630 GQuark f_name
, e_name
;
1634 LttvTraceHookByFacility
*thf
;
1640 GString
*fe_name
= g_string_new("");
1642 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1644 LttvAttributeValue v
;
1646 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1648 g_assert(*(v
.v_pointer
) == NULL
);
1649 *(v
.v_pointer
) = name_tables
;
1650 #if 0 // Use iteration over the facilities_by_name and then list all event
1651 // types of each facility
1652 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1653 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1654 for(i
= 0 ; i
< nb
; i
++) {
1655 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1656 e_name
= ltt_eventtype_name(et
);
1657 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1658 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1659 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1662 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1663 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1664 LTT_FIELD_SYSCALL_ID
, 0, 0,
1667 thf
= lttv_trace_hook_get_first(&h
);
1669 t
= ltt_field_type(thf
->f1
);
1670 nb
= ltt_type_element_number(t
);
1672 lttv_trace_hook_destroy(&h
);
1674 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1675 name_tables
->nb_syscalls
= nb
;
1677 for(i
= 0 ; i
< nb
; i
++) {
1678 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1679 if(!name_tables
->syscall_names
[i
]) {
1680 GString
*string
= g_string_new("");
1681 g_string_printf(string
, "syscall %u", i
);
1682 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1683 g_string_free(string
, TRUE
);
1687 //name_tables->syscall_names = g_new(GQuark, 256);
1688 //for(i = 0 ; i < 256 ; i++) {
1689 // g_string_printf(fe_name, "syscall %d", i);
1690 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1693 name_tables
->syscall_names
= NULL
;
1694 name_tables
->nb_syscalls
= 0;
1697 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1698 LTT_EVENT_TRAP_ENTRY
,
1699 LTT_FIELD_TRAP_ID
, 0, 0,
1702 thf
= lttv_trace_hook_get_first(&h
);
1704 t
= ltt_field_type(thf
->f1
);
1705 //nb = ltt_type_element_number(t);
1707 lttv_trace_hook_destroy(&h
);
1710 name_tables->trap_names = g_new(GQuark, nb);
1711 for(i = 0 ; i < nb ; i++) {
1712 name_tables->trap_names[i] = g_quark_from_string(
1713 ltt_enum_string_get(t, i));
1716 name_tables
->nb_traps
= 256;
1717 name_tables
->trap_names
= g_new(GQuark
, 256);
1718 for(i
= 0 ; i
< 256 ; i
++) {
1719 g_string_printf(fe_name
, "trap %d", i
);
1720 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1723 name_tables
->trap_names
= NULL
;
1724 name_tables
->nb_traps
= 0;
1727 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1728 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1729 LTT_FIELD_IRQ_ID
, 0, 0,
1732 thf
= lttv_trace_hook_get_first(&h
);
1734 t
= ltt_field_type(thf
->f1
);
1735 //nb = ltt_type_element_number(t);
1737 lttv_trace_hook_destroy(&h
);
1740 name_tables->irq_names = g_new(GQuark, nb);
1741 for(i = 0 ; i < nb ; i++) {
1742 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1746 name_tables
->nb_irqs
= 256;
1747 name_tables
->irq_names
= g_new(GQuark
, 256);
1748 for(i
= 0 ; i
< 256 ; i
++) {
1749 g_string_printf(fe_name
, "irq %d", i
);
1750 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1753 name_tables
->nb_irqs
= 0;
1754 name_tables
->irq_names
= NULL
;
1757 name_tables->soft_irq_names = g_new(GQuark, nb);
1758 for(i = 0 ; i < nb ; i++) {
1759 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1763 name_tables
->nb_softirqs
= 256;
1764 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1765 for(i
= 0 ; i
< 256 ; i
++) {
1766 g_string_printf(fe_name
, "softirq %d", i
);
1767 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1771 g_string_free(fe_name
, TRUE
);
1776 get_name_tables(LttvTraceState
*tcs
)
1778 LttvNameTables
*name_tables
;
1780 LttvAttributeValue v
;
1782 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1784 g_assert(*(v
.v_pointer
) != NULL
);
1785 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1786 //tcs->eventtype_names = name_tables->eventtype_names;
1787 tcs
->syscall_names
= name_tables
->syscall_names
;
1788 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1789 tcs
->trap_names
= name_tables
->trap_names
;
1790 tcs
->nb_traps
= name_tables
->nb_traps
;
1791 tcs
->irq_names
= name_tables
->irq_names
;
1792 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1793 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1794 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1799 free_name_tables(LttvTraceState
*tcs
)
1801 LttvNameTables
*name_tables
;
1803 LttvAttributeValue v
;
1805 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1807 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1808 *(v
.v_pointer
) = NULL
;
1810 // g_free(name_tables->eventtype_names);
1811 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1812 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1813 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1814 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1815 if(name_tables
) g_free(name_tables
);
1818 #ifdef HASH_TABLE_DEBUG
1820 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1822 LttvProcessState
*process
= (LttvProcessState
*)value
;
1824 /* Test for process corruption */
1825 guint stack_len
= process
->execution_stack
->len
;
1828 static void hash_table_check(GHashTable
*table
)
1830 g_hash_table_foreach(table
, test_process
, NULL
);
1836 /* clears the stack and sets the state passed as argument */
1837 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1839 g_array_set_size(cpust
->mode_stack
, 1);
1840 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1843 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1845 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1846 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1849 static void cpu_pop_mode(LttvCPUState
*cpust
)
1851 if(cpust
->mode_stack
->len
<= 1)
1852 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1854 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1857 /* clears the stack and sets the state passed as argument */
1858 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1860 g_array_set_size(bdevst
->mode_stack
, 1);
1861 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1864 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1866 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1867 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1870 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1872 if(bdevst
->mode_stack
->len
<= 1)
1873 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1875 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1878 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1880 g_array_set_size(irqst
->mode_stack
, 1);
1881 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1884 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1886 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1887 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1890 static void irq_pop_mode(LttvIRQState
*irqst
)
1892 if(irqst
->mode_stack
->len
<= 1)
1893 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1895 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1898 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1901 LttvExecutionState
*es
;
1903 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1904 guint cpu
= tfs
->cpu
;
1906 #ifdef HASH_TABLE_DEBUG
1907 hash_table_check(ts
->processes
);
1909 LttvProcessState
*process
= ts
->running_process
[cpu
];
1911 guint depth
= process
->execution_stack
->len
;
1913 process
->execution_stack
=
1914 g_array_set_size(process
->execution_stack
, depth
+ 1);
1917 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1919 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1922 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1923 es
->cum_cpu_time
= ltt_time_zero
;
1924 es
->s
= process
->state
->s
;
1925 process
->state
= es
;
1929 * return 1 when empty, else 0 */
1930 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1931 LttvTracefileState
*tfs
)
1933 guint cpu
= tfs
->cpu
;
1934 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1936 guint depth
= process
->execution_stack
->len
;
1942 process
->execution_stack
=
1943 g_array_set_size(process
->execution_stack
, depth
- 1);
1944 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1946 process
->state
->change
= tfs
->parent
.timestamp
;
1951 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1953 guint cpu
= tfs
->cpu
;
1954 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1955 LttvProcessState
*process
= ts
->running_process
[cpu
];
1957 guint depth
= process
->execution_stack
->len
;
1959 if(process
->state
->t
!= t
){
1960 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1961 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1962 g_info("process state has %s when pop_int is %s\n",
1963 g_quark_to_string(process
->state
->t
),
1964 g_quark_to_string(t
));
1965 g_info("{ %u, %u, %s, %s, %s }\n",
1968 g_quark_to_string(process
->name
),
1969 g_quark_to_string(process
->brand
),
1970 g_quark_to_string(process
->state
->s
));
1975 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1976 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1980 process
->execution_stack
=
1981 g_array_set_size(process
->execution_stack
, depth
- 1);
1982 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1984 process
->state
->change
= tfs
->parent
.timestamp
;
1987 struct search_result
{
1988 const LttTime
*time
; /* Requested time */
1989 LttTime
*best
; /* Best result */
1992 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1994 const LttTime
*elem_time
= (const LttTime
*)a
;
1995 /* Explicit non const cast */
1996 struct search_result
*res
= (struct search_result
*)b
;
1998 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1999 /* The usertrace was created before the schedchange */
2000 /* Get larger keys */
2002 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
2003 /* The usertrace was created after the schedchange time */
2004 /* Get smaller keys */
2006 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
2007 res
->best
= elem_time
;
2010 res
->best
= elem_time
;
2017 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
2018 guint pid
, const LttTime
*timestamp
)
2020 LttvTracefileState
*tfs
= NULL
;
2021 struct search_result res
;
2022 /* Find the usertrace associated with a pid and time interval.
2023 * Search in the usertraces by PID (within a hash) and then, for each
2024 * corresponding element of the array, find the first one with creation
2025 * timestamp the lowest, but higher or equal to "timestamp". */
2026 res
.time
= timestamp
;
2028 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
2029 if(usertrace_tree
) {
2030 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
2032 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2040 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2041 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2043 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2045 LttvExecutionState
*es
;
2047 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
2052 process
->tgid
= tgid
;
2054 process
->name
= name
;
2055 process
->brand
= LTTV_STATE_UNBRANDED
;
2056 //process->last_cpu = tfs->cpu_name;
2057 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2058 process
->type
= LTTV_STATE_USER_THREAD
;
2059 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2060 process
->current_function
= 0; //function 0x0 by default.
2062 g_info("Process %u, core %p", process
->pid
, process
);
2063 g_hash_table_insert(tcs
->processes
, process
, process
);
2066 process
->ppid
= parent
->pid
;
2067 process
->creation_time
= *timestamp
;
2070 /* No parent. This process exists but we are missing all information about
2071 its creation. The birth time is set to zero but we remember the time of
2076 process
->creation_time
= ltt_time_zero
;
2079 process
->insertion_time
= *timestamp
;
2080 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2081 process
->creation_time
.tv_nsec
);
2082 process
->pid_time
= g_quark_from_string(buffer
);
2084 //process->last_cpu = tfs->cpu_name;
2085 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2086 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2087 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2088 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2089 es
= process
->state
= &g_array_index(process
->execution_stack
,
2090 LttvExecutionState
, 0);
2091 es
->t
= LTTV_STATE_USER_MODE
;
2092 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2093 es
->entry
= *timestamp
;
2094 //g_assert(timestamp->tv_sec != 0);
2095 es
->change
= *timestamp
;
2096 es
->cum_cpu_time
= ltt_time_zero
;
2097 es
->s
= LTTV_STATE_RUN
;
2099 es
= process
->state
= &g_array_index(process
->execution_stack
,
2100 LttvExecutionState
, 1);
2101 es
->t
= LTTV_STATE_SYSCALL
;
2102 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2103 es
->entry
= *timestamp
;
2104 //g_assert(timestamp->tv_sec != 0);
2105 es
->change
= *timestamp
;
2106 es
->cum_cpu_time
= ltt_time_zero
;
2107 es
->s
= LTTV_STATE_WAIT_FORK
;
2109 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2110 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2111 sizeof(guint64
), 0);
2116 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2119 LttvProcessState key
;
2120 LttvProcessState
*process
;
2124 process
= g_hash_table_lookup(ts
->processes
, &key
);
2129 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2130 const LttTime
*timestamp
)
2132 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2133 LttvExecutionState
*es
;
2135 /* Put ltt_time_zero creation time for unexisting processes */
2136 if(unlikely(process
== NULL
)) {
2137 process
= lttv_state_create_process(ts
,
2138 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2139 /* We are not sure is it's a kernel thread or normal thread, put the
2140 * bottom stack state to unknown */
2141 process
->execution_stack
=
2142 g_array_set_size(process
->execution_stack
, 1);
2143 process
->state
= es
=
2144 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2145 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2146 es
->s
= LTTV_STATE_UNNAMED
;
2151 /* FIXME : this function should be called when we receive an event telling that
2152 * release_task has been called in the kernel. In happens generally when
2153 * the parent waits for its child terminaison, but may also happen in special
2154 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2155 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2156 * of a killed thread ground, but isn't the leader.
2158 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2160 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2161 LttvProcessState key
;
2163 key
.pid
= process
->pid
;
2164 key
.cpu
= process
->cpu
;
2165 g_hash_table_remove(ts
->processes
, &key
);
2166 g_array_free(process
->execution_stack
, TRUE
);
2167 g_array_free(process
->user_stack
, TRUE
);
2172 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2174 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2175 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2180 static void lttv_state_free_process_table(GHashTable
*processes
)
2182 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2183 g_hash_table_destroy(processes
);
2187 static gboolean
syscall_entry(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
];
2193 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2194 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2195 LttField
*f
= thf
->f1
;
2197 LttvExecutionSubmode submode
;
2199 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2200 guint syscall
= ltt_event_get_unsigned(e
, f
);
2202 if(syscall
< nb_syscalls
) {
2203 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2206 /* Fixup an incomplete syscall table */
2207 GString
*string
= g_string_new("");
2208 g_string_printf(string
, "syscall %u", syscall
);
2209 submode
= g_quark_from_string(string
->str
);
2210 g_string_free(string
, TRUE
);
2212 /* There can be no system call from PID 0 : unknown state */
2213 if(process
->pid
!= 0)
2214 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2219 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2221 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2223 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2224 LttvProcessState
*process
= ts
->running_process
[cpu
];
2226 /* There can be no system call from PID 0 : unknown state */
2227 if(process
->pid
!= 0)
2228 pop_state(s
, LTTV_STATE_SYSCALL
);
2233 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2235 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2236 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2237 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2238 LttField
*f
= thf
->f1
;
2240 LttvExecutionSubmode submode
;
2242 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2243 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2245 if(trap
< nb_traps
) {
2246 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2248 /* Fixup an incomplete trap table */
2249 GString
*string
= g_string_new("");
2250 g_string_printf(string
, "trap %llu", trap
);
2251 submode
= g_quark_from_string(string
->str
);
2252 g_string_free(string
, TRUE
);
2255 push_state(s
, LTTV_STATE_TRAP
, submode
);
2257 /* update cpu status */
2258 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2263 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2265 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2267 pop_state(s
, LTTV_STATE_TRAP
);
2269 /* update cpu status */
2270 cpu_pop_mode(s
->cpu_state
);
2275 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2277 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2278 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2279 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2280 guint8 fac_id
= ltt_event_facility_id(e
);
2281 guint8 ev_id
= ltt_event_eventtype_id(e
);
2282 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2283 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2284 g_assert(thf
->f1
!= NULL
);
2285 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2286 LttField
*f
= thf
->f1
;
2288 LttvExecutionSubmode submode
;
2289 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2290 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2294 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2296 /* Fixup an incomplete irq table */
2297 GString
*string
= g_string_new("");
2298 g_string_printf(string
, "irq %llu", irq
);
2299 submode
= g_quark_from_string(string
->str
);
2300 g_string_free(string
, TRUE
);
2303 /* Do something with the info about being in user or system mode when int? */
2304 push_state(s
, LTTV_STATE_IRQ
, submode
);
2306 /* update cpu status */
2307 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2309 /* update irq status */
2310 s
->cpu_state
->last_irq
= irq
;
2311 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2316 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2318 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2320 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2326 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2328 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2329 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2331 pop_state(s
, LTTV_STATE_IRQ
);
2333 /* update cpu status */
2334 cpu_pop_mode(s
->cpu_state
);
2336 /* update irq status */
2337 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2342 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2344 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2345 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2346 guint8 fac_id
= ltt_event_facility_id(e
);
2347 guint8 ev_id
= ltt_event_eventtype_id(e
);
2348 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2349 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2350 g_assert(thf
->f1
!= NULL
);
2351 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2352 LttField
*f
= thf
->f1
;
2354 LttvExecutionSubmode submode
;
2355 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2356 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2359 if(softirq
< nb_softirqs
) {
2360 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2362 /* Fixup an incomplete irq table */
2363 GString
*string
= g_string_new("");
2364 g_string_printf(string
, "softirq %llu", softirq
);
2365 submode
= g_quark_from_string(string
->str
);
2366 g_string_free(string
, TRUE
);
2369 /* Do something with the info about being in user or system mode when int? */
2370 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2374 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2376 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2377 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2378 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2379 guint8 fac_id
= ltt_event_facility_id(e
);
2380 guint8 ev_id
= ltt_event_eventtype_id(e
);
2381 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2383 GQuark action
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2384 guint irq
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2386 ts
->irq_names
[irq
] = action
;
2392 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2394 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2395 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2396 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2397 guint8 fac_id
= ltt_event_facility_id(e
);
2398 guint8 ev_id
= ltt_event_eventtype_id(e
);
2399 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2401 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2402 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2403 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2404 guint16 devcode
= MKDEV(major
,minor
);
2406 /* have we seen this block device before? */
2407 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2410 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2412 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2417 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2419 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2420 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2421 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2422 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2424 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2425 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2426 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2427 guint16 devcode
= MKDEV(major
,minor
);
2429 /* have we seen this block device before? */
2430 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2432 /* update block device */
2433 bdev_pop_mode(bdev
);
2438 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2442 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2443 guint cpu
= tfs
->cpu
;
2444 LttvProcessState
*process
= ts
->running_process
[cpu
];
2446 guint depth
= process
->user_stack
->len
;
2448 process
->user_stack
=
2449 g_array_set_size(process
->user_stack
, depth
+ 1);
2451 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2452 *new_func
= funcptr
;
2453 process
->current_function
= funcptr
;
2456 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2458 guint cpu
= tfs
->cpu
;
2459 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2460 LttvProcessState
*process
= ts
->running_process
[cpu
];
2462 if(process
->current_function
!= funcptr
){
2463 g_info("Different functions (%lu.%09lu): ignore it\n",
2464 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2465 g_info("process state has %llu when pop_function is %llu\n",
2466 process
->current_function
, funcptr
);
2467 g_info("{ %u, %u, %s, %s, %s }\n",
2470 g_quark_to_string(process
->name
),
2471 g_quark_to_string(process
->brand
),
2472 g_quark_to_string(process
->state
->s
));
2475 guint depth
= process
->user_stack
->len
;
2478 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2479 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2483 process
->user_stack
=
2484 g_array_set_size(process
->user_stack
, depth
- 1);
2485 process
->current_function
=
2486 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2490 static gboolean
function_entry(void *hook_data
, void *call_data
)
2492 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2493 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2494 guint8 fac_id
= ltt_event_facility_id(e
);
2495 guint8 ev_id
= ltt_event_eventtype_id(e
);
2496 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2497 g_assert(thf
->f1
!= NULL
);
2498 LttField
*f
= thf
->f1
;
2499 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2501 push_function(s
, funcptr
);
2505 static gboolean
function_exit(void *hook_data
, void *call_data
)
2507 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2508 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2509 guint8 fac_id
= ltt_event_facility_id(e
);
2510 guint8 ev_id
= ltt_event_eventtype_id(e
);
2511 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2512 g_assert(thf
->f1
!= NULL
);
2513 LttField
*f
= thf
->f1
;
2514 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2516 LttvExecutionSubmode submode
;
2518 pop_function(s
, funcptr
);
2522 static gboolean
schedchange(void *hook_data
, void *call_data
)
2524 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2526 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2527 LttvProcessState
*process
= ts
->running_process
[cpu
];
2528 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2530 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2531 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2532 guint pid_in
, pid_out
;
2535 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2536 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2537 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2539 if(likely(process
!= NULL
)) {
2541 /* We could not know but it was not the idle process executing.
2542 This should only happen at the beginning, before the first schedule
2543 event, and when the initial information (current process for each CPU)
2544 is missing. It is not obvious how we could, after the fact, compensate
2545 the wrongly attributed statistics. */
2547 //This test only makes sense once the state is known and if there is no
2548 //missing events. We need to silently ignore schedchange coming after a
2549 //process_free, or it causes glitches. (FIXME)
2550 //if(unlikely(process->pid != pid_out)) {
2551 // g_assert(process->pid == 0);
2553 if(process
->pid
== 0
2554 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2556 /* Scheduling out of pid 0 at beginning of the trace :
2557 * we know for sure it is in syscall mode at this point. */
2558 g_assert(process
->execution_stack
->len
== 1);
2559 process
->state
->t
= LTTV_STATE_SYSCALL
;
2560 process
->state
->s
= LTTV_STATE_WAIT
;
2561 process
->state
->change
= s
->parent
.timestamp
;
2562 process
->state
->entry
= s
->parent
.timestamp
;
2565 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2566 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2567 process
->state
->change
= s
->parent
.timestamp
;
2569 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2570 else process
->state
->s
= LTTV_STATE_WAIT
;
2571 process
->state
->change
= s
->parent
.timestamp
;
2574 if(state_out
== 32 || state_out
== 128)
2575 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2576 /* see sched.h for states */
2579 process
= ts
->running_process
[cpu
] =
2580 lttv_state_find_process_or_create(
2581 (LttvTraceState
*)s
->parent
.t_context
,
2583 &s
->parent
.timestamp
);
2584 process
->state
->s
= LTTV_STATE_RUN
;
2586 if(process
->usertrace
)
2587 process
->usertrace
->cpu
= cpu
;
2588 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2589 process
->state
->change
= s
->parent
.timestamp
;
2591 /* update cpu status */
2593 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2595 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2600 static gboolean
process_fork(void *hook_data
, void *call_data
)
2602 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2603 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2604 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2606 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2607 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2608 LttvProcessState
*zombie_process
;
2610 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2611 LttvProcessState
*process
= ts
->running_process
[cpu
];
2612 LttvProcessState
*child_process
;
2615 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2618 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2619 s
->parent
.target_pid
= child_pid
;
2622 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2623 else child_tgid
= 0;
2625 /* Mathieu : it seems like the process might have been scheduled in before the
2626 * fork, and, in a rare case, might be the current process. This might happen
2627 * in a SMP case where we don't have enough precision on the clocks.
2629 * Test reenabled after precision fixes on time. (Mathieu) */
2631 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2633 if(unlikely(zombie_process
!= NULL
)) {
2634 /* Reutilisation of PID. Only now we are sure that the old PID
2635 * has been released. FIXME : should know when release_task happens instead.
2637 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2639 for(i
=0; i
< num_cpus
; i
++) {
2640 g_assert(zombie_process
!= ts
->running_process
[i
]);
2643 exit_process(s
, zombie_process
);
2646 g_assert(process
->pid
!= child_pid
);
2647 // FIXME : Add this test in the "known state" section
2648 // g_assert(process->pid == parent_pid);
2649 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2650 if(child_process
== NULL
) {
2651 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2652 child_pid
, child_tgid
,
2653 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2655 /* The process has already been created : due to time imprecision between
2656 * multiple CPUs : it has been scheduled in before creation. Note that we
2657 * shouldn't have this kind of imprecision.
2659 * Simply put a correct parent.
2661 g_assert(0); /* This is a problematic case : the process has been created
2662 before the fork event */
2663 child_process
->ppid
= process
->pid
;
2664 child_process
->tgid
= child_tgid
;
2666 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2667 child_process
->name
= process
->name
;
2668 child_process
->brand
= process
->brand
;
2673 /* We stamp a newly created process as kernel_thread.
2674 * The thread should not be running yet. */
2675 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2677 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2678 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2679 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2682 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2683 LttvProcessState
*process
;
2684 LttvExecutionState
*es
;
2687 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2688 s
->parent
.target_pid
= pid
;
2690 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2692 process
->execution_stack
=
2693 g_array_set_size(process
->execution_stack
, 1);
2694 es
= process
->state
=
2695 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2696 es
->t
= LTTV_STATE_SYSCALL
;
2697 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2702 static gboolean
process_exit(void *hook_data
, void *call_data
)
2704 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2705 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2706 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2710 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2711 LttvProcessState
*process
; // = ts->running_process[cpu];
2713 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2714 s
->parent
.target_pid
= pid
;
2716 // FIXME : Add this test in the "known state" section
2717 // g_assert(process->pid == pid);
2719 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2720 if(likely(process
!= NULL
)) {
2721 process
->state
->s
= LTTV_STATE_EXIT
;
2726 static gboolean
process_free(void *hook_data
, void *call_data
)
2728 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2729 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2730 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2731 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2733 LttvProcessState
*process
;
2735 /* PID of the process to release */
2736 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2737 s
->parent
.target_pid
= release_pid
;
2739 g_assert(release_pid
!= 0);
2741 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2743 if(likely(process
!= NULL
)) {
2744 /* release_task is happening at kernel level : we can now safely release
2745 * the data structure of the process */
2746 //This test is fun, though, as it may happen that
2747 //at time t : CPU 0 : process_free
2748 //at time t+150ns : CPU 1 : schedule out
2749 //Clearly due to time imprecision, we disable it. (Mathieu)
2750 //If this weird case happen, we have no choice but to put the
2751 //Currently running process on the cpu to 0.
2752 //I re-enable it following time precision fixes. (Mathieu)
2753 //Well, in the case where an process is freed by a process on another CPU
2754 //and still scheduled, it happens that this is the schedchange that will
2755 //drop the last reference count. Do not free it here!
2756 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2758 for(i
=0; i
< num_cpus
; i
++) {
2759 //g_assert(process != ts->running_process[i]);
2760 if(process
== ts
->running_process
[i
]) {
2761 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2765 if(i
== num_cpus
) /* process is not scheduled */
2766 exit_process(s
, process
);
2773 static gboolean
process_exec(void *hook_data
, void *call_data
)
2775 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2776 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2777 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2778 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2781 LttvProcessState
*process
= ts
->running_process
[cpu
];
2783 #if 0//how to use a sequence that must be transformed in a string
2784 /* PID of the process to release */
2785 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2786 //name = ltt_event_get_string(e, thf->f1);
2787 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2789 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2790 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2791 memcpy(null_term_name
, name_begin
, name_len
);
2792 null_term_name
[name_len
] = '\0';
2793 process
->name
= g_quark_from_string(null_term_name
);
2796 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2797 process
->brand
= LTTV_STATE_UNBRANDED
;
2798 //g_free(null_term_name);
2802 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2804 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2805 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2806 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2807 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2810 LttvProcessState
*process
= ts
->running_process
[cpu
];
2812 name
= ltt_event_get_string(e
, thf
->f1
);
2813 process
->brand
= g_quark_from_string(name
);
2818 static void fix_process(gpointer key
, gpointer value
,
2821 LttvProcessState
*process
;
2822 LttvExecutionState
*es
;
2823 process
= (LttvProcessState
*)value
;
2824 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2825 LttTime
*timestamp
= (LttTime
*)user_data
;
2827 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2828 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2829 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2830 es
->t
= LTTV_STATE_SYSCALL
;
2831 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2832 es
->entry
= *timestamp
;
2833 es
->change
= *timestamp
;
2834 es
->cum_cpu_time
= ltt_time_zero
;
2835 if(es
->s
== LTTV_STATE_UNNAMED
)
2836 es
->s
= LTTV_STATE_WAIT
;
2839 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2840 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2841 es
->t
= LTTV_STATE_USER_MODE
;
2842 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2843 es
->entry
= *timestamp
;
2844 //g_assert(timestamp->tv_sec != 0);
2845 es
->change
= *timestamp
;
2846 es
->cum_cpu_time
= ltt_time_zero
;
2847 if(es
->s
== LTTV_STATE_UNNAMED
)
2848 es
->s
= LTTV_STATE_RUN
;
2850 if(process
->execution_stack
->len
== 1) {
2851 /* Still in bottom unknown mode, means never did a system call
2852 * May be either in user mode, syscall mode, running or waiting.*/
2853 /* FIXME : we may be tagging syscall mode when being user mode */
2854 process
->execution_stack
=
2855 g_array_set_size(process
->execution_stack
, 2);
2856 es
= process
->state
= &g_array_index(process
->execution_stack
,
2857 LttvExecutionState
, 1);
2858 es
->t
= LTTV_STATE_SYSCALL
;
2859 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2860 es
->entry
= *timestamp
;
2861 //g_assert(timestamp->tv_sec != 0);
2862 es
->change
= *timestamp
;
2863 es
->cum_cpu_time
= ltt_time_zero
;
2864 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2865 es
->s
= LTTV_STATE_WAIT
;
2871 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2873 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2874 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2875 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2876 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2877 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2879 /* For all processes */
2880 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2881 /* else, if stack[0] is unknown, set to user mode, running */
2883 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2886 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2888 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2889 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2890 //It's slow : optimise later by doing this before reading trace.
2891 LttEventType
*et
= ltt_event_eventtype(e
);
2893 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2899 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2900 LttvProcessState
*process
= ts
->running_process
[cpu
];
2901 LttvProcessState
*parent_process
;
2902 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2903 GQuark type
, mode
, submode
, status
;
2904 LttvExecutionState
*es
;
2908 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2909 s
->parent
.target_pid
= pid
;
2912 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2915 command
= ltt_event_get_string(e
, thf
->f3
);
2918 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2919 type
= ltt_enum_string_get(ltt_field_type(f4
),
2920 ltt_event_get_unsigned(e
, f4
));
2923 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2924 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2925 ltt_event_get_unsigned(e
, f5
));
2928 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2929 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2930 ltt_event_get_unsigned(e
, f6
));
2933 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2934 status
= ltt_enum_string_get(ltt_field_type(f7
),
2935 ltt_event_get_unsigned(e
, f7
));
2938 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2939 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2944 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2945 for(i
=0; i
<nb_cpus
; i
++) {
2946 process
= lttv_state_find_process(ts
, i
, pid
);
2947 g_assert(process
!= NULL
);
2949 process
->ppid
= parent_pid
;
2950 process
->tgid
= tgid
;
2951 process
->name
= g_quark_from_string(command
);
2953 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2954 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2958 /* The process might exist if a process was forked while performing the
2960 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2961 if(process
== NULL
) {
2962 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2963 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2964 pid
, tgid
, g_quark_from_string(command
),
2965 &s
->parent
.timestamp
);
2967 /* Keep the stack bottom : a running user mode */
2968 /* Disabled because of inconsistencies in the current statedump states. */
2969 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2970 /* Only keep the bottom
2971 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2972 /* Will cause expected trap when in fact being syscall (even after end of
2974 * Will cause expected interrupt when being syscall. (only before end of
2975 * statedump event) */
2976 // This will cause a "popping last state on stack, ignoring it."
2977 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2978 es
= process
->state
= &g_array_index(process
->execution_stack
,
2979 LttvExecutionState
, 0);
2980 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2981 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2982 es
->s
= LTTV_STATE_UNNAMED
;
2983 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2985 es
->t
= LTTV_STATE_SYSCALL
;
2990 /* User space process :
2991 * bottom : user mode
2992 * either currently running or scheduled out.
2993 * can be scheduled out because interrupted in (user mode or in syscall)
2994 * or because of an explicit call to the scheduler in syscall. Note that
2995 * the scheduler call comes after the irq_exit, so never in interrupt
2997 // temp workaround : set size to 1 : only have user mode bottom of stack.
2998 // will cause g_info message of expected syscall mode when in fact being
2999 // in user mode. Can also cause expected trap when in fact being user
3000 // mode in the event of a page fault reenabling interrupts in the handler.
3001 // Expected syscall and trap can also happen after the end of statedump
3002 // This will cause a "popping last state on stack, ignoring it."
3003 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
3004 es
= process
->state
= &g_array_index(process
->execution_stack
,
3005 LttvExecutionState
, 0);
3006 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3007 es
->s
= LTTV_STATE_UNNAMED
;
3008 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3010 es
->t
= LTTV_STATE_USER_MODE
;
3018 es
= process
->state
= &g_array_index(process
->execution_stack
,
3019 LttvExecutionState
, 1);
3020 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
3021 es
->s
= LTTV_STATE_UNNAMED
;
3022 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
3026 /* The process has already been created :
3027 * Probably was forked while dumping the process state or
3028 * was simply scheduled in prior to get the state dump event.
3030 process
->ppid
= parent_pid
;
3031 process
->tgid
= tgid
;
3032 process
->name
= g_quark_from_string(command
);
3033 process
->type
= type
;
3035 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
3037 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
3038 if(type
== LTTV_STATE_KERNEL_THREAD
)
3039 es
->t
= LTTV_STATE_SYSCALL
;
3041 es
->t
= LTTV_STATE_USER_MODE
;
3044 /* Don't mess around with the stack, it will eventually become
3045 * ok after the end of state dump. */
3052 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3054 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3056 lttv_state_add_event_hooks(tss
);
3061 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3063 LttvTraceset
*traceset
= self
->parent
.ts
;
3065 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3069 LttvTracefileState
*tfs
;
3073 LttvTraceHookByFacility
*thf
;
3075 LttvTraceHook
*hook
;
3077 LttvAttributeValue val
;
3082 nb_trace
= lttv_traceset_number(traceset
);
3083 for(i
= 0 ; i
< nb_trace
; i
++) {
3084 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3086 /* Find the eventtype id for the following events and register the
3087 associated by id hooks. */
3089 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3090 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
3093 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3094 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3095 LTT_FIELD_SYSCALL_ID
, 0, 0,
3096 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3099 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3100 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3102 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3105 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3106 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
3107 LTT_FIELD_TRAP_ID
, 0, 0,
3108 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3111 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3112 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
3114 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3117 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3118 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3119 LTT_FIELD_IRQ_ID
, 0, 0,
3120 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3123 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3124 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3126 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3129 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3130 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3131 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3132 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3135 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3136 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3138 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3141 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3142 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
3143 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
3144 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3147 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3148 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
3149 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
3150 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3153 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3154 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
3155 LTT_FIELD_PID
, 0, 0,
3156 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3160 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3161 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3162 LTT_FIELD_PID
, 0, 0,
3163 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3166 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3167 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3168 LTT_FIELD_PID
, 0, 0,
3169 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3172 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3173 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3174 LTT_FIELD_FILENAME
, 0, 0,
3175 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3178 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3179 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3180 LTT_FIELD_NAME
, 0, 0,
3181 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3184 /* statedump-related hooks */
3185 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3186 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3187 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3188 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3191 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3192 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3194 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3197 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3198 LTT_FACILITY_LIST
, LTT_EVENT_LIST_INTERRUPT
,
3199 LTT_FIELD_ACTION
, LTT_FIELD_NUM
, 0,
3200 enum_interrupt
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3203 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3204 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3205 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3206 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3209 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3210 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3211 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3212 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3215 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3216 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3217 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3218 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3221 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3222 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3223 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3224 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3227 hooks
= g_array_set_size(hooks
, hn
);
3229 /* Add these hooks to each event_by_id hooks list */
3231 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3233 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3235 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3236 LttvTracefileContext
*, j
));
3238 for(k
= 0 ; k
< hooks
->len
; k
++) {
3239 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3240 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3241 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3243 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3250 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3251 *(val
.v_pointer
) = hooks
;
3255 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3257 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3259 lttv_state_remove_event_hooks(tss
);
3264 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3266 LttvTraceset
*traceset
= self
->parent
.ts
;
3268 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3272 LttvTracefileState
*tfs
;
3276 LttvTraceHook
*hook
;
3278 LttvTraceHookByFacility
*thf
;
3280 LttvAttributeValue val
;
3282 nb_trace
= lttv_traceset_number(traceset
);
3283 for(i
= 0 ; i
< nb_trace
; i
++) {
3284 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3286 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3287 hooks
= *(val
.v_pointer
);
3289 /* Remove these hooks from each event_by_id hooks list */
3291 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3293 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3295 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3296 LttvTracefileContext
*, j
));
3298 for(k
= 0 ; k
< hooks
->len
; k
++) {
3299 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3300 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3301 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3303 lttv_hooks_remove_data(
3304 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3310 for(k
= 0 ; k
< hooks
->len
; k
++)
3311 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3312 g_array_free(hooks
, TRUE
);
3316 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3318 guint
*event_count
= (guint
*)hook_data
;
3320 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3321 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3326 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3328 LttvTracefileState
*tfcs
;
3330 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3332 LttEventPosition
*ep
;
3338 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3340 LttvAttributeValue value
;
3342 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3343 LTTV_STATE_SAVED_STATES
);
3344 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3345 value
= lttv_attribute_add(saved_states_tree
,
3346 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3347 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3348 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3349 *(value
.v_time
) = self
->parent
.timestamp
;
3350 lttv_state_save(tcs
, saved_state_tree
);
3351 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3352 self
->parent
.timestamp
.tv_nsec
);
3354 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3359 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3361 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3363 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3368 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3376 static gboolean
block_start(void *hook_data
, void *call_data
)
3378 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3380 LttvTracefileState
*tfcs
;
3382 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3384 LttEventPosition
*ep
;
3386 guint i
, nb_block
, nb_event
, nb_tracefile
;
3390 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3392 LttvAttributeValue value
;
3394 ep
= ltt_event_position_new();
3396 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3398 /* Count the number of events added since the last block end in any
3401 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3403 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3404 LttvTracefileContext
, i
));
3405 ltt_event_position(tfcs
->parent
.e
, ep
);
3406 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3407 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3408 tfcs
->saved_position
= nb_event
;
3412 if(tcs
->nb_event
>= tcs
->save_interval
) {
3413 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3414 LTTV_STATE_SAVED_STATES
);
3415 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3416 value
= lttv_attribute_add(saved_states_tree
,
3417 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3418 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3419 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3420 *(value
.v_time
) = self
->parent
.timestamp
;
3421 lttv_state_save(tcs
, saved_state_tree
);
3423 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3424 self
->parent
.timestamp
.tv_nsec
);
3426 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3432 static gboolean
block_end(void *hook_data
, void *call_data
)
3434 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3436 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3440 LttEventPosition
*ep
;
3442 guint nb_block
, nb_event
;
3444 ep
= ltt_event_position_new();
3445 ltt_event_position(self
->parent
.e
, ep
);
3446 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3447 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3448 self
->saved_position
= 0;
3449 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3456 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3458 LttvTraceset
*traceset
= self
->parent
.ts
;
3460 guint i
, j
, nb_trace
, nb_tracefile
;
3464 LttvTracefileState
*tfs
;
3466 LttvTraceHook hook_start
, hook_end
;
3468 nb_trace
= lttv_traceset_number(traceset
);
3469 for(i
= 0 ; i
< nb_trace
; i
++) {
3470 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3472 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3473 NULL
, NULL
, block_start
, &hook_start
);
3474 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3475 NULL
, NULL
, block_end
, &hook_end
);
3477 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3479 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3481 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3482 LttvTracefileContext
, j
));
3483 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3484 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3485 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3486 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3492 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3494 LttvTraceset
*traceset
= self
->parent
.ts
;
3496 guint i
, j
, nb_trace
, nb_tracefile
;
3500 LttvTracefileState
*tfs
;
3503 nb_trace
= lttv_traceset_number(traceset
);
3504 for(i
= 0 ; i
< nb_trace
; i
++) {
3506 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3507 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3509 if(ts
->has_precomputed_states
) continue;
3511 guint
*event_count
= g_new(guint
, 1);
3514 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3516 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3517 LttvTracefileContext
*, j
));
3518 lttv_hooks_add(tfs
->parent
.event
,
3519 state_save_event_hook
,
3526 lttv_process_traceset_begin(&self
->parent
,
3527 NULL
, NULL
, NULL
, NULL
, NULL
);
3531 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3533 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3535 lttv_state_save_add_event_hooks(tss
);
3542 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3544 LttvTraceset
*traceset
= self
->parent
.ts
;
3546 guint i
, j
, nb_trace
, nb_tracefile
;
3550 LttvTracefileState
*tfs
;
3552 LttvTraceHook hook_start
, hook_end
;
3554 nb_trace
= lttv_traceset_number(traceset
);
3555 for(i
= 0 ; i
< nb_trace
; i
++) {
3556 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3558 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3559 NULL
, NULL
, block_start
, &hook_start
);
3561 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3562 NULL
, NULL
, block_end
, &hook_end
);
3564 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3566 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3568 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3569 LttvTracefileContext
, j
));
3570 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3571 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3572 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3573 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3579 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3581 LttvTraceset
*traceset
= self
->parent
.ts
;
3583 guint i
, j
, nb_trace
, nb_tracefile
;
3587 LttvTracefileState
*tfs
;
3589 LttvHooks
*after_trace
= lttv_hooks_new();
3591 lttv_hooks_add(after_trace
,
3592 state_save_after_trace_hook
,
3597 lttv_process_traceset_end(&self
->parent
,
3598 NULL
, after_trace
, NULL
, NULL
, NULL
);
3600 lttv_hooks_destroy(after_trace
);
3602 nb_trace
= lttv_traceset_number(traceset
);
3603 for(i
= 0 ; i
< nb_trace
; i
++) {
3605 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3606 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3608 if(ts
->has_precomputed_states
) continue;
3610 guint
*event_count
= NULL
;
3612 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3614 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3615 LttvTracefileContext
*, j
));
3616 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3617 state_save_event_hook
);
3619 if(event_count
) g_free(event_count
);
3623 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3625 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3627 lttv_state_save_remove_event_hooks(tss
);
3632 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3634 LttvTraceset
*traceset
= self
->parent
.ts
;
3638 int min_pos
, mid_pos
, max_pos
;
3640 guint call_rest
= 0;
3642 LttvTraceState
*tcs
;
3644 LttvAttributeValue value
;
3646 LttvAttributeType type
;
3648 LttvAttributeName name
;
3652 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3654 //g_tree_destroy(self->parent.pqueue);
3655 //self->parent.pqueue = g_tree_new(compare_tracefile);
3657 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3659 nb_trace
= lttv_traceset_number(traceset
);
3660 for(i
= 0 ; i
< nb_trace
; i
++) {
3661 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3663 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3664 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3665 LTTV_STATE_SAVED_STATES
);
3668 if(saved_states_tree
) {
3669 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3670 mid_pos
= max_pos
/ 2;
3671 while(min_pos
< max_pos
) {
3672 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3674 g_assert(type
== LTTV_GOBJECT
);
3675 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3676 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3678 g_assert(type
== LTTV_TIME
);
3679 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3681 closest_tree
= saved_state_tree
;
3683 else max_pos
= mid_pos
- 1;
3685 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3689 /* restore the closest earlier saved state */
3691 lttv_state_restore(tcs
, closest_tree
);
3695 /* There is no saved state, yet we want to have it. Restart at T0 */
3697 restore_init_state(tcs
);
3698 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3701 /* We want to seek quickly without restoring/updating the state */
3703 restore_init_state(tcs
);
3704 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3707 if(!call_rest
) g_info("NOT Calling restore");
3712 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3718 traceset_state_finalize (LttvTracesetState
*self
)
3720 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3721 finalize(G_OBJECT(self
));
3726 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3728 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3730 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3731 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3732 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3733 klass
->new_traceset_context
= new_traceset_context
;
3734 klass
->new_trace_context
= new_trace_context
;
3735 klass
->new_tracefile_context
= new_tracefile_context
;
3740 lttv_traceset_state_get_type(void)
3742 static GType type
= 0;
3744 static const GTypeInfo info
= {
3745 sizeof (LttvTracesetStateClass
),
3746 NULL
, /* base_init */
3747 NULL
, /* base_finalize */
3748 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3749 NULL
, /* class_finalize */
3750 NULL
, /* class_data */
3751 sizeof (LttvTracesetState
),
3752 0, /* n_preallocs */
3753 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3754 NULL
/* value handling */
3757 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3765 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3771 trace_state_finalize (LttvTraceState
*self
)
3773 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3774 finalize(G_OBJECT(self
));
3779 trace_state_class_init (LttvTraceStateClass
*klass
)
3781 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3783 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3784 klass
->state_save
= state_save
;
3785 klass
->state_restore
= state_restore
;
3786 klass
->state_saved_free
= state_saved_free
;
3791 lttv_trace_state_get_type(void)
3793 static GType type
= 0;
3795 static const GTypeInfo info
= {
3796 sizeof (LttvTraceStateClass
),
3797 NULL
, /* base_init */
3798 NULL
, /* base_finalize */
3799 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3800 NULL
, /* class_finalize */
3801 NULL
, /* class_data */
3802 sizeof (LttvTraceState
),
3803 0, /* n_preallocs */
3804 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3805 NULL
/* value handling */
3808 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3809 "LttvTraceStateType", &info
, 0);
3816 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3822 tracefile_state_finalize (LttvTracefileState
*self
)
3824 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3825 finalize(G_OBJECT(self
));
3830 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3832 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3834 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3839 lttv_tracefile_state_get_type(void)
3841 static GType type
= 0;
3843 static const GTypeInfo info
= {
3844 sizeof (LttvTracefileStateClass
),
3845 NULL
, /* base_init */
3846 NULL
, /* base_finalize */
3847 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3848 NULL
, /* class_finalize */
3849 NULL
, /* class_data */
3850 sizeof (LttvTracefileState
),
3851 0, /* n_preallocs */
3852 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3853 NULL
/* value handling */
3856 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3857 "LttvTracefileStateType", &info
, 0);
3863 static void module_init()
3865 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3866 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3867 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3868 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3869 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3870 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3871 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3872 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3873 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3874 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3875 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3876 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3877 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3878 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3879 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3880 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3881 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3882 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3883 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3884 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3885 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3886 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3887 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3888 LTTV_STATE_EVENT
= g_quark_from_string("event");
3889 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3890 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3891 LTTV_STATE_TIME
= g_quark_from_string("time");
3892 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3893 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3894 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3895 g_quark_from_string("trace_state_use_count");
3896 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3897 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3898 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3901 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3902 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3903 LTT_FACILITY_FS
= g_quark_from_string("fs");
3904 LTT_FACILITY_LIST
= g_quark_from_string("list");
3905 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3906 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3909 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3910 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3911 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3912 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3913 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3914 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3915 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3916 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3917 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3918 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3919 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3920 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3921 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3922 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3923 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3924 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3925 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3926 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3927 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3928 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3929 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3930 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3933 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3934 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3935 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3936 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3937 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3938 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3939 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3940 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3941 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3942 LTT_FIELD_PID
= g_quark_from_string("pid");
3943 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3944 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3945 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3946 LTT_FIELD_NAME
= g_quark_from_string("name");
3947 LTT_FIELD_TYPE
= g_quark_from_string("type");
3948 LTT_FIELD_MODE
= g_quark_from_string("mode");
3949 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3950 LTT_FIELD_STATUS
= g_quark_from_string("status");
3951 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3952 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3953 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3954 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3955 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3956 LTT_FIELD_ACTION
= g_quark_from_string("action");
3957 LTT_FIELD_NUM
= g_quark_from_string("num");
3959 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3960 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3961 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3962 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3963 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3965 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3966 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3967 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3969 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3970 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3971 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3972 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3975 static void module_destroy()
3980 LTTV_MODULE("state", "State computation", \
3981 "Update the system state, possibly saving it at intervals", \
3982 module_init
, module_destroy
)