1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_STATEDUMP
,
53 LTT_FACILITY_USER_GENERIC
,
54 /****************************************************
55 * JOV - XenoLTT - 2006-09-27
56 * New facility XenoLTT
57 ****************************************************/
63 LTT_EVENT_SYSCALL_ENTRY
,
64 LTT_EVENT_SYSCALL_EXIT
,
69 LTT_EVENT_SOFT_IRQ_ENTRY
,
70 LTT_EVENT_SOFT_IRQ_EXIT
,
71 LTT_EVENT_SCHEDCHANGE
,
73 LTT_EVENT_KERNEL_THREAD
,
77 LTT_EVENT_ENUM_PROCESS_STATE
,
78 LTT_EVENT_FUNCTION_ENTRY
,
79 LTT_EVENT_FUNCTION_EXIT
,
80 LTT_EVENT_THREAD_BRAND
,
81 /****************************************************
82 * JOV - XenoLTT - 2006-09-27
83 * New events for facility XenoLTT
84 ****************************************************/
85 LTT_EVENT_XENOLTT_THREAD_INIT
,
86 LTT_EVENT_XENOLTT_THREAD_SET_PERIOD
,
87 LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD
,
88 LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD
,
89 LTT_EVENT_XENOLTT_THREAD_SUSPEND
,
90 LTT_EVENT_XENOLTT_THREAD_START
,
91 LTT_EVENT_XENOLTT_THREAD_RESUME
,
92 LTT_EVENT_XENOLTT_THREAD_DELETE
,
93 LTT_EVENT_XENOLTT_THREAD_UNBLOCK
,
94 LTT_EVENT_XENOLTT_THREAD_RENICE
,
95 LTT_EVENT_XENOLTT_TIMER_TICK
,
96 LTT_EVENT_XENOLTT_SYNCH_SET_OWNER
,
97 LTT_EVENT_XENOLTT_SYNCH_UNLOCK
,
98 LTT_EVENT_XENOLTT_SYNCH_WAKEUP1
,
99 LTT_EVENT_XENOLTT_SYNCH_WAKEUPX
,
100 LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON
,
101 LTT_EVENT_XENOLTT_SYNCH_FLUSH
,
102 LTT_EVENT_XENOLTT_SYNCH_FORGET
,
103 LTT_EVENT_XENOLTT_THREAD_SWITCH
;
108 LTT_FIELD_SYSCALL_ID
,
111 LTT_FIELD_SOFT_IRQ_ID
,
115 LTT_FIELD_PARENT_PID
,
127 /****************************************************
128 * JOV - XenoLTT - 2006-09-27
129 * New fields for XenoLTT events
130 ****************************************************/
131 LTT_FIELD_XENOLTT_NAME
,
132 LTT_FIELD_XENOLTT_ADDRESS
,
133 LTT_FIELD_XENOLTT_FLAGS
,
134 LTT_FIELD_XENOLTT_PRIO
,
135 LTT_FIELD_XENOLTT_PERIOD
,
136 LTT_FIELD_XENOLTT_IDATE
,
137 LTT_FIELD_XENOLTT_SYNCH
,
138 LTT_FIELD_XENOLTT_THREAD_ADDRESS
,
139 LTT_FIELD_XENOLTT_TIMER_ADDRESS
,
140 LTT_FIELD_XENOLTT_OVERRUNS
,
141 LTT_FIELD_XENOLTT_NAME_OUT
,
142 LTT_FIELD_XENOLTT_ADDRESS_OUT
;
146 LTTV_STATE_MODE_UNKNOWN
,
147 LTTV_STATE_USER_MODE
,
154 LTTV_STATE_SUBMODE_UNKNOWN
,
155 LTTV_STATE_SUBMODE_NONE
;
159 LTTV_STATE_UNBRANDED
,
160 LTTV_STATE_WAIT_FORK
,
169 /****************************************************
170 * JOV - XenoLTT - 2006-09-27
171 * New status and modes for Xenomai Tasks
172 ****************************************************/
173 LttvXenoExecutionMode
174 LTTV_XENO_MODE_UNKNOWN
,
175 LTTV_XENO_MODE_NORMAL
,
176 LTTV_XENO_MODE_OVERRUN
;
179 LTTV_XENO_STATE_INIT
,
180 LTTV_XENO_STATE_UNNAMED
,
181 LTTV_XENO_STATE_SUSPEND
,
183 LTTV_XENO_STATE_DEAD
,
184 LTTV_XENO_STATE_WAIT_PERIOD
,
185 LTTV_XENO_STATE_START
,
186 LTTV_XENO_STATE_READY
;
189 LTTV_STATE_USER_THREAD
,
190 LTTV_STATE_KERNEL_THREAD
;
193 LTTV_STATE_TRACEFILES
,
194 LTTV_STATE_PROCESSES
,
196 LTTV_STATE_RUNNING_PROCESS
,
198 LTTV_STATE_SAVED_STATES
,
199 LTTV_STATE_SAVED_STATES_TIME
,
202 LTTV_STATE_NAME_TABLES
,
203 LTTV_STATE_TRACE_STATE_USE_COUNT
;
205 static void create_max_time(LttvTraceState
*tcs
);
207 static void get_max_time(LttvTraceState
*tcs
);
209 static void free_max_time(LttvTraceState
*tcs
);
211 static void create_name_tables(LttvTraceState
*tcs
);
213 static void get_name_tables(LttvTraceState
*tcs
);
215 static void free_name_tables(LttvTraceState
*tcs
);
217 static void free_saved_state(LttvTraceState
*tcs
);
219 static void lttv_state_free_process_table(GHashTable
*processes
);
221 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
222 GPtrArray
*quarktable
);
224 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
226 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
230 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
232 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
236 void lttv_state_state_saved_free(LttvTraceState
*self
,
237 LttvAttribute
*container
)
239 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
243 guint
process_hash(gconstpointer key
)
245 guint pid
= ((const LttvProcessState
*)key
)->pid
;
246 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
250 /* If the hash table hash function is well distributed,
251 * the process_equal should compare different pid */
252 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
254 const LttvProcessState
*process_a
, *process_b
;
257 process_a
= (const LttvProcessState
*)a
;
258 process_b
= (const LttvProcessState
*)b
;
260 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
261 else if(likely(process_a
->pid
== 0 &&
262 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
267 /******************************************************************************/
268 guint
thread_hash(gconstpointer key
)
270 guint address
= ((const LttvXenoThreadState
*)key
)->address
;
271 return (address
>>8 ^ address
>>4 ^ address
>>2 ^ address
) ;
275 /* If the hash table hash function is well distributed,
276 * the process_equal should compare different pid */
277 gboolean
thread_equal(gconstpointer a
, gconstpointer b
)
279 const LttvXenoThreadState
*thread_a
, *thread_b
;
282 thread_a
= (const LttvXenoThreadState
*)a
;
283 thread_b
= (const LttvXenoThreadState
*)b
;
285 if(likely(thread_a
->address
!= thread_b
->address
)) ret
= FALSE
;
286 else if(likely(thread_a
->address
== 0 && thread_a
->cpu
!= thread_b
->cpu
)) ret
= FALSE
;
292 guint
synch_hash(gconstpointer key
)
294 guint address
= ((const LttvXenoSynchState
*)key
)->address
;
295 return (address
>>8 ^ address
>>4 ^ address
>>2 ^ address
) ;
299 /* If the hash table hash function is well distributed,
300 * the process_equal should compare different pid */
301 gboolean
synch_equal(gconstpointer a
, gconstpointer b
)
303 const LttvXenoSynchState
*synch_a
, *synch_b
;
306 synch_a
= (const LttvXenoSynchState
*)a
;
307 synch_b
= (const LttvXenoSynchState
*)b
;
309 if(likely(synch_a
->address
!= synch_b
->address
)) ret
= FALSE
;
313 /******************************************************************************/
315 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
317 g_tree_destroy((GTree
*)value
);
320 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
322 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
323 g_hash_table_destroy(usertraces
);
329 restore_init_state(LttvTraceState
*self
)
333 LttTime start_time
, end_time
;
335 /* Free the process tables */
336 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
337 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
338 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
339 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
342 /******************************************************************************/
343 self
->threads
= g_hash_table_new(thread_hash
, thread_equal
);
344 self
->synchs
= g_hash_table_new(synch_hash
, synch_equal
);
345 /******************************************************************************/
347 /* Seek time to beginning */
348 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
349 // closest. It's the tracecontext job to seek the trace to the beginning
350 // anyway : the init state might be used at the middle of the trace as well...
351 //g_tree_destroy(self->parent.ts_context->pqueue);
352 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
354 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
356 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
358 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
360 /* Put the per cpu running_process to beginning state : process 0. */
361 for(i
=0; i
< nb_cpus
; i
++) {
362 LttvExecutionState
*es
;
363 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
364 LTTV_STATE_UNNAMED
, &start_time
);
365 /* We are not sure is it's a kernel thread or normal thread, put the
366 * bottom stack state to unknown */
367 self
->running_process
[i
]->execution_stack
=
368 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
369 es
= self
->running_process
[i
]->state
=
370 &g_array_index(self
->running_process
[i
]->execution_stack
,
371 LttvExecutionState
, 0);
372 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
374 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
375 self
->running_process
[i
]->cpu
= i
;
379 nb_tracefile
= self
->parent
.tracefiles
->len
;
381 for(i
= 0 ; i
< nb_tracefile
; i
++) {
383 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
384 LttvTracefileContext
*, i
));
385 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
386 // tfcs->saved_position = 0;
387 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
388 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
389 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
390 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
395 //static LttTime time_zero = {0,0};
397 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
400 const LttTime
*t1
= (const LttTime
*)a
;
401 const LttTime
*t2
= (const LttTime
*)b
;
403 return ltt_time_compare(*t1
, *t2
);
406 static void free_usertrace_key(gpointer data
)
411 #define MAX_STRING_LEN 4096
414 state_load_saved_states(LttvTraceState
*tcs
)
417 GPtrArray
*quarktable
;
422 tcs
->has_precomputed_states
= FALSE
;
426 gchar buf
[MAX_STRING_LEN
];
429 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
430 strncpy(path
, trace_path
, PATH_MAX
-1);
431 count
= strnlen(trace_path
, PATH_MAX
-1);
432 // quarktable : open, test
433 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
434 fp
= fopen(path
, "r");
436 quarktable
= g_ptr_array_sized_new(4096);
438 /* Index 0 is null */
440 if(hdr
== EOF
) return;
441 g_assert(hdr
== HDR_QUARKS
);
445 if(hdr
== EOF
) break;
446 g_assert(hdr
== HDR_QUARK
);
447 g_ptr_array_set_size(quarktable
, q
+1);
450 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
451 if(buf
[i
] == '\0' || feof(fp
)) break;
454 len
= strnlen(buf
, MAX_STRING_LEN
-1);
455 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
456 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
462 // saved_states : open, test
463 strncpy(path
, trace_path
, PATH_MAX
-1);
464 count
= strnlen(trace_path
, PATH_MAX
-1);
465 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
466 fp
= fopen(path
, "r");
470 if(hdr
!= HDR_TRACE
) goto end
;
472 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
474 tcs
->has_precomputed_states
= TRUE
;
479 /* Free the quarktable */
480 for(i
=0; i
<quarktable
->len
; i
++) {
481 string
= g_ptr_array_index (quarktable
, i
);
484 g_ptr_array_free(quarktable
, TRUE
);
489 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
491 guint i
, j
, nb_trace
, nb_tracefile
;
493 LttvTraceContext
*tc
;
497 LttvTracefileState
*tfcs
;
499 LttvAttributeValue v
;
501 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
502 init((LttvTracesetContext
*)self
, ts
);
504 nb_trace
= lttv_traceset_number(ts
);
505 for(i
= 0 ; i
< nb_trace
; i
++) {
506 tc
= self
->parent
.traces
[i
];
507 tcs
= LTTV_TRACE_STATE(tc
);
508 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
509 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
513 if(*(v
.v_uint
) == 1) {
514 create_name_tables(tcs
);
515 create_max_time(tcs
);
517 get_name_tables(tcs
);
520 nb_tracefile
= tc
->tracefiles
->len
;
521 tcs
->processes
= NULL
;
523 /******************************************************************************/
526 /******************************************************************************/
528 tcs
->usertraces
= NULL
;
529 tcs
->running_process
= g_new(LttvProcessState
*,
530 ltt_trace_get_num_cpu(tc
->t
));
532 tcs
->running_thread
= g_new(LttvXenoThreadState
*, ltt_trace_get_num_cpu(tc
->t
));
534 restore_init_state(tcs
);
535 for(j
= 0 ; j
< nb_tracefile
; j
++) {
537 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
538 LttvTracefileContext
*, j
));
539 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
540 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
541 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
542 /* It's a Usertrace */
543 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
544 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
546 if(!usertrace_tree
) {
547 usertrace_tree
= g_tree_new_full(compare_usertraces
,
548 NULL
, free_usertrace_key
, NULL
);
549 g_hash_table_insert(tcs
->usertraces
,
550 (gpointer
)tid
, usertrace_tree
);
552 LttTime
*timestamp
= g_new(LttTime
, 1);
553 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
554 ltt_tracefile_creation(tfcs
->parent
.tf
));
555 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
559 /* See if the trace has saved states */
560 state_load_saved_states(tcs
);
565 fini(LttvTracesetState
*self
)
571 LttvAttributeValue v
;
573 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
574 for(i
= 0 ; i
< nb_trace
; i
++) {
575 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
576 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
579 g_assert(*(v
.v_uint
) != 0);
582 if(*(v
.v_uint
) == 0) {
583 free_name_tables(tcs
);
585 free_saved_state(tcs
);
587 g_free(tcs
->running_process
);
588 tcs
->running_process
= NULL
;
589 lttv_state_free_process_table(tcs
->processes
);
590 lttv_state_free_usertraces(tcs
->usertraces
);
591 tcs
->processes
= NULL
;
592 tcs
->usertraces
= NULL
;
594 /******************************************************************************/
597 /******************************************************************************/
599 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
600 fini((LttvTracesetContext
*)self
);
604 static LttvTracesetContext
*
605 new_traceset_context(LttvTracesetContext
*self
)
607 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
611 static LttvTraceContext
*
612 new_trace_context(LttvTracesetContext
*self
)
614 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
618 static LttvTracefileContext
*
619 new_tracefile_context(LttvTracesetContext
*self
)
621 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
625 /* Write the process state of the trace */
627 static void write_process_state(gpointer key
, gpointer value
,
630 LttvProcessState
*process
;
632 LttvExecutionState
*es
;
634 FILE *fp
= (FILE *)user_data
;
639 process
= (LttvProcessState
*)value
;
641 " <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",
642 process
, process
->pid
, process
->tgid
, process
->ppid
,
643 g_quark_to_string(process
->type
),
644 process
->creation_time
.tv_sec
,
645 process
->creation_time
.tv_nsec
,
646 process
->insertion_time
.tv_sec
,
647 process
->insertion_time
.tv_nsec
,
648 g_quark_to_string(process
->name
),
649 g_quark_to_string(process
->brand
),
652 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
653 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
654 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
655 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
656 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
657 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
658 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
661 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
662 address
= &g_array_index(process
->user_stack
, guint64
, i
);
663 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
667 if(process
->usertrace
) {
668 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
669 g_quark_to_string(process
->usertrace
->tracefile_name
),
670 process
->usertrace
->cpu
);
674 fprintf(fp
, " </PROCESS>\n");
678 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
680 guint i
, nb_tracefile
, nb_block
, offset
;
683 LttvTracefileState
*tfcs
;
687 LttEventPosition
*ep
;
691 ep
= ltt_event_position_new();
693 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
695 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
697 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
698 for(i
=0;i
<nb_cpus
;i
++) {
699 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
700 i
, self
->running_process
[i
]->pid
);
703 nb_tracefile
= self
->parent
.tracefiles
->len
;
705 for(i
= 0 ; i
< nb_tracefile
; i
++) {
707 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
708 LttvTracefileContext
*, i
));
709 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
710 tfcs
->parent
.timestamp
.tv_sec
,
711 tfcs
->parent
.timestamp
.tv_nsec
);
712 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
713 if(e
== NULL
) fprintf(fp
,"/>\n");
715 ltt_event_position(e
, ep
);
716 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
717 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
722 fprintf(fp
,"</PROCESS_STATE>\n");
726 static void write_process_state_raw(gpointer key
, gpointer value
,
729 LttvProcessState
*process
;
731 LttvExecutionState
*es
;
733 FILE *fp
= (FILE *)user_data
;
738 process
= (LttvProcessState
*)value
;
739 fputc(HDR_PROCESS
, fp
);
740 //fwrite(&header, sizeof(header), 1, fp);
741 //fprintf(fp, "%s", g_quark_to_string(process->type));
743 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
744 //fprintf(fp, "%s", g_quark_to_string(process->name));
746 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
747 //fprintf(fp, "%s", g_quark_to_string(process->brand));
749 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
750 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
751 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
752 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
753 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
754 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
755 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
759 " <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",
760 process
, process
->pid
, process
->tgid
, process
->ppid
,
761 g_quark_to_string(process
->type
),
762 process
->creation_time
.tv_sec
,
763 process
->creation_time
.tv_nsec
,
764 process
->insertion_time
.tv_sec
,
765 process
->insertion_time
.tv_nsec
,
766 g_quark_to_string(process
->name
),
767 g_quark_to_string(process
->brand
),
771 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
772 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
775 //fprintf(fp, "%s", g_quark_to_string(es->t));
777 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
778 //fprintf(fp, "%s", g_quark_to_string(es->n));
780 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
781 //fprintf(fp, "%s", g_quark_to_string(es->s));
783 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
784 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
785 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
786 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
788 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
789 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
790 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
791 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
792 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
796 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
797 address
= &g_array_index(process
->user_stack
, guint64
, i
);
798 fputc(HDR_USER_STACK
, fp
);
799 fwrite(&address
, sizeof(address
), 1, fp
);
801 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
806 if(process
->usertrace
) {
807 fputc(HDR_USERTRACE
, fp
);
808 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
810 fwrite(&process
->usertrace
->tracefile_name
,
811 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
812 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
814 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
815 g_quark_to_string(process
->usertrace
->tracefile_name
),
816 process
->usertrace
->cpu
);
823 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
825 guint i
, nb_tracefile
, nb_block
, offset
;
828 LttvTracefileState
*tfcs
;
832 LttEventPosition
*ep
;
836 ep
= ltt_event_position_new();
838 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
839 fputc(HDR_PROCESS_STATE
, fp
);
840 fwrite(&t
, sizeof(t
), 1, fp
);
842 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
844 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
845 for(i
=0;i
<nb_cpus
;i
++) {
847 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
848 fwrite(&self
->running_process
[i
]->pid
,
849 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
850 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
851 // i, self->running_process[i]->pid);
854 nb_tracefile
= self
->parent
.tracefiles
->len
;
856 for(i
= 0 ; i
< nb_tracefile
; i
++) {
858 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
859 LttvTracefileContext
*, i
));
860 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
861 // tfcs->parent.timestamp.tv_sec,
862 // tfcs->parent.timestamp.tv_nsec);
863 fputc(HDR_TRACEFILE
, fp
);
864 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
865 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
866 * position following : end of trace */
867 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
869 ltt_event_position(e
, ep
);
870 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
871 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
873 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
874 fwrite(&offset
, sizeof(offset
), 1, fp
);
875 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
882 /* Read process state from a file */
884 /* Called because a HDR_PROCESS was found */
885 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
886 GPtrArray
*quarktable
)
888 LttvExecutionState
*es
;
889 LttvProcessState
*process
, *parent_process
;
890 LttvProcessState tmp
;
895 /* TODO : check return value */
896 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
897 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
898 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
899 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
900 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
901 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
902 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
903 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
904 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
907 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
909 /* We must link to the parent */
910 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
912 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
913 if(process
== NULL
) {
914 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
916 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
920 process
->insertion_time
= tmp
.insertion_time
;
921 process
->creation_time
= tmp
.creation_time
;
922 process
->type
= g_quark_from_string(
923 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
924 process
->tgid
= tmp
.tgid
;
925 process
->ppid
= tmp
.ppid
;
926 process
->brand
= g_quark_from_string(
927 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
929 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
933 if(feof(fp
) || ferror(fp
)) goto end_loop
;
935 gint hdr
= fgetc(fp
);
936 if(hdr
== EOF
) goto end_loop
;
940 process
->execution_stack
=
941 g_array_set_size(process
->execution_stack
,
942 process
->execution_stack
->len
+ 1);
943 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
944 process
->execution_stack
->len
-1);
947 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
948 es
->t
= g_quark_from_string(
949 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
950 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
951 es
->n
= g_quark_from_string(
952 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
953 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
954 es
->s
= g_quark_from_string(
955 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
956 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
957 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
958 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
961 process
->user_stack
= g_array_set_size(process
->user_stack
,
962 process
->user_stack
->len
+ 1);
963 address
= &g_array_index(process
->user_stack
, guint64
,
964 process
->user_stack
->len
-1);
965 fread(address
, sizeof(address
), 1, fp
);
966 process
->current_function
= *address
;
969 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
970 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
982 /* Called because a HDR_PROCESS_STATE was found */
983 /* Append a saved state to the trace states */
984 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
986 guint i
, nb_tracefile
, nb_block
, offset
;
988 LttvTracefileState
*tfcs
;
990 LttEventPosition
*ep
;
998 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1000 LttvAttributeValue value
;
1001 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
1002 ep
= ltt_event_position_new();
1004 restore_init_state(self
);
1006 fread(&t
, sizeof(t
), 1, fp
);
1009 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1011 if(hdr
== EOF
) goto end_loop
;
1015 /* Call read_process_state_raw */
1016 read_process_state_raw(self
, fp
, quarktable
);
1024 case HDR_USER_STACK
:
1026 case HDR_PROCESS_STATE
:
1032 g_error("Error while parsing saved state file : unknown data header %d",
1038 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1039 for(i
=0;i
<nb_cpus
;i
++) {
1042 g_assert(hdr
== HDR_CPU
);
1043 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
1044 g_assert(i
== cpu_num
);
1045 fread(&self
->running_process
[i
]->pid
,
1046 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
1049 nb_tracefile
= self
->parent
.tracefiles
->len
;
1051 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1053 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1054 LttvTracefileContext
*, i
));
1055 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1056 // tfcs->parent.timestamp.tv_sec,
1057 // tfcs->parent.timestamp.tv_nsec);
1058 g_tree_remove(pqueue
, &tfcs
->parent
);
1060 g_assert(hdr
== HDR_TRACEFILE
);
1061 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
1062 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1063 * position following : end of trace */
1064 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
1065 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1066 fread(&offset
, sizeof(offset
), 1, fp
);
1067 fread(&tsc
, sizeof(tsc
), 1, fp
);
1068 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1069 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1071 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1076 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1077 LTTV_STATE_SAVED_STATES
);
1078 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1079 value
= lttv_attribute_add(saved_states_tree
,
1080 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1081 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1082 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1083 *(value
.v_time
) = t
;
1084 lttv_state_save(self
, saved_state_tree
);
1085 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1088 *(self
->max_time_state_recomputed_in_seek
) = t
;
1092 /* Called when a HDR_TRACE is found */
1093 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1094 GPtrArray
*quarktable
)
1099 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1101 if(hdr
== EOF
) goto end_loop
;
1104 case HDR_PROCESS_STATE
:
1105 /* Call read_process_state_raw */
1106 lttv_state_read_raw(tcs
, fp
, quarktable
);
1114 case HDR_USER_STACK
:
1118 g_error("Error while parsing saved state file :"
1119 " unexpected data header %d",
1123 g_error("Error while parsing saved state file : unknown data header %d",
1128 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1129 restore_init_state(tcs
);
1130 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1136 /* Copy each process from an existing hash table to a new one */
1138 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1140 LttvProcessState
*process
, *new_process
;
1142 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1146 process
= (LttvProcessState
*)value
;
1147 new_process
= g_new(LttvProcessState
, 1);
1148 *new_process
= *process
;
1149 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1150 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1151 new_process
->execution_stack
=
1152 g_array_set_size(new_process
->execution_stack
,
1153 process
->execution_stack
->len
);
1154 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1155 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1156 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1158 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1159 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1160 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1161 sizeof(guint64
), 0);
1162 new_process
->user_stack
=
1163 g_array_set_size(new_process
->user_stack
,
1164 process
->user_stack
->len
);
1165 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1166 g_array_index(new_process
->user_stack
, guint64
, i
) =
1167 g_array_index(process
->user_stack
, guint64
, i
);
1169 new_process
->current_function
= process
->current_function
;
1170 g_hash_table_insert(new_processes
, new_process
, new_process
);
1174 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1176 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1178 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1179 return new_processes
;
1183 /* The saved state for each trace contains a member "processes", which
1184 stores a copy of the process table, and a member "tracefiles" with
1185 one entry per tracefile. Each tracefile has a "process" member pointing
1186 to the current process and a "position" member storing the tracefile
1187 position (needed to seek to the current "next" event. */
1189 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1191 guint i
, nb_tracefile
, nb_cpus
;
1193 LttvTracefileState
*tfcs
;
1195 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1197 guint
*running_process
;
1199 LttvAttributeValue value
;
1201 LttEventPosition
*ep
;
1203 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1204 LTTV_STATE_TRACEFILES
);
1206 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1208 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1210 /* Add the currently running processes array */
1211 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1212 running_process
= g_new(guint
, nb_cpus
);
1213 for(i
=0;i
<nb_cpus
;i
++) {
1214 running_process
[i
] = self
->running_process
[i
]->pid
;
1216 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1218 *(value
.v_pointer
) = running_process
;
1220 g_info("State save");
1222 nb_tracefile
= self
->parent
.tracefiles
->len
;
1224 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1226 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1227 LttvTracefileContext
*, i
));
1228 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1229 value
= lttv_attribute_add(tracefiles_tree
, i
,
1231 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1233 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1235 *(value
.v_uint
) = tfcs
->process
->pid
;
1237 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1239 /* Only save the position if the tfs has not infinite time. */
1240 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1241 // && current_tfcs != tfcs) {
1242 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1243 *(value
.v_pointer
) = NULL
;
1245 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1246 ep
= ltt_event_position_new();
1247 ltt_event_position(e
, ep
);
1248 *(value
.v_pointer
) = ep
;
1250 guint nb_block
, offset
;
1253 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1254 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1256 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1262 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1264 guint i
, nb_tracefile
, pid
, nb_cpus
;
1266 LttvTracefileState
*tfcs
;
1268 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1270 guint
*running_process
;
1272 LttvAttributeType type
;
1274 LttvAttributeValue value
;
1276 LttvAttributeName name
;
1280 LttEventPosition
*ep
;
1282 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1284 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1285 LTTV_STATE_TRACEFILES
);
1287 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1289 g_assert(type
== LTTV_POINTER
);
1290 lttv_state_free_process_table(self
->processes
);
1291 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1293 /* Add the currently running processes array */
1294 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1295 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1297 g_assert(type
== LTTV_POINTER
);
1298 running_process
= *(value
.v_pointer
);
1299 for(i
=0;i
<nb_cpus
;i
++) {
1300 pid
= running_process
[i
];
1301 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1302 g_assert(self
->running_process
[i
] != NULL
);
1306 nb_tracefile
= self
->parent
.tracefiles
->len
;
1308 //g_tree_destroy(tsc->pqueue);
1309 //tsc->pqueue = g_tree_new(compare_tracefile);
1311 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1313 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1314 LttvTracefileContext
*, i
));
1315 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1316 g_assert(type
== LTTV_GOBJECT
);
1317 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1319 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1321 g_assert(type
== LTTV_UINT
);
1322 pid
= *(value
.v_uint
);
1323 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1325 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1327 g_assert(type
== LTTV_POINTER
);
1328 //g_assert(*(value.v_pointer) != NULL);
1329 ep
= *(value
.v_pointer
);
1330 g_assert(tfcs
->parent
.t_context
!= NULL
);
1332 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1333 g_tree_remove(tsc
->pqueue
, tfc
);
1336 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1337 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1338 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1339 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1340 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1342 tfc
->timestamp
= ltt_time_infinite
;
1348 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1350 guint i
, nb_tracefile
, nb_cpus
;
1352 LttvTracefileState
*tfcs
;
1354 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1356 guint
*running_process
;
1358 LttvAttributeType type
;
1360 LttvAttributeValue value
;
1362 LttvAttributeName name
;
1366 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1367 LTTV_STATE_TRACEFILES
);
1368 g_object_ref(G_OBJECT(tracefiles_tree
));
1369 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1371 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1373 g_assert(type
== LTTV_POINTER
);
1374 lttv_state_free_process_table(*(value
.v_pointer
));
1375 *(value
.v_pointer
) = NULL
;
1376 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1378 /* Free running processes array */
1379 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1380 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1382 g_assert(type
== LTTV_POINTER
);
1383 running_process
= *(value
.v_pointer
);
1384 g_free(running_process
);
1386 nb_tracefile
= self
->parent
.tracefiles
->len
;
1388 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1390 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1391 LttvTracefileContext
*, i
));
1392 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1393 g_assert(type
== LTTV_GOBJECT
);
1394 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1396 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1398 g_assert(type
== LTTV_POINTER
);
1399 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1401 g_object_unref(G_OBJECT(tracefiles_tree
));
1405 static void free_saved_state(LttvTraceState
*self
)
1409 LttvAttributeType type
;
1411 LttvAttributeValue value
;
1413 LttvAttributeName name
;
1417 LttvAttribute
*saved_states
;
1419 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1420 LTTV_STATE_SAVED_STATES
);
1422 nb
= lttv_attribute_get_number(saved_states
);
1423 for(i
= 0 ; i
< nb
; i
++) {
1424 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1425 g_assert(type
== LTTV_GOBJECT
);
1426 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1429 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1434 create_max_time(LttvTraceState
*tcs
)
1436 LttvAttributeValue v
;
1438 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1440 g_assert(*(v
.v_pointer
) == NULL
);
1441 *(v
.v_pointer
) = g_new(LttTime
,1);
1442 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1447 get_max_time(LttvTraceState
*tcs
)
1449 LttvAttributeValue v
;
1451 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1453 g_assert(*(v
.v_pointer
) != NULL
);
1454 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1459 free_max_time(LttvTraceState
*tcs
)
1461 LttvAttributeValue v
;
1463 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1465 g_free(*(v
.v_pointer
));
1466 *(v
.v_pointer
) = NULL
;
1470 typedef struct _LttvNameTables
{
1471 // FIXME GQuark *eventtype_names;
1472 GQuark
*syscall_names
;
1477 GQuark
*soft_irq_names
;
1482 create_name_tables(LttvTraceState
*tcs
)
1488 LttvTraceHookByFacility
*thf
;
1492 GString
*fe_name
= g_string_new("");
1494 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1496 LttvAttributeValue v
;
1498 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1500 g_assert(*(v
.v_pointer
) == NULL
);
1501 *(v
.v_pointer
) = name_tables
;
1502 #if 0 // Use iteration over the facilities_by_name and then list all event
1503 // types of each facility
1504 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1505 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1506 for(i
= 0 ; i
< nb
; i
++) {
1507 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1508 e_name
= ltt_eventtype_name(et
);
1509 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1510 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1511 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1514 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1515 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1516 LTT_FIELD_SYSCALL_ID
, 0, 0,
1519 thf
= lttv_trace_hook_get_first(&h
);
1521 t
= ltt_field_type(thf
->f1
);
1522 nb
= ltt_type_element_number(t
);
1524 lttv_trace_hook_destroy(&h
);
1526 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1527 name_tables
->nb_syscalls
= nb
;
1529 for(i
= 0 ; i
< nb
; i
++) {
1530 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1533 //name_tables->syscall_names = g_new(GQuark, 256);
1534 //for(i = 0 ; i < 256 ; i++) {
1535 // g_string_printf(fe_name, "syscall %d", i);
1536 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1539 name_tables
->syscall_names
= NULL
;
1540 name_tables
->nb_syscalls
= 0;
1543 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
1544 LTT_EVENT_TRAP_ENTRY
,
1545 LTT_FIELD_TRAP_ID
, 0, 0,
1548 thf
= lttv_trace_hook_get_first(&h
);
1550 t
= ltt_field_type(thf
->f1
);
1551 //nb = ltt_type_element_number(t);
1553 lttv_trace_hook_destroy(&h
);
1556 name_tables->trap_names = g_new(GQuark, nb);
1557 for(i = 0 ; i < nb ; i++) {
1558 name_tables->trap_names[i] = g_quark_from_string(
1559 ltt_enum_string_get(t, i));
1562 name_tables
->nb_traps
= 256;
1563 name_tables
->trap_names
= g_new(GQuark
, 256);
1564 for(i
= 0 ; i
< 256 ; i
++) {
1565 g_string_printf(fe_name
, "trap %d", i
);
1566 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1569 name_tables
->trap_names
= NULL
;
1570 name_tables
->nb_traps
= 0;
1573 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1574 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1575 LTT_FIELD_IRQ_ID
, 0, 0,
1578 thf
= lttv_trace_hook_get_first(&h
);
1580 t
= ltt_field_type(thf
->f1
);
1581 //nb = ltt_type_element_number(t);
1583 lttv_trace_hook_destroy(&h
);
1586 name_tables->irq_names = g_new(GQuark, nb);
1587 for(i = 0 ; i < nb ; i++) {
1588 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1592 name_tables
->irq_names
= g_new(GQuark
, 256);
1593 for(i
= 0 ; i
< 256 ; i
++) {
1594 g_string_printf(fe_name
, "irq %d", i
);
1595 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1598 name_tables
->irq_names
= NULL
;
1601 name_tables->soft_irq_names = g_new(GQuark, nb);
1602 for(i = 0 ; i < nb ; i++) {
1603 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1607 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1608 for(i
= 0 ; i
< 256 ; i
++) {
1609 g_string_printf(fe_name
, "softirq %d", i
);
1610 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1614 g_string_free(fe_name
, TRUE
);
1619 get_name_tables(LttvTraceState
*tcs
)
1621 LttvNameTables
*name_tables
;
1623 LttvAttributeValue v
;
1625 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1627 g_assert(*(v
.v_pointer
) != NULL
);
1628 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1629 //tcs->eventtype_names = name_tables->eventtype_names;
1630 tcs
->syscall_names
= name_tables
->syscall_names
;
1631 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1632 tcs
->trap_names
= name_tables
->trap_names
;
1633 tcs
->nb_traps
= name_tables
->nb_traps
;
1634 tcs
->irq_names
= name_tables
->irq_names
;
1635 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1640 free_name_tables(LttvTraceState
*tcs
)
1642 LttvNameTables
*name_tables
;
1644 LttvAttributeValue v
;
1646 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1648 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1649 *(v
.v_pointer
) = NULL
;
1651 // g_free(name_tables->eventtype_names);
1652 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1653 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1654 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1655 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1656 if(name_tables
) g_free(name_tables
);
1659 #ifdef HASH_TABLE_DEBUG
1661 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1663 LttvProcessState
*process
= (LttvProcessState
*)value
;
1665 /* Test for process corruption */
1666 guint stack_len
= process
->execution_stack
->len
;
1669 static void hash_table_check(GHashTable
*table
)
1671 g_hash_table_foreach(table
, test_process
, NULL
);
1678 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1681 LttvExecutionState
*es
;
1683 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1684 guint cpu
= tfs
->cpu
;
1686 #ifdef HASH_TABLE_DEBUG
1687 hash_table_check(ts
->processes
);
1689 LttvProcessState
*process
= ts
->running_process
[cpu
];
1691 guint depth
= process
->execution_stack
->len
;
1693 process
->execution_stack
=
1694 g_array_set_size(process
->execution_stack
, depth
+ 1);
1697 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1699 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1702 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1703 es
->cum_cpu_time
= ltt_time_zero
;
1704 es
->s
= process
->state
->s
;
1705 process
->state
= es
;
1709 * return 1 when empty, else 0 */
1710 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1711 LttvTracefileState
*tfs
)
1713 guint depth
= process
->execution_stack
->len
;
1719 process
->execution_stack
=
1720 g_array_set_size(process
->execution_stack
, depth
- 1);
1721 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1723 process
->state
->change
= tfs
->parent
.timestamp
;
1728 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1730 guint cpu
= tfs
->cpu
;
1731 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1732 LttvProcessState
*process
= ts
->running_process
[cpu
];
1734 guint depth
= process
->execution_stack
->len
;
1736 if(process
->state
->t
!= t
){
1737 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1738 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1739 g_info("process state has %s when pop_int is %s\n",
1740 g_quark_to_string(process
->state
->t
),
1741 g_quark_to_string(t
));
1742 g_info("{ %u, %u, %s, %s, %s }\n",
1745 g_quark_to_string(process
->name
),
1746 g_quark_to_string(process
->brand
),
1747 g_quark_to_string(process
->state
->s
));
1752 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1753 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1757 process
->execution_stack
=
1758 g_array_set_size(process
->execution_stack
, depth
- 1);
1759 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1761 process
->state
->change
= tfs
->parent
.timestamp
;
1764 struct search_result
{
1765 const LttTime
*time
; /* Requested time */
1766 LttTime
*best
; /* Best result */
1769 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1771 const LttTime
*elem_time
= (const LttTime
*)a
;
1772 /* Explicit non const cast */
1773 struct search_result
*res
= (struct search_result
*)b
;
1775 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1776 /* The usertrace was created before the schedchange */
1777 /* Get larger keys */
1779 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1780 /* The usertrace was created after the schedchange time */
1781 /* Get smaller keys */
1783 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1784 res
->best
= elem_time
;
1787 res
->best
= elem_time
;
1794 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1795 guint pid
, const LttTime
*timestamp
)
1797 LttvTracefileState
*tfs
= NULL
;
1798 struct search_result res
;
1799 /* Find the usertrace associated with a pid and time interval.
1800 * Search in the usertraces by PID (within a hash) and then, for each
1801 * corresponding element of the array, find the first one with creation
1802 * timestamp the lowest, but higher or equal to "timestamp". */
1803 res
.time
= timestamp
;
1805 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1806 if(usertrace_tree
) {
1807 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1809 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1817 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1818 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1820 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1822 LttvExecutionState
*es
;
1827 process
->tgid
= tgid
;
1829 process
->name
= name
;
1830 process
->brand
= LTTV_STATE_UNBRANDED
;
1831 //process->last_cpu = tfs->cpu_name;
1832 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1833 process
->type
= LTTV_STATE_USER_THREAD
;
1834 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1835 process
->current_function
= 0; //function 0x0 by default.
1837 g_info("Process %u, core %p", process
->pid
, process
);
1838 g_hash_table_insert(tcs
->processes
, process
, process
);
1841 process
->ppid
= parent
->pid
;
1842 process
->creation_time
= *timestamp
;
1845 /* No parent. This process exists but we are missing all information about
1846 its creation. The birth time is set to zero but we remember the time of
1851 process
->creation_time
= ltt_time_zero
;
1854 process
->insertion_time
= *timestamp
;
1855 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1856 process
->creation_time
.tv_nsec
);
1857 process
->pid_time
= g_quark_from_string(buffer
);
1859 //process->last_cpu = tfs->cpu_name;
1860 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1861 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1862 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1863 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1864 es
= process
->state
= &g_array_index(process
->execution_stack
,
1865 LttvExecutionState
, 0);
1866 es
->t
= LTTV_STATE_USER_MODE
;
1867 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1868 es
->entry
= *timestamp
;
1869 //g_assert(timestamp->tv_sec != 0);
1870 es
->change
= *timestamp
;
1871 es
->cum_cpu_time
= ltt_time_zero
;
1872 es
->s
= LTTV_STATE_RUN
;
1874 es
= process
->state
= &g_array_index(process
->execution_stack
,
1875 LttvExecutionState
, 1);
1876 es
->t
= LTTV_STATE_SYSCALL
;
1877 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1878 es
->entry
= *timestamp
;
1879 //g_assert(timestamp->tv_sec != 0);
1880 es
->change
= *timestamp
;
1881 es
->cum_cpu_time
= ltt_time_zero
;
1882 es
->s
= LTTV_STATE_WAIT_FORK
;
1884 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1885 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1886 sizeof(guint64
), 0);
1891 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1894 LttvProcessState key
;
1895 LttvProcessState
*process
;
1899 process
= g_hash_table_lookup(ts
->processes
, &key
);
1904 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1905 const LttTime
*timestamp
)
1907 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1908 LttvExecutionState
*es
;
1910 /* Put ltt_time_zero creation time for unexisting processes */
1911 if(unlikely(process
== NULL
)) {
1912 process
= lttv_state_create_process(ts
,
1913 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1914 /* We are not sure is it's a kernel thread or normal thread, put the
1915 * bottom stack state to unknown */
1916 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1917 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1922 /* FIXME : this function should be called when we receive an event telling that
1923 * release_task has been called in the kernel. In happens generally when
1924 * the parent waits for its child terminaison, but may also happen in special
1925 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1926 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1927 * of a killed thread ground, but isn't the leader.
1929 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1931 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1932 LttvProcessState key
;
1934 key
.pid
= process
->pid
;
1935 key
.cpu
= process
->cpu
;
1936 g_hash_table_remove(ts
->processes
, &key
);
1937 g_array_free(process
->execution_stack
, TRUE
);
1938 g_array_free(process
->user_stack
, TRUE
);
1943 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1945 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1946 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1951 static void lttv_state_free_process_table(GHashTable
*processes
)
1953 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1954 g_hash_table_destroy(processes
);
1958 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1960 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1962 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1963 LttvProcessState
*process
= ts
->running_process
[cpu
];
1964 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1965 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1966 LttField
*f
= thf
->f1
;
1968 LttvExecutionSubmode submode
;
1970 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1971 guint syscall
= ltt_event_get_unsigned(e
, f
);
1973 if(syscall
< nb_syscalls
) {
1974 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1977 /* Fixup an incomplete syscall table */
1978 GString
*string
= g_string_new("");
1979 g_string_printf(string
, "syscall %u", syscall
);
1980 submode
= g_quark_from_string(string
->str
);
1981 g_string_free(string
, TRUE
);
1983 /* There can be no system call from PID 0 : unknown state */
1984 if(process
->pid
!= 0)
1985 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1990 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1992 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1994 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1995 LttvProcessState
*process
= ts
->running_process
[cpu
];
1997 /* There can be no system call from PID 0 : unknown state */
1998 if(process
->pid
!= 0)
1999 pop_state(s
, LTTV_STATE_SYSCALL
);
2004 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2006 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2007 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2008 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2009 LttField
*f
= thf
->f1
;
2011 LttvExecutionSubmode submode
;
2013 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2014 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2016 if(trap
< nb_traps
) {
2017 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2019 /* Fixup an incomplete trap table */
2020 GString
*string
= g_string_new("");
2021 g_string_printf(string
, "trap %llu", trap
);
2022 submode
= g_quark_from_string(string
->str
);
2023 g_string_free(string
, TRUE
);
2026 push_state(s
, LTTV_STATE_TRAP
, submode
);
2031 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2033 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2035 pop_state(s
, LTTV_STATE_TRAP
);
2040 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2042 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2043 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2044 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2045 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2046 g_assert(thf
->f1
!= NULL
);
2047 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2048 LttField
*f
= thf
->f1
;
2050 LttvExecutionSubmode submode
;
2052 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
2053 ltt_event_get_unsigned(e
, f
)];
2055 /* Do something with the info about being in user or system mode when int? */
2056 push_state(s
, LTTV_STATE_IRQ
, submode
);
2060 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2062 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2064 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2070 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2072 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2074 pop_state(s
, LTTV_STATE_IRQ
);
2078 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2080 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2081 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2082 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2083 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2084 g_assert(thf
->f1
!= NULL
);
2085 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2086 LttField
*f
= thf
->f1
;
2088 LttvExecutionSubmode submode
;
2090 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
2091 ltt_event_get_long_unsigned(e
, f
)];
2093 /* Do something with the info about being in user or system mode when int? */
2094 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2098 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2102 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2103 guint cpu
= tfs
->cpu
;
2104 LttvProcessState
*process
= ts
->running_process
[cpu
];
2106 guint depth
= process
->user_stack
->len
;
2108 process
->user_stack
=
2109 g_array_set_size(process
->user_stack
, depth
+ 1);
2111 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2112 *new_func
= funcptr
;
2113 process
->current_function
= funcptr
;
2116 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2118 guint cpu
= tfs
->cpu
;
2119 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2120 LttvProcessState
*process
= ts
->running_process
[cpu
];
2122 if(process
->current_function
!= funcptr
){
2123 g_info("Different functions (%lu.%09lu): ignore it\n",
2124 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2125 g_info("process state has %llu when pop_function is %llu\n",
2126 process
->current_function
, funcptr
);
2127 g_info("{ %u, %u, %s, %s, %s }\n",
2130 g_quark_to_string(process
->name
),
2131 g_quark_to_string(process
->brand
),
2132 g_quark_to_string(process
->state
->s
));
2135 guint depth
= process
->user_stack
->len
;
2138 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2139 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2143 process
->user_stack
=
2144 g_array_set_size(process
->user_stack
, depth
- 1);
2145 process
->current_function
=
2146 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2150 static gboolean
function_entry(void *hook_data
, void *call_data
)
2152 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2153 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2154 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2155 g_assert(thf
->f1
!= NULL
);
2156 LttField
*f
= thf
->f1
;
2157 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2159 push_function(s
, funcptr
);
2163 static gboolean
function_exit(void *hook_data
, void *call_data
)
2165 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2166 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2167 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2168 g_assert(thf
->f1
!= NULL
);
2169 LttField
*f
= thf
->f1
;
2170 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2172 pop_function(s
, funcptr
);
2176 static gboolean
schedchange(void *hook_data
, void *call_data
)
2178 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2180 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2181 LttvProcessState
*process
= ts
->running_process
[cpu
];
2183 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2184 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2185 guint pid_in
, pid_out
;
2188 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2189 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2190 state_out
= ltt_event_get_int(e
, thf
->f3
);
2192 if(likely(process
!= NULL
)) {
2194 /* We could not know but it was not the idle process executing.
2195 This should only happen at the beginning, before the first schedule
2196 event, and when the initial information (current process for each CPU)
2197 is missing. It is not obvious how we could, after the fact, compensate
2198 the wrongly attributed statistics. */
2200 //This test only makes sense once the state is known and if there is no
2201 //missing events. We need to silently ignore schedchange coming after a
2202 //process_free, or it causes glitches. (FIXME)
2203 //if(unlikely(process->pid != pid_out)) {
2204 // g_assert(process->pid == 0);
2206 if(process
->pid
== 0 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2207 /* Scheduling out of pid 0 at beginning of the trace :
2208 * we know for sure it is in syscall mode at this point. */
2209 g_assert(process
->execution_stack
->len
== 1);
2210 process
->state
->t
= LTTV_STATE_SYSCALL
;
2212 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2213 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2214 process
->state
->change
= s
->parent
.timestamp
;
2216 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2217 else process
->state
->s
= LTTV_STATE_WAIT
;
2218 process
->state
->change
= s
->parent
.timestamp
;
2222 exit_process(s
, process
); /* EXIT_DEAD */
2223 /* see sched.h for states */
2225 process
= ts
->running_process
[cpu
] =
2226 lttv_state_find_process_or_create(
2227 (LttvTraceState
*)s
->parent
.t_context
,
2229 &s
->parent
.timestamp
);
2230 process
->state
->s
= LTTV_STATE_RUN
;
2232 if(process
->usertrace
)
2233 process
->usertrace
->cpu
= cpu
;
2234 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2235 process
->state
->change
= s
->parent
.timestamp
;
2239 static gboolean
process_fork(void *hook_data
, void *call_data
)
2241 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2242 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2243 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2245 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2246 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2248 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2249 LttvProcessState
*process
= ts
->running_process
[cpu
];
2250 LttvProcessState
*child_process
;
2253 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2256 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2257 s
->parent
.target_pid
= child_pid
;
2260 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2261 else child_tgid
= 0;
2263 /* Mathieu : it seems like the process might have been scheduled in before the
2264 * fork, and, in a rare case, might be the current process. This might happen
2265 * in a SMP case where we don't have enough precision on the clocks.
2267 * Test reenabled after precision fixes on time. (Mathieu) */
2269 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2271 if(unlikely(zombie_process
!= NULL
)) {
2272 /* Reutilisation of PID. Only now we are sure that the old PID
2273 * has been released. FIXME : should know when release_task happens instead.
2275 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2277 for(i
=0; i
< num_cpus
; i
++) {
2278 g_assert(zombie_process
!= ts
->running_process
[i
]);
2281 exit_process(s
, zombie_process
);
2284 g_assert(process
->pid
!= child_pid
);
2285 // FIXME : Add this test in the "known state" section
2286 // g_assert(process->pid == parent_pid);
2287 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2288 if(child_process
== NULL
) {
2289 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2290 child_pid
, child_tgid
,
2291 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2293 /* The process has already been created : due to time imprecision between
2294 * multiple CPUs : it has been scheduled in before creation. Note that we
2295 * shouldn't have this kind of imprecision.
2297 * Simply put a correct parent.
2299 g_assert(0); /* This is a problematic case : the process has been created
2300 before the fork event */
2301 child_process
->ppid
= process
->pid
;
2302 child_process
->tgid
= child_tgid
;
2304 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2305 child_process
->name
= process
->name
;
2306 child_process
->brand
= process
->brand
;
2311 /* We stamp a newly created process as kernel_thread */
2312 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2314 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2315 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2316 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2318 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2319 LttvProcessState
*process
;
2320 LttvExecutionState
*es
;
2323 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2324 s
->parent
.target_pid
= pid
;
2326 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2327 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2328 es
->t
= LTTV_STATE_SYSCALL
;
2329 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2334 static gboolean
process_exit(void *hook_data
, void *call_data
)
2336 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2337 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2338 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2340 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2341 LttvProcessState
*process
; // = ts->running_process[cpu];
2343 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2344 s
->parent
.target_pid
= pid
;
2346 // FIXME : Add this test in the "known state" section
2347 // g_assert(process->pid == pid);
2349 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2350 if(likely(process
!= NULL
)) {
2351 process
->state
->s
= LTTV_STATE_EXIT
;
2356 static gboolean
process_free(void *hook_data
, void *call_data
)
2358 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2359 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2360 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2361 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2363 LttvProcessState
*process
;
2365 /* PID of the process to release */
2366 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2367 s
->parent
.target_pid
= release_pid
;
2369 g_assert(release_pid
!= 0);
2371 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2373 if(likely(process
!= NULL
)) {
2374 /* release_task is happening at kernel level : we can now safely release
2375 * the data structure of the process */
2376 //This test is fun, though, as it may happen that
2377 //at time t : CPU 0 : process_free
2378 //at time t+150ns : CPU 1 : schedule out
2379 //Clearly due to time imprecision, we disable it. (Mathieu)
2380 //If this weird case happen, we have no choice but to put the
2381 //Currently running process on the cpu to 0.
2382 //I re-enable it following time precision fixes. (Mathieu)
2383 //Well, in the case where an process is freed by a process on another CPU
2384 //and still scheduled, it happens that this is the schedchange that will
2385 //drop the last reference count. Do not free it here!
2386 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2388 for(i
=0; i
< num_cpus
; i
++) {
2389 //g_assert(process != ts->running_process[i]);
2390 if(process
== ts
->running_process
[i
]) {
2391 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2395 if(i
== num_cpus
) /* process is not scheduled */
2396 exit_process(s
, process
);
2403 static gboolean
process_exec(void *hook_data
, void *call_data
)
2405 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2406 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2407 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2408 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2411 LttvProcessState
*process
= ts
->running_process
[cpu
];
2413 /* PID of the process to release */
2414 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2415 //name = ltt_event_get_string(e, thf->f1);
2416 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2418 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2419 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2420 memcpy(null_term_name
, name_begin
, name_len
);
2421 null_term_name
[name_len
] = '\0';
2423 process
->name
= g_quark_from_string(null_term_name
);
2424 process
->brand
= LTTV_STATE_UNBRANDED
;
2425 g_free(null_term_name
);
2429 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2431 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2432 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2433 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2434 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2437 LttvProcessState
*process
= ts
->running_process
[cpu
];
2439 name
= ltt_event_get_string(e
, thf
->f1
);
2440 process
->brand
= g_quark_from_string(name
);
2445 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2447 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2448 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2449 //It's slow : optimise later by doing this before reading trace.
2450 LttEventType
*et
= ltt_event_eventtype(e
);
2452 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2458 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2459 LttvProcessState
*process
= ts
->running_process
[cpu
];
2460 LttvProcessState
*parent_process
;
2461 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2462 GQuark type
, mode
, submode
, status
;
2463 LttvExecutionState
*es
;
2466 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2467 s
->parent
.target_pid
= pid
;
2470 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2473 command
= ltt_event_get_string(e
, thf
->f3
);
2476 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2477 type
= ltt_enum_string_get(ltt_field_type(f4
),
2478 ltt_event_get_unsigned(e
, f4
));
2481 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2482 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2483 ltt_event_get_unsigned(e
, f5
));
2486 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2487 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2488 ltt_event_get_unsigned(e
, f6
));
2491 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2492 status
= ltt_enum_string_get(ltt_field_type(f7
),
2493 ltt_event_get_unsigned(e
, f7
));
2496 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2497 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2500 /* The process might exist if a process was forked while performing the state
2502 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2503 if(process
== NULL
) {
2504 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2505 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2506 pid
, tgid
, g_quark_from_string(command
),
2507 &s
->parent
.timestamp
);
2509 /* Keep the stack bottom : a running user mode */
2510 /* Disabled because of inconsistencies in the current statedump states. */
2511 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2512 /* Only keep the bottom
2513 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2514 /* Will cause expected trap when in fact being syscall (even after end of
2516 * Will cause expected interrupt when being syscall. (only before end of
2517 * statedump event) */
2518 // This will cause a "popping last state on stack, ignoring it."
2519 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2520 es
= process
->state
= &g_array_index(process
->execution_stack
,
2521 LttvExecutionState
, 0);
2522 es
->t
= LTTV_STATE_SYSCALL
;
2526 /* User space process :
2527 * bottom : user mode
2528 * either currently running or scheduled out.
2529 * can be scheduled out because interrupted in (user mode or in syscall)
2530 * or because of an explicit call to the scheduler in syscall. Note that
2531 * the scheduler call comes after the irq_exit, so never in interrupt
2533 // temp workaround : set size to 1 : only have user mode bottom of stack.
2534 // will cause g_info message of expected syscall mode when in fact being
2535 // in user mode. Can also cause expected trap when in fact being user
2536 // mode in the event of a page fault reenabling interrupts in the handler.
2537 // Expected syscall and trap can also happen after the end of statedump
2538 // This will cause a "popping last state on stack, ignoring it."
2539 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2541 es
= process
->state
= &g_array_index(process
->execution_stack
,
2542 LttvExecutionState
, 1);
2543 es
->t
= LTTV_STATE_USER_MODE
;
2551 es
= process
->state
= &g_array_index(process
->execution_stack
,
2552 LttvExecutionState
, 1);
2553 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2554 es
->s
= LTTV_STATE_UNNAMED
;
2555 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2559 /* The process has already been created :
2560 * Probably was forked while dumping the process state or
2561 * was simply scheduled in prior to get the state dump event.
2562 * We know for sure if it is a user space thread.
2564 process
->ppid
= parent_pid
;
2565 process
->tgid
= tgid
;
2566 process
->name
= g_quark_from_string(command
);
2567 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2568 if(type
!= LTTV_STATE_KERNEL_THREAD
)
2569 es
->t
= LTTV_STATE_USER_MODE
;
2570 /* Don't mess around with the stack, it will eventually become
2571 * ok after the end of state dump. */
2578 /*****************************************************************************
2579 * XENOLTT thread functions
2580 *****************************************************************************/
2581 static void xeno_push_status(LttvTracefileState
*tfs
, LttvXenoThreadStatus status
){
2582 LttvXenoExecutionState
*es
;
2584 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2585 guint cpu
= tfs
->cpu
;
2587 LttvXenoThreadState
*thread
= ts
->running_thread
[cpu
];
2589 guint depth
= thread
->execution_stack
->len
;
2591 thread
->execution_stack
= g_array_set_size(thread
->execution_stack
, depth
+ 1);
2593 thread
->state
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
- 1);
2595 es
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
);
2596 es
->mode
= thread
->state
->mode
;
2597 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2598 es
->cum_cpu_time
= ltt_time_zero
;
2599 es
->status
= status
;
2600 if (status
== LTTV_XENO_STATE_INIT
) es
->started
= FALSE
;
2601 else if(status
== LTTV_XENO_STATE_START
) es
->started
= TRUE
;
2602 else es
->started
= thread
->state
->started
;
2603 es
->overrun_start
= thread
->state
->overrun_start
;
2604 es
->running
= thread
->state
->running
;
2609 static void xeno_set_running(LttvTracefileState
*tfs
,gboolean running
){
2610 LttvXenoExecutionState
*es
;
2611 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2612 guint cpu
= tfs
->cpu
;
2613 LttvXenoThreadState
*thread
= ts
->running_thread
[cpu
];
2614 guint depth
= thread
->execution_stack
->len
;
2615 thread
->execution_stack
= g_array_set_size(thread
->execution_stack
, depth
+ 1);
2617 thread
->state
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
- 1);
2619 es
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
);
2620 es
->mode
= thread
->state
->mode
;
2621 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2622 es
->cum_cpu_time
= ltt_time_zero
;
2623 es
->status
= thread
->state
->status
;
2624 es
->started
= thread
->state
->started
;
2625 es
->overrun_start
= thread
->state
->overrun_start
;
2626 es
->running
= running
;
2631 static void xeno_push_mode(LttvTracefileState
*tfs
,LttvXenoExecutionMode mode
){
2632 LttvXenoExecutionState
*es
;
2634 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2635 guint cpu
= tfs
->cpu
;
2637 LttvXenoThreadState
*thread
= ts
->running_thread
[cpu
];
2639 guint depth
= thread
->execution_stack
->len
;
2641 thread
->execution_stack
= g_array_set_size(thread
->execution_stack
, depth
+ 1);
2643 thread
->state
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
- 1);
2645 es
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, depth
);
2647 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
2648 es
->cum_cpu_time
= ltt_time_zero
;
2649 es
->status
= thread
->state
->status
;
2650 es
->started
= thread
->state
->started
;
2651 if (mode
== LTTV_XENO_MODE_OVERRUN
&& thread
->state
->mode
!= LTTV_XENO_MODE_OVERRUN
) es
->overrun_start
= tfs
->parent
.timestamp
;
2652 else es
->overrun_start
= thread
->state
->overrun_start
;
2654 es
->running
= thread
->state
->running
;
2659 static void xeno_new_synch(LttvTracefileState
*tfs
, guint synch_address
, LttvXenoThreadState
*thread
){
2660 LttvXenoExecutionSynch
*es
;
2661 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2663 LttvXenoSynchState
*synch
= lttv_xeno_state_find_synch(ts
,synch_address
);
2665 synch
= lttv_xeno_state_create_synch(ts
, synch_address
, &tfs
->parent
.timestamp
);
2668 guint depth
= synch
->execution_stack
->len
;
2670 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, depth
+ 1);
2672 synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
- 1);
2674 es
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
);
2677 es
->start_time
= tfs
->parent
.timestamp
;
2678 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2680 LttvXenoThreadState
*temp_thread
;
2681 for(i
=0;i
<synch
->state
->waiting_threads
->len
;i
++){
2682 temp_thread
= g_array_index(synch
->state
->waiting_threads
, LttvXenoThreadState
*, i
);
2683 if (temp_thread
->address
!= thread
->address
){
2684 if (thread
->prio
< temp_thread
->prio
){
2685 printf("inversion de priorité:\n\t%s - %u\n\t%s - %u\n",
2686 g_quark_to_string(thread
->name
),thread
->prio
,
2687 g_quark_to_string(temp_thread
->name
),temp_thread
->prio
);
2689 g_array_append_val(es
->waiting_threads
,temp_thread
);
2696 static void xeno_wait_synch(LttvTracefileState
*tfs
, guint synch_address
, LttvXenoThreadState
*thread
){
2697 LttvXenoExecutionSynch
*es
;
2698 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2700 LttvXenoSynchState
*synch
= lttv_xeno_state_find_synch(ts
,synch_address
);
2702 synch
= lttv_xeno_state_create_synch(ts
, synch_address
, &tfs
->parent
.timestamp
);
2705 guint depth
= synch
->execution_stack
->len
;
2707 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, depth
+ 1);
2709 synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
- 1);
2711 es
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
);
2712 es
->owner
= synch
->state
->owner
;
2713 es
->start_time
= synch
->state
->start_time
;
2714 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2716 LttvXenoThreadState
*temp_thread
;
2717 for(i
=0;i
<synch
->state
->waiting_threads
->len
;i
++){
2718 temp_thread
= g_array_index(synch
->state
->waiting_threads
, LttvXenoThreadState
*, i
);
2719 g_array_append_val(es
->waiting_threads
,temp_thread
);
2722 g_array_append_val(es
->waiting_threads
,thread
);
2727 static void xeno_release_synch(LttvTracefileState
*tfs
, guint synch_address
){
2728 LttvXenoExecutionSynch
*es
;
2729 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2731 LttvXenoSynchState
*synch
= lttv_xeno_state_find_synch(ts
,synch_address
);
2733 synch
= lttv_xeno_state_create_synch(ts
, synch_address
, &tfs
->parent
.timestamp
);
2736 guint depth
= synch
->execution_stack
->len
;
2738 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, depth
+ 1);
2740 synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
- 1);
2742 es
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
);
2744 es
->start_time
= ltt_time_zero
;
2745 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2747 LttvXenoThreadState
*temp_thread
;
2748 for(i
=0;i
<synch
->state
->waiting_threads
->len
;i
++){
2749 temp_thread
= g_array_index(synch
->state
->waiting_threads
, LttvXenoThreadState
*, i
);
2750 g_array_append_val(es
->waiting_threads
,temp_thread
);
2756 static void xeno_flush_synch(LttvTracefileState
*tfs
, guint synch_address
){
2757 LttvXenoExecutionSynch
*es
;
2758 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2760 LttvXenoSynchState
*synch
= lttv_xeno_state_find_synch(ts
,synch_address
);
2762 synch
= lttv_xeno_state_create_synch(ts
, synch_address
, &tfs
->parent
.timestamp
);
2765 guint depth
= synch
->execution_stack
->len
;
2767 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, depth
+ 1);
2769 synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
- 1);
2771 es
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
);
2773 es
->start_time
= ltt_time_zero
;
2774 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2779 static void xeno_forget_synch(LttvTracefileState
*tfs
, guint synch_address
, LttvXenoThreadState
*thread
){
2780 LttvXenoExecutionSynch
*es
;
2781 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2783 LttvXenoSynchState
*synch
= lttv_xeno_state_find_synch(ts
,synch_address
);
2785 synch
= lttv_xeno_state_create_synch(ts
, synch_address
, &tfs
->parent
.timestamp
);
2788 guint depth
= synch
->execution_stack
->len
;
2790 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, depth
+ 1);
2792 synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
- 1);
2794 es
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, depth
);
2795 es
->owner
= synch
->state
->owner
;
2796 es
->start_time
= synch
->state
->start_time
;
2797 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2799 LttvXenoThreadState
*temp_thread
;
2800 for(i
=0;i
<synch
->state
->waiting_threads
->len
;i
++){
2801 temp_thread
= g_array_index(synch
->state
->waiting_threads
, LttvXenoThreadState
*, i
);
2802 if (temp_thread
->address
!= thread
->address
) g_array_append_val(es
->waiting_threads
,temp_thread
);
2808 LttvXenoThreadState
*lttv_xeno_state_create_thread(LttvTraceState
*tcs
, guint cpu
, guint address
, guint prio
, GQuark name
, const LttTime
*timestamp
){
2809 LttvXenoThreadState
*thread
= g_new(LttvXenoThreadState
, 1);
2811 LttvXenoExecutionState
*es
;
2813 thread
->address
= address
;
2814 thread
->prio
= prio
;
2816 thread
->name
= name
;
2817 thread
->usertrace
= ltt_state_usertrace_find(tcs
, address
, timestamp
);
2818 g_info("Thread %p", (void *) thread
->address
);
2820 if(lttv_xeno_state_find_thread(tcs
,cpu
,address
) == NULL
){
2821 g_hash_table_insert(tcs
->threads
, thread
, thread
);
2824 g_hash_table_replace(tcs
->threads
, thread
, thread
);
2827 thread
->creation_time
= *timestamp
;
2828 thread
->insertion_time
= *timestamp
;
2831 thread
->execution_stack
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvXenoExecutionState
), PREALLOCATED_EXECUTION_STACK
);
2832 thread
->execution_stack
= g_array_set_size(thread
->execution_stack
, 2);
2833 es
= thread
->state
= &g_array_index(thread
->execution_stack
, LttvXenoExecutionState
, 0);
2834 es
->mode
= LTTV_XENO_MODE_NORMAL
;
2835 es
->entry
= *timestamp
;
2836 es
->change
= *timestamp
;
2837 es
->cum_cpu_time
= ltt_time_zero
;
2838 es
->status
= LTTV_XENO_STATE_INIT
;
2839 es
->started
= FALSE
;
2840 es
->running
= FALSE
;
2846 LttvXenoThreadState
*lttv_xeno_state_find_thread(LttvTraceState
*ts
, guint cpu
, guint address
){
2847 LttvXenoThreadState key
;
2848 LttvXenoThreadState
*thread
;
2850 key
.address
= address
;
2852 thread
= g_hash_table_lookup(ts
->threads
, &key
);
2856 static gboolean
find_timer(gpointer key
, gpointer value
, gpointer user_data
){
2857 const LttvXenoThreadState
*pa
= (const LttvXenoThreadState
*)value
;
2858 const gulong pb
= (const gulong
)user_data
;
2860 return likely(pa
->timer_address
== pb
);
2863 LttvXenoThreadState
*lttv_xeno_state_find_thread_from_timer(LttvTraceState
*ts
, guint cpu
, guint timer_address
){
2864 LttvXenoThreadState
*thread
;
2866 thread
= g_hash_table_find(ts
->threads
,find_timer
,(gpointer
)timer_address
);
2871 LttvXenoSynchState
*lttv_xeno_state_create_synch(LttvTraceState
*tcs
, guint address
, const LttTime
*timestamp
){
2872 LttvXenoSynchState
*synch
= g_new(LttvXenoSynchState
, 1);
2874 LttvXenoExecutionSynch
*es
;
2876 synch
->address
= address
;
2877 g_hash_table_insert(tcs
->synchs
, synch
, synch
);
2879 synch
->creation_time
= *timestamp
;
2881 synch
->execution_stack
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvXenoExecutionSynch
), PREALLOCATED_EXECUTION_STACK
);
2882 synch
->execution_stack
= g_array_set_size(synch
->execution_stack
, 1);
2883 es
= synch
->state
= &g_array_index(synch
->execution_stack
, LttvXenoExecutionSynch
, 0);
2885 es
->waiting_threads
= g_array_new(FALSE
, FALSE
, sizeof(LttvXenoThreadState
*));
2890 LttvXenoSynchState
*lttv_xeno_state_find_synch(LttvTraceState
*ts
, guint address
){
2891 LttvXenoSynchState key
;
2892 LttvXenoSynchState
*synch
;
2894 key
.address
= address
;
2895 synch
= g_hash_table_lookup(ts
->synchs
, &key
);
2899 static gboolean
find_thread_synch(gpointer key
, gpointer value
, gpointer user_data
){
2900 const LttvXenoSynchState
*pa
= (const LttvXenoSynchState
*)value
;
2901 const LttvXenoThreadState
*pb
= (const LttvXenoThreadState
*)user_data
;
2903 return likely(pa
->state
->owner
== pb
);
2906 gboolean
lttv_xeno_thread_synch_owner(LttvTraceState
*ts
, LttvXenoThreadState
* thread
){
2907 return (g_hash_table_find(ts
->synchs
,find_thread_synch
,(gpointer
)thread
) != NULL
);
2911 static gboolean
find_thread_synch_wait(gpointer key
, gpointer value
, gpointer user_data
){
2912 const LttvXenoSynchState
*pa
= (const LttvXenoSynchState
*)value
;
2913 const LttvXenoThreadState
*pb
= (const LttvXenoThreadState
*)user_data
;
2915 LttvXenoThreadState
* temp_thread
;
2917 for(i
=0;i
<pa
->state
->waiting_threads
->len
;i
++){
2918 temp_thread
= g_array_index(pa
->state
->waiting_threads
, LttvXenoThreadState
*, i
);
2919 if(temp_thread
->address
== pb
->address
) return TRUE
;
2924 gboolean
lttv_xeno_thread_synch_waiting(LttvTraceState
*ts
, LttvXenoThreadState
* thread
){
2925 return (g_hash_table_find(ts
->synchs
,find_thread_synch_wait
,(gpointer
)thread
) != NULL
);
2929 /*****************************************************************************
2931 *****************************************************************************/
2933 static gboolean
xenoltt_thread_init(void *hook_data
, void *call_data
){
2934 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2935 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2936 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2937 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2940 g_assert(thf
->f1
!= NULL
);
2941 GQuark name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2942 gulong address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2943 guint prio
= ltt_event_get_unsigned(e
, thf
->f3
);
2944 LttvXenoThreadState
*new_thread
;// = lttv_xeno_state_find_thread(ts,cpu,address);
2946 new_thread
= lttv_xeno_state_create_thread(ts
, cpu
, address
, prio
, name
, &s
->parent
.timestamp
);
2948 ts
->running_thread
[cpu
] = new_thread
;
2949 xeno_push_status(s
,LTTV_XENO_STATE_INIT
);
2953 static gboolean
xenoltt_thread_change_state(void *hook_data
, void *call_data
){
2954 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2955 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2956 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2957 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2959 // We must update the state of the current Xenomai Thread
2960 GQuark event_name
= ltt_eventtype_name(ltt_event_eventtype(e
));
2962 // First, suspend the thread out in thread_switch event
2963 if(event_name
== LTT_EVENT_XENOLTT_THREAD_SWITCH
) {
2964 g_assert(thf
->f2
!= NULL
);
2965 gulong address_out
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2966 LttvXenoThreadState
*thread_out
= lttv_xeno_state_find_thread(ts
,cpu
,address_out
);
2967 if(thread_out
!= NULL
) {
2968 ts
->running_thread
[cpu
] = thread_out
;
2969 xeno_set_running(s
,FALSE
);
2970 if (thread_out
->state
->status
== LTTV_XENO_STATE_RUN
) xeno_push_status(s
,LTTV_XENO_STATE_READY
);
2974 // Then set the nrunning thread
2975 g_assert(thf
->f1
!= NULL
);
2976 gulong address
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2977 LttvXenoThreadState
*thread
= lttv_xeno_state_find_thread(ts
,cpu
,address
);
2979 if(thread
!= NULL
) {
2980 ts
->running_thread
[cpu
] = thread
;
2981 if(event_name
== LTT_EVENT_XENOLTT_THREAD_START
) {
2982 xeno_push_status(s
,LTTV_XENO_STATE_START
);
2984 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_RENICE
) {
2985 g_assert(thf
->f2
!= NULL
);
2986 guint prio
= ltt_event_get_unsigned(e
, thf
->f2
);
2987 thread
->prio
= prio
;
2989 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_SWITCH
) {
2990 xeno_set_running(s
,TRUE
);
2991 if (thread
->state
->status
== LTTV_XENO_STATE_READY
) xeno_push_status(s
,LTTV_XENO_STATE_RUN
);
2993 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_RESUME
) {
2994 xeno_push_status(s
,LTTV_XENO_STATE_READY
);
2996 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_DELETE
) {
2997 xeno_push_status(s
,LTTV_XENO_STATE_DEAD
);
2999 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD
) {
3000 thread
->wait_period_call
= TRUE
;
3001 xeno_push_mode(s
,LTTV_XENO_MODE_NORMAL
);
3002 xeno_push_status(s
,LTTV_XENO_STATE_WAIT_PERIOD
);
3004 else if(event_name
== LTT_EVENT_XENOLTT_THREAD_SUSPEND
) {
3005 xeno_push_status(s
,LTTV_XENO_STATE_SUSPEND
);
3008 // printf("-> %s : \t%s\n",g_quark_to_string(thread->name),g_quark_to_string(thread->state->synch_mode));
3014 static gboolean
xenoltt_synch_change(void *hook_data
, void *call_data
){
3015 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3016 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3017 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
3018 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3020 // We must update the state of the current Xenomai Thread
3021 GQuark event_name
= ltt_eventtype_name(ltt_event_eventtype(e
));
3023 if(event_name
== LTT_EVENT_XENOLTT_SYNCH_FLUSH
) {
3024 g_assert(thf
->f1
!= NULL
);
3025 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f1
);
3026 xeno_flush_synch(s
,synch_address
);
3029 g_assert(thf
->f1
!= NULL
);
3030 gulong address
= ltt_event_get_long_unsigned(e
, thf
->f1
);
3031 LttvXenoThreadState
*thread
= lttv_xeno_state_find_thread(ts
,cpu
,address
);
3033 if(thread
!= NULL
) {
3034 if(event_name
== LTT_EVENT_XENOLTT_SYNCH_SET_OWNER
){
3035 if (thread
->state
->started
== TRUE
){
3036 g_assert(thf
->f2
!= NULL
);
3037 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3038 xeno_new_synch(s
,synch_address
,thread
);
3041 else if(event_name
== LTT_EVENT_XENOLTT_SYNCH_WAKEUP1
||
3042 event_name
== LTT_EVENT_XENOLTT_SYNCH_WAKEUPX
) {
3043 // thread->start_wait_synch = ltt_time_zero;
3044 g_assert(thf
->f2
!= NULL
);
3045 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3046 xeno_new_synch(s
,synch_address
,thread
);
3049 else if(event_name
== LTT_EVENT_XENOLTT_SYNCH_UNLOCK
) {
3050 g_assert(thf
->f2
!= NULL
);
3051 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3052 xeno_release_synch(s
,synch_address
);
3054 else if(event_name
== LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON
) {
3055 thread
->start_wait_synch
= s
->parent
.timestamp
;
3056 g_assert(thf
->f2
!= NULL
);
3057 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3058 xeno_wait_synch(s
,synch_address
,thread
);
3060 else if(event_name
== LTT_EVENT_XENOLTT_SYNCH_FORGET
) {
3061 g_assert(thf
->f2
!= NULL
);
3062 gulong synch_address
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3063 xeno_forget_synch(s
,synch_address
,thread
);
3066 // printf("-> %s : \t%s\n",g_quark_to_string(thread->name),g_quark_to_string(thread->state->synch_mode));
3072 /*****************************************************************************
3073 * XENOLTT HOOK TO SET THE PERIOD OF A TASK
3074 *****************************************************************************/
3075 static gboolean
xenoltt_thread_set_period(void *hook_data
, void *call_data
){
3076 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3077 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3078 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
3079 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3082 g_assert(thf
->f1
!= NULL
);
3083 g_assert(thf
->f2
!= NULL
);
3084 g_assert(thf
->f3
!= NULL
);
3085 gulong address
= ltt_event_get_long_unsigned(e
, thf
->f1
);
3086 guint period
= ltt_event_get_long_unsigned(e
, thf
->f2
);
3087 gulong timer_address
= ltt_event_get_long_unsigned(e
, thf
->f3
);
3088 LttvXenoThreadState
*thread
= lttv_xeno_state_find_thread(ts
,cpu
,address
);
3090 if(thread
!= NULL
) {
3091 ts
->running_thread
[cpu
] = thread
;
3092 thread
->period
= period
;
3093 thread
->timer_address
= timer_address
;
3100 /*****************************************************************************
3101 * XENOLTT HOOK TIMER TICK
3102 * If a task has not called wait_period before the timer tick, it means that
3103 * it's going in overrun mode
3104 *****************************************************************************/
3105 static gboolean
xenoltt_timer_tick(void *hook_data
, void *call_data
){
3106 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
3107 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
3108 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
3109 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
3112 g_assert(thf
->f1
!= NULL
);
3113 gulong timer_address
= ltt_event_get_long_unsigned(e
, thf
->f1
);
3115 LttvXenoThreadState
*thread
= lttv_xeno_state_find_thread_from_timer(ts
,cpu
,timer_address
);
3117 if(thread
!= NULL
) {
3118 ts
->running_thread
[cpu
] = thread
;
3119 if (thread
->wait_period_call
== FALSE
){
3120 xeno_push_mode(s
,LTTV_XENO_MODE_OVERRUN
);
3122 else xeno_push_mode(s
,LTTV_XENO_MODE_NORMAL
);
3123 thread
->wait_period_call
= FALSE
;
3130 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
3132 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3134 lttv_state_add_event_hooks(tss
);
3139 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
3141 LttvTraceset
*traceset
= self
->parent
.ts
;
3143 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3147 LttvTracefileState
*tfs
;
3151 LttvTraceHookByFacility
*thf
;
3153 LttvTraceHook
*hook
;
3155 LttvAttributeValue val
;
3160 nb_trace
= lttv_traceset_number(traceset
);
3161 for(i
= 0 ; i
< nb_trace
; i
++) {
3162 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3164 /* Find the eventtype id for the following events and register the
3165 associated by id hooks. */
3167 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 35);
3168 hooks
= g_array_set_size(hooks
, 35); // Max possible number of hooks.
3171 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3172 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
3173 LTT_FIELD_SYSCALL_ID
, 0, 0,
3174 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3177 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3178 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
3180 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3183 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3184 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
3185 LTT_FIELD_TRAP_ID
, 0, 0,
3186 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3189 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3190 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
3192 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3195 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3196 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
3197 LTT_FIELD_IRQ_ID
, 0, 0,
3198 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3201 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3202 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
3204 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3207 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3208 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
3209 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
3210 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3213 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3214 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
3216 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3219 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3220 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
3221 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
3222 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3225 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3226 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
3227 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_TGID
,
3228 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3231 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3232 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
3233 LTT_FIELD_PID
, 0, 0,
3234 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3238 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3239 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
3240 LTT_FIELD_PID
, 0, 0,
3241 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3244 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3245 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
3246 LTT_FIELD_PID
, 0, 0,
3247 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3250 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3251 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3252 LTT_FIELD_FILENAME
, 0, 0,
3253 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3256 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3257 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3258 LTT_FIELD_NAME
, 0, 0,
3259 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3262 /* statedump-related hooks */
3263 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3264 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
3265 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3266 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3269 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3270 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3271 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3272 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3275 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3276 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3277 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3278 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3282 /*************************************************************************
3283 ************ XENOLTT HOOKS *********************************************/
3285 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3286 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_INIT
,
3287 LTT_FIELD_XENOLTT_NAME
, LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_PRIO
,
3288 xenoltt_thread_init
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3292 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3293 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_RENICE
,
3294 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_PRIO
, 0,
3295 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3299 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3300 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_START
,
3301 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3302 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3306 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3307 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_SWITCH
,
3308 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_ADDRESS_OUT
, LTT_FIELD_XENOLTT_NAME_OUT
,
3309 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3313 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3314 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_RESUME
,
3315 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3316 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3319 // THREAD WAIT_PERIOD
3320 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3321 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD
,
3322 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3323 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3327 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3328 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_SUSPEND
,
3329 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3330 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3334 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3335 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_DELETE
,
3336 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3337 xenoltt_thread_change_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3340 // THREAD SET PERIOD
3341 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3342 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_THREAD_SET_PERIOD
,
3343 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_PERIOD
, LTT_FIELD_XENOLTT_TIMER_ADDRESS
,
3344 xenoltt_thread_set_period
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3348 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3349 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_TIMER_TICK
,
3350 LTT_FIELD_XENOLTT_ADDRESS
, 0, 0,
3351 xenoltt_timer_tick
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3355 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3356 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_SET_OWNER
,
3357 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3358 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3362 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3363 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_WAKEUP1
,
3364 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3365 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3369 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3370 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_WAKEUPX
,
3371 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3372 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3376 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3377 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_UNLOCK
,
3378 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3379 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3383 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3384 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON
,
3385 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3386 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3390 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3391 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_FLUSH
,
3392 LTT_FIELD_XENOLTT_SYNCH
, 0, 0,
3393 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3397 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3398 LTT_FACILITY_XENOLTT
, LTT_EVENT_XENOLTT_SYNCH_FORGET
,
3399 LTT_FIELD_XENOLTT_ADDRESS
, LTT_FIELD_XENOLTT_SYNCH
, 0,
3400 xenoltt_synch_change
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3404 hooks
= g_array_set_size(hooks
, hn
);
3406 /* Add these hooks to each event_by_id hooks list */
3408 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3410 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3412 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3413 LttvTracefileContext
*, j
));
3415 for(k
= 0 ; k
< hooks
->len
; k
++) {
3416 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3417 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3418 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3420 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3427 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3428 *(val
.v_pointer
) = hooks
;
3432 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3434 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3436 lttv_state_remove_event_hooks(tss
);
3441 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3443 LttvTraceset
*traceset
= self
->parent
.ts
;
3445 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3449 LttvTracefileState
*tfs
;
3453 LttvTraceHook
*hook
;
3455 LttvTraceHookByFacility
*thf
;
3457 LttvAttributeValue val
;
3459 nb_trace
= lttv_traceset_number(traceset
);
3460 for(i
= 0 ; i
< nb_trace
; i
++) {
3461 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3463 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3464 hooks
= *(val
.v_pointer
);
3466 /* Remove these hooks from each event_by_id hooks list */
3468 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3470 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3472 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3473 LttvTracefileContext
*, j
));
3475 for(k
= 0 ; k
< hooks
->len
; k
++) {
3476 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3477 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3478 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3480 lttv_hooks_remove_data(
3481 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3487 for(k
= 0 ; k
< hooks
->len
; k
++)
3488 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3489 g_array_free(hooks
, TRUE
);
3493 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3495 guint
*event_count
= (guint
*)hook_data
;
3497 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3498 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3503 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3505 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3507 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3509 LttvAttributeValue value
;
3511 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3512 LTTV_STATE_SAVED_STATES
);
3513 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3514 value
= lttv_attribute_add(saved_states_tree
,
3515 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3516 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3517 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3518 *(value
.v_time
) = self
->parent
.timestamp
;
3519 lttv_state_save(tcs
, saved_state_tree
);
3520 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3521 self
->parent
.timestamp
.tv_nsec
);
3523 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3528 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3530 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3532 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3537 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3545 static gboolean
block_start(void *hook_data
, void *call_data
)
3547 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3549 LttvTracefileState
*tfcs
;
3551 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3553 LttEventPosition
*ep
;
3555 guint i
, nb_block
, nb_event
, nb_tracefile
;
3559 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3561 LttvAttributeValue value
;
3563 ep
= ltt_event_position_new();
3565 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3567 /* Count the number of events added since the last block end in any
3570 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3572 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3573 LttvTracefileContext
, i
));
3574 ltt_event_position(tfcs
->parent
.e
, ep
);
3575 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3576 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3577 tfcs
->saved_position
= nb_event
;
3581 if(tcs
->nb_event
>= tcs
->save_interval
) {
3582 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3583 LTTV_STATE_SAVED_STATES
);
3584 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3585 value
= lttv_attribute_add(saved_states_tree
,
3586 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3587 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3588 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3589 *(value
.v_time
) = self
->parent
.timestamp
;
3590 lttv_state_save(tcs
, saved_state_tree
);
3592 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3593 self
->parent
.timestamp
.tv_nsec
);
3595 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3601 static gboolean
block_end(void *hook_data
, void *call_data
)
3603 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3605 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3609 LttEventPosition
*ep
;
3611 guint nb_block
, nb_event
;
3613 ep
= ltt_event_position_new();
3614 ltt_event_position(self
->parent
.e
, ep
);
3615 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3616 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3617 self
->saved_position
= 0;
3618 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3625 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3627 LttvTraceset
*traceset
= self
->parent
.ts
;
3629 guint i
, j
, nb_trace
, nb_tracefile
;
3633 LttvTracefileState
*tfs
;
3635 LttvTraceHook hook_start
, hook_end
;
3637 nb_trace
= lttv_traceset_number(traceset
);
3638 for(i
= 0 ; i
< nb_trace
; i
++) {
3639 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3641 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3642 NULL
, NULL
, block_start
, &hook_start
);
3643 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3644 NULL
, NULL
, block_end
, &hook_end
);
3646 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3648 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3650 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3651 LttvTracefileContext
, j
));
3652 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3653 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3654 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3655 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3661 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3663 LttvTraceset
*traceset
= self
->parent
.ts
;
3665 guint i
, j
, nb_trace
, nb_tracefile
;
3669 LttvTracefileState
*tfs
;
3672 nb_trace
= lttv_traceset_number(traceset
);
3673 for(i
= 0 ; i
< nb_trace
; i
++) {
3675 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3676 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3678 if(ts
->has_precomputed_states
) continue;
3680 guint
*event_count
= g_new(guint
, 1);
3683 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3685 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3686 LttvTracefileContext
*, j
));
3687 lttv_hooks_add(tfs
->parent
.event
,
3688 state_save_event_hook
,
3695 lttv_process_traceset_begin(&self
->parent
,
3696 NULL
, NULL
, NULL
, NULL
, NULL
);
3700 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3702 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3704 lttv_state_save_add_event_hooks(tss
);
3711 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3713 LttvTraceset
*traceset
= self
->parent
.ts
;
3715 guint i
, j
, nb_trace
, nb_tracefile
;
3719 LttvTracefileState
*tfs
;
3721 LttvTraceHook hook_start
, hook_end
;
3723 nb_trace
= lttv_traceset_number(traceset
);
3724 for(i
= 0 ; i
< nb_trace
; i
++) {
3725 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3727 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3728 NULL
, NULL
, block_start
, &hook_start
);
3730 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3731 NULL
, NULL
, block_end
, &hook_end
);
3733 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3735 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3737 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3738 LttvTracefileContext
, j
));
3739 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3740 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3741 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3742 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3748 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3750 LttvTraceset
*traceset
= self
->parent
.ts
;
3752 guint i
, j
, nb_trace
, nb_tracefile
;
3756 LttvTracefileState
*tfs
;
3758 LttvHooks
*after_trace
= lttv_hooks_new();
3760 lttv_hooks_add(after_trace
,
3761 state_save_after_trace_hook
,
3766 lttv_process_traceset_end(&self
->parent
,
3767 NULL
, after_trace
, NULL
, NULL
, NULL
);
3769 lttv_hooks_destroy(after_trace
);
3771 nb_trace
= lttv_traceset_number(traceset
);
3772 for(i
= 0 ; i
< nb_trace
; i
++) {
3774 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3775 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3777 if(ts
->has_precomputed_states
) continue;
3779 guint
*event_count
= NULL
;
3781 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3783 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3784 LttvTracefileContext
*, j
));
3785 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3786 state_save_event_hook
);
3788 if(event_count
) g_free(event_count
);
3792 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3794 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3796 lttv_state_save_remove_event_hooks(tss
);
3801 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3803 LttvTraceset
*traceset
= self
->parent
.ts
;
3807 int min_pos
, mid_pos
, max_pos
;
3809 guint call_rest
= 0;
3811 LttvTraceState
*tcs
;
3813 LttvAttributeValue value
;
3815 LttvAttributeType type
;
3817 LttvAttributeName name
;
3821 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3823 //g_tree_destroy(self->parent.pqueue);
3824 //self->parent.pqueue = g_tree_new(compare_tracefile);
3826 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3828 nb_trace
= lttv_traceset_number(traceset
);
3829 for(i
= 0 ; i
< nb_trace
; i
++) {
3830 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3832 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3833 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3834 LTTV_STATE_SAVED_STATES
);
3837 if(saved_states_tree
) {
3838 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3839 mid_pos
= max_pos
/ 2;
3840 while(min_pos
< max_pos
) {
3841 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3843 g_assert(type
== LTTV_GOBJECT
);
3844 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3845 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3847 g_assert(type
== LTTV_TIME
);
3848 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3850 closest_tree
= saved_state_tree
;
3852 else max_pos
= mid_pos
- 1;
3854 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3858 /* restore the closest earlier saved state */
3860 lttv_state_restore(tcs
, closest_tree
);
3864 /* There is no saved state, yet we want to have it. Restart at T0 */
3866 restore_init_state(tcs
);
3867 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3870 /* We want to seek quickly without restoring/updating the state */
3872 restore_init_state(tcs
);
3873 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3876 if(!call_rest
) g_info("NOT Calling restore");
3881 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3887 traceset_state_finalize (LttvTracesetState
*self
)
3889 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3890 finalize(G_OBJECT(self
));
3895 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3897 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3899 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3900 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3901 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3902 klass
->new_traceset_context
= new_traceset_context
;
3903 klass
->new_trace_context
= new_trace_context
;
3904 klass
->new_tracefile_context
= new_tracefile_context
;
3909 lttv_traceset_state_get_type(void)
3911 static GType type
= 0;
3913 static const GTypeInfo info
= {
3914 sizeof (LttvTracesetStateClass
),
3915 NULL
, /* base_init */
3916 NULL
, /* base_finalize */
3917 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3918 NULL
, /* class_finalize */
3919 NULL
, /* class_data */
3920 sizeof (LttvTracesetState
),
3921 0, /* n_preallocs */
3922 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3923 NULL
/* value handling */
3926 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3934 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3940 trace_state_finalize (LttvTraceState
*self
)
3942 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3943 finalize(G_OBJECT(self
));
3948 trace_state_class_init (LttvTraceStateClass
*klass
)
3950 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3952 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3953 klass
->state_save
= state_save
;
3954 klass
->state_restore
= state_restore
;
3955 klass
->state_saved_free
= state_saved_free
;
3960 lttv_trace_state_get_type(void)
3962 static GType type
= 0;
3964 static const GTypeInfo info
= {
3965 sizeof (LttvTraceStateClass
),
3966 NULL
, /* base_init */
3967 NULL
, /* base_finalize */
3968 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3969 NULL
, /* class_finalize */
3970 NULL
, /* class_data */
3971 sizeof (LttvTraceState
),
3972 0, /* n_preallocs */
3973 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3974 NULL
/* value handling */
3977 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3978 "LttvTraceStateType", &info
, 0);
3985 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3991 tracefile_state_finalize (LttvTracefileState
*self
)
3993 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3994 finalize(G_OBJECT(self
));
3999 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
4001 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
4003 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
4008 lttv_tracefile_state_get_type(void)
4010 static GType type
= 0;
4012 static const GTypeInfo info
= {
4013 sizeof (LttvTracefileStateClass
),
4014 NULL
, /* base_init */
4015 NULL
, /* base_finalize */
4016 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
4017 NULL
, /* class_finalize */
4018 NULL
, /* class_data */
4019 sizeof (LttvTracefileState
),
4020 0, /* n_preallocs */
4021 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
4022 NULL
/* value handling */
4025 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
4026 "LttvTracefileStateType", &info
, 0);
4032 static void module_init()
4034 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
4035 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
4036 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
4037 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
4038 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
4039 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
4040 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
4041 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
4042 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4043 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
4044 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
4045 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
4046 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
4047 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
4048 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
4049 LTTV_STATE_RUN
= g_quark_from_string("RUN");
4050 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
4051 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
4052 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
4053 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
4054 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
4055 LTTV_STATE_PROCESS
= g_quark_from_string("process");
4056 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
4057 LTTV_STATE_EVENT
= g_quark_from_string("event");
4058 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
4059 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
4060 LTTV_STATE_TIME
= g_quark_from_string("time");
4061 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
4062 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
4063 LTTV_STATE_TRACE_STATE_USE_COUNT
=
4064 g_quark_from_string("trace_state_use_count");
4067 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
4068 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
4069 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
4070 LTT_FACILITY_FS
= g_quark_from_string("fs");
4071 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
4072 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
4075 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
4076 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
4077 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
4078 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
4079 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
4080 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
4081 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
4082 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
4083 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
4084 LTT_EVENT_FORK
= g_quark_from_string("fork");
4085 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
4086 LTT_EVENT_EXIT
= g_quark_from_string("exit");
4087 LTT_EVENT_FREE
= g_quark_from_string("free");
4088 LTT_EVENT_EXEC
= g_quark_from_string("exec");
4089 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
4090 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
4091 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
4092 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
4095 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
4096 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
4097 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
4098 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
4099 LTT_FIELD_OUT
= g_quark_from_string("out");
4100 LTT_FIELD_IN
= g_quark_from_string("in");
4101 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
4102 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
4103 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
4104 LTT_FIELD_PID
= g_quark_from_string("pid");
4105 LTT_FIELD_TGID
= g_quark_from_string("tgid");
4106 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
4107 LTT_FIELD_NAME
= g_quark_from_string("name");
4108 LTT_FIELD_TYPE
= g_quark_from_string("type");
4109 LTT_FIELD_MODE
= g_quark_from_string("mode");
4110 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
4111 LTT_FIELD_STATUS
= g_quark_from_string("status");
4112 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
4113 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
4116 /****************************************************
4117 * JOV - XenoLTT - 2006-09-27
4118 * New facility XenoLTT
4119 ****************************************************/
4120 LTT_FACILITY_XENOLTT
= g_quark_from_string("xenoltt");
4122 /****************************************************
4123 * New events for facility XenoLTT
4124 ****************************************************/
4125 LTT_EVENT_XENOLTT_THREAD_INIT
= g_quark_from_string("xeno_thread_init");
4126 LTT_EVENT_XENOLTT_THREAD_SET_PERIOD
= g_quark_from_string("xeno_thread_set_period");
4127 LTT_EVENT_XENOLTT_THREAD_WAIT_PERIOD
= g_quark_from_string("xeno_thread_wait_period");
4128 LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD
= g_quark_from_string("xeno_thread_missed_period");
4129 LTT_EVENT_XENOLTT_THREAD_SUSPEND
= g_quark_from_string("xeno_thread_suspend");
4130 LTT_EVENT_XENOLTT_THREAD_START
= g_quark_from_string("xeno_thread_start");
4131 LTT_EVENT_XENOLTT_THREAD_RESUME
= g_quark_from_string("xeno_thread_resume");
4132 LTT_EVENT_XENOLTT_THREAD_DELETE
= g_quark_from_string("xeno_thread_delete"),
4133 LTT_EVENT_XENOLTT_THREAD_UNBLOCK
= g_quark_from_string("xeno_thread_unblock");
4134 LTT_EVENT_XENOLTT_THREAD_RENICE
= g_quark_from_string("xeno_thread_renice");
4135 LTT_EVENT_XENOLTT_TIMER_TICK
= g_quark_from_string("xeno_timer_tick");
4136 LTT_EVENT_XENOLTT_SYNCH_SET_OWNER
= g_quark_from_string("xeno_synch_set_owner");
4137 LTT_EVENT_XENOLTT_SYNCH_UNLOCK
= g_quark_from_string("xeno_synch_unlock");
4138 LTT_EVENT_XENOLTT_SYNCH_WAKEUP1
= g_quark_from_string("xeno_synch_wakeup1");
4139 LTT_EVENT_XENOLTT_SYNCH_WAKEUPX
= g_quark_from_string("xeno_synch_wakeupx");
4140 LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON
= g_quark_from_string("xeno_synch_sleepon");
4141 LTT_EVENT_XENOLTT_SYNCH_FLUSH
= g_quark_from_string("xeno_synch_syncflush");
4142 LTT_EVENT_XENOLTT_SYNCH_FORGET
= g_quark_from_string("xeno_synch_syncforget");
4143 LTT_EVENT_XENOLTT_THREAD_SWITCH
= g_quark_from_string("xeno_thread_switch");
4145 /****************************************************
4146 * New fields for XenoLTT events
4147 ****************************************************/
4148 LTT_FIELD_XENOLTT_NAME
= g_quark_from_string("thread");
4149 LTT_FIELD_XENOLTT_ADDRESS
= g_quark_from_string("address");
4150 LTT_FIELD_XENOLTT_FLAGS
= g_quark_from_string("flags");
4151 LTT_FIELD_XENOLTT_PRIO
= g_quark_from_string("prio");
4152 LTT_FIELD_XENOLTT_PERIOD
= g_quark_from_string("period");
4153 LTT_FIELD_XENOLTT_IDATE
= g_quark_from_string("idate");
4154 LTT_FIELD_XENOLTT_SYNCH
= g_quark_from_string("sync");
4155 LTT_FIELD_XENOLTT_THREAD_ADDRESS
= g_quark_from_string("thread_address");
4156 LTT_FIELD_XENOLTT_TIMER_ADDRESS
= g_quark_from_string("timer_address");
4157 LTT_FIELD_XENOLTT_OVERRUNS
= g_quark_from_string("overruns");
4158 LTT_FIELD_XENOLTT_NAME_OUT
= g_quark_from_string("thread_out");
4159 LTT_FIELD_XENOLTT_ADDRESS_OUT
= g_quark_from_string("address_out");
4161 /****************************************************
4162 * New states for Xenoami Task
4163 ****************************************************/
4164 LTTV_XENO_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
4165 LTTV_XENO_STATE_SUSPEND
= g_quark_from_string("SUSPEND");
4166 LTTV_XENO_STATE_RUN
= g_quark_from_string("RUN");
4167 LTTV_XENO_STATE_DEAD
= g_quark_from_string("DEAD");
4168 LTTV_XENO_STATE_INIT
= g_quark_from_string("INIT"),
4169 LTTV_XENO_STATE_WAIT_PERIOD
= g_quark_from_string("WAIT PERIOD");
4170 LTTV_XENO_STATE_START
= g_quark_from_string("START");
4171 LTTV_XENO_STATE_READY
= g_quark_from_string("READY");
4174 LTTV_XENO_MODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
4175 LTTV_XENO_MODE_NORMAL
= g_quark_from_string("NORMAL");
4176 LTTV_XENO_MODE_OVERRUN
= g_quark_from_string("OVERRUN");
4180 static void module_destroy()
4185 LTTV_MODULE("state", "State computation", \
4186 "Update the system state, possibly saving it at intervals", \
4187 module_init
, module_destroy
)