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>
33 #define PREALLOCATED_EXECUTION_STACK 10
35 /* Facilities Quarks */
39 LTT_FACILITY_KERNEL_ARCH
,
42 LTT_FACILITY_STATEDUMP
;
47 LTT_EVENT_SYSCALL_ENTRY
,
48 LTT_EVENT_SYSCALL_EXIT
,
53 LTT_EVENT_SOFT_IRQ_ENTRY
,
54 LTT_EVENT_SOFT_IRQ_EXIT
,
55 LTT_EVENT_SCHEDCHANGE
,
57 LTT_EVENT_KERNEL_THREAD
,
61 LTT_EVENT_ENUM_PROCESS_STATE
;
69 LTT_FIELD_SOFT_IRQ_ID
,
83 LTTV_STATE_MODE_UNKNOWN
,
91 LTTV_STATE_SUBMODE_UNKNOWN
,
92 LTTV_STATE_SUBMODE_NONE
;
105 LTTV_STATE_TRACEFILES
,
106 LTTV_STATE_PROCESSES
,
108 LTTV_STATE_RUNNING_PROCESS
,
110 LTTV_STATE_SAVED_STATES
,
111 LTTV_STATE_SAVED_STATES_TIME
,
114 LTTV_STATE_NAME_TABLES
,
115 LTTV_STATE_TRACE_STATE_USE_COUNT
;
117 static void create_max_time(LttvTraceState
*tcs
);
119 static void get_max_time(LttvTraceState
*tcs
);
121 static void free_max_time(LttvTraceState
*tcs
);
123 static void create_name_tables(LttvTraceState
*tcs
);
125 static void get_name_tables(LttvTraceState
*tcs
);
127 static void free_name_tables(LttvTraceState
*tcs
);
129 static void free_saved_state(LttvTraceState
*tcs
);
131 static void lttv_state_free_process_table(GHashTable
*processes
);
134 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
136 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
140 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
142 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
146 void lttv_state_state_saved_free(LttvTraceState
*self
,
147 LttvAttribute
*container
)
149 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
153 guint
process_hash(gconstpointer key
)
155 guint pid
= ((const LttvProcessState
*)key
)->pid
;
156 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
160 /* If the hash table hash function is well distributed,
161 * the process_equal should compare different pid */
162 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
164 const LttvProcessState
*process_a
, *process_b
;
167 process_a
= (const LttvProcessState
*)a
;
168 process_b
= (const LttvProcessState
*)b
;
170 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
171 else if(likely(process_a
->pid
== 0 &&
172 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
177 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
179 g_tree_destroy((GTree
*)value
);
182 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
184 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
185 g_hash_table_destroy(usertraces
);
191 restore_init_state(LttvTraceState
*self
)
195 LttvTracefileState
*tfcs
;
197 /* Free the process tables */
198 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
199 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
200 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
201 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
204 /* Seek time to beginning */
205 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
206 // closest. It's the tracecontext job to seek the trace to the beginning
207 // anyway : the init state might be used at the middle of the trace as well...
208 //g_tree_destroy(self->parent.ts_context->pqueue);
209 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
212 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
214 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
216 /* Put the per cpu running_process to beginning state : process 0. */
217 for(i
=0; i
< nb_cpus
; i
++) {
218 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
219 LTTV_STATE_UNNAMED
, <t_time_zero
);
220 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
221 self
->running_process
[i
]->cpu
= i
;
225 nb_tracefile
= self
->parent
.tracefiles
->len
;
227 for(i
= 0 ; i
< nb_tracefile
; i
++) {
229 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
230 LttvTracefileContext
*, i
));
231 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
232 // tfcs->saved_position = 0;
233 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
234 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
235 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
236 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
241 //static LttTime time_zero = {0,0};
243 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
246 const LttTime
*t1
= (const LttTime
*)a
;
247 const LttTime
*t2
= (const LttTime
*)b
;
249 return ltt_time_compare(*t1
, *t2
);
252 static void free_usertrace_key(gpointer data
)
258 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
260 guint i
, j
, nb_trace
, nb_tracefile
;
262 LttvTraceContext
*tc
;
266 LttvTracefileState
*tfcs
;
268 LttvAttributeValue v
;
270 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
271 init((LttvTracesetContext
*)self
, ts
);
273 nb_trace
= lttv_traceset_number(ts
);
274 for(i
= 0 ; i
< nb_trace
; i
++) {
275 tc
= self
->parent
.traces
[i
];
276 tcs
= LTTV_TRACE_STATE(tc
);
277 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
278 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
282 if(*(v
.v_uint
) == 1) {
283 create_name_tables(tcs
);
284 create_max_time(tcs
);
286 get_name_tables(tcs
);
289 nb_tracefile
= tc
->tracefiles
->len
;
290 tcs
->processes
= NULL
;
291 tcs
->usertraces
= NULL
;
292 tcs
->running_process
= g_new(LttvProcessState
*,
293 ltt_trace_get_num_cpu(tc
->t
));
294 restore_init_state(tcs
);
295 for(j
= 0 ; j
< nb_tracefile
; j
++) {
297 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
298 LttvTracefileContext
*, j
));
299 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
300 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
302 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
303 /* It's a Usertrace */
304 LttvProcessState
*process
;
306 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
307 ltt_tracefile_creation(tfcs
->parent
.tf
));
308 process
= lttv_state_find_process_or_create(
310 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
312 process
->usertrace
= tfcs
;
316 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
317 /* It's a Usertrace */
318 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
319 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
321 if(!usertrace_tree
) {
322 usertrace_tree
= g_tree_new_full(compare_usertraces
,
323 NULL
, free_usertrace_key
, NULL
);
324 g_hash_table_insert(tcs
->usertraces
,
325 (gpointer
)tid
, usertrace_tree
);
327 LttTime
*timestamp
= g_new(LttTime
, 1);
328 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
329 ltt_tracefile_creation(tfcs
->parent
.tf
));
330 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
338 fini(LttvTracesetState
*self
)
344 LttvTracefileState
*tfcs
;
346 LttvAttributeValue v
;
348 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
349 for(i
= 0 ; i
< nb_trace
; i
++) {
350 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
351 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
354 g_assert(*(v
.v_uint
) != 0);
357 if(*(v
.v_uint
) == 0) {
358 free_name_tables(tcs
);
360 free_saved_state(tcs
);
362 g_free(tcs
->running_process
);
363 tcs
->running_process
= NULL
;
364 lttv_state_free_process_table(tcs
->processes
);
365 lttv_state_free_usertraces(tcs
->usertraces
);
366 tcs
->processes
= NULL
;
367 tcs
->usertraces
= NULL
;
369 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
370 fini((LttvTracesetContext
*)self
);
374 static LttvTracesetContext
*
375 new_traceset_context(LttvTracesetContext
*self
)
377 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
381 static LttvTraceContext
*
382 new_trace_context(LttvTracesetContext
*self
)
384 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
388 static LttvTracefileContext
*
389 new_tracefile_context(LttvTracesetContext
*self
)
391 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
395 /* Write the process state of the trace */
397 static void write_process_state(gpointer key
, gpointer value
,
400 LttvProcessState
*process
;
402 LttvExecutionState
*es
;
404 FILE *fp
= (FILE *)user_data
;
408 process
= (LttvProcessState
*)value
;
410 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
411 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
412 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
415 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
416 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
417 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
418 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
419 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
420 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
421 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
423 fprintf(fp
, " </PROCESS>\n");
427 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
429 guint i
, nb_tracefile
, nb_block
, offset
;
432 LttvTracefileState
*tfcs
;
436 LttEventPosition
*ep
;
440 ep
= ltt_event_position_new();
442 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
444 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
446 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
447 for(i
=0;i
<nb_cpus
;i
++) {
448 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
449 i
, self
->running_process
[i
]->pid
);
452 nb_tracefile
= self
->parent
.tracefiles
->len
;
454 for(i
= 0 ; i
< nb_tracefile
; i
++) {
456 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
457 LttvTracefileContext
*, i
));
458 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
459 tfcs
->parent
.timestamp
.tv_sec
,
460 tfcs
->parent
.timestamp
.tv_nsec
);
461 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
462 if(e
== NULL
) fprintf(fp
,"/>\n");
464 ltt_event_position(e
, ep
);
465 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
466 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
471 fprintf(fp
,"</PROCESS_STATE>");
475 /* Copy each process from an existing hash table to a new one */
477 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
479 LttvProcessState
*process
, *new_process
;
481 GHashTable
*new_processes
= (GHashTable
*)user_data
;
485 process
= (LttvProcessState
*)value
;
486 new_process
= g_new(LttvProcessState
, 1);
487 *new_process
= *process
;
488 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
489 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
490 new_process
->execution_stack
=
491 g_array_set_size(new_process
->execution_stack
,
492 process
->execution_stack
->len
);
493 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
494 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
495 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
497 new_process
->state
= &g_array_index(new_process
->execution_stack
,
498 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
499 g_hash_table_insert(new_processes
, new_process
, new_process
);
503 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
505 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
507 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
508 return new_processes
;
512 /* The saved state for each trace contains a member "processes", which
513 stores a copy of the process table, and a member "tracefiles" with
514 one entry per tracefile. Each tracefile has a "process" member pointing
515 to the current process and a "position" member storing the tracefile
516 position (needed to seek to the current "next" event. */
518 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
520 guint i
, nb_tracefile
, nb_cpus
;
522 LttvTracefileState
*tfcs
;
524 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
526 guint
*running_process
;
528 LttvAttributeType type
;
530 LttvAttributeValue value
;
532 LttvAttributeName name
;
534 LttEventPosition
*ep
;
536 tracefiles_tree
= lttv_attribute_find_subdir(container
,
537 LTTV_STATE_TRACEFILES
);
539 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
541 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
543 /* Add the currently running processes array */
544 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
545 running_process
= g_new(guint
, nb_cpus
);
546 for(i
=0;i
<nb_cpus
;i
++) {
547 running_process
[i
] = self
->running_process
[i
]->pid
;
549 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
551 *(value
.v_pointer
) = running_process
;
553 g_info("State save");
555 nb_tracefile
= self
->parent
.tracefiles
->len
;
557 for(i
= 0 ; i
< nb_tracefile
; i
++) {
559 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
560 LttvTracefileContext
*, i
));
561 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
562 value
= lttv_attribute_add(tracefiles_tree
, i
,
564 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
566 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
568 *(value
.v_uint
) = tfcs
->process
->pid
;
570 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
572 /* Only save the position if the tfs has not infinite time. */
573 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
574 // && current_tfcs != tfcs) {
575 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
576 *(value
.v_pointer
) = NULL
;
578 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
579 ep
= ltt_event_position_new();
580 ltt_event_position(e
, ep
);
581 *(value
.v_pointer
) = ep
;
583 guint nb_block
, offset
;
586 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
587 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
589 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
595 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
597 guint i
, nb_tracefile
, pid
, nb_cpus
;
599 LttvTracefileState
*tfcs
;
601 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
603 guint
*running_process
;
605 LttvAttributeType type
;
607 LttvAttributeValue value
;
609 LttvAttributeName name
;
611 LttEventPosition
*ep
;
613 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
615 tracefiles_tree
= lttv_attribute_find_subdir(container
,
616 LTTV_STATE_TRACEFILES
);
618 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
620 g_assert(type
== LTTV_POINTER
);
621 lttv_state_free_process_table(self
->processes
);
622 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
624 /* Add the currently running processes array */
625 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
626 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
628 g_assert(type
== LTTV_POINTER
);
629 running_process
= *(value
.v_pointer
);
630 for(i
=0;i
<nb_cpus
;i
++) {
631 pid
= running_process
[i
];
632 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
633 g_assert(self
->running_process
[i
] != NULL
);
637 nb_tracefile
= self
->parent
.tracefiles
->len
;
639 //g_tree_destroy(tsc->pqueue);
640 //tsc->pqueue = g_tree_new(compare_tracefile);
642 for(i
= 0 ; i
< nb_tracefile
; i
++) {
644 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
645 LttvTracefileContext
*, i
));
646 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
647 g_assert(type
== LTTV_GOBJECT
);
648 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
650 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
652 g_assert(type
== LTTV_UINT
);
653 pid
= *(value
.v_uint
);
654 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
656 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
658 g_assert(type
== LTTV_POINTER
);
659 //g_assert(*(value.v_pointer) != NULL);
660 ep
= *(value
.v_pointer
);
661 g_assert(tfcs
->parent
.t_context
!= NULL
);
663 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
664 g_tree_remove(tsc
->pqueue
, tfc
);
667 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
668 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
669 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
670 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
671 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
673 tfc
->timestamp
= ltt_time_infinite
;
679 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
681 guint i
, nb_tracefile
, nb_cpus
;
683 LttvTracefileState
*tfcs
;
685 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
687 guint
*running_process
;
689 LttvAttributeType type
;
691 LttvAttributeValue value
;
693 LttvAttributeName name
;
695 LttEventPosition
*ep
;
697 tracefiles_tree
= lttv_attribute_find_subdir(container
,
698 LTTV_STATE_TRACEFILES
);
699 g_object_ref(G_OBJECT(tracefiles_tree
));
700 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
702 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
704 g_assert(type
== LTTV_POINTER
);
705 lttv_state_free_process_table(*(value
.v_pointer
));
706 *(value
.v_pointer
) = NULL
;
707 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
709 /* Free running processes array */
710 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
711 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
713 g_assert(type
== LTTV_POINTER
);
714 running_process
= *(value
.v_pointer
);
715 g_free(running_process
);
717 nb_tracefile
= self
->parent
.tracefiles
->len
;
719 for(i
= 0 ; i
< nb_tracefile
; i
++) {
721 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
722 LttvTracefileContext
*, i
));
723 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
724 g_assert(type
== LTTV_GOBJECT
);
725 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
727 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
729 g_assert(type
== LTTV_POINTER
);
730 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
732 g_object_unref(G_OBJECT(tracefiles_tree
));
736 static void free_saved_state(LttvTraceState
*self
)
740 LttvAttributeType type
;
742 LttvAttributeValue value
;
744 LttvAttributeName name
;
746 LttvAttribute
*saved_states
;
748 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
749 LTTV_STATE_SAVED_STATES
);
751 nb
= lttv_attribute_get_number(saved_states
);
752 for(i
= 0 ; i
< nb
; i
++) {
753 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
754 g_assert(type
== LTTV_GOBJECT
);
755 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
758 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
763 create_max_time(LttvTraceState
*tcs
)
765 LttvAttributeValue v
;
767 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
769 g_assert(*(v
.v_pointer
) == NULL
);
770 *(v
.v_pointer
) = g_new(LttTime
,1);
771 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
776 get_max_time(LttvTraceState
*tcs
)
778 LttvAttributeValue v
;
780 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
782 g_assert(*(v
.v_pointer
) != NULL
);
783 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
788 free_max_time(LttvTraceState
*tcs
)
790 LttvAttributeValue v
;
792 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
794 g_free(*(v
.v_pointer
));
795 *(v
.v_pointer
) = NULL
;
799 typedef struct _LttvNameTables
{
800 // FIXME GQuark *eventtype_names;
801 GQuark
*syscall_names
;
804 GQuark
*soft_irq_names
;
809 create_name_tables(LttvTraceState
*tcs
)
813 GQuark f_name
, e_name
;
817 LttvTraceHookByFacility
*thf
;
823 GString
*fe_name
= g_string_new("");
825 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
827 LttvAttributeValue v
;
829 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
831 g_assert(*(v
.v_pointer
) == NULL
);
832 *(v
.v_pointer
) = name_tables
;
833 #if 0 // Use iteration over the facilities_by_name and then list all event
834 // types of each facility
835 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
836 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
837 for(i
= 0 ; i
< nb
; i
++) {
838 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
839 e_name
= ltt_eventtype_name(et
);
840 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
841 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
842 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
845 if(lttv_trace_find_hook(tcs
->parent
.t
,
846 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
847 LTT_FIELD_SYSCALL_ID
, 0, 0,
851 thf
= lttv_trace_hook_get_first(&h
);
853 t
= ltt_field_type(thf
->f1
);
854 nb
= ltt_type_element_number(t
);
856 lttv_trace_hook_destroy(&h
);
858 name_tables
->syscall_names
= g_new(GQuark
, nb
);
860 for(i
= 0 ; i
< nb
; i
++) {
861 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
864 //name_tables->syscall_names = g_new(GQuark, 256);
865 //for(i = 0 ; i < 256 ; i++) {
866 // g_string_printf(fe_name, "syscall %d", i);
867 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
870 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
871 LTT_EVENT_TRAP_ENTRY
,
872 LTT_FIELD_TRAP_ID
, 0, 0,
876 thf
= lttv_trace_hook_get_first(&h
);
878 t
= ltt_field_type(thf
->f1
);
879 //nb = ltt_type_element_number(t);
881 lttv_trace_hook_destroy(&h
);
884 name_tables->trap_names = g_new(GQuark, nb);
885 for(i = 0 ; i < nb ; i++) {
886 name_tables->trap_names[i] = g_quark_from_string(
887 ltt_enum_string_get(t, i));
891 name_tables
->trap_names
= g_new(GQuark
, 256);
892 for(i
= 0 ; i
< 256 ; i
++) {
893 g_string_printf(fe_name
, "trap %d", i
);
894 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
897 if(lttv_trace_find_hook(tcs
->parent
.t
,
898 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
899 LTT_FIELD_IRQ_ID
, 0, 0,
903 thf
= lttv_trace_hook_get_first(&h
);
905 t
= ltt_field_type(thf
->f1
);
906 //nb = ltt_type_element_number(t);
908 lttv_trace_hook_destroy(&h
);
911 name_tables->irq_names = g_new(GQuark, nb);
912 for(i = 0 ; i < nb ; i++) {
913 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
917 name_tables
->irq_names
= g_new(GQuark
, 256);
918 for(i
= 0 ; i
< 256 ; i
++) {
919 g_string_printf(fe_name
, "irq %d", i
);
920 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
924 name_tables->soft_irq_names = g_new(GQuark, nb);
925 for(i = 0 ; i < nb ; i++) {
926 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
930 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
931 for(i
= 0 ; i
< 256 ; i
++) {
932 g_string_printf(fe_name
, "softirq %d", i
);
933 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
937 g_string_free(fe_name
, TRUE
);
942 get_name_tables(LttvTraceState
*tcs
)
944 LttvNameTables
*name_tables
;
946 LttvAttributeValue v
;
948 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
950 g_assert(*(v
.v_pointer
) != NULL
);
951 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
952 //tcs->eventtype_names = name_tables->eventtype_names;
953 tcs
->syscall_names
= name_tables
->syscall_names
;
954 tcs
->trap_names
= name_tables
->trap_names
;
955 tcs
->irq_names
= name_tables
->irq_names
;
956 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
961 free_name_tables(LttvTraceState
*tcs
)
963 LttvNameTables
*name_tables
;
965 LttvAttributeValue v
;
967 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
969 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
970 *(v
.v_pointer
) = NULL
;
972 // g_free(name_tables->eventtype_names);
973 g_free(name_tables
->syscall_names
);
974 g_free(name_tables
->trap_names
);
975 g_free(name_tables
->irq_names
);
976 g_free(name_tables
->soft_irq_names
);
980 #ifdef HASH_TABLE_DEBUG
982 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
984 LttvProcessState
*process
= (LttvProcessState
*)value
;
986 /* Test for process corruption */
987 guint stack_len
= process
->execution_stack
->len
;
990 static void hash_table_check(GHashTable
*table
)
992 g_hash_table_foreach(table
, test_process
, NULL
);
999 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1002 LttvExecutionState
*es
;
1004 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1005 guint cpu
= tfs
->cpu
;
1007 #ifdef HASH_TABLE_DEBUG
1008 hash_table_check(ts
->processes
);
1010 LttvProcessState
*process
= ts
->running_process
[cpu
];
1012 guint depth
= process
->execution_stack
->len
;
1014 process
->execution_stack
=
1015 g_array_set_size(process
->execution_stack
, depth
+ 1);
1018 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1020 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1023 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1024 es
->s
= process
->state
->s
;
1025 process
->state
= es
;
1029 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1031 guint cpu
= tfs
->cpu
;
1032 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1033 LttvProcessState
*process
= ts
->running_process
[cpu
];
1035 guint depth
= process
->execution_stack
->len
;
1037 if(process
->state
->t
!= t
){
1038 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1039 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1040 g_info("process state has %s when pop_int is %s\n",
1041 g_quark_to_string(process
->state
->t
),
1042 g_quark_to_string(t
));
1043 g_info("{ %u, %u, %s, %s }\n",
1046 g_quark_to_string(process
->name
),
1047 g_quark_to_string(process
->state
->s
));
1052 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1053 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1057 process
->execution_stack
=
1058 g_array_set_size(process
->execution_stack
, depth
- 1);
1059 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1061 process
->state
->change
= tfs
->parent
.timestamp
;
1064 struct search_result
{
1065 const LttTime
*time
; /* Requested time */
1066 LttTime
*best
; /* Best result */
1069 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1071 const LttTime
*elem_time
= (const LttTime
*)a
;
1072 /* Explicit non const cast */
1073 struct search_result
*res
= (struct search_result
*)b
;
1075 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1076 /* The usertrace was created before the schedchange */
1077 /* Get larger keys */
1079 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1080 /* The usertrace was created after the schedchange time */
1081 /* Get smaller keys */
1083 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1084 res
->best
= elem_time
;
1087 res
->best
= elem_time
;
1093 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1094 guint pid
, const LttTime
*timestamp
)
1096 LttvTracefileState
*tfs
= NULL
;
1097 struct search_result res
;
1098 /* Find the usertrace associated with a pid and time interval.
1099 * Search in the usertraces by PID (within a hash) and then, for each
1100 * corresponding element of the array, find the first one with creation
1101 * timestamp the lowest, but higher or equal to "timestamp". */
1102 res
.time
= timestamp
;
1104 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1105 if(usertrace_tree
) {
1106 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1108 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1116 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1117 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1119 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1121 LttvExecutionState
*es
;
1123 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1129 process
->name
= name
;
1130 //process->last_cpu = tfs->cpu_name;
1131 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1132 process
->kernel_thread
= 0;
1133 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1135 g_info("Process %u, core %p", process
->pid
, process
);
1136 g_hash_table_insert(tcs
->processes
, process
, process
);
1139 process
->ppid
= parent
->pid
;
1140 process
->creation_time
= *timestamp
;
1143 /* No parent. This process exists but we are missing all information about
1144 its creation. The birth time is set to zero but we remember the time of
1149 process
->creation_time
= ltt_time_zero
;
1152 process
->insertion_time
= *timestamp
;
1153 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1154 process
->creation_time
.tv_nsec
);
1155 process
->pid_time
= g_quark_from_string(buffer
);
1157 //process->last_cpu = tfs->cpu_name;
1158 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1159 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1160 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1161 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1162 es
= process
->state
= &g_array_index(process
->execution_stack
,
1163 LttvExecutionState
, 0);
1164 es
->t
= LTTV_STATE_USER_MODE
;
1165 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1166 es
->entry
= *timestamp
;
1167 //g_assert(timestamp->tv_sec != 0);
1168 es
->change
= *timestamp
;
1169 es
->s
= LTTV_STATE_RUN
;
1171 es
= process
->state
= &g_array_index(process
->execution_stack
,
1172 LttvExecutionState
, 1);
1173 es
->t
= LTTV_STATE_SYSCALL
;
1174 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1175 es
->entry
= *timestamp
;
1176 //g_assert(timestamp->tv_sec != 0);
1177 es
->change
= *timestamp
;
1178 es
->s
= LTTV_STATE_WAIT_FORK
;
1183 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1186 LttvProcessState key
;
1187 LttvProcessState
*process
;
1191 process
= g_hash_table_lookup(ts
->processes
, &key
);
1196 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1199 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1200 LttvExecutionState
*es
;
1202 /* Put ltt_time_zero creation time for unexisting processes */
1203 if(unlikely(process
== NULL
)) {
1204 process
= lttv_state_create_process(ts
,
1205 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1206 /* We are not sure is it's a kernel thread or normal thread, put the
1207 * bottom stack state to unknown */
1208 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1209 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1214 /* FIXME : this function should be called when we receive an event telling that
1215 * release_task has been called in the kernel. In happens generally when
1216 * the parent waits for its child terminaison, but may also happen in special
1217 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1218 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1219 * of a killed thread ground, but isn't the leader.
1221 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1223 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1224 LttvProcessState key
;
1226 key
.pid
= process
->pid
;
1227 key
.cpu
= process
->cpu
;
1228 g_hash_table_remove(ts
->processes
, &key
);
1229 g_array_free(process
->execution_stack
, TRUE
);
1234 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1236 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1241 static void lttv_state_free_process_table(GHashTable
*processes
)
1243 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1244 g_hash_table_destroy(processes
);
1248 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1250 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1251 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1252 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1253 LttField
*f
= thf
->f1
;
1255 LttvExecutionSubmode submode
;
1257 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1258 ltt_event_get_unsigned(e
, f
)];
1259 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1264 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1266 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1268 pop_state(s
, LTTV_STATE_SYSCALL
);
1273 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1275 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1276 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1277 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1278 LttField
*f
= thf
->f1
;
1280 LttvExecutionSubmode submode
;
1282 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1283 ltt_event_get_unsigned(e
, f
)];
1284 push_state(s
, LTTV_STATE_TRAP
, submode
);
1289 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1291 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1293 pop_state(s
, LTTV_STATE_TRAP
);
1298 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1300 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1301 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1302 guint8 fac_id
= ltt_event_facility_id(e
);
1303 guint8 ev_id
= ltt_event_eventtype_id(e
);
1304 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1305 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1306 g_assert(thf
->f1
!= NULL
);
1307 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1308 LttField
*f
= thf
->f1
;
1310 LttvExecutionSubmode submode
;
1312 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1313 ltt_event_get_unsigned(e
, f
)];
1315 /* Do something with the info about being in user or system mode when int? */
1316 push_state(s
, LTTV_STATE_IRQ
, submode
);
1321 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1323 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1325 pop_state(s
, LTTV_STATE_IRQ
);
1329 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1331 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1332 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1333 guint8 fac_id
= ltt_event_facility_id(e
);
1334 guint8 ev_id
= ltt_event_eventtype_id(e
);
1335 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1336 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1337 g_assert(thf
->f1
!= NULL
);
1338 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1339 LttField
*f
= thf
->f1
;
1341 LttvExecutionSubmode submode
;
1343 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1344 ltt_event_get_unsigned(e
, f
)];
1346 /* Do something with the info about being in user or system mode when int? */
1347 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1352 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1354 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1356 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1361 static gboolean
schedchange(void *hook_data
, void *call_data
)
1363 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1365 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1366 LttvProcessState
*process
= ts
->running_process
[cpu
];
1367 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1369 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1370 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1371 guint pid_in
, pid_out
;
1374 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1375 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1376 state_out
= ltt_event_get_int(e
, thf
->f3
);
1378 if(likely(process
!= NULL
)) {
1380 /* We could not know but it was not the idle process executing.
1381 This should only happen at the beginning, before the first schedule
1382 event, and when the initial information (current process for each CPU)
1383 is missing. It is not obvious how we could, after the fact, compensate
1384 the wrongly attributed statistics. */
1386 //This test only makes sense once the state is known and if there is no
1387 //missing events. We need to silently ignore schedchange coming after a
1388 //process_free, or it causes glitches. (FIXME)
1389 //if(unlikely(process->pid != pid_out)) {
1390 // g_assert(process->pid == 0);
1393 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1394 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1395 process
->state
->change
= s
->parent
.timestamp
;
1397 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1398 else process
->state
->s
= LTTV_STATE_WAIT
;
1399 process
->state
->change
= s
->parent
.timestamp
;
1403 exit_process(s
, process
); /* EXIT_DEAD */
1404 /* see sched.h for states */
1406 process
= ts
->running_process
[cpu
] =
1407 lttv_state_find_process_or_create(
1408 (LttvTraceState
*)s
->parent
.t_context
,
1410 &s
->parent
.timestamp
);
1411 process
->state
->s
= LTTV_STATE_RUN
;
1413 if(process
->usertrace
)
1414 process
->usertrace
->cpu
= cpu
;
1415 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1416 process
->state
->change
= s
->parent
.timestamp
;
1420 static gboolean
process_fork(void *hook_data
, void *call_data
)
1422 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1423 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1424 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1427 LttvProcessState
*zombie_process
;
1429 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1430 LttvProcessState
*process
= ts
->running_process
[cpu
];
1431 LttvProcessState
*child_process
;
1434 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1437 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1439 /* Mathieu : it seems like the process might have been scheduled in before the
1440 * fork, and, in a rare case, might be the current process. This might happen
1441 * in a SMP case where we don't have enough precision on the clocks.
1443 * Test reenabled after precision fixes on time. (Mathieu) */
1445 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1447 if(unlikely(zombie_process
!= NULL
)) {
1448 /* Reutilisation of PID. Only now we are sure that the old PID
1449 * has been released. FIXME : should know when release_task happens instead.
1451 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1453 for(i
=0; i
< num_cpus
; i
++) {
1454 g_assert(zombie_process
!= ts
->running_process
[i
]);
1457 exit_process(s
, zombie_process
);
1460 g_assert(process
->pid
!= child_pid
);
1461 // FIXME : Add this test in the "known state" section
1462 // g_assert(process->pid == parent_pid);
1463 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1464 if(child_process
== NULL
) {
1465 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1466 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1468 /* The process has already been created : due to time imprecision between
1469 * multiple CPUs : it has been scheduled in before creation. Note that we
1470 * shouldn't have this kind of imprecision.
1472 * Simply put a correct parent.
1474 g_assert(0); /* This is a problematic case : the process has been created
1475 before the fork event */
1476 child_process
->ppid
= process
->pid
;
1478 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1479 child_process
->name
= process
->name
;
1484 /* We stamp a newly created process as kernel_thread */
1485 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1487 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1488 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1489 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1492 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1493 LttvProcessState
*process
;
1494 LttvExecutionState
*es
;
1497 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1499 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1500 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1501 es
->t
= LTTV_STATE_SYSCALL
;
1502 process
->kernel_thread
= 1;
1507 static gboolean
process_exit(void *hook_data
, void *call_data
)
1509 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1510 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1511 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1515 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1516 LttvProcessState
*process
= ts
->running_process
[cpu
];
1518 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1520 // FIXME : Add this test in the "known state" section
1521 // g_assert(process->pid == pid);
1523 if(likely(process
!= NULL
)) {
1524 process
->state
->s
= LTTV_STATE_EXIT
;
1529 static gboolean
process_free(void *hook_data
, void *call_data
)
1531 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1532 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1533 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1534 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1536 LttvProcessState
*process
;
1538 /* PID of the process to release */
1539 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1541 g_assert(release_pid
!= 0);
1543 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1545 if(likely(process
!= NULL
)) {
1546 /* release_task is happening at kernel level : we can now safely release
1547 * the data structure of the process */
1548 //This test is fun, though, as it may happen that
1549 //at time t : CPU 0 : process_free
1550 //at time t+150ns : CPU 1 : schedule out
1551 //Clearly due to time imprecision, we disable it. (Mathieu)
1552 //If this weird case happen, we have no choice but to put the
1553 //Currently running process on the cpu to 0.
1554 //I re-enable it following time precision fixes. (Mathieu)
1555 //Well, in the case where an process is freed by a process on another CPU
1556 //and still scheduled, it happens that this is the schedchange that will
1557 //drop the last reference count. Do not free it here!
1558 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1560 for(i
=0; i
< num_cpus
; i
++) {
1561 //g_assert(process != ts->running_process[i]);
1562 if(process
== ts
->running_process
[i
]) {
1563 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1567 //if(i == num_cpus) /* process is not scheduled */
1568 //exit_process(s, process); // do nothing : wait for the schedchange to
1569 //delete the process.
1576 static gboolean
process_exec(void *hook_data
, void *call_data
)
1578 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1579 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1580 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1581 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1584 LttvProcessState
*process
= ts
->running_process
[cpu
];
1586 /* PID of the process to release */
1587 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1588 //name = ltt_event_get_string(e, thf->f1);
1589 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1591 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1592 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1593 memcpy(null_term_name
, name_begin
, name_len
);
1594 null_term_name
[name_len
] = '\0';
1596 process
->name
= g_quark_from_string(null_term_name
);
1597 g_free(null_term_name
);
1601 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1603 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1604 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1605 //It's slow : optimise later by doing this before reading trace.
1606 LttEventType
*et
= ltt_event_eventtype(e
);
1608 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1613 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1614 LttvProcessState
*process
= ts
->running_process
[cpu
];
1615 LttvProcessState
*parent_process
;
1616 LttField
*f4
, *f5
, *f6
;
1617 GQuark mode
, submode
, status
;
1620 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1623 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1626 command
= ltt_event_get_string(e
, thf
->f3
);
1629 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1630 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1631 ltt_event_get_unsigned(e
, f4
));
1634 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1635 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1636 ltt_event_get_unsigned(e
, f5
));
1639 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1640 status
= ltt_enum_string_get(ltt_field_type(f6
),
1641 ltt_event_get_unsigned(e
, f6
));
1643 /* The process might exist if a process was forked while performing the sate dump. */
1644 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1645 if(process
== NULL
) {
1646 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1647 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1648 pid
, g_quark_from_string(command
),
1649 &s
->parent
.timestamp
);
1651 /* Keep the stack bottom : a running user mode */
1653 /* Disabled because of inconsistencies in the current statedump states. */
1654 if(mode
== LTTV_STATE_USER_MODE
) {
1655 /* Only keep the bottom */
1656 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1658 /* On top of it : */
1659 LttvExecutionState
*es
;
1660 es
= process
->state
= &g_array_index(process
->execution_stack
,
1661 LttvExecutionState
, 1);
1670 LttvExecutionState
*es
;
1671 es
= process
->state
= &g_array_index(process
->execution_stack
,
1672 LttvExecutionState
, 1);
1673 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1674 es
->s
= LTTV_STATE_UNNAMED
;
1675 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1678 /* The process has already been created :
1679 * Probably was forked while dumping the process state or
1680 * was simply scheduled in prior to get the state dump event.
1682 process
->ppid
= parent_pid
;
1683 process
->name
= g_quark_from_string(command
);
1684 /* Don't mess around with the stack, it will eventually become
1685 * ok after the end of state dump. */
1691 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1693 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1695 lttv_state_add_event_hooks(tss
);
1700 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1702 LttvTraceset
*traceset
= self
->parent
.ts
;
1704 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1708 LttvTracefileState
*tfs
;
1712 LttvTraceHookByFacility
*thf
;
1714 LttvTraceHook
*hook
;
1716 LttvAttributeValue val
;
1720 nb_trace
= lttv_traceset_number(traceset
);
1721 for(i
= 0 ; i
< nb_trace
; i
++) {
1722 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1724 /* Find the eventtype id for the following events and register the
1725 associated by id hooks. */
1727 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 15);
1728 hooks
= g_array_set_size(hooks
, 15);
1730 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1731 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1732 LTT_FIELD_SYSCALL_ID
, 0, 0,
1733 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1736 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1737 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1739 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1742 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1743 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1744 LTT_FIELD_TRAP_ID
, 0, 0,
1745 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1748 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1749 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1751 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1754 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1755 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1756 LTT_FIELD_IRQ_ID
, 0, 0,
1757 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1760 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1761 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1763 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1766 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1767 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1768 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1769 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1772 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1773 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1775 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1778 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1779 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1780 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1781 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1784 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1785 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1786 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1787 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1790 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1791 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1792 LTT_FIELD_PID
, 0, 0,
1793 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1796 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1797 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1798 LTT_FIELD_PID
, 0, 0,
1799 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1802 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1803 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1804 LTT_FIELD_PID
, 0, 0,
1805 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1808 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1809 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1810 LTT_FIELD_FILENAME
, 0, 0,
1811 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1814 /* statedump-related hooks */
1815 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1816 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1817 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1818 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 14));
1822 /* Add these hooks to each event_by_id hooks list */
1824 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1826 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1828 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1829 LttvTracefileContext
*, j
));
1831 for(k
= 0 ; k
< hooks
->len
; k
++) {
1832 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1833 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1834 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1836 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1843 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1844 *(val
.v_pointer
) = hooks
;
1848 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1850 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1852 lttv_state_remove_event_hooks(tss
);
1857 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1859 LttvTraceset
*traceset
= self
->parent
.ts
;
1861 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1865 LttvTracefileState
*tfs
;
1869 LttvTraceHook
*hook
;
1871 LttvTraceHookByFacility
*thf
;
1873 LttvAttributeValue val
;
1875 nb_trace
= lttv_traceset_number(traceset
);
1876 for(i
= 0 ; i
< nb_trace
; i
++) {
1877 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1878 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1879 hooks
= *(val
.v_pointer
);
1881 /* Remove these hooks from each event_by_id hooks list */
1883 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1885 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1887 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1888 LttvTracefileContext
*, j
));
1890 for(k
= 0 ; k
< hooks
->len
; k
++) {
1891 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1892 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1893 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1895 lttv_hooks_remove_data(
1896 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1902 for(k
= 0 ; k
< hooks
->len
; k
++)
1903 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1904 g_array_free(hooks
, TRUE
);
1908 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1910 guint
*event_count
= (guint
*)hook_data
;
1912 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1913 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1918 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1920 LttvTracefileState
*tfcs
;
1922 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1924 LttEventPosition
*ep
;
1930 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1932 LttvAttributeValue value
;
1934 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1935 LTTV_STATE_SAVED_STATES
);
1936 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1937 value
= lttv_attribute_add(saved_states_tree
,
1938 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1939 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1940 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1941 *(value
.v_time
) = self
->parent
.timestamp
;
1942 lttv_state_save(tcs
, saved_state_tree
);
1943 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1944 self
->parent
.timestamp
.tv_nsec
);
1946 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1951 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1953 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1955 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1960 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
1968 static gboolean
block_start(void *hook_data
, void *call_data
)
1970 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1972 LttvTracefileState
*tfcs
;
1974 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1976 LttEventPosition
*ep
;
1978 guint i
, nb_block
, nb_event
, nb_tracefile
;
1982 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1984 LttvAttributeValue value
;
1986 ep
= ltt_event_position_new();
1988 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1990 /* Count the number of events added since the last block end in any
1993 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1995 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1996 LttvTracefileContext
, i
));
1997 ltt_event_position(tfcs
->parent
.e
, ep
);
1998 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1999 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2000 tfcs
->saved_position
= nb_event
;
2004 if(tcs
->nb_event
>= tcs
->save_interval
) {
2005 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2006 LTTV_STATE_SAVED_STATES
);
2007 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2008 value
= lttv_attribute_add(saved_states_tree
,
2009 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2010 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2011 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2012 *(value
.v_time
) = self
->parent
.timestamp
;
2013 lttv_state_save(tcs
, saved_state_tree
);
2015 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2016 self
->parent
.timestamp
.tv_nsec
);
2018 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2024 static gboolean
block_end(void *hook_data
, void *call_data
)
2026 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2028 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2032 LttEventPosition
*ep
;
2034 guint nb_block
, nb_event
;
2036 ep
= ltt_event_position_new();
2037 ltt_event_position(self
->parent
.e
, ep
);
2038 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2039 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2040 self
->saved_position
= 0;
2041 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2048 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2050 LttvTraceset
*traceset
= self
->parent
.ts
;
2052 guint i
, j
, nb_trace
, nb_tracefile
;
2056 LttvTracefileState
*tfs
;
2058 LttvTraceHook hook_start
, hook_end
;
2060 nb_trace
= lttv_traceset_number(traceset
);
2061 for(i
= 0 ; i
< nb_trace
; i
++) {
2062 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2064 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2065 NULL
, NULL
, block_start
, &hook_start
);
2066 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2067 NULL
, NULL
, block_end
, &hook_end
);
2069 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2071 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2073 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2074 LttvTracefileContext
, j
));
2075 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2076 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2077 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2078 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2084 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2086 LttvTraceset
*traceset
= self
->parent
.ts
;
2088 guint i
, j
, nb_trace
, nb_tracefile
;
2092 LttvTracefileState
*tfs
;
2095 nb_trace
= lttv_traceset_number(traceset
);
2096 for(i
= 0 ; i
< nb_trace
; i
++) {
2098 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2099 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2101 guint
*event_count
= g_new(guint
, 1);
2104 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2106 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2107 LttvTracefileContext
*, j
));
2108 lttv_hooks_add(tfs
->parent
.event
,
2109 state_save_event_hook
,
2116 lttv_process_traceset_begin(&self
->parent
,
2117 NULL
, NULL
, NULL
, NULL
, NULL
);
2121 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2123 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2125 lttv_state_save_add_event_hooks(tss
);
2132 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2134 LttvTraceset
*traceset
= self
->parent
.ts
;
2136 guint i
, j
, nb_trace
, nb_tracefile
;
2140 LttvTracefileState
*tfs
;
2142 LttvTraceHook hook_start
, hook_end
;
2144 nb_trace
= lttv_traceset_number(traceset
);
2145 for(i
= 0 ; i
< nb_trace
; i
++) {
2146 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2148 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2149 NULL
, NULL
, block_start
, &hook_start
);
2151 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2152 NULL
, NULL
, block_end
, &hook_end
);
2154 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2156 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2158 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2159 LttvTracefileContext
, j
));
2160 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2161 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2162 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2163 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2169 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2171 LttvTraceset
*traceset
= self
->parent
.ts
;
2173 guint i
, j
, nb_trace
, nb_tracefile
;
2177 LttvTracefileState
*tfs
;
2179 LttvHooks
*after_trace
= lttv_hooks_new();
2181 lttv_hooks_add(after_trace
,
2182 state_save_after_trace_hook
,
2187 lttv_process_traceset_end(&self
->parent
,
2188 NULL
, after_trace
, NULL
, NULL
, NULL
);
2190 lttv_hooks_destroy(after_trace
);
2192 nb_trace
= lttv_traceset_number(traceset
);
2193 for(i
= 0 ; i
< nb_trace
; i
++) {
2195 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2196 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2198 guint
*event_count
= NULL
;
2200 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2202 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2203 LttvTracefileContext
*, j
));
2204 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2205 state_save_event_hook
);
2207 if(event_count
) g_free(event_count
);
2211 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2213 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2215 lttv_state_save_remove_event_hooks(tss
);
2220 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2222 LttvTraceset
*traceset
= self
->parent
.ts
;
2226 int min_pos
, mid_pos
, max_pos
;
2228 guint call_rest
= 0;
2230 LttvTraceState
*tcs
;
2232 LttvAttributeValue value
;
2234 LttvAttributeType type
;
2236 LttvAttributeName name
;
2238 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2240 //g_tree_destroy(self->parent.pqueue);
2241 //self->parent.pqueue = g_tree_new(compare_tracefile);
2243 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2245 nb_trace
= lttv_traceset_number(traceset
);
2246 for(i
= 0 ; i
< nb_trace
; i
++) {
2247 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2249 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2250 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2251 LTTV_STATE_SAVED_STATES
);
2254 if(saved_states_tree
) {
2255 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2256 mid_pos
= max_pos
/ 2;
2257 while(min_pos
< max_pos
) {
2258 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2259 g_assert(type
== LTTV_GOBJECT
);
2260 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2261 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2263 g_assert(type
== LTTV_TIME
);
2264 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2266 closest_tree
= saved_state_tree
;
2268 else max_pos
= mid_pos
- 1;
2270 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2274 /* restore the closest earlier saved state */
2276 lttv_state_restore(tcs
, closest_tree
);
2280 /* There is no saved state, yet we want to have it. Restart at T0 */
2282 restore_init_state(tcs
);
2283 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2286 /* We want to seek quickly without restoring/updating the state */
2288 restore_init_state(tcs
);
2289 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2292 if(!call_rest
) g_info("NOT Calling restore");
2297 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2303 traceset_state_finalize (LttvTracesetState
*self
)
2305 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2306 finalize(G_OBJECT(self
));
2311 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2313 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2315 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2316 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2317 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2318 klass
->new_traceset_context
= new_traceset_context
;
2319 klass
->new_trace_context
= new_trace_context
;
2320 klass
->new_tracefile_context
= new_tracefile_context
;
2325 lttv_traceset_state_get_type(void)
2327 static GType type
= 0;
2329 static const GTypeInfo info
= {
2330 sizeof (LttvTracesetStateClass
),
2331 NULL
, /* base_init */
2332 NULL
, /* base_finalize */
2333 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2334 NULL
, /* class_finalize */
2335 NULL
, /* class_data */
2336 sizeof (LttvTracesetState
),
2337 0, /* n_preallocs */
2338 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2339 NULL
/* value handling */
2342 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2350 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2356 trace_state_finalize (LttvTraceState
*self
)
2358 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2359 finalize(G_OBJECT(self
));
2364 trace_state_class_init (LttvTraceStateClass
*klass
)
2366 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2368 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2369 klass
->state_save
= state_save
;
2370 klass
->state_restore
= state_restore
;
2371 klass
->state_saved_free
= state_saved_free
;
2376 lttv_trace_state_get_type(void)
2378 static GType type
= 0;
2380 static const GTypeInfo info
= {
2381 sizeof (LttvTraceStateClass
),
2382 NULL
, /* base_init */
2383 NULL
, /* base_finalize */
2384 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2385 NULL
, /* class_finalize */
2386 NULL
, /* class_data */
2387 sizeof (LttvTraceState
),
2388 0, /* n_preallocs */
2389 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2390 NULL
/* value handling */
2393 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2394 "LttvTraceStateType", &info
, 0);
2401 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2407 tracefile_state_finalize (LttvTracefileState
*self
)
2409 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2410 finalize(G_OBJECT(self
));
2415 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2417 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2419 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2424 lttv_tracefile_state_get_type(void)
2426 static GType type
= 0;
2428 static const GTypeInfo info
= {
2429 sizeof (LttvTracefileStateClass
),
2430 NULL
, /* base_init */
2431 NULL
, /* base_finalize */
2432 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2433 NULL
, /* class_finalize */
2434 NULL
, /* class_data */
2435 sizeof (LttvTracefileState
),
2436 0, /* n_preallocs */
2437 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2438 NULL
/* value handling */
2441 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2442 "LttvTracefileStateType", &info
, 0);
2448 static void module_init()
2450 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2451 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2452 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2453 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2454 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2455 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2456 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2457 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2458 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2459 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2460 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2461 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2462 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2463 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2464 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2465 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2466 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2467 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2468 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2469 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2470 LTTV_STATE_EVENT
= g_quark_from_string("event");
2471 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2472 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2473 LTTV_STATE_TIME
= g_quark_from_string("time");
2474 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2475 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2476 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2477 g_quark_from_string("trace_state_use_count");
2480 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2481 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2482 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2483 LTT_FACILITY_FS
= g_quark_from_string("fs");
2484 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2487 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2488 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2489 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2490 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2491 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2492 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2493 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2494 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2495 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2496 LTT_EVENT_FORK
= g_quark_from_string("fork");
2497 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2498 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2499 LTT_EVENT_FREE
= g_quark_from_string("free");
2500 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2501 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2504 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2505 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2506 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2507 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2508 LTT_FIELD_OUT
= g_quark_from_string("out");
2509 LTT_FIELD_IN
= g_quark_from_string("in");
2510 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2511 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2512 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2513 LTT_FIELD_PID
= g_quark_from_string("pid");
2514 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2515 LTT_FIELD_NAME
= g_quark_from_string("name");
2516 LTT_FIELD_MODE
= g_quark_from_string("mode");
2517 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2518 LTT_FIELD_STATUS
= g_quark_from_string("status");
2522 static void module_destroy()
2527 LTTV_MODULE("state", "State computation", \
2528 "Update the system state, possibly saving it at intervals", \
2529 module_init
, module_destroy
)