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
;
805 GQuark
*soft_irq_names
;
810 create_name_tables(LttvTraceState
*tcs
)
814 GQuark f_name
, e_name
;
818 LttvTraceHookByFacility
*thf
;
824 GString
*fe_name
= g_string_new("");
826 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
828 LttvAttributeValue v
;
830 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
832 g_assert(*(v
.v_pointer
) == NULL
);
833 *(v
.v_pointer
) = name_tables
;
834 #if 0 // Use iteration over the facilities_by_name and then list all event
835 // types of each facility
836 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
837 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
838 for(i
= 0 ; i
< nb
; i
++) {
839 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
840 e_name
= ltt_eventtype_name(et
);
841 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
842 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
843 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
846 if(lttv_trace_find_hook(tcs
->parent
.t
,
847 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
848 LTT_FIELD_SYSCALL_ID
, 0, 0,
852 thf
= lttv_trace_hook_get_first(&h
);
854 t
= ltt_field_type(thf
->f1
);
855 nb
= ltt_type_element_number(t
);
857 lttv_trace_hook_destroy(&h
);
859 name_tables
->syscall_names
= g_new(GQuark
, nb
);
860 name_tables
->nb_syscalls
= nb
;
862 for(i
= 0 ; i
< nb
; i
++) {
863 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
866 //name_tables->syscall_names = g_new(GQuark, 256);
867 //for(i = 0 ; i < 256 ; i++) {
868 // g_string_printf(fe_name, "syscall %d", i);
869 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
872 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
873 LTT_EVENT_TRAP_ENTRY
,
874 LTT_FIELD_TRAP_ID
, 0, 0,
878 thf
= lttv_trace_hook_get_first(&h
);
880 t
= ltt_field_type(thf
->f1
);
881 //nb = ltt_type_element_number(t);
883 lttv_trace_hook_destroy(&h
);
886 name_tables->trap_names = g_new(GQuark, nb);
887 for(i = 0 ; i < nb ; i++) {
888 name_tables->trap_names[i] = g_quark_from_string(
889 ltt_enum_string_get(t, i));
893 name_tables
->trap_names
= g_new(GQuark
, 256);
894 for(i
= 0 ; i
< 256 ; i
++) {
895 g_string_printf(fe_name
, "trap %d", i
);
896 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
899 if(lttv_trace_find_hook(tcs
->parent
.t
,
900 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
901 LTT_FIELD_IRQ_ID
, 0, 0,
905 thf
= lttv_trace_hook_get_first(&h
);
907 t
= ltt_field_type(thf
->f1
);
908 //nb = ltt_type_element_number(t);
910 lttv_trace_hook_destroy(&h
);
913 name_tables->irq_names = g_new(GQuark, nb);
914 for(i = 0 ; i < nb ; i++) {
915 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
919 name_tables
->irq_names
= g_new(GQuark
, 256);
920 for(i
= 0 ; i
< 256 ; i
++) {
921 g_string_printf(fe_name
, "irq %d", i
);
922 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
926 name_tables->soft_irq_names = g_new(GQuark, nb);
927 for(i = 0 ; i < nb ; i++) {
928 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
932 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
933 for(i
= 0 ; i
< 256 ; i
++) {
934 g_string_printf(fe_name
, "softirq %d", i
);
935 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
939 g_string_free(fe_name
, TRUE
);
944 get_name_tables(LttvTraceState
*tcs
)
946 LttvNameTables
*name_tables
;
948 LttvAttributeValue v
;
950 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
952 g_assert(*(v
.v_pointer
) != NULL
);
953 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
954 //tcs->eventtype_names = name_tables->eventtype_names;
955 tcs
->syscall_names
= name_tables
->syscall_names
;
956 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
957 tcs
->trap_names
= name_tables
->trap_names
;
958 tcs
->irq_names
= name_tables
->irq_names
;
959 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
964 free_name_tables(LttvTraceState
*tcs
)
966 LttvNameTables
*name_tables
;
968 LttvAttributeValue v
;
970 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
972 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
973 *(v
.v_pointer
) = NULL
;
975 // g_free(name_tables->eventtype_names);
976 g_free(name_tables
->syscall_names
);
977 g_free(name_tables
->trap_names
);
978 g_free(name_tables
->irq_names
);
979 g_free(name_tables
->soft_irq_names
);
983 #ifdef HASH_TABLE_DEBUG
985 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
987 LttvProcessState
*process
= (LttvProcessState
*)value
;
989 /* Test for process corruption */
990 guint stack_len
= process
->execution_stack
->len
;
993 static void hash_table_check(GHashTable
*table
)
995 g_hash_table_foreach(table
, test_process
, NULL
);
1002 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1005 LttvExecutionState
*es
;
1007 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1008 guint cpu
= tfs
->cpu
;
1010 #ifdef HASH_TABLE_DEBUG
1011 hash_table_check(ts
->processes
);
1013 LttvProcessState
*process
= ts
->running_process
[cpu
];
1015 guint depth
= process
->execution_stack
->len
;
1017 process
->execution_stack
=
1018 g_array_set_size(process
->execution_stack
, depth
+ 1);
1021 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1023 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1026 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1027 es
->s
= process
->state
->s
;
1028 process
->state
= es
;
1032 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1034 guint cpu
= tfs
->cpu
;
1035 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1036 LttvProcessState
*process
= ts
->running_process
[cpu
];
1038 guint depth
= process
->execution_stack
->len
;
1040 if(process
->state
->t
!= t
){
1041 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1042 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1043 g_info("process state has %s when pop_int is %s\n",
1044 g_quark_to_string(process
->state
->t
),
1045 g_quark_to_string(t
));
1046 g_info("{ %u, %u, %s, %s }\n",
1049 g_quark_to_string(process
->name
),
1050 g_quark_to_string(process
->state
->s
));
1055 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1056 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1060 process
->execution_stack
=
1061 g_array_set_size(process
->execution_stack
, depth
- 1);
1062 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1064 process
->state
->change
= tfs
->parent
.timestamp
;
1067 struct search_result
{
1068 const LttTime
*time
; /* Requested time */
1069 LttTime
*best
; /* Best result */
1072 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1074 const LttTime
*elem_time
= (const LttTime
*)a
;
1075 /* Explicit non const cast */
1076 struct search_result
*res
= (struct search_result
*)b
;
1078 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1079 /* The usertrace was created before the schedchange */
1080 /* Get larger keys */
1082 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1083 /* The usertrace was created after the schedchange time */
1084 /* Get smaller keys */
1086 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1087 res
->best
= elem_time
;
1090 res
->best
= elem_time
;
1096 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1097 guint pid
, const LttTime
*timestamp
)
1099 LttvTracefileState
*tfs
= NULL
;
1100 struct search_result res
;
1101 /* Find the usertrace associated with a pid and time interval.
1102 * Search in the usertraces by PID (within a hash) and then, for each
1103 * corresponding element of the array, find the first one with creation
1104 * timestamp the lowest, but higher or equal to "timestamp". */
1105 res
.time
= timestamp
;
1107 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1108 if(usertrace_tree
) {
1109 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1111 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1119 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1120 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1122 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1124 LttvExecutionState
*es
;
1126 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1132 process
->name
= name
;
1133 //process->last_cpu = tfs->cpu_name;
1134 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1135 process
->kernel_thread
= 0;
1136 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1138 g_info("Process %u, core %p", process
->pid
, process
);
1139 g_hash_table_insert(tcs
->processes
, process
, process
);
1142 process
->ppid
= parent
->pid
;
1143 process
->creation_time
= *timestamp
;
1146 /* No parent. This process exists but we are missing all information about
1147 its creation. The birth time is set to zero but we remember the time of
1152 process
->creation_time
= ltt_time_zero
;
1155 process
->insertion_time
= *timestamp
;
1156 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1157 process
->creation_time
.tv_nsec
);
1158 process
->pid_time
= g_quark_from_string(buffer
);
1160 //process->last_cpu = tfs->cpu_name;
1161 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1162 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1163 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1164 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1165 es
= process
->state
= &g_array_index(process
->execution_stack
,
1166 LttvExecutionState
, 0);
1167 es
->t
= LTTV_STATE_USER_MODE
;
1168 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1169 es
->entry
= *timestamp
;
1170 //g_assert(timestamp->tv_sec != 0);
1171 es
->change
= *timestamp
;
1172 es
->s
= LTTV_STATE_RUN
;
1174 es
= process
->state
= &g_array_index(process
->execution_stack
,
1175 LttvExecutionState
, 1);
1176 es
->t
= LTTV_STATE_SYSCALL
;
1177 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1178 es
->entry
= *timestamp
;
1179 //g_assert(timestamp->tv_sec != 0);
1180 es
->change
= *timestamp
;
1181 es
->s
= LTTV_STATE_WAIT_FORK
;
1186 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1189 LttvProcessState key
;
1190 LttvProcessState
*process
;
1194 process
= g_hash_table_lookup(ts
->processes
, &key
);
1199 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1202 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1203 LttvExecutionState
*es
;
1205 /* Put ltt_time_zero creation time for unexisting processes */
1206 if(unlikely(process
== NULL
)) {
1207 process
= lttv_state_create_process(ts
,
1208 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1209 /* We are not sure is it's a kernel thread or normal thread, put the
1210 * bottom stack state to unknown */
1211 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1212 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1217 /* FIXME : this function should be called when we receive an event telling that
1218 * release_task has been called in the kernel. In happens generally when
1219 * the parent waits for its child terminaison, but may also happen in special
1220 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1221 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1222 * of a killed thread ground, but isn't the leader.
1224 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1226 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1227 LttvProcessState key
;
1229 key
.pid
= process
->pid
;
1230 key
.cpu
= process
->cpu
;
1231 g_hash_table_remove(ts
->processes
, &key
);
1232 g_array_free(process
->execution_stack
, TRUE
);
1237 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1239 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1244 static void lttv_state_free_process_table(GHashTable
*processes
)
1246 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1247 g_hash_table_destroy(processes
);
1251 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1253 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1254 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1255 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1256 LttField
*f
= thf
->f1
;
1258 LttvExecutionSubmode submode
;
1260 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1261 guint syscall
= ltt_event_get_unsigned(e
, f
);
1263 if(syscall
< nb_syscalls
) {
1264 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1267 /* Fixup an incomplete syscall table */
1268 GString
*string
= g_string_new("");
1269 g_string_printf(string
, "syscall %u", syscall
);
1270 submode
= g_quark_from_string(string
->str
);
1271 g_string_free(string
, TRUE
);
1273 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1278 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1280 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1282 pop_state(s
, LTTV_STATE_SYSCALL
);
1287 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1289 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1290 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1291 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1292 LttField
*f
= thf
->f1
;
1294 LttvExecutionSubmode submode
;
1296 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1297 ltt_event_get_unsigned(e
, f
)];
1298 push_state(s
, LTTV_STATE_TRAP
, submode
);
1303 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1305 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1307 pop_state(s
, LTTV_STATE_TRAP
);
1312 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1314 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1315 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1316 guint8 fac_id
= ltt_event_facility_id(e
);
1317 guint8 ev_id
= ltt_event_eventtype_id(e
);
1318 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1319 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1320 g_assert(thf
->f1
!= NULL
);
1321 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1322 LttField
*f
= thf
->f1
;
1324 LttvExecutionSubmode submode
;
1326 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1327 ltt_event_get_unsigned(e
, f
)];
1329 /* Do something with the info about being in user or system mode when int? */
1330 push_state(s
, LTTV_STATE_IRQ
, submode
);
1335 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1337 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1339 pop_state(s
, LTTV_STATE_IRQ
);
1343 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1345 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1346 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1347 guint8 fac_id
= ltt_event_facility_id(e
);
1348 guint8 ev_id
= ltt_event_eventtype_id(e
);
1349 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1350 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1351 g_assert(thf
->f1
!= NULL
);
1352 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1353 LttField
*f
= thf
->f1
;
1355 LttvExecutionSubmode submode
;
1357 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1358 ltt_event_get_unsigned(e
, f
)];
1360 /* Do something with the info about being in user or system mode when int? */
1361 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1366 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1368 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1370 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1375 static gboolean
schedchange(void *hook_data
, void *call_data
)
1377 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1379 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1380 LttvProcessState
*process
= ts
->running_process
[cpu
];
1381 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1383 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1384 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1385 guint pid_in
, pid_out
;
1388 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1389 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1390 state_out
= ltt_event_get_int(e
, thf
->f3
);
1392 if(likely(process
!= NULL
)) {
1394 /* We could not know but it was not the idle process executing.
1395 This should only happen at the beginning, before the first schedule
1396 event, and when the initial information (current process for each CPU)
1397 is missing. It is not obvious how we could, after the fact, compensate
1398 the wrongly attributed statistics. */
1400 //This test only makes sense once the state is known and if there is no
1401 //missing events. We need to silently ignore schedchange coming after a
1402 //process_free, or it causes glitches. (FIXME)
1403 //if(unlikely(process->pid != pid_out)) {
1404 // g_assert(process->pid == 0);
1407 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1408 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1409 process
->state
->change
= s
->parent
.timestamp
;
1411 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1412 else process
->state
->s
= LTTV_STATE_WAIT
;
1413 process
->state
->change
= s
->parent
.timestamp
;
1417 exit_process(s
, process
); /* EXIT_DEAD */
1418 /* see sched.h for states */
1420 process
= ts
->running_process
[cpu
] =
1421 lttv_state_find_process_or_create(
1422 (LttvTraceState
*)s
->parent
.t_context
,
1424 &s
->parent
.timestamp
);
1425 process
->state
->s
= LTTV_STATE_RUN
;
1427 if(process
->usertrace
)
1428 process
->usertrace
->cpu
= cpu
;
1429 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1430 process
->state
->change
= s
->parent
.timestamp
;
1434 static gboolean
process_fork(void *hook_data
, void *call_data
)
1436 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1437 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1438 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1441 LttvProcessState
*zombie_process
;
1443 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1444 LttvProcessState
*process
= ts
->running_process
[cpu
];
1445 LttvProcessState
*child_process
;
1448 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1451 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1453 /* Mathieu : it seems like the process might have been scheduled in before the
1454 * fork, and, in a rare case, might be the current process. This might happen
1455 * in a SMP case where we don't have enough precision on the clocks.
1457 * Test reenabled after precision fixes on time. (Mathieu) */
1459 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1461 if(unlikely(zombie_process
!= NULL
)) {
1462 /* Reutilisation of PID. Only now we are sure that the old PID
1463 * has been released. FIXME : should know when release_task happens instead.
1465 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1467 for(i
=0; i
< num_cpus
; i
++) {
1468 g_assert(zombie_process
!= ts
->running_process
[i
]);
1471 exit_process(s
, zombie_process
);
1474 g_assert(process
->pid
!= child_pid
);
1475 // FIXME : Add this test in the "known state" section
1476 // g_assert(process->pid == parent_pid);
1477 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1478 if(child_process
== NULL
) {
1479 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1480 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1482 /* The process has already been created : due to time imprecision between
1483 * multiple CPUs : it has been scheduled in before creation. Note that we
1484 * shouldn't have this kind of imprecision.
1486 * Simply put a correct parent.
1488 g_assert(0); /* This is a problematic case : the process has been created
1489 before the fork event */
1490 child_process
->ppid
= process
->pid
;
1492 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1493 child_process
->name
= process
->name
;
1498 /* We stamp a newly created process as kernel_thread */
1499 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1501 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1502 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1503 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1506 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1507 LttvProcessState
*process
;
1508 LttvExecutionState
*es
;
1511 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1513 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1514 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1515 es
->t
= LTTV_STATE_SYSCALL
;
1516 process
->kernel_thread
= 1;
1521 static gboolean
process_exit(void *hook_data
, void *call_data
)
1523 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1524 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1525 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1529 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1530 LttvProcessState
*process
= ts
->running_process
[cpu
];
1532 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1534 // FIXME : Add this test in the "known state" section
1535 // g_assert(process->pid == pid);
1537 if(likely(process
!= NULL
)) {
1538 process
->state
->s
= LTTV_STATE_EXIT
;
1543 static gboolean
process_free(void *hook_data
, void *call_data
)
1545 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1546 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1547 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1548 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1550 LttvProcessState
*process
;
1552 /* PID of the process to release */
1553 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1555 g_assert(release_pid
!= 0);
1557 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1559 if(likely(process
!= NULL
)) {
1560 /* release_task is happening at kernel level : we can now safely release
1561 * the data structure of the process */
1562 //This test is fun, though, as it may happen that
1563 //at time t : CPU 0 : process_free
1564 //at time t+150ns : CPU 1 : schedule out
1565 //Clearly due to time imprecision, we disable it. (Mathieu)
1566 //If this weird case happen, we have no choice but to put the
1567 //Currently running process on the cpu to 0.
1568 //I re-enable it following time precision fixes. (Mathieu)
1569 //Well, in the case where an process is freed by a process on another CPU
1570 //and still scheduled, it happens that this is the schedchange that will
1571 //drop the last reference count. Do not free it here!
1572 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1574 for(i
=0; i
< num_cpus
; i
++) {
1575 //g_assert(process != ts->running_process[i]);
1576 if(process
== ts
->running_process
[i
]) {
1577 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1581 //if(i == num_cpus) /* process is not scheduled */
1582 //exit_process(s, process); // do nothing : wait for the schedchange to
1583 //delete the process.
1590 static gboolean
process_exec(void *hook_data
, void *call_data
)
1592 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1593 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1594 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1595 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1598 LttvProcessState
*process
= ts
->running_process
[cpu
];
1600 /* PID of the process to release */
1601 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1602 //name = ltt_event_get_string(e, thf->f1);
1603 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1605 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1606 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1607 memcpy(null_term_name
, name_begin
, name_len
);
1608 null_term_name
[name_len
] = '\0';
1610 process
->name
= g_quark_from_string(null_term_name
);
1611 g_free(null_term_name
);
1615 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1617 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1618 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1619 //It's slow : optimise later by doing this before reading trace.
1620 LttEventType
*et
= ltt_event_eventtype(e
);
1622 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1627 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1628 LttvProcessState
*process
= ts
->running_process
[cpu
];
1629 LttvProcessState
*parent_process
;
1630 LttField
*f4
, *f5
, *f6
;
1631 GQuark mode
, submode
, status
;
1634 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1637 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1640 command
= ltt_event_get_string(e
, thf
->f3
);
1643 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1644 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1645 ltt_event_get_unsigned(e
, f4
));
1648 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1649 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1650 ltt_event_get_unsigned(e
, f5
));
1653 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1654 status
= ltt_enum_string_get(ltt_field_type(f6
),
1655 ltt_event_get_unsigned(e
, f6
));
1657 /* The process might exist if a process was forked while performing the sate dump. */
1658 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1659 if(process
== NULL
) {
1660 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1661 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1662 pid
, g_quark_from_string(command
),
1663 &s
->parent
.timestamp
);
1665 /* Keep the stack bottom : a running user mode */
1667 /* Disabled because of inconsistencies in the current statedump states. */
1668 if(mode
== LTTV_STATE_USER_MODE
) {
1669 /* Only keep the bottom */
1670 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1672 /* On top of it : */
1673 LttvExecutionState
*es
;
1674 es
= process
->state
= &g_array_index(process
->execution_stack
,
1675 LttvExecutionState
, 1);
1684 LttvExecutionState
*es
;
1685 es
= process
->state
= &g_array_index(process
->execution_stack
,
1686 LttvExecutionState
, 1);
1687 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1688 es
->s
= LTTV_STATE_UNNAMED
;
1689 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1692 /* The process has already been created :
1693 * Probably was forked while dumping the process state or
1694 * was simply scheduled in prior to get the state dump event.
1696 process
->ppid
= parent_pid
;
1697 process
->name
= g_quark_from_string(command
);
1698 /* Don't mess around with the stack, it will eventually become
1699 * ok after the end of state dump. */
1705 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1707 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1709 lttv_state_add_event_hooks(tss
);
1714 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1716 LttvTraceset
*traceset
= self
->parent
.ts
;
1718 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1722 LttvTracefileState
*tfs
;
1726 LttvTraceHookByFacility
*thf
;
1728 LttvTraceHook
*hook
;
1730 LttvAttributeValue val
;
1734 nb_trace
= lttv_traceset_number(traceset
);
1735 for(i
= 0 ; i
< nb_trace
; i
++) {
1736 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1738 /* Find the eventtype id for the following events and register the
1739 associated by id hooks. */
1741 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 15);
1742 hooks
= g_array_set_size(hooks
, 15);
1744 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1745 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1746 LTT_FIELD_SYSCALL_ID
, 0, 0,
1747 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1750 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1751 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1753 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1756 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1757 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1758 LTT_FIELD_TRAP_ID
, 0, 0,
1759 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1762 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1763 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1765 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1768 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1769 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1770 LTT_FIELD_IRQ_ID
, 0, 0,
1771 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1774 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1775 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1777 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1780 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1781 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1782 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1783 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1786 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1787 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1789 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1792 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1793 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1794 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1795 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1798 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1799 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1800 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1801 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1804 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1805 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1806 LTT_FIELD_PID
, 0, 0,
1807 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1810 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1811 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1812 LTT_FIELD_PID
, 0, 0,
1813 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1816 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1817 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1818 LTT_FIELD_PID
, 0, 0,
1819 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1822 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1823 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1824 LTT_FIELD_FILENAME
, 0, 0,
1825 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1828 /* statedump-related hooks */
1829 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1830 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1831 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1832 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 14));
1836 /* Add these hooks to each event_by_id hooks list */
1838 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1840 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1842 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1843 LttvTracefileContext
*, j
));
1845 for(k
= 0 ; k
< hooks
->len
; k
++) {
1846 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1847 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1848 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1850 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1857 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1858 *(val
.v_pointer
) = hooks
;
1862 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1864 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1866 lttv_state_remove_event_hooks(tss
);
1871 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1873 LttvTraceset
*traceset
= self
->parent
.ts
;
1875 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1879 LttvTracefileState
*tfs
;
1883 LttvTraceHook
*hook
;
1885 LttvTraceHookByFacility
*thf
;
1887 LttvAttributeValue val
;
1889 nb_trace
= lttv_traceset_number(traceset
);
1890 for(i
= 0 ; i
< nb_trace
; i
++) {
1891 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1892 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1893 hooks
= *(val
.v_pointer
);
1895 /* Remove these hooks from each event_by_id hooks list */
1897 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1899 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1901 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1902 LttvTracefileContext
*, j
));
1904 for(k
= 0 ; k
< hooks
->len
; k
++) {
1905 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1906 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1907 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1909 lttv_hooks_remove_data(
1910 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1916 for(k
= 0 ; k
< hooks
->len
; k
++)
1917 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1918 g_array_free(hooks
, TRUE
);
1922 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1924 guint
*event_count
= (guint
*)hook_data
;
1926 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1927 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1932 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1934 LttvTracefileState
*tfcs
;
1936 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1938 LttEventPosition
*ep
;
1944 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1946 LttvAttributeValue value
;
1948 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1949 LTTV_STATE_SAVED_STATES
);
1950 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1951 value
= lttv_attribute_add(saved_states_tree
,
1952 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1953 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1954 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1955 *(value
.v_time
) = self
->parent
.timestamp
;
1956 lttv_state_save(tcs
, saved_state_tree
);
1957 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1958 self
->parent
.timestamp
.tv_nsec
);
1960 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1965 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1967 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1969 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1974 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
1982 static gboolean
block_start(void *hook_data
, void *call_data
)
1984 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1986 LttvTracefileState
*tfcs
;
1988 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1990 LttEventPosition
*ep
;
1992 guint i
, nb_block
, nb_event
, nb_tracefile
;
1996 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1998 LttvAttributeValue value
;
2000 ep
= ltt_event_position_new();
2002 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2004 /* Count the number of events added since the last block end in any
2007 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2009 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2010 LttvTracefileContext
, i
));
2011 ltt_event_position(tfcs
->parent
.e
, ep
);
2012 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2013 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2014 tfcs
->saved_position
= nb_event
;
2018 if(tcs
->nb_event
>= tcs
->save_interval
) {
2019 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2020 LTTV_STATE_SAVED_STATES
);
2021 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2022 value
= lttv_attribute_add(saved_states_tree
,
2023 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2024 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2025 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2026 *(value
.v_time
) = self
->parent
.timestamp
;
2027 lttv_state_save(tcs
, saved_state_tree
);
2029 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2030 self
->parent
.timestamp
.tv_nsec
);
2032 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2038 static gboolean
block_end(void *hook_data
, void *call_data
)
2040 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2042 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2046 LttEventPosition
*ep
;
2048 guint nb_block
, nb_event
;
2050 ep
= ltt_event_position_new();
2051 ltt_event_position(self
->parent
.e
, ep
);
2052 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2053 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2054 self
->saved_position
= 0;
2055 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2062 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2064 LttvTraceset
*traceset
= self
->parent
.ts
;
2066 guint i
, j
, nb_trace
, nb_tracefile
;
2070 LttvTracefileState
*tfs
;
2072 LttvTraceHook hook_start
, hook_end
;
2074 nb_trace
= lttv_traceset_number(traceset
);
2075 for(i
= 0 ; i
< nb_trace
; i
++) {
2076 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2078 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2079 NULL
, NULL
, block_start
, &hook_start
);
2080 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2081 NULL
, NULL
, block_end
, &hook_end
);
2083 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2085 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2087 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2088 LttvTracefileContext
, j
));
2089 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2090 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2091 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2092 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2098 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2100 LttvTraceset
*traceset
= self
->parent
.ts
;
2102 guint i
, j
, nb_trace
, nb_tracefile
;
2106 LttvTracefileState
*tfs
;
2109 nb_trace
= lttv_traceset_number(traceset
);
2110 for(i
= 0 ; i
< nb_trace
; i
++) {
2112 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2113 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2115 guint
*event_count
= g_new(guint
, 1);
2118 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2120 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2121 LttvTracefileContext
*, j
));
2122 lttv_hooks_add(tfs
->parent
.event
,
2123 state_save_event_hook
,
2130 lttv_process_traceset_begin(&self
->parent
,
2131 NULL
, NULL
, NULL
, NULL
, NULL
);
2135 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2137 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2139 lttv_state_save_add_event_hooks(tss
);
2146 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2148 LttvTraceset
*traceset
= self
->parent
.ts
;
2150 guint i
, j
, nb_trace
, nb_tracefile
;
2154 LttvTracefileState
*tfs
;
2156 LttvTraceHook hook_start
, hook_end
;
2158 nb_trace
= lttv_traceset_number(traceset
);
2159 for(i
= 0 ; i
< nb_trace
; i
++) {
2160 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2162 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2163 NULL
, NULL
, block_start
, &hook_start
);
2165 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2166 NULL
, NULL
, block_end
, &hook_end
);
2168 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2170 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2172 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2173 LttvTracefileContext
, j
));
2174 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2175 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2176 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2177 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2183 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2185 LttvTraceset
*traceset
= self
->parent
.ts
;
2187 guint i
, j
, nb_trace
, nb_tracefile
;
2191 LttvTracefileState
*tfs
;
2193 LttvHooks
*after_trace
= lttv_hooks_new();
2195 lttv_hooks_add(after_trace
,
2196 state_save_after_trace_hook
,
2201 lttv_process_traceset_end(&self
->parent
,
2202 NULL
, after_trace
, NULL
, NULL
, NULL
);
2204 lttv_hooks_destroy(after_trace
);
2206 nb_trace
= lttv_traceset_number(traceset
);
2207 for(i
= 0 ; i
< nb_trace
; i
++) {
2209 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2210 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2212 guint
*event_count
= NULL
;
2214 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2216 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2217 LttvTracefileContext
*, j
));
2218 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2219 state_save_event_hook
);
2221 if(event_count
) g_free(event_count
);
2225 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2227 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2229 lttv_state_save_remove_event_hooks(tss
);
2234 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2236 LttvTraceset
*traceset
= self
->parent
.ts
;
2240 int min_pos
, mid_pos
, max_pos
;
2242 guint call_rest
= 0;
2244 LttvTraceState
*tcs
;
2246 LttvAttributeValue value
;
2248 LttvAttributeType type
;
2250 LttvAttributeName name
;
2252 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2254 //g_tree_destroy(self->parent.pqueue);
2255 //self->parent.pqueue = g_tree_new(compare_tracefile);
2257 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2259 nb_trace
= lttv_traceset_number(traceset
);
2260 for(i
= 0 ; i
< nb_trace
; i
++) {
2261 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2263 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2264 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2265 LTTV_STATE_SAVED_STATES
);
2268 if(saved_states_tree
) {
2269 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2270 mid_pos
= max_pos
/ 2;
2271 while(min_pos
< max_pos
) {
2272 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2273 g_assert(type
== LTTV_GOBJECT
);
2274 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2275 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2277 g_assert(type
== LTTV_TIME
);
2278 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2280 closest_tree
= saved_state_tree
;
2282 else max_pos
= mid_pos
- 1;
2284 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2288 /* restore the closest earlier saved state */
2290 lttv_state_restore(tcs
, closest_tree
);
2294 /* There is no saved state, yet we want to have it. Restart at T0 */
2296 restore_init_state(tcs
);
2297 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2300 /* We want to seek quickly without restoring/updating the state */
2302 restore_init_state(tcs
);
2303 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2306 if(!call_rest
) g_info("NOT Calling restore");
2311 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2317 traceset_state_finalize (LttvTracesetState
*self
)
2319 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2320 finalize(G_OBJECT(self
));
2325 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2327 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2329 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2330 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2331 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2332 klass
->new_traceset_context
= new_traceset_context
;
2333 klass
->new_trace_context
= new_trace_context
;
2334 klass
->new_tracefile_context
= new_tracefile_context
;
2339 lttv_traceset_state_get_type(void)
2341 static GType type
= 0;
2343 static const GTypeInfo info
= {
2344 sizeof (LttvTracesetStateClass
),
2345 NULL
, /* base_init */
2346 NULL
, /* base_finalize */
2347 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2348 NULL
, /* class_finalize */
2349 NULL
, /* class_data */
2350 sizeof (LttvTracesetState
),
2351 0, /* n_preallocs */
2352 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2353 NULL
/* value handling */
2356 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2364 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2370 trace_state_finalize (LttvTraceState
*self
)
2372 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2373 finalize(G_OBJECT(self
));
2378 trace_state_class_init (LttvTraceStateClass
*klass
)
2380 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2382 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2383 klass
->state_save
= state_save
;
2384 klass
->state_restore
= state_restore
;
2385 klass
->state_saved_free
= state_saved_free
;
2390 lttv_trace_state_get_type(void)
2392 static GType type
= 0;
2394 static const GTypeInfo info
= {
2395 sizeof (LttvTraceStateClass
),
2396 NULL
, /* base_init */
2397 NULL
, /* base_finalize */
2398 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2399 NULL
, /* class_finalize */
2400 NULL
, /* class_data */
2401 sizeof (LttvTraceState
),
2402 0, /* n_preallocs */
2403 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2404 NULL
/* value handling */
2407 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2408 "LttvTraceStateType", &info
, 0);
2415 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2421 tracefile_state_finalize (LttvTracefileState
*self
)
2423 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2424 finalize(G_OBJECT(self
));
2429 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2431 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2433 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2438 lttv_tracefile_state_get_type(void)
2440 static GType type
= 0;
2442 static const GTypeInfo info
= {
2443 sizeof (LttvTracefileStateClass
),
2444 NULL
, /* base_init */
2445 NULL
, /* base_finalize */
2446 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2447 NULL
, /* class_finalize */
2448 NULL
, /* class_data */
2449 sizeof (LttvTracefileState
),
2450 0, /* n_preallocs */
2451 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2452 NULL
/* value handling */
2455 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2456 "LttvTracefileStateType", &info
, 0);
2462 static void module_init()
2464 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2465 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2466 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2467 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2468 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2469 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2470 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2471 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2472 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2473 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2474 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2475 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2476 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2477 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2478 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2479 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2480 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2481 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2482 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2483 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2484 LTTV_STATE_EVENT
= g_quark_from_string("event");
2485 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2486 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2487 LTTV_STATE_TIME
= g_quark_from_string("time");
2488 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2489 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2490 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2491 g_quark_from_string("trace_state_use_count");
2494 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2495 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2496 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2497 LTT_FACILITY_FS
= g_quark_from_string("fs");
2498 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2501 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2502 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2503 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2504 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2505 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2506 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2507 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2508 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2509 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2510 LTT_EVENT_FORK
= g_quark_from_string("fork");
2511 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2512 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2513 LTT_EVENT_FREE
= g_quark_from_string("free");
2514 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2515 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2518 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2519 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2520 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2521 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2522 LTT_FIELD_OUT
= g_quark_from_string("out");
2523 LTT_FIELD_IN
= g_quark_from_string("in");
2524 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2525 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2526 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2527 LTT_FIELD_PID
= g_quark_from_string("pid");
2528 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2529 LTT_FIELD_NAME
= g_quark_from_string("name");
2530 LTT_FIELD_MODE
= g_quark_from_string("mode");
2531 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2532 LTT_FIELD_STATUS
= g_quark_from_string("status");
2536 static void module_destroy()
2541 LTTV_MODULE("state", "State computation", \
2542 "Update the system state, possibly saving it at intervals", \
2543 module_init
, module_destroy
)