1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <lttv/lttv.h>
25 #include <lttv/module.h>
26 #include <lttv/state.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_USER_GENERIC
,
58 LTT_EVENT_SYSCALL_ENTRY
,
59 LTT_EVENT_SYSCALL_EXIT
,
64 LTT_EVENT_SOFT_IRQ_ENTRY
,
65 LTT_EVENT_SOFT_IRQ_EXIT
,
66 LTT_EVENT_SCHED_SCHEDULE
,
67 LTT_EVENT_PROCESS_FORK
,
68 LTT_EVENT_KTHREAD_CREATE
,
69 LTT_EVENT_PROCESS_EXIT
,
70 LTT_EVENT_PROCESS_FREE
,
72 LTT_EVENT_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
,
77 LTT_EVENT_REQUEST_ISSUE
,
78 LTT_EVENT_REQUEST_COMPLETE
,
79 LTT_EVENT_LIST_INTERRUPT
;
87 LTT_FIELD_SOFT_IRQ_ID
,
111 LTTV_STATE_MODE_UNKNOWN
,
112 LTTV_STATE_USER_MODE
,
119 LTTV_STATE_SUBMODE_UNKNOWN
,
120 LTTV_STATE_SUBMODE_NONE
;
124 LTTV_STATE_WAIT_FORK
,
133 LTTV_STATE_UNBRANDED
;
136 LTTV_STATE_USER_THREAD
,
137 LTTV_STATE_KERNEL_THREAD
;
154 LTTV_BDEV_BUSY_READING
,
155 LTTV_BDEV_BUSY_WRITING
;
158 LTTV_STATE_TRACEFILES
,
159 LTTV_STATE_PROCESSES
,
161 LTTV_STATE_RUNNING_PROCESS
,
163 LTTV_STATE_SAVED_STATES
,
164 LTTV_STATE_SAVED_STATES_TIME
,
167 LTTV_STATE_NAME_TABLES
,
168 LTTV_STATE_TRACE_STATE_USE_COUNT
,
169 LTTV_STATE_RESOURCE_CPUS
,
170 LTTV_STATE_RESOURCE_IRQS
,
171 LTTV_STATE_RESOURCE_BLKDEVS
;
173 static void create_max_time(LttvTraceState
*tcs
);
175 static void get_max_time(LttvTraceState
*tcs
);
177 static void free_max_time(LttvTraceState
*tcs
);
179 static void create_name_tables(LttvTraceState
*tcs
);
181 static void get_name_tables(LttvTraceState
*tcs
);
183 static void free_name_tables(LttvTraceState
*tcs
);
185 static void free_saved_state(LttvTraceState
*tcs
);
187 static void lttv_state_free_process_table(GHashTable
*processes
);
189 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
190 GPtrArray
*quarktable
);
192 /* Resource function prototypes */
193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
);
194 static LttvBdevState
*bdevstate_new(void);
195 static void bdevstate_free(LttvBdevState
*);
196 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
);
197 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
);
200 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
202 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
206 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
208 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
212 void lttv_state_state_saved_free(LttvTraceState
*self
,
213 LttvAttribute
*container
)
215 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
219 guint
process_hash(gconstpointer key
)
221 guint pid
= ((const LttvProcessState
*)key
)->pid
;
222 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
226 /* If the hash table hash function is well distributed,
227 * the process_equal should compare different pid */
228 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
230 const LttvProcessState
*process_a
, *process_b
;
233 process_a
= (const LttvProcessState
*)a
;
234 process_b
= (const LttvProcessState
*)b
;
236 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
237 else if(likely(process_a
->pid
== 0 &&
238 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
243 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
245 g_tree_destroy((GTree
*)value
);
248 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
250 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
251 g_hash_table_destroy(usertraces
);
257 restore_init_state(LttvTraceState
*self
)
259 guint i
, nb_cpus
, nb_irqs
;
261 //LttvTracefileState *tfcs;
263 LttTime start_time
, end_time
;
265 /* Free the process tables */
266 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
267 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
268 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
269 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
272 /* Seek time to beginning */
273 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
274 // closest. It's the tracecontext job to seek the trace to the beginning
275 // anyway : the init state might be used at the middle of the trace as well...
276 //g_tree_destroy(self->parent.ts_context->pqueue);
277 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
279 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
281 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
283 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
284 nb_irqs
= self
->nb_irqs
;
286 /* Put the per cpu running_process to beginning state : process 0. */
287 for(i
=0; i
< nb_cpus
; i
++) {
288 LttvExecutionState
*es
;
289 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
290 LTTV_STATE_UNNAMED
, &start_time
);
291 /* We are not sure is it's a kernel thread or normal thread, put the
292 * bottom stack state to unknown */
293 self
->running_process
[i
]->execution_stack
=
294 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
295 es
= self
->running_process
[i
]->state
=
296 &g_array_index(self
->running_process
[i
]->execution_stack
,
297 LttvExecutionState
, 0);
298 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
299 es
->s
= LTTV_STATE_UNNAMED
;
301 //self->running_process[i]->state->s = LTTV_STATE_RUN;
302 self
->running_process
[i
]->cpu
= i
;
304 /* reset cpu states */
305 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
306 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
309 /* reset irq states */
310 for(i
=0; i
<nb_irqs
; i
++) {
311 if(self
->irq_states
[i
].mode_stack
->len
> 0)
312 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
315 /* reset bdev states */
316 g_hash_table_foreach(self
->bdev_states
, bdevstate_free_cb
, NULL
);
317 g_hash_table_steal_all(self
->bdev_states
);
320 nb_tracefile
= self
->parent
.tracefiles
->len
;
322 for(i
= 0 ; i
< nb_tracefile
; i
++) {
324 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
325 LttvTracefileContext
*, i
));
326 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
327 // tfcs->saved_position = 0;
328 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
329 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
330 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
331 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
336 //static LttTime time_zero = {0,0};
338 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
341 const LttTime
*t1
= (const LttTime
*)a
;
342 const LttTime
*t2
= (const LttTime
*)b
;
344 return ltt_time_compare(*t1
, *t2
);
347 static void free_usertrace_key(gpointer data
)
352 #define MAX_STRING_LEN 4096
355 state_load_saved_states(LttvTraceState
*tcs
)
358 GPtrArray
*quarktable
;
359 const char *trace_path
;
363 tcs
->has_precomputed_states
= FALSE
;
367 gchar buf
[MAX_STRING_LEN
];
370 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
371 strncpy(path
, trace_path
, PATH_MAX
-1);
372 count
= strnlen(trace_path
, PATH_MAX
-1);
373 // quarktable : open, test
374 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
375 fp
= fopen(path
, "r");
377 quarktable
= g_ptr_array_sized_new(4096);
379 /* Index 0 is null */
381 if(hdr
== EOF
) return;
382 g_assert(hdr
== HDR_QUARKS
);
386 if(hdr
== EOF
) break;
387 g_assert(hdr
== HDR_QUARK
);
388 g_ptr_array_set_size(quarktable
, q
+1);
391 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
392 if(buf
[i
] == '\0' || feof(fp
)) break;
395 len
= strnlen(buf
, MAX_STRING_LEN
-1);
396 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
397 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
403 // saved_states : open, test
404 strncpy(path
, trace_path
, PATH_MAX
-1);
405 count
= strnlen(trace_path
, PATH_MAX
-1);
406 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
407 fp
= fopen(path
, "r");
411 if(hdr
!= HDR_TRACE
) goto end
;
413 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
415 tcs
->has_precomputed_states
= TRUE
;
420 /* Free the quarktable */
421 for(i
=0; i
<quarktable
->len
; i
++) {
422 string
= g_ptr_array_index (quarktable
, i
);
425 g_ptr_array_free(quarktable
, TRUE
);
430 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
432 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
435 LttvTraceContext
*tc
;
439 LttvTracefileState
*tfcs
;
441 LttvAttributeValue v
;
443 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
444 init((LttvTracesetContext
*)self
, ts
);
446 nb_trace
= lttv_traceset_number(ts
);
447 for(i
= 0 ; i
< nb_trace
; i
++) {
448 tc
= self
->parent
.traces
[i
];
449 tcs
= LTTV_TRACE_STATE(tc
);
450 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
451 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
455 if(*(v
.v_uint
) == 1) {
456 create_name_tables(tcs
);
457 create_max_time(tcs
);
459 get_name_tables(tcs
);
462 nb_tracefile
= tc
->tracefiles
->len
;
463 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
464 nb_irq
= tcs
->nb_irqs
;
465 tcs
->processes
= NULL
;
466 tcs
->usertraces
= NULL
;
467 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
469 /* init cpu resource stuff */
470 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
471 for(j
= 0; j
<nb_cpu
; j
++) {
472 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
473 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
476 /* init irq resource stuff */
477 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
478 for(j
= 0; j
<nb_irq
; j
++) {
479 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
480 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
483 /* init bdev resource stuff */
484 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
486 restore_init_state(tcs
);
487 for(j
= 0 ; j
< nb_tracefile
; j
++) {
489 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
490 LttvTracefileContext
*, j
));
491 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
492 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
493 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
494 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
495 /* It's a Usertrace */
496 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
497 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
499 if(!usertrace_tree
) {
500 usertrace_tree
= g_tree_new_full(compare_usertraces
,
501 NULL
, free_usertrace_key
, NULL
);
502 g_hash_table_insert(tcs
->usertraces
,
503 (gpointer
)tid
, usertrace_tree
);
505 LttTime
*timestamp
= g_new(LttTime
, 1);
506 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
507 ltt_tracefile_creation(tfcs
->parent
.tf
));
508 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
512 /* See if the trace has saved states */
513 state_load_saved_states(tcs
);
518 fini(LttvTracesetState
*self
)
524 //LttvTracefileState *tfcs;
526 LttvAttributeValue v
;
528 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
529 for(i
= 0 ; i
< nb_trace
; i
++) {
530 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
531 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
534 g_assert(*(v
.v_uint
) != 0);
537 if(*(v
.v_uint
) == 0) {
538 free_name_tables(tcs
);
540 free_saved_state(tcs
);
542 g_free(tcs
->running_process
);
543 tcs
->running_process
= NULL
;
544 lttv_state_free_process_table(tcs
->processes
);
545 lttv_state_free_usertraces(tcs
->usertraces
);
546 tcs
->processes
= NULL
;
547 tcs
->usertraces
= NULL
;
549 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
550 fini((LttvTracesetContext
*)self
);
554 static LttvTracesetContext
*
555 new_traceset_context(LttvTracesetContext
*self
)
557 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
561 static LttvTraceContext
*
562 new_trace_context(LttvTracesetContext
*self
)
564 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
568 static LttvTracefileContext
*
569 new_tracefile_context(LttvTracesetContext
*self
)
571 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
575 /* Write the process state of the trace */
577 static void write_process_state(gpointer key
, gpointer value
,
580 LttvProcessState
*process
;
582 LttvExecutionState
*es
;
584 FILE *fp
= (FILE *)user_data
;
589 process
= (LttvProcessState
*)value
;
591 " <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",
592 process
, process
->pid
, process
->tgid
, process
->ppid
,
593 g_quark_to_string(process
->type
),
594 process
->creation_time
.tv_sec
,
595 process
->creation_time
.tv_nsec
,
596 process
->insertion_time
.tv_sec
,
597 process
->insertion_time
.tv_nsec
,
598 g_quark_to_string(process
->name
),
599 g_quark_to_string(process
->brand
),
602 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
603 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
604 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
605 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
606 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
607 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
608 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
611 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
612 address
= g_array_index(process
->user_stack
, guint64
, i
);
613 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
617 if(process
->usertrace
) {
618 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
619 g_quark_to_string(process
->usertrace
->tracefile_name
),
620 process
->usertrace
->cpu
);
624 fprintf(fp
, " </PROCESS>\n");
628 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
630 guint i
, nb_tracefile
, nb_block
, offset
;
633 LttvTracefileState
*tfcs
;
637 LttEventPosition
*ep
;
641 ep
= ltt_event_position_new();
643 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
645 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
647 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
648 for(i
=0;i
<nb_cpus
;i
++) {
649 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
650 i
, self
->running_process
[i
]->pid
);
653 nb_tracefile
= self
->parent
.tracefiles
->len
;
655 for(i
= 0 ; i
< nb_tracefile
; i
++) {
657 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
658 LttvTracefileContext
*, i
));
659 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
660 tfcs
->parent
.timestamp
.tv_sec
,
661 tfcs
->parent
.timestamp
.tv_nsec
);
662 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
663 if(e
== NULL
) fprintf(fp
,"/>\n");
665 ltt_event_position(e
, ep
);
666 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
667 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
672 fprintf(fp
,"</PROCESS_STATE>\n");
676 static void write_process_state_raw(gpointer key
, gpointer value
,
679 LttvProcessState
*process
;
681 LttvExecutionState
*es
;
683 FILE *fp
= (FILE *)user_data
;
688 process
= (LttvProcessState
*)value
;
689 fputc(HDR_PROCESS
, fp
);
690 //fwrite(&header, sizeof(header), 1, fp);
691 //fprintf(fp, "%s", g_quark_to_string(process->type));
693 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
694 //fprintf(fp, "%s", g_quark_to_string(process->name));
696 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
697 //fprintf(fp, "%s", g_quark_to_string(process->brand));
699 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
700 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
701 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
702 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
703 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
704 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
705 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
709 " <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",
710 process
, process
->pid
, process
->tgid
, process
->ppid
,
711 g_quark_to_string(process
->type
),
712 process
->creation_time
.tv_sec
,
713 process
->creation_time
.tv_nsec
,
714 process
->insertion_time
.tv_sec
,
715 process
->insertion_time
.tv_nsec
,
716 g_quark_to_string(process
->name
),
717 g_quark_to_string(process
->brand
),
721 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
722 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
725 //fprintf(fp, "%s", g_quark_to_string(es->t));
727 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
728 //fprintf(fp, "%s", g_quark_to_string(es->n));
730 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
731 //fprintf(fp, "%s", g_quark_to_string(es->s));
733 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
734 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
735 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
736 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
738 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
739 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
740 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
741 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
742 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
746 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
747 address
= g_array_index(process
->user_stack
, guint64
, i
);
748 fputc(HDR_USER_STACK
, fp
);
749 fwrite(&address
, sizeof(address
), 1, fp
);
751 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
756 if(process
->usertrace
) {
757 fputc(HDR_USERTRACE
, fp
);
758 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
760 fwrite(&process
->usertrace
->tracefile_name
,
761 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
762 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
764 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
765 g_quark_to_string(process
->usertrace
->tracefile_name
),
766 process
->usertrace
->cpu
);
773 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
775 guint i
, nb_tracefile
, nb_block
, offset
;
778 LttvTracefileState
*tfcs
;
782 LttEventPosition
*ep
;
786 ep
= ltt_event_position_new();
788 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
789 fputc(HDR_PROCESS_STATE
, fp
);
790 fwrite(&t
, sizeof(t
), 1, fp
);
792 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
794 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
795 for(i
=0;i
<nb_cpus
;i
++) {
797 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
798 fwrite(&self
->running_process
[i
]->pid
,
799 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
800 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
801 // i, self->running_process[i]->pid);
804 nb_tracefile
= self
->parent
.tracefiles
->len
;
806 for(i
= 0 ; i
< nb_tracefile
; i
++) {
808 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
809 LttvTracefileContext
*, i
));
810 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
811 // tfcs->parent.timestamp.tv_sec,
812 // tfcs->parent.timestamp.tv_nsec);
813 fputc(HDR_TRACEFILE
, fp
);
814 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
815 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
816 * position following : end of trace */
817 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
819 ltt_event_position(e
, ep
);
820 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
821 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
823 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
824 fwrite(&offset
, sizeof(offset
), 1, fp
);
825 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
832 /* Read process state from a file */
834 /* Called because a HDR_PROCESS was found */
835 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
836 GPtrArray
*quarktable
)
838 LttvExecutionState
*es
;
839 LttvProcessState
*process
, *parent_process
;
840 LttvProcessState tmp
;
845 /* TODO : check return value */
846 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
847 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
848 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
849 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
850 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
851 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
852 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
853 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
854 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
857 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
859 /* We must link to the parent */
860 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
862 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
863 if(process
== NULL
) {
864 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
866 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
870 process
->insertion_time
= tmp
.insertion_time
;
871 process
->creation_time
= tmp
.creation_time
;
872 process
->type
= g_quark_from_string(
873 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
874 process
->tgid
= tmp
.tgid
;
875 process
->ppid
= tmp
.ppid
;
876 process
->brand
= g_quark_from_string(
877 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
879 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
883 if(feof(fp
) || ferror(fp
)) goto end_loop
;
885 gint hdr
= fgetc(fp
);
886 if(hdr
== EOF
) goto end_loop
;
890 process
->execution_stack
=
891 g_array_set_size(process
->execution_stack
,
892 process
->execution_stack
->len
+ 1);
893 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
894 process
->execution_stack
->len
-1);
897 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
898 es
->t
= g_quark_from_string(
899 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
900 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
901 es
->n
= g_quark_from_string(
902 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
903 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
904 es
->s
= g_quark_from_string(
905 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
906 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
907 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
908 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
911 process
->user_stack
= g_array_set_size(process
->user_stack
,
912 process
->user_stack
->len
+ 1);
913 address
= &g_array_index(process
->user_stack
, guint64
,
914 process
->user_stack
->len
-1);
915 fread(address
, sizeof(address
), 1, fp
);
916 process
->current_function
= *address
;
919 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
920 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
932 /* Called because a HDR_PROCESS_STATE was found */
933 /* Append a saved state to the trace states */
934 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
936 guint i
, nb_tracefile
, nb_block
, offset
;
938 LttvTracefileState
*tfcs
;
940 LttEventPosition
*ep
;
948 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
950 LttvAttributeValue value
;
951 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
952 ep
= ltt_event_position_new();
954 restore_init_state(self
);
956 fread(&t
, sizeof(t
), 1, fp
);
959 if(feof(fp
) || ferror(fp
)) goto end_loop
;
961 if(hdr
== EOF
) goto end_loop
;
965 /* Call read_process_state_raw */
966 read_process_state_raw(self
, fp
, quarktable
);
976 case HDR_PROCESS_STATE
:
982 g_error("Error while parsing saved state file : unknown data header %d",
988 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
989 for(i
=0;i
<nb_cpus
;i
++) {
992 g_assert(hdr
== HDR_CPU
);
993 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
994 g_assert(i
== cpu_num
);
995 fread(&self
->running_process
[i
]->pid
,
996 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
999 nb_tracefile
= self
->parent
.tracefiles
->len
;
1001 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1003 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1004 LttvTracefileContext
*, i
));
1005 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1006 // tfcs->parent.timestamp.tv_sec,
1007 // tfcs->parent.timestamp.tv_nsec);
1008 g_tree_remove(pqueue
, &tfcs
->parent
);
1010 g_assert(hdr
== HDR_TRACEFILE
);
1011 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1012 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1013 * position following : end of trace */
1014 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1015 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1016 fread(&offset
, sizeof(offset
), 1, fp
);
1017 fread(&tsc
, sizeof(tsc
), 1, fp
);
1018 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1019 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1021 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1026 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1027 LTTV_STATE_SAVED_STATES
);
1028 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1029 value
= lttv_attribute_add(saved_states_tree
,
1030 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1031 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1032 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1033 *(value
.v_time
) = t
;
1034 lttv_state_save(self
, saved_state_tree
);
1035 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1038 *(self
->max_time_state_recomputed_in_seek
) = t
;
1042 /* Called when a HDR_TRACE is found */
1043 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1044 GPtrArray
*quarktable
)
1049 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1051 if(hdr
== EOF
) goto end_loop
;
1054 case HDR_PROCESS_STATE
:
1055 /* Call read_process_state_raw */
1056 lttv_state_read_raw(tcs
, fp
, quarktable
);
1064 case HDR_USER_STACK
:
1068 g_error("Error while parsing saved state file :"
1069 " unexpected data header %d",
1073 g_error("Error while parsing saved state file : unknown data header %d",
1078 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1079 restore_init_state(tcs
);
1080 lttv_process_trace_seek_time(&tcs
->parent
, ltt_time_zero
);
1086 /* Copy each process from an existing hash table to a new one */
1088 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1090 LttvProcessState
*process
, *new_process
;
1092 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1096 process
= (LttvProcessState
*)value
;
1097 new_process
= g_new(LttvProcessState
, 1);
1098 *new_process
= *process
;
1099 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1100 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1101 new_process
->execution_stack
=
1102 g_array_set_size(new_process
->execution_stack
,
1103 process
->execution_stack
->len
);
1104 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1105 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1106 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1108 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1109 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1110 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1111 sizeof(guint64
), 0);
1112 new_process
->user_stack
=
1113 g_array_set_size(new_process
->user_stack
,
1114 process
->user_stack
->len
);
1115 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1116 g_array_index(new_process
->user_stack
, guint64
, i
) =
1117 g_array_index(process
->user_stack
, guint64
, i
);
1119 new_process
->current_function
= process
->current_function
;
1120 g_hash_table_insert(new_processes
, new_process
, new_process
);
1124 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1126 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1128 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1129 return new_processes
;
1132 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1135 LttvCPUState
*retval
;
1137 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1139 for(i
=0; i
<n
; i
++) {
1140 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1141 retval
[i
].last_irq
= states
[i
].last_irq
;
1142 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1143 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1144 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1151 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1155 for(i
=0; i
<n
; i
++) {
1156 g_array_free(states
[i
].mode_stack
, FALSE
);
1162 static LttvIRQState
*lttv_state_copy_irq_states(LttvIRQState
*states
, guint n
)
1165 LttvIRQState
*retval
;
1167 retval
= g_malloc(n
*sizeof(LttvIRQState
));
1169 for(i
=0; i
<n
; i
++) {
1170 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
1171 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1172 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1173 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1180 static void lttv_state_free_irq_states(LttvIRQState
*states
, guint n
)
1184 for(i
=0; i
<n
; i
++) {
1185 g_array_free(states
[i
].mode_stack
, FALSE
);
1191 /* bdevstate stuff */
1193 static LttvBdevState
*get_hashed_bdevstate(LttvTraceState
*ts
, guint16 devcode
)
1195 gint devcode_gint
= devcode
;
1196 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1198 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
1199 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1201 gint
* key
= g_malloc(sizeof(gint
));
1203 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
1211 static LttvBdevState
*bdevstate_new(void)
1213 LttvBdevState
*retval
;
1214 retval
= g_malloc(sizeof(LttvBdevState
));
1215 retval
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
1220 static void bdevstate_free(LttvBdevState
*bds
)
1222 g_array_free(bds
->mode_stack
, FALSE
);
1226 static void bdevstate_free_cb(gpointer key
, gpointer value
, gpointer user_data
)
1228 LttvBdevState
*bds
= (LttvBdevState
*) value
;
1230 bdevstate_free(bds
);
1233 static LttvBdevState
*bdevstate_copy(LttvBdevState
*bds
)
1235 LttvBdevState
*retval
;
1237 retval
= bdevstate_new();
1238 g_array_insert_vals(retval
->mode_stack
, 0, bds
->mode_stack
->data
, bds
->mode_stack
->len
);
1243 static void insert_and_copy_bdev_state(gpointer k
, gpointer v
, gpointer u
)
1245 //GHashTable *ht = (GHashTable *)u;
1246 LttvBdevState
*bds
= (LttvBdevState
*)v
;
1247 LttvBdevState
*newbds
;
1249 newbds
= bdevstate_copy(bds
);
1251 g_hash_table_insert(u
, k
, newbds
);
1254 static GHashTable
*lttv_state_copy_blkdev_hashtable(GHashTable
*ht
)
1258 retval
= g_hash_table_new(g_int_hash
, g_int_equal
);
1260 g_hash_table_foreach(ht
, insert_and_copy_bdev_state
, retval
);
1265 /* Free a hashtable and the LttvBdevState structures its values
1268 static void lttv_state_free_blkdev_hashtable(GHashTable
*ht
)
1270 g_hash_table_foreach(ht
, bdevstate_free_cb
, NULL
);
1271 g_hash_table_destroy(ht
);
1274 /* The saved state for each trace contains a member "processes", which
1275 stores a copy of the process table, and a member "tracefiles" with
1276 one entry per tracefile. Each tracefile has a "process" member pointing
1277 to the current process and a "position" member storing the tracefile
1278 position (needed to seek to the current "next" event. */
1280 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1282 guint i
, nb_tracefile
, nb_cpus
, nb_irqs
;
1284 LttvTracefileState
*tfcs
;
1286 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1288 guint
*running_process
;
1290 LttvAttributeValue value
;
1292 LttEventPosition
*ep
;
1294 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1295 LTTV_STATE_TRACEFILES
);
1297 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1299 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1301 /* Add the currently running processes array */
1302 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1303 running_process
= g_new(guint
, nb_cpus
);
1304 for(i
=0;i
<nb_cpus
;i
++) {
1305 running_process
[i
] = self
->running_process
[i
]->pid
;
1307 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1309 *(value
.v_pointer
) = running_process
;
1311 g_info("State save");
1313 nb_tracefile
= self
->parent
.tracefiles
->len
;
1315 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1317 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1318 LttvTracefileContext
*, i
));
1319 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1320 value
= lttv_attribute_add(tracefiles_tree
, i
,
1322 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1324 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1326 *(value
.v_uint
) = tfcs
->process
->pid
;
1328 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1330 /* Only save the position if the tfs has not infinite time. */
1331 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1332 // && current_tfcs != tfcs) {
1333 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1334 *(value
.v_pointer
) = NULL
;
1336 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1337 ep
= ltt_event_position_new();
1338 ltt_event_position(e
, ep
);
1339 *(value
.v_pointer
) = ep
;
1341 guint nb_block
, offset
;
1344 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1345 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1347 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1351 /* save the cpu state */
1353 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1355 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1358 /* save the irq state */
1359 nb_irqs
= self
->nb_irqs
;
1361 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_IRQS
,
1363 *(value
.v_pointer
) = lttv_state_copy_irq_states(self
->irq_states
, nb_irqs
);
1366 /* save the blkdev states */
1367 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_BLKDEVS
,
1369 *(value
.v_pointer
) = lttv_state_copy_blkdev_hashtable(self
->bdev_states
);
1373 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1375 guint i
, nb_tracefile
, pid
, nb_cpus
, nb_irqs
;
1377 LttvTracefileState
*tfcs
;
1379 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1381 guint
*running_process
;
1383 LttvAttributeType type
;
1385 LttvAttributeValue value
;
1387 LttvAttributeName name
;
1391 LttEventPosition
*ep
;
1393 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1395 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1396 LTTV_STATE_TRACEFILES
);
1398 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1400 g_assert(type
== LTTV_POINTER
);
1401 lttv_state_free_process_table(self
->processes
);
1402 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1404 /* Add the currently running processes array */
1405 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1406 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1408 g_assert(type
== LTTV_POINTER
);
1409 running_process
= *(value
.v_pointer
);
1410 for(i
=0;i
<nb_cpus
;i
++) {
1411 pid
= running_process
[i
];
1412 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1413 g_assert(self
->running_process
[i
] != NULL
);
1416 nb_tracefile
= self
->parent
.tracefiles
->len
;
1418 //g_tree_destroy(tsc->pqueue);
1419 //tsc->pqueue = g_tree_new(compare_tracefile);
1421 /* restore cpu resource states */
1422 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1423 g_assert(type
== LTTV_POINTER
);
1424 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1425 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1427 /* restore irq resource states */
1428 nb_irqs
= self
->nb_irqs
;
1429 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_IRQS
, &value
);
1430 g_assert(type
== LTTV_POINTER
);
1431 lttv_state_free_irq_states(self
->irq_states
, nb_irqs
);
1432 self
->irq_states
= lttv_state_copy_irq_states(*(value
.v_pointer
), nb_irqs
);
1434 /* restore the blkdev states */
1435 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_BLKDEVS
, &value
);
1436 g_assert(type
== LTTV_POINTER
);
1437 lttv_state_free_blkdev_hashtable(self
->bdev_states
);
1438 self
->bdev_states
= lttv_state_copy_blkdev_hashtable(*(value
.v_pointer
));
1440 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1442 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1443 LttvTracefileContext
*, i
));
1444 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1445 g_assert(type
== LTTV_GOBJECT
);
1446 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1448 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1450 g_assert(type
== LTTV_UINT
);
1451 pid
= *(value
.v_uint
);
1452 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1454 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1456 g_assert(type
== LTTV_POINTER
);
1457 //g_assert(*(value.v_pointer) != NULL);
1458 ep
= *(value
.v_pointer
);
1459 g_assert(tfcs
->parent
.t_context
!= NULL
);
1461 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1463 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1464 g_tree_remove(tsc
->pqueue
, tfc
);
1467 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1468 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1469 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1470 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1471 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1473 tfc
->timestamp
= ltt_time_infinite
;
1479 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1481 guint i
, nb_tracefile
, nb_cpus
;
1483 LttvTracefileState
*tfcs
;
1485 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1487 guint
*running_process
;
1489 LttvAttributeType type
;
1491 LttvAttributeValue value
;
1493 LttvAttributeName name
;
1497 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1498 LTTV_STATE_TRACEFILES
);
1499 g_object_ref(G_OBJECT(tracefiles_tree
));
1500 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1502 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1504 g_assert(type
== LTTV_POINTER
);
1505 lttv_state_free_process_table(*(value
.v_pointer
));
1506 *(value
.v_pointer
) = NULL
;
1507 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1509 /* Free running processes array */
1510 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1511 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1513 g_assert(type
== LTTV_POINTER
);
1514 running_process
= *(value
.v_pointer
);
1515 g_free(running_process
);
1517 nb_tracefile
= self
->parent
.tracefiles
->len
;
1519 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1521 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1522 LttvTracefileContext
*, i
));
1523 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1524 g_assert(type
== LTTV_GOBJECT
);
1525 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1527 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1529 g_assert(type
== LTTV_POINTER
);
1530 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1532 g_object_unref(G_OBJECT(tracefiles_tree
));
1536 static void free_saved_state(LttvTraceState
*self
)
1540 LttvAttributeType type
;
1542 LttvAttributeValue value
;
1544 LttvAttributeName name
;
1548 LttvAttribute
*saved_states
;
1550 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1551 LTTV_STATE_SAVED_STATES
);
1553 nb
= lttv_attribute_get_number(saved_states
);
1554 for(i
= 0 ; i
< nb
; i
++) {
1555 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1556 g_assert(type
== LTTV_GOBJECT
);
1557 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1560 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1565 create_max_time(LttvTraceState
*tcs
)
1567 LttvAttributeValue v
;
1569 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1571 g_assert(*(v
.v_pointer
) == NULL
);
1572 *(v
.v_pointer
) = g_new(LttTime
,1);
1573 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1578 get_max_time(LttvTraceState
*tcs
)
1580 LttvAttributeValue v
;
1582 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1584 g_assert(*(v
.v_pointer
) != NULL
);
1585 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1590 free_max_time(LttvTraceState
*tcs
)
1592 LttvAttributeValue v
;
1594 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1596 g_free(*(v
.v_pointer
));
1597 *(v
.v_pointer
) = NULL
;
1601 typedef struct _LttvNameTables
{
1602 // FIXME GQuark *eventtype_names;
1603 GQuark
*syscall_names
;
1609 GQuark
*soft_irq_names
;
1615 create_name_tables(LttvTraceState
*tcs
)
1619 GString
*fe_name
= g_string_new("");
1621 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1623 LttvAttributeValue v
;
1627 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1629 g_assert(*(v
.v_pointer
) == NULL
);
1630 *(v
.v_pointer
) = name_tables
;
1632 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 1);
1634 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1635 LTT_EVENT_SYSCALL_ENTRY
,
1636 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
1637 NULL
, NULL
, &hooks
)) {
1639 // th = lttv_trace_hook_get_first(&th);
1641 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1642 // nb = ltt_type_element_number(t);
1644 // name_tables->syscall_names = g_new(GQuark, nb);
1645 // name_tables->nb_syscalls = nb;
1647 // for(i = 0 ; i < nb ; i++) {
1648 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1649 // if(!name_tables->syscall_names[i]) {
1650 // GString *string = g_string_new("");
1651 // g_string_printf(string, "syscall %u", i);
1652 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1653 // g_string_free(string, TRUE);
1657 name_tables
->syscall_names
= g_new(GQuark
, 256);
1658 for(i
= 0 ; i
< 256 ; i
++) {
1659 g_string_printf(fe_name
, "syscall %d", i
);
1660 name_tables
->syscall_names
[i
] = g_quark_from_string(fe_name
->str
);
1663 name_tables
->syscall_names
= NULL
;
1664 name_tables
->nb_syscalls
= 0;
1666 lttv_trace_hook_remove_all(&hooks
);
1668 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1669 LTT_EVENT_TRAP_ENTRY
,
1670 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
1671 NULL
, NULL
, &hooks
)) {
1673 // th = lttv_trace_hook_get_first(&th);
1675 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1676 // //nb = ltt_type_element_number(t);
1678 // name_tables->trap_names = g_new(GQuark, nb);
1679 // for(i = 0 ; i < nb ; i++) {
1680 // name_tables->trap_names[i] = g_quark_from_string(
1681 // ltt_enum_string_get(t, i));
1684 name_tables
->nb_traps
= 256;
1685 name_tables
->trap_names
= g_new(GQuark
, 256);
1686 for(i
= 0 ; i
< 256 ; i
++) {
1687 g_string_printf(fe_name
, "trap %d", i
);
1688 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1691 name_tables
->trap_names
= NULL
;
1692 name_tables
->nb_traps
= 0;
1694 lttv_trace_hook_remove_all(&hooks
);
1696 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1697 LTT_EVENT_IRQ_ENTRY
,
1698 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
1699 NULL
, NULL
, &hooks
)) {
1702 name_tables->irq_names = g_new(GQuark, nb);
1703 for(i = 0 ; i < nb ; i++) {
1704 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1708 name_tables
->nb_irqs
= 256;
1709 name_tables
->irq_names
= g_new(GQuark
, 256);
1710 for(i
= 0 ; i
< 256 ; i
++) {
1711 g_string_printf(fe_name
, "irq %d", i
);
1712 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1715 name_tables
->nb_irqs
= 0;
1716 name_tables
->irq_names
= NULL
;
1718 lttv_trace_hook_remove_all(&hooks
);
1720 name_tables->soft_irq_names = g_new(GQuark, nb);
1721 for(i = 0 ; i < nb ; i++) {
1722 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1726 name_tables
->nb_softirqs
= 256;
1727 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1728 for(i
= 0 ; i
< 256 ; i
++) {
1729 g_string_printf(fe_name
, "softirq %d", i
);
1730 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1732 g_array_free(hooks
, TRUE
);
1734 g_string_free(fe_name
, TRUE
);
1739 get_name_tables(LttvTraceState
*tcs
)
1741 LttvNameTables
*name_tables
;
1743 LttvAttributeValue v
;
1745 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1747 g_assert(*(v
.v_pointer
) != NULL
);
1748 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1749 //tcs->eventtype_names = name_tables->eventtype_names;
1750 tcs
->syscall_names
= name_tables
->syscall_names
;
1751 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1752 tcs
->trap_names
= name_tables
->trap_names
;
1753 tcs
->nb_traps
= name_tables
->nb_traps
;
1754 tcs
->irq_names
= name_tables
->irq_names
;
1755 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1756 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1757 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1762 free_name_tables(LttvTraceState
*tcs
)
1764 LttvNameTables
*name_tables
;
1766 LttvAttributeValue v
;
1768 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1770 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1771 *(v
.v_pointer
) = NULL
;
1773 // g_free(name_tables->eventtype_names);
1774 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1775 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1776 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1777 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1778 if(name_tables
) g_free(name_tables
);
1781 #ifdef HASH_TABLE_DEBUG
1783 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1785 LttvProcessState
*process
= (LttvProcessState
*)value
;
1787 /* Test for process corruption */
1788 guint stack_len
= process
->execution_stack
->len
;
1791 static void hash_table_check(GHashTable
*table
)
1793 g_hash_table_foreach(table
, test_process
, NULL
);
1799 /* clears the stack and sets the state passed as argument */
1800 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1802 g_array_set_size(cpust
->mode_stack
, 1);
1803 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1806 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1808 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1809 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1812 static void cpu_pop_mode(LttvCPUState
*cpust
)
1814 if(cpust
->mode_stack
->len
<= 1)
1815 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1817 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1820 /* clears the stack and sets the state passed as argument */
1821 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1823 g_array_set_size(bdevst
->mode_stack
, 1);
1824 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1827 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1829 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1830 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1833 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1835 if(bdevst
->mode_stack
->len
<= 1)
1836 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1838 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1841 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1843 g_array_set_size(irqst
->mode_stack
, 1);
1844 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1847 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1849 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1850 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1853 static void irq_pop_mode(LttvIRQState
*irqst
)
1855 if(irqst
->mode_stack
->len
<= 1)
1856 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1858 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1861 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1864 LttvExecutionState
*es
;
1866 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1867 guint cpu
= tfs
->cpu
;
1869 #ifdef HASH_TABLE_DEBUG
1870 hash_table_check(ts
->processes
);
1872 LttvProcessState
*process
= ts
->running_process
[cpu
];
1874 guint depth
= process
->execution_stack
->len
;
1876 process
->execution_stack
=
1877 g_array_set_size(process
->execution_stack
, depth
+ 1);
1880 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1882 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1885 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1886 es
->cum_cpu_time
= ltt_time_zero
;
1887 es
->s
= process
->state
->s
;
1888 process
->state
= es
;
1892 * return 1 when empty, else 0 */
1893 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1894 LttvTracefileState
*tfs
)
1896 guint depth
= process
->execution_stack
->len
;
1902 process
->execution_stack
=
1903 g_array_set_size(process
->execution_stack
, depth
- 1);
1904 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1906 process
->state
->change
= tfs
->parent
.timestamp
;
1911 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1913 guint cpu
= tfs
->cpu
;
1914 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1915 LttvProcessState
*process
= ts
->running_process
[cpu
];
1917 guint depth
= process
->execution_stack
->len
;
1919 if(process
->state
->t
!= t
){
1920 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1921 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1922 g_info("process state has %s when pop_int is %s\n",
1923 g_quark_to_string(process
->state
->t
),
1924 g_quark_to_string(t
));
1925 g_info("{ %u, %u, %s, %s, %s }\n",
1928 g_quark_to_string(process
->name
),
1929 g_quark_to_string(process
->brand
),
1930 g_quark_to_string(process
->state
->s
));
1935 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1936 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1940 process
->execution_stack
=
1941 g_array_set_size(process
->execution_stack
, depth
- 1);
1942 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1944 process
->state
->change
= tfs
->parent
.timestamp
;
1947 struct search_result
{
1948 const LttTime
*time
; /* Requested time */
1949 LttTime
*best
; /* Best result */
1952 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1954 const LttTime
*elem_time
= (const LttTime
*)a
;
1955 /* Explicit non const cast */
1956 struct search_result
*res
= (struct search_result
*)b
;
1958 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1959 /* The usertrace was created before the schedchange */
1960 /* Get larger keys */
1962 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1963 /* The usertrace was created after the schedchange time */
1964 /* Get smaller keys */
1966 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1967 res
->best
= (LttTime
*)elem_time
;
1970 res
->best
= (LttTime
*)elem_time
;
1977 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1978 guint pid
, const LttTime
*timestamp
)
1980 LttvTracefileState
*tfs
= NULL
;
1981 struct search_result res
;
1982 /* Find the usertrace associated with a pid and time interval.
1983 * Search in the usertraces by PID (within a hash) and then, for each
1984 * corresponding element of the array, find the first one with creation
1985 * timestamp the lowest, but higher or equal to "timestamp". */
1986 res
.time
= timestamp
;
1988 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1989 if(usertrace_tree
) {
1990 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1992 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
2000 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
2001 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
2003 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
2005 LttvExecutionState
*es
;
2010 process
->tgid
= tgid
;
2012 process
->name
= name
;
2013 process
->brand
= LTTV_STATE_UNBRANDED
;
2014 //process->last_cpu = tfs->cpu_name;
2015 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2016 process
->type
= LTTV_STATE_USER_THREAD
;
2017 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
2018 process
->current_function
= 0; //function 0x0 by default.
2020 g_info("Process %u, core %p", process
->pid
, process
);
2021 g_hash_table_insert(tcs
->processes
, process
, process
);
2024 process
->ppid
= parent
->pid
;
2025 process
->creation_time
= *timestamp
;
2028 /* No parent. This process exists but we are missing all information about
2029 its creation. The birth time is set to zero but we remember the time of
2034 process
->creation_time
= ltt_time_zero
;
2037 process
->insertion_time
= *timestamp
;
2038 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
2039 process
->creation_time
.tv_nsec
);
2040 process
->pid_time
= g_quark_from_string(buffer
);
2042 //process->last_cpu = tfs->cpu_name;
2043 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2044 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
2045 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2046 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
2047 es
= process
->state
= &g_array_index(process
->execution_stack
,
2048 LttvExecutionState
, 0);
2049 es
->t
= LTTV_STATE_USER_MODE
;
2050 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2051 es
->entry
= *timestamp
;
2052 //g_assert(timestamp->tv_sec != 0);
2053 es
->change
= *timestamp
;
2054 es
->cum_cpu_time
= ltt_time_zero
;
2055 es
->s
= LTTV_STATE_RUN
;
2057 es
= process
->state
= &g_array_index(process
->execution_stack
,
2058 LttvExecutionState
, 1);
2059 es
->t
= LTTV_STATE_SYSCALL
;
2060 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2061 es
->entry
= *timestamp
;
2062 //g_assert(timestamp->tv_sec != 0);
2063 es
->change
= *timestamp
;
2064 es
->cum_cpu_time
= ltt_time_zero
;
2065 es
->s
= LTTV_STATE_WAIT_FORK
;
2067 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2068 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
2069 sizeof(guint64
), 0);
2074 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
2077 LttvProcessState key
;
2078 LttvProcessState
*process
;
2082 process
= g_hash_table_lookup(ts
->processes
, &key
);
2087 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
2088 const LttTime
*timestamp
)
2090 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
2091 LttvExecutionState
*es
;
2093 /* Put ltt_time_zero creation time for unexisting processes */
2094 if(unlikely(process
== NULL
)) {
2095 process
= lttv_state_create_process(ts
,
2096 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
2097 /* We are not sure is it's a kernel thread or normal thread, put the
2098 * bottom stack state to unknown */
2099 process
->execution_stack
=
2100 g_array_set_size(process
->execution_stack
, 1);
2101 process
->state
= es
=
2102 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2103 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2104 es
->s
= LTTV_STATE_UNNAMED
;
2109 /* FIXME : this function should be called when we receive an event telling that
2110 * release_task has been called in the kernel. In happens generally when
2111 * the parent waits for its child terminaison, but may also happen in special
2112 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2113 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2114 * of a killed thread ground, but isn't the leader.
2116 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2118 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2119 LttvProcessState key
;
2121 key
.pid
= process
->pid
;
2122 key
.cpu
= process
->cpu
;
2123 g_hash_table_remove(ts
->processes
, &key
);
2124 g_array_free(process
->execution_stack
, TRUE
);
2125 g_array_free(process
->user_stack
, TRUE
);
2130 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2132 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2133 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2138 static void lttv_state_free_process_table(GHashTable
*processes
)
2140 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2141 g_hash_table_destroy(processes
);
2145 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2147 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2149 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2150 LttvProcessState
*process
= ts
->running_process
[cpu
];
2151 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2152 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2153 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2155 LttvExecutionSubmode submode
;
2157 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2158 guint syscall
= ltt_event_get_unsigned(e
, f
);
2160 if(syscall
< nb_syscalls
) {
2161 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2164 /* Fixup an incomplete syscall table */
2165 GString
*string
= g_string_new("");
2166 g_string_printf(string
, "syscall %u", syscall
);
2167 submode
= g_quark_from_string(string
->str
);
2168 g_string_free(string
, TRUE
);
2170 /* There can be no system call from PID 0 : unknown state */
2171 if(process
->pid
!= 0)
2172 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2177 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2179 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2181 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2182 LttvProcessState
*process
= ts
->running_process
[cpu
];
2184 /* There can be no system call from PID 0 : unknown state */
2185 if(process
->pid
!= 0)
2186 pop_state(s
, LTTV_STATE_SYSCALL
);
2191 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2193 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2194 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2195 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2196 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2198 LttvExecutionSubmode submode
;
2200 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2201 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2203 if(trap
< nb_traps
) {
2204 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2206 /* Fixup an incomplete trap table */
2207 GString
*string
= g_string_new("");
2208 g_string_printf(string
, "trap %llu", trap
);
2209 submode
= g_quark_from_string(string
->str
);
2210 g_string_free(string
, TRUE
);
2213 push_state(s
, LTTV_STATE_TRAP
, submode
);
2215 /* update cpu status */
2216 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2221 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2223 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2225 pop_state(s
, LTTV_STATE_TRAP
);
2227 /* update cpu status */
2228 cpu_pop_mode(s
->cpu_state
);
2233 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2235 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2236 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2237 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2238 //guint8 ev_id = ltt_event_eventtype_id(e);
2239 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2240 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2242 LttvExecutionSubmode submode
;
2243 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2244 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2247 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2249 /* Fixup an incomplete irq table */
2250 GString
*string
= g_string_new("");
2251 g_string_printf(string
, "irq %llu", irq
);
2252 submode
= g_quark_from_string(string
->str
);
2253 g_string_free(string
, TRUE
);
2256 /* Do something with the info about being in user or system mode when int? */
2257 push_state(s
, LTTV_STATE_IRQ
, submode
);
2259 /* update cpu status */
2260 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2262 /* update irq status */
2263 s
->cpu_state
->last_irq
= irq
;
2264 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2269 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2271 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2273 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2279 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2281 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2282 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2284 pop_state(s
, LTTV_STATE_IRQ
);
2286 /* update cpu status */
2287 cpu_pop_mode(s
->cpu_state
);
2289 /* update irq status */
2290 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2295 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2297 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2298 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2299 //guint8 ev_id = ltt_event_eventtype_id(e);
2300 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2301 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2303 LttvExecutionSubmode submode
;
2304 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2305 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2307 if(softirq
< nb_softirqs
) {
2308 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2310 /* Fixup an incomplete irq table */
2311 GString
*string
= g_string_new("");
2312 g_string_printf(string
, "softirq %llu", softirq
);
2313 submode
= g_quark_from_string(string
->str
);
2314 g_string_free(string
, TRUE
);
2317 /* Do something with the info about being in user or system mode when int? */
2318 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2322 static gboolean
enum_interrupt(void *hook_data
, void *call_data
)
2324 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2325 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2326 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2327 //guint8 ev_id = ltt_event_eventtype_id(e);
2328 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2330 GQuark action
= g_quark_from_string(ltt_event_get_string(e
,
2331 lttv_trace_get_hook_field(th
, 0)));
2332 guint irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2334 ts
->irq_names
[irq
] = action
;
2340 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2342 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2343 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2344 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2345 //guint8 ev_id = ltt_event_eventtype_id(e);
2346 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2348 guint major
= ltt_event_get_long_unsigned(e
,
2349 lttv_trace_get_hook_field(th
, 0));
2350 guint minor
= ltt_event_get_long_unsigned(e
,
2351 lttv_trace_get_hook_field(th
, 1));
2352 guint oper
= ltt_event_get_long_unsigned(e
,
2353 lttv_trace_get_hook_field(th
, 2));
2354 guint16 devcode
= MKDEV(major
,minor
);
2356 /* have we seen this block device before? */
2357 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2360 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2362 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2367 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2369 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2370 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2371 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2372 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2374 guint major
= ltt_event_get_long_unsigned(e
,
2375 lttv_trace_get_hook_field(th
, 0));
2376 guint minor
= ltt_event_get_long_unsigned(e
,
2377 lttv_trace_get_hook_field(th
, 1));
2378 //guint oper = ltt_event_get_long_unsigned(e,
2379 // lttv_trace_get_hook_field(th, 2));
2380 guint16 devcode
= MKDEV(major
,minor
);
2382 /* have we seen this block device before? */
2383 gpointer bdev
= get_hashed_bdevstate(ts
, devcode
);
2385 /* update block device */
2386 bdev_pop_mode(bdev
);
2391 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2395 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2396 guint cpu
= tfs
->cpu
;
2397 LttvProcessState
*process
= ts
->running_process
[cpu
];
2399 guint depth
= process
->user_stack
->len
;
2401 process
->user_stack
=
2402 g_array_set_size(process
->user_stack
, depth
+ 1);
2404 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2405 *new_func
= funcptr
;
2406 process
->current_function
= funcptr
;
2409 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2411 guint cpu
= tfs
->cpu
;
2412 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2413 LttvProcessState
*process
= ts
->running_process
[cpu
];
2415 if(process
->current_function
!= funcptr
){
2416 g_info("Different functions (%lu.%09lu): ignore it\n",
2417 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2418 g_info("process state has %llu when pop_function is %llu\n",
2419 process
->current_function
, funcptr
);
2420 g_info("{ %u, %u, %s, %s, %s }\n",
2423 g_quark_to_string(process
->name
),
2424 g_quark_to_string(process
->brand
),
2425 g_quark_to_string(process
->state
->s
));
2428 guint depth
= process
->user_stack
->len
;
2431 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2432 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2436 process
->user_stack
=
2437 g_array_set_size(process
->user_stack
, depth
- 1);
2438 process
->current_function
=
2439 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2443 static gboolean
function_entry(void *hook_data
, void *call_data
)
2445 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2446 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2447 //guint8 ev_id = ltt_event_eventtype_id(e);
2448 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2449 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2450 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2452 push_function(s
, funcptr
);
2456 static gboolean
function_exit(void *hook_data
, void *call_data
)
2458 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2459 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2460 //guint8 ev_id = ltt_event_eventtype_id(e);
2461 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2462 struct marker_field
*f
= lttv_trace_get_hook_field(th
, 0);
2463 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2465 pop_function(s
, funcptr
);
2469 static gboolean
schedchange(void *hook_data
, void *call_data
)
2471 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2473 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2474 LttvProcessState
*process
= ts
->running_process
[cpu
];
2475 //LttvProcessState *old_process = ts->running_process[cpu];
2477 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2478 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2479 guint pid_in
, pid_out
;
2482 pid_out
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2483 pid_in
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2484 state_out
= ltt_event_get_long_int(e
, lttv_trace_get_hook_field(th
, 2));
2486 if(likely(process
!= NULL
)) {
2488 /* We could not know but it was not the idle process executing.
2489 This should only happen at the beginning, before the first schedule
2490 event, and when the initial information (current process for each CPU)
2491 is missing. It is not obvious how we could, after the fact, compensate
2492 the wrongly attributed statistics. */
2494 //This test only makes sense once the state is known and if there is no
2495 //missing events. We need to silently ignore schedchange coming after a
2496 //process_free, or it causes glitches. (FIXME)
2497 //if(unlikely(process->pid != pid_out)) {
2498 // g_assert(process->pid == 0);
2500 if(process
->pid
== 0
2501 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2503 /* Scheduling out of pid 0 at beginning of the trace :
2504 * we know for sure it is in syscall mode at this point. */
2505 g_assert(process
->execution_stack
->len
== 1);
2506 process
->state
->t
= LTTV_STATE_SYSCALL
;
2507 process
->state
->s
= LTTV_STATE_WAIT
;
2508 process
->state
->change
= s
->parent
.timestamp
;
2509 process
->state
->entry
= s
->parent
.timestamp
;
2512 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2513 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2514 process
->state
->change
= s
->parent
.timestamp
;
2516 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2517 else process
->state
->s
= LTTV_STATE_WAIT
;
2518 process
->state
->change
= s
->parent
.timestamp
;
2521 if(state_out
== 32 || state_out
== 128)
2522 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2523 /* see sched.h for states */
2526 process
= ts
->running_process
[cpu
] =
2527 lttv_state_find_process_or_create(
2528 (LttvTraceState
*)s
->parent
.t_context
,
2530 &s
->parent
.timestamp
);
2531 process
->state
->s
= LTTV_STATE_RUN
;
2533 if(process
->usertrace
)
2534 process
->usertrace
->cpu
= cpu
;
2535 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2536 process
->state
->change
= s
->parent
.timestamp
;
2538 /* update cpu status */
2540 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2542 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2547 static gboolean
process_fork(void *hook_data
, void *call_data
)
2549 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2550 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2551 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2553 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2554 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2555 //LttvProcessState *zombie_process;
2557 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2558 LttvProcessState
*process
= ts
->running_process
[cpu
];
2559 LttvProcessState
*child_process
;
2560 struct marker_field
*f
;
2563 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2566 child_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2567 s
->parent
.target_pid
= child_pid
;
2570 f
= lttv_trace_get_hook_field(th
, 2);
2572 child_tgid
= ltt_event_get_unsigned(e
, f
);
2576 /* Mathieu : it seems like the process might have been scheduled in before the
2577 * fork, and, in a rare case, might be the current process. This might happen
2578 * in a SMP case where we don't have enough precision on the clocks.
2580 * Test reenabled after precision fixes on time. (Mathieu) */
2582 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2584 if(unlikely(zombie_process
!= NULL
)) {
2585 /* Reutilisation of PID. Only now we are sure that the old PID
2586 * has been released. FIXME : should know when release_task happens instead.
2588 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2590 for(i
=0; i
< num_cpus
; i
++) {
2591 g_assert(zombie_process
!= ts
->running_process
[i
]);
2594 exit_process(s
, zombie_process
);
2597 g_assert(process
->pid
!= child_pid
);
2598 // FIXME : Add this test in the "known state" section
2599 // g_assert(process->pid == parent_pid);
2600 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2601 if(child_process
== NULL
) {
2602 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2603 child_pid
, child_tgid
,
2604 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2606 /* The process has already been created : due to time imprecision between
2607 * multiple CPUs : it has been scheduled in before creation. Note that we
2608 * shouldn't have this kind of imprecision.
2610 * Simply put a correct parent.
2612 g_assert(0); /* This is a problematic case : the process has been created
2613 before the fork event */
2614 child_process
->ppid
= process
->pid
;
2615 child_process
->tgid
= child_tgid
;
2617 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2618 child_process
->name
= process
->name
;
2619 child_process
->brand
= process
->brand
;
2624 /* We stamp a newly created process as kernel_thread.
2625 * The thread should not be running yet. */
2626 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2628 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2629 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2630 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2632 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2633 LttvProcessState
*process
;
2634 LttvExecutionState
*es
;
2637 pid
= (guint
)ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2638 s
->parent
.target_pid
= pid
;
2640 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2642 process
->execution_stack
=
2643 g_array_set_size(process
->execution_stack
, 1);
2644 es
= process
->state
=
2645 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2646 es
->t
= LTTV_STATE_SYSCALL
;
2647 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2652 static gboolean
process_exit(void *hook_data
, void *call_data
)
2654 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2655 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2656 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2658 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2659 LttvProcessState
*process
; // = ts->running_process[cpu];
2661 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2662 s
->parent
.target_pid
= pid
;
2664 // FIXME : Add this test in the "known state" section
2665 // g_assert(process->pid == pid);
2667 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2668 if(likely(process
!= NULL
)) {
2669 process
->state
->s
= LTTV_STATE_EXIT
;
2674 static gboolean
process_free(void *hook_data
, void *call_data
)
2676 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2677 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2678 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2679 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2681 LttvProcessState
*process
;
2683 /* PID of the process to release */
2684 release_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2685 s
->parent
.target_pid
= release_pid
;
2687 g_assert(release_pid
!= 0);
2689 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2691 if(likely(process
!= NULL
)) {
2692 /* release_task is happening at kernel level : we can now safely release
2693 * the data structure of the process */
2694 //This test is fun, though, as it may happen that
2695 //at time t : CPU 0 : process_free
2696 //at time t+150ns : CPU 1 : schedule out
2697 //Clearly due to time imprecision, we disable it. (Mathieu)
2698 //If this weird case happen, we have no choice but to put the
2699 //Currently running process on the cpu to 0.
2700 //I re-enable it following time precision fixes. (Mathieu)
2701 //Well, in the case where an process is freed by a process on another CPU
2702 //and still scheduled, it happens that this is the schedchange that will
2703 //drop the last reference count. Do not free it here!
2704 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2706 for(i
=0; i
< num_cpus
; i
++) {
2707 //g_assert(process != ts->running_process[i]);
2708 if(process
== ts
->running_process
[i
]) {
2709 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2713 if(i
== num_cpus
) /* process is not scheduled */
2714 exit_process(s
, process
);
2721 static gboolean
process_exec(void *hook_data
, void *call_data
)
2723 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2724 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2725 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2726 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2729 LttvProcessState
*process
= ts
->running_process
[cpu
];
2731 #if 0//how to use a sequence that must be transformed in a string
2732 /* PID of the process to release */
2733 guint64 name_len
= ltt_event_field_element_number(e
,
2734 lttv_trace_get_hook_field(th
, 0));
2735 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2736 LttField
*child
= ltt_event_field_element_select(e
,
2737 lttv_trace_get_hook_field(th
, 0), 0);
2739 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2740 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2741 memcpy(null_term_name
, name_begin
, name_len
);
2742 null_term_name
[name_len
] = '\0';
2743 process
->name
= g_quark_from_string(null_term_name
);
2746 process
->name
= g_quark_from_string(ltt_event_get_string(e
,
2747 lttv_trace_get_hook_field(th
, 0)));
2748 process
->brand
= LTTV_STATE_UNBRANDED
;
2749 //g_free(null_term_name);
2753 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2755 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2756 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2757 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2758 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2761 LttvProcessState
*process
= ts
->running_process
[cpu
];
2763 name
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 0));
2764 process
->brand
= g_quark_from_string(name
);
2769 static void fix_process(gpointer key
, gpointer value
,
2772 LttvProcessState
*process
;
2773 LttvExecutionState
*es
;
2774 process
= (LttvProcessState
*)value
;
2775 LttTime
*timestamp
= (LttTime
*)user_data
;
2777 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2778 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2779 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2780 es
->t
= LTTV_STATE_SYSCALL
;
2781 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2782 es
->entry
= *timestamp
;
2783 es
->change
= *timestamp
;
2784 es
->cum_cpu_time
= ltt_time_zero
;
2785 if(es
->s
== LTTV_STATE_UNNAMED
)
2786 es
->s
= LTTV_STATE_WAIT
;
2789 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2790 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2791 es
->t
= LTTV_STATE_USER_MODE
;
2792 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2793 es
->entry
= *timestamp
;
2794 //g_assert(timestamp->tv_sec != 0);
2795 es
->change
= *timestamp
;
2796 es
->cum_cpu_time
= ltt_time_zero
;
2797 if(es
->s
== LTTV_STATE_UNNAMED
)
2798 es
->s
= LTTV_STATE_RUN
;
2800 if(process
->execution_stack
->len
== 1) {
2801 /* Still in bottom unknown mode, means never did a system call
2802 * May be either in user mode, syscall mode, running or waiting.*/
2803 /* FIXME : we may be tagging syscall mode when being user mode */
2804 process
->execution_stack
=
2805 g_array_set_size(process
->execution_stack
, 2);
2806 es
= process
->state
= &g_array_index(process
->execution_stack
,
2807 LttvExecutionState
, 1);
2808 es
->t
= LTTV_STATE_SYSCALL
;
2809 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2810 es
->entry
= *timestamp
;
2811 //g_assert(timestamp->tv_sec != 0);
2812 es
->change
= *timestamp
;
2813 es
->cum_cpu_time
= ltt_time_zero
;
2814 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2815 es
->s
= LTTV_STATE_WAIT
;
2821 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2823 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2824 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2825 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2826 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2827 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2829 /* For all processes */
2830 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2831 /* else, if stack[0] is unknown, set to user mode, running */
2833 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2838 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2840 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2841 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2842 //It's slow : optimise later by doing this before reading trace.
2843 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2849 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2850 LttvProcessState
*process
= ts
->running_process
[cpu
];
2851 LttvProcessState
*parent_process
;
2852 struct marker_field
*f
;
2853 GQuark type
, mode
, submode
, status
;
2854 LttvExecutionState
*es
;
2858 pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2859 s
->parent
.target_pid
= pid
;
2862 parent_pid
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
2865 command
= ltt_event_get_string(e
, lttv_trace_get_hook_field(th
, 2));
2868 f
= lttv_trace_get_hook_field(th
, 3);
2869 type
= ltt_enum_string_get(ltt_field_type(f
),
2870 ltt_event_get_unsigned(e
, f
));
2873 f
= lttv_trace_get_hook_field(th
, 4);
2874 mode
= ltt_enum_string_get(ltt_field_type(f
),
2875 ltt_event_get_unsigned(e
, f
));
2878 f
= lttv_trace_get_hook_field(th
, 5);
2879 submode
= ltt_enum_string_get(ltt_field_type(f
),
2880 ltt_event_get_unsigned(e
, f
));
2883 f
= lttv_trace_get_hook_field(th
, 6);
2884 status
= ltt_enum_string_get(ltt_field_type(f
),
2885 ltt_event_get_unsigned(e
, f
));
2888 f
= lttv_trace_get_hook_field(th
, 7);
2890 tgid
= ltt_event_get_unsigned(e
, f
);
2895 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2896 for(i
=0; i
<nb_cpus
; i
++) {
2897 process
= lttv_state_find_process(ts
, i
, pid
);
2898 g_assert(process
!= NULL
);
2900 process
->ppid
= parent_pid
;
2901 process
->tgid
= tgid
;
2902 process
->name
= g_quark_from_string(command
);
2904 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2905 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2909 /* The process might exist if a process was forked while performing the
2911 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2912 if(process
== NULL
) {
2913 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2914 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2915 pid
, tgid
, g_quark_from_string(command
),
2916 &s
->parent
.timestamp
);
2918 /* Keep the stack bottom : a running user mode */
2919 /* Disabled because of inconsistencies in the current statedump states. */
2920 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2921 /* Only keep the bottom
2922 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2923 /* Will cause expected trap when in fact being syscall (even after end of
2925 * Will cause expected interrupt when being syscall. (only before end of
2926 * statedump event) */
2927 // This will cause a "popping last state on stack, ignoring it."
2928 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2929 es
= process
->state
= &g_array_index(process
->execution_stack
,
2930 LttvExecutionState
, 0);
2931 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2932 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2933 es
->s
= LTTV_STATE_UNNAMED
;
2934 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2936 es
->t
= LTTV_STATE_SYSCALL
;
2941 /* User space process :
2942 * bottom : user mode
2943 * either currently running or scheduled out.
2944 * can be scheduled out because interrupted in (user mode or in syscall)
2945 * or because of an explicit call to the scheduler in syscall. Note that
2946 * the scheduler call comes after the irq_exit, so never in interrupt
2948 // temp workaround : set size to 1 : only have user mode bottom of stack.
2949 // will cause g_info message of expected syscall mode when in fact being
2950 // in user mode. Can also cause expected trap when in fact being user
2951 // mode in the event of a page fault reenabling interrupts in the handler.
2952 // Expected syscall and trap can also happen after the end of statedump
2953 // This will cause a "popping last state on stack, ignoring it."
2954 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2955 es
= process
->state
= &g_array_index(process
->execution_stack
,
2956 LttvExecutionState
, 0);
2957 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2958 es
->s
= LTTV_STATE_UNNAMED
;
2959 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2961 es
->t
= LTTV_STATE_USER_MODE
;
2969 es
= process
->state
= &g_array_index(process
->execution_stack
,
2970 LttvExecutionState
, 1);
2971 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2972 es
->s
= LTTV_STATE_UNNAMED
;
2973 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2977 /* The process has already been created :
2978 * Probably was forked while dumping the process state or
2979 * was simply scheduled in prior to get the state dump event.
2981 process
->ppid
= parent_pid
;
2982 process
->tgid
= tgid
;
2983 process
->name
= g_quark_from_string(command
);
2984 process
->type
= type
;
2986 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2988 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2989 if(type
== LTTV_STATE_KERNEL_THREAD
)
2990 es
->t
= LTTV_STATE_SYSCALL
;
2992 es
->t
= LTTV_STATE_USER_MODE
;
2995 /* Don't mess around with the stack, it will eventually become
2996 * ok after the end of state dump. */
3003 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3005 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3007 lttv_state_add_event_hooks(tss
);
3012 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3014 LttvTraceset
*traceset
= self
->parent
.ts
;
3016 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3020 LttvTracefileState
*tfs
;
3026 LttvAttributeValue val
;
3031 nb_trace
= lttv_traceset_number(traceset
);
3032 for(i
= 0 ; i
< nb_trace
; i
++) {
3033 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3035 /* Find the eventtype id for the following events and register the
3036 associated by id hooks. */
3038 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
3039 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3042 lttv_trace_find_hook(ts
->parent
.t
,
3043 LTT_EVENT_SYSCALL_ENTRY
,
3044 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID
),
3045 syscall_entry
, NULL
, &hooks
);
3047 lttv_trace_find_hook(ts
->parent
.t
,
3048 LTT_EVENT_SYSCALL_EXIT
,
3050 syscall_exit
, NULL
, &hooks
);
3052 lttv_trace_find_hook(ts
->parent
.t
,
3053 LTT_EVENT_TRAP_ENTRY
,
3054 FIELD_ARRAY(LTT_FIELD_TRAP_ID
),
3055 trap_entry
, NULL
, &hooks
);
3057 lttv_trace_find_hook(ts
->parent
.t
,
3058 LTT_EVENT_TRAP_EXIT
,
3060 trap_exit
, NULL
, &hooks
);
3062 lttv_trace_find_hook(ts
->parent
.t
,
3063 LTT_EVENT_IRQ_ENTRY
,
3064 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
3065 irq_entry
, NULL
, &hooks
);
3067 lttv_trace_find_hook(ts
->parent
.t
,
3070 irq_exit
, NULL
, &hooks
);
3072 lttv_trace_find_hook(ts
->parent
.t
,
3073 LTT_EVENT_SOFT_IRQ_ENTRY
,
3074 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID
),
3075 soft_irq_entry
, NULL
, &hooks
);
3077 lttv_trace_find_hook(ts
->parent
.t
,
3078 LTT_EVENT_SOFT_IRQ_EXIT
,
3080 soft_irq_exit
, NULL
, &hooks
);
3082 lttv_trace_find_hook(ts
->parent
.t
,
3083 LTT_EVENT_SCHED_SCHEDULE
,
3084 FIELD_ARRAY(LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
,
3085 LTT_FIELD_PREV_STATE
),
3086 schedchange
, NULL
, &hooks
);
3088 lttv_trace_find_hook(ts
->parent
.t
,
3089 LTT_EVENT_PROCESS_FORK
,
3090 FIELD_ARRAY(LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
,
3091 LTT_FIELD_CHILD_TGID
),
3092 process_fork
, NULL
, &hooks
);
3094 lttv_trace_find_hook(ts
->parent
.t
,
3095 LTT_EVENT_KTHREAD_CREATE
,
3096 FIELD_ARRAY(LTT_FIELD_PID
)
3097 process_kernel_thread
, NULL
, &hooks
);
3099 lttv_trace_find_hook(ts
->parent
.t
,
3100 LTT_EVENT_PROCESS_EXIT
,
3101 FIELD_ARRAY(LTT_FIELD_PID
),
3102 process_exit
, NULL
, &hooks
);
3104 lttv_trace_find_hook(ts
->parent
.t
,
3105 LTT_EVENT_PROCESS_FREE
,
3106 FIELD_ARRAY(LTT_FIELD_PID
),
3107 process_free
, NULL
, &hooks
);
3109 lttv_trace_find_hook(ts
->parent
.t
,
3111 FIELD_ARRAY(LTT_FIELD_FILENAME
),
3112 process_exec
, NULL
, &hooks
);
3114 lttv_trace_find_hook(ts
->parent
.t
,
3115 LTT_EVENT_THREAD_BRAND
,
3116 FIELD_ARRAY(LTT_FIELD_NAME
),
3117 thread_brand
, NULL
, &hooks
);
3119 /* statedump-related hooks */
3120 lttv_trace_find_hook(ts
->parent
.t
,
3121 LTT_EVENT_PROCESS_STATE
,
3122 FIELD_ARRAY(LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3123 LTT_FIELD_TYPE
, LTT_FIELD_MODE
, LTT_FIELD_SUBMODE
,
3124 LTT_FIELD_STATUS
, LTT_FIELD_TGID
),
3125 enum_process_state
, NULL
, &hooks
);
3127 lttv_trace_find_hook(ts
->parent
.t
,
3128 LTT_EVENT_STATEDUMP_END
,
3130 statedump_end
, NULL
, &hooks
);
3132 lttv_trace_find_hook(ts
->parent
.t
,
3133 LTT_EVENT_LIST_INTERRUPT
,
3134 FIELD_ARRAY(LTT_FIELD_ACTION
, LTT_FIELD_NUM
),
3135 enum_interrupt
, NULL
, &hooks
);
3137 lttv_trace_find_hook(ts
->parent
.t
,
3138 LTT_EVENT_REQUEST_ISSUE
,
3139 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3140 bdev_request_issue
, NULL
, &hooks
);
3142 lttv_trace_find_hook(ts
->parent
.t
,
3143 LTT_EVENT_REQUEST_COMPLETE
,
3144 FIELD_ARRAY(LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
),
3145 bdev_request_complete
, NULL
, &hooks
);
3147 lttv_trace_find_hook(ts
->parent
.t
,
3148 LTT_EVENT_FUNCTION_ENTRY
,
3149 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3150 function_entry
, NULL
, &hooks
);
3152 lttv_trace_find_hook(ts
->parent
.t
,
3153 LTT_EVENT_FUNCTION_EXIT
,
3154 FIELD_ARRAY(LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
),
3155 function_exit
, NULL
, &hooks
);
3157 /* Add these hooks to each event_by_id hooks list */
3159 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3161 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3163 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3164 LttvTracefileContext
*, j
));
3166 for(k
= 0 ; k
< hooks
->len
; k
++) {
3167 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3169 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3175 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3176 *(val
.v_pointer
) = hooks
;
3180 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3182 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3184 lttv_state_remove_event_hooks(tss
);
3189 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3191 LttvTraceset
*traceset
= self
->parent
.ts
;
3193 guint i
, j
, k
, nb_trace
, nb_tracefile
;
3197 LttvTracefileState
*tfs
;
3203 LttvAttributeValue val
;
3205 nb_trace
= lttv_traceset_number(traceset
);
3206 for(i
= 0 ; i
< nb_trace
; i
++) {
3207 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3209 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3210 hooks
= *(val
.v_pointer
);
3212 /* Remove these hooks from each event_by_id hooks list */
3214 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3216 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3218 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3219 LttvTracefileContext
*, j
));
3221 for(k
= 0 ; k
< hooks
->len
; k
++) {
3222 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
3223 lttv_hooks_remove_data(
3224 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, th
->id
),
3229 lttv_trace_hook_remove_all(&hooks
);
3230 g_array_free(hooks
, TRUE
);
3234 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3236 guint
*event_count
= (guint
*)hook_data
;
3238 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3239 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3244 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3246 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3248 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3250 LttvAttributeValue value
;
3252 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3253 LTTV_STATE_SAVED_STATES
);
3254 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3255 value
= lttv_attribute_add(saved_states_tree
,
3256 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3257 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3258 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3259 *(value
.v_time
) = self
->parent
.timestamp
;
3260 lttv_state_save(tcs
, saved_state_tree
);
3261 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3262 self
->parent
.timestamp
.tv_nsec
);
3264 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3269 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3271 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3273 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3278 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3286 static gboolean
block_start(void *hook_data
, void *call_data
)
3288 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3290 LttvTracefileState
*tfcs
;
3292 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3294 LttEventPosition
*ep
;
3296 guint i
, nb_block
, nb_event
, nb_tracefile
;
3300 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3302 LttvAttributeValue value
;
3304 ep
= ltt_event_position_new();
3306 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3308 /* Count the number of events added since the last block end in any
3311 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3313 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3314 LttvTracefileContext
, i
));
3315 ltt_event_position(tfcs
->parent
.e
, ep
);
3316 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3317 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3318 tfcs
->saved_position
= nb_event
;
3322 if(tcs
->nb_event
>= tcs
->save_interval
) {
3323 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3324 LTTV_STATE_SAVED_STATES
);
3325 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3326 value
= lttv_attribute_add(saved_states_tree
,
3327 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3328 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3329 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3330 *(value
.v_time
) = self
->parent
.timestamp
;
3331 lttv_state_save(tcs
, saved_state_tree
);
3333 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3334 self
->parent
.timestamp
.tv_nsec
);
3336 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3342 static gboolean
block_end(void *hook_data
, void *call_data
)
3344 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3346 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3350 LttEventPosition
*ep
;
3352 guint nb_block
, nb_event
;
3354 ep
= ltt_event_position_new();
3355 ltt_event_position(self
->parent
.e
, ep
);
3356 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3357 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3358 self
->saved_position
= 0;
3359 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3366 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3368 LttvTraceset
*traceset
= self
->parent
.ts
;
3370 guint i
, j
, nb_trace
, nb_tracefile
;
3374 LttvTracefileState
*tfs
;
3376 LttvTraceHook hook_start
, hook_end
;
3378 nb_trace
= lttv_traceset_number(traceset
);
3379 for(i
= 0 ; i
< nb_trace
; i
++) {
3380 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3382 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3383 NULL
, NULL
, block_start
, &hook_start
);
3384 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3385 NULL
, NULL
, block_end
, &hook_end
);
3387 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3389 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3391 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3392 LttvTracefileContext
, j
));
3393 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3394 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3395 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3396 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3402 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3404 LttvTraceset
*traceset
= self
->parent
.ts
;
3406 guint i
, j
, nb_trace
, nb_tracefile
;
3410 LttvTracefileState
*tfs
;
3413 nb_trace
= lttv_traceset_number(traceset
);
3414 for(i
= 0 ; i
< nb_trace
; i
++) {
3416 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3417 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3419 if(ts
->has_precomputed_states
) continue;
3421 guint
*event_count
= g_new(guint
, 1);
3424 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3426 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3427 LttvTracefileContext
*, j
));
3428 lttv_hooks_add(tfs
->parent
.event
,
3429 state_save_event_hook
,
3436 lttv_process_traceset_begin(&self
->parent
,
3437 NULL
, NULL
, NULL
, NULL
, NULL
);
3441 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3443 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3445 lttv_state_save_add_event_hooks(tss
);
3452 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3454 LttvTraceset
*traceset
= self
->parent
.ts
;
3456 guint i
, j
, nb_trace
, nb_tracefile
;
3460 LttvTracefileState
*tfs
;
3462 LttvTraceHook hook_start
, hook_end
;
3464 nb_trace
= lttv_traceset_number(traceset
);
3465 for(i
= 0 ; i
< nb_trace
; i
++) {
3466 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3468 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3469 NULL
, NULL
, block_start
, &hook_start
);
3471 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3472 NULL
, NULL
, block_end
, &hook_end
);
3474 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3476 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3478 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3479 LttvTracefileContext
, j
));
3480 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3481 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3482 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3483 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3489 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3491 LttvTraceset
*traceset
= self
->parent
.ts
;
3493 guint i
, j
, nb_trace
, nb_tracefile
;
3497 LttvTracefileState
*tfs
;
3499 LttvHooks
*after_trace
= lttv_hooks_new();
3501 lttv_hooks_add(after_trace
,
3502 state_save_after_trace_hook
,
3507 lttv_process_traceset_end(&self
->parent
,
3508 NULL
, after_trace
, NULL
, NULL
, NULL
);
3510 lttv_hooks_destroy(after_trace
);
3512 nb_trace
= lttv_traceset_number(traceset
);
3513 for(i
= 0 ; i
< nb_trace
; i
++) {
3515 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3516 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3518 if(ts
->has_precomputed_states
) continue;
3520 guint
*event_count
= NULL
;
3522 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3524 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3525 LttvTracefileContext
*, j
));
3526 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3527 state_save_event_hook
);
3529 if(event_count
) g_free(event_count
);
3533 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3535 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3537 lttv_state_save_remove_event_hooks(tss
);
3542 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3544 LttvTraceset
*traceset
= self
->parent
.ts
;
3548 int min_pos
, mid_pos
, max_pos
;
3550 guint call_rest
= 0;
3552 LttvTraceState
*tcs
;
3554 LttvAttributeValue value
;
3556 LttvAttributeType type
;
3558 LttvAttributeName name
;
3562 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3564 //g_tree_destroy(self->parent.pqueue);
3565 //self->parent.pqueue = g_tree_new(compare_tracefile);
3567 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3569 nb_trace
= lttv_traceset_number(traceset
);
3570 for(i
= 0 ; i
< nb_trace
; i
++) {
3571 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3573 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3574 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3575 LTTV_STATE_SAVED_STATES
);
3578 if(saved_states_tree
) {
3579 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3580 mid_pos
= max_pos
/ 2;
3581 while(min_pos
< max_pos
) {
3582 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3584 g_assert(type
== LTTV_GOBJECT
);
3585 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3586 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3588 g_assert(type
== LTTV_TIME
);
3589 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3591 closest_tree
= saved_state_tree
;
3593 else max_pos
= mid_pos
- 1;
3595 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3599 /* restore the closest earlier saved state */
3601 lttv_state_restore(tcs
, closest_tree
);
3605 /* There is no saved state, yet we want to have it. Restart at T0 */
3607 restore_init_state(tcs
);
3608 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3611 /* We want to seek quickly without restoring/updating the state */
3613 restore_init_state(tcs
);
3614 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3617 if(!call_rest
) g_info("NOT Calling restore");
3622 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3628 traceset_state_finalize (LttvTracesetState
*self
)
3630 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3631 finalize(G_OBJECT(self
));
3636 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3638 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3640 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3641 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3642 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3643 klass
->new_traceset_context
= new_traceset_context
;
3644 klass
->new_trace_context
= new_trace_context
;
3645 klass
->new_tracefile_context
= new_tracefile_context
;
3650 lttv_traceset_state_get_type(void)
3652 static GType type
= 0;
3654 static const GTypeInfo info
= {
3655 sizeof (LttvTracesetStateClass
),
3656 NULL
, /* base_init */
3657 NULL
, /* base_finalize */
3658 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3659 NULL
, /* class_finalize */
3660 NULL
, /* class_data */
3661 sizeof (LttvTracesetState
),
3662 0, /* n_preallocs */
3663 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3664 NULL
/* value handling */
3667 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3675 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3681 trace_state_finalize (LttvTraceState
*self
)
3683 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3684 finalize(G_OBJECT(self
));
3689 trace_state_class_init (LttvTraceStateClass
*klass
)
3691 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3693 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3694 klass
->state_save
= state_save
;
3695 klass
->state_restore
= state_restore
;
3696 klass
->state_saved_free
= state_saved_free
;
3701 lttv_trace_state_get_type(void)
3703 static GType type
= 0;
3705 static const GTypeInfo info
= {
3706 sizeof (LttvTraceStateClass
),
3707 NULL
, /* base_init */
3708 NULL
, /* base_finalize */
3709 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3710 NULL
, /* class_finalize */
3711 NULL
, /* class_data */
3712 sizeof (LttvTraceState
),
3713 0, /* n_preallocs */
3714 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3715 NULL
/* value handling */
3718 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3719 "LttvTraceStateType", &info
, 0);
3726 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3732 tracefile_state_finalize (LttvTracefileState
*self
)
3734 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3735 finalize(G_OBJECT(self
));
3740 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3742 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3744 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3749 lttv_tracefile_state_get_type(void)
3751 static GType type
= 0;
3753 static const GTypeInfo info
= {
3754 sizeof (LttvTracefileStateClass
),
3755 NULL
, /* base_init */
3756 NULL
, /* base_finalize */
3757 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3758 NULL
, /* class_finalize */
3759 NULL
, /* class_data */
3760 sizeof (LttvTracefileState
),
3761 0, /* n_preallocs */
3762 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3763 NULL
/* value handling */
3766 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3767 "LttvTracefileStateType", &info
, 0);
3773 static void module_init()
3775 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3776 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3777 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3778 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3779 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3780 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3781 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3782 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3783 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3784 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3785 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3786 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3787 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3788 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3789 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3790 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3791 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3792 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3793 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3794 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3795 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3796 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3797 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3798 LTTV_STATE_EVENT
= g_quark_from_string("event");
3799 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3800 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3801 LTTV_STATE_TIME
= g_quark_from_string("time");
3802 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3803 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3804 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3805 g_quark_from_string("trace_state_use_count");
3806 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3807 LTTV_STATE_RESOURCE_IRQS
= g_quark_from_string("irq resource states");
3808 LTTV_STATE_RESOURCE_BLKDEVS
= g_quark_from_string("blkdevs resource states");
3811 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3812 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3813 LTT_FACILITY_FS
= g_quark_from_string("fs");
3814 LTT_FACILITY_LIST
= g_quark_from_string("list");
3815 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3816 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3819 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3820 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3821 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3822 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3823 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3824 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3825 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3826 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3827 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3828 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3829 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3830 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3831 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3832 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3833 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3834 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3835 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3836 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3837 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3838 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3839 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3840 LTT_EVENT_LIST_INTERRUPT
= g_quark_from_string("interrupt");;
3843 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3844 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3845 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3846 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3847 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3848 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3849 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3850 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3851 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3852 LTT_FIELD_PID
= g_quark_from_string("pid");
3853 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3854 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3855 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3856 LTT_FIELD_NAME
= g_quark_from_string("name");
3857 LTT_FIELD_TYPE
= g_quark_from_string("type");
3858 LTT_FIELD_MODE
= g_quark_from_string("mode");
3859 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3860 LTT_FIELD_STATUS
= g_quark_from_string("status");
3861 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3862 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3863 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3864 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3865 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3866 LTT_FIELD_ACTION
= g_quark_from_string("action");
3867 LTT_FIELD_NUM
= g_quark_from_string("num");
3869 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3870 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3871 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3872 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3873 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3875 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3876 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3877 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3879 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3880 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3881 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3882 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3885 static void module_destroy()
3890 LTTV_MODULE("state", "State computation", \
3891 "Update the system state, possibly saving it at intervals", \
3892 module_init
, module_destroy
)