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
,
60 LTT_EVENT_ENUM_PROCESS_STATE
;
68 LTT_FIELD_SOFT_IRQ_ID
,
82 LTTV_STATE_MODE_UNKNOWN
,
90 LTTV_STATE_SUBMODE_UNKNOWN
,
91 LTTV_STATE_SUBMODE_NONE
;
104 LTTV_STATE_TRACEFILES
,
105 LTTV_STATE_PROCESSES
,
107 LTTV_STATE_RUNNING_PROCESS
,
109 LTTV_STATE_SAVED_STATES
,
110 LTTV_STATE_SAVED_STATES_TIME
,
113 LTTV_STATE_NAME_TABLES
,
114 LTTV_STATE_TRACE_STATE_USE_COUNT
;
116 static void create_max_time(LttvTraceState
*tcs
);
118 static void get_max_time(LttvTraceState
*tcs
);
120 static void free_max_time(LttvTraceState
*tcs
);
122 static void create_name_tables(LttvTraceState
*tcs
);
124 static void get_name_tables(LttvTraceState
*tcs
);
126 static void free_name_tables(LttvTraceState
*tcs
);
128 static void free_saved_state(LttvTraceState
*tcs
);
130 static void lttv_state_free_process_table(GHashTable
*processes
);
133 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
135 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
139 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
141 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
145 void lttv_state_state_saved_free(LttvTraceState
*self
,
146 LttvAttribute
*container
)
148 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
152 guint
process_hash(gconstpointer key
)
154 guint pid
= ((const LttvProcessState
*)key
)->pid
;
155 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
159 /* If the hash table hash function is well distributed,
160 * the process_equal should compare different pid */
161 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
163 const LttvProcessState
*process_a
, *process_b
;
166 process_a
= (const LttvProcessState
*)a
;
167 process_b
= (const LttvProcessState
*)b
;
169 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
170 else if(likely(process_a
->pid
== 0 &&
171 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
178 restore_init_state(LttvTraceState
*self
)
182 LttvTracefileState
*tfcs
;
184 /* Free the process tables */
185 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
186 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
189 /* Seek time to beginning */
190 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
191 // closest. It's the tracecontext job to seek the trace to the beginning
192 // anyway : the init state might be used at the middle of the trace as well...
193 //g_tree_destroy(self->parent.ts_context->pqueue);
194 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
197 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
199 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
201 /* Put the per cpu running_process to beginning state : process 0. */
202 for(i
=0; i
< nb_cpus
; i
++) {
203 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
204 LTTV_STATE_UNNAMED
, <t_time_zero
);
205 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
206 self
->running_process
[i
]->cpu
= i
;
210 nb_tracefile
= self
->parent
.tracefiles
->len
;
212 for(i
= 0 ; i
< nb_tracefile
; i
++) {
214 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
215 LttvTracefileContext
*, i
));
216 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
217 // tfcs->saved_position = 0;
218 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
219 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
220 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
221 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
226 //static LttTime time_zero = {0,0};
229 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
231 guint i
, j
, nb_trace
, nb_tracefile
;
233 LttvTraceContext
*tc
;
237 LttvTracefileState
*tfcs
;
239 LttvAttributeValue v
;
241 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
242 init((LttvTracesetContext
*)self
, ts
);
244 nb_trace
= lttv_traceset_number(ts
);
245 for(i
= 0 ; i
< nb_trace
; i
++) {
246 tc
= self
->parent
.traces
[i
];
247 tcs
= LTTV_TRACE_STATE(tc
);
248 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
249 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
253 if(*(v
.v_uint
) == 1) {
254 create_name_tables(tcs
);
255 create_max_time(tcs
);
257 get_name_tables(tcs
);
260 nb_tracefile
= tc
->tracefiles
->len
;
262 for(j
= 0 ; j
< nb_tracefile
; j
++) {
264 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
265 LttvTracefileContext
*, j
));
266 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
269 tcs
->processes
= NULL
;
270 tcs
->running_process
= g_new(LttvProcessState
*,
271 ltt_trace_get_num_cpu(tc
->t
));
272 restore_init_state(tcs
);
278 fini(LttvTracesetState
*self
)
284 LttvTracefileState
*tfcs
;
286 LttvAttributeValue v
;
288 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
289 for(i
= 0 ; i
< nb_trace
; i
++) {
290 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
291 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
294 g_assert(*(v
.v_uint
) != 0);
297 if(*(v
.v_uint
) == 0) {
298 free_name_tables(tcs
);
300 free_saved_state(tcs
);
302 g_free(tcs
->running_process
);
303 tcs
->running_process
= NULL
;
304 lttv_state_free_process_table(tcs
->processes
);
305 tcs
->processes
= NULL
;
307 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
308 fini((LttvTracesetContext
*)self
);
312 static LttvTracesetContext
*
313 new_traceset_context(LttvTracesetContext
*self
)
315 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
319 static LttvTraceContext
*
320 new_trace_context(LttvTracesetContext
*self
)
322 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
326 static LttvTracefileContext
*
327 new_tracefile_context(LttvTracesetContext
*self
)
329 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
333 /* Write the process state of the trace */
335 static void write_process_state(gpointer key
, gpointer value
,
338 LttvProcessState
*process
;
340 LttvExecutionState
*es
;
342 FILE *fp
= (FILE *)user_data
;
346 process
= (LttvProcessState
*)value
;
348 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
349 process
, process
->pid
, process
->ppid
, process
->creation_time
.tv_sec
,
350 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
353 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
354 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
355 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
356 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
357 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
358 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
359 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
361 fprintf(fp
, " </PROCESS>\n");
365 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
367 guint i
, nb_tracefile
, nb_block
, offset
;
370 LttvTracefileState
*tfcs
;
374 LttEventPosition
*ep
;
378 ep
= ltt_event_position_new();
380 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
382 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
384 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
385 for(i
=0;i
<nb_cpus
;i
++) {
386 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
387 i
, self
->running_process
[i
]->pid
);
390 nb_tracefile
= self
->parent
.tracefiles
->len
;
392 for(i
= 0 ; i
< nb_tracefile
; i
++) {
394 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
395 LttvTracefileContext
*, i
));
396 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
397 tfcs
->parent
.timestamp
.tv_sec
,
398 tfcs
->parent
.timestamp
.tv_nsec
);
399 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
400 if(e
== NULL
) fprintf(fp
,"/>\n");
402 ltt_event_position(e
, ep
);
403 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
404 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
409 fprintf(fp
,"</PROCESS_STATE>");
413 /* Copy each process from an existing hash table to a new one */
415 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
417 LttvProcessState
*process
, *new_process
;
419 GHashTable
*new_processes
= (GHashTable
*)user_data
;
423 process
= (LttvProcessState
*)value
;
424 new_process
= g_new(LttvProcessState
, 1);
425 *new_process
= *process
;
426 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
427 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
428 new_process
->execution_stack
=
429 g_array_set_size(new_process
->execution_stack
,
430 process
->execution_stack
->len
);
431 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
432 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
433 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
435 new_process
->state
= &g_array_index(new_process
->execution_stack
,
436 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
437 g_hash_table_insert(new_processes
, new_process
, new_process
);
441 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
443 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
445 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
446 return new_processes
;
450 /* The saved state for each trace contains a member "processes", which
451 stores a copy of the process table, and a member "tracefiles" with
452 one entry per tracefile. Each tracefile has a "process" member pointing
453 to the current process and a "position" member storing the tracefile
454 position (needed to seek to the current "next" event. */
456 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
458 guint i
, nb_tracefile
, nb_cpus
;
460 LttvTracefileState
*tfcs
;
462 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
464 guint
*running_process
;
466 LttvAttributeType type
;
468 LttvAttributeValue value
;
470 LttvAttributeName name
;
472 LttEventPosition
*ep
;
474 tracefiles_tree
= lttv_attribute_find_subdir(container
,
475 LTTV_STATE_TRACEFILES
);
477 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
479 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
481 /* Add the currently running processes array */
482 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
483 running_process
= g_new(guint
, nb_cpus
);
484 for(i
=0;i
<nb_cpus
;i
++) {
485 running_process
[i
] = self
->running_process
[i
]->pid
;
487 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
489 *(value
.v_pointer
) = running_process
;
491 g_info("State save");
493 nb_tracefile
= self
->parent
.tracefiles
->len
;
495 for(i
= 0 ; i
< nb_tracefile
; i
++) {
497 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
498 LttvTracefileContext
*, i
));
499 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
500 value
= lttv_attribute_add(tracefiles_tree
, i
,
502 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
504 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
506 *(value
.v_uint
) = tfcs
->process
->pid
;
508 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
510 /* Only save the position if the tfs has not infinite time. */
511 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
512 // && current_tfcs != tfcs) {
513 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
514 *(value
.v_pointer
) = NULL
;
516 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
517 ep
= ltt_event_position_new();
518 ltt_event_position(e
, ep
);
519 *(value
.v_pointer
) = ep
;
521 guint nb_block
, offset
;
524 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
525 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
527 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
533 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
535 guint i
, nb_tracefile
, pid
, nb_cpus
;
537 LttvTracefileState
*tfcs
;
539 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
541 guint
*running_process
;
543 LttvAttributeType type
;
545 LttvAttributeValue value
;
547 LttvAttributeName name
;
549 LttEventPosition
*ep
;
551 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
553 tracefiles_tree
= lttv_attribute_find_subdir(container
,
554 LTTV_STATE_TRACEFILES
);
556 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
558 g_assert(type
== LTTV_POINTER
);
559 lttv_state_free_process_table(self
->processes
);
560 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
562 /* Add the currently running processes array */
563 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
564 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
566 g_assert(type
== LTTV_POINTER
);
567 running_process
= *(value
.v_pointer
);
568 for(i
=0;i
<nb_cpus
;i
++) {
569 pid
= running_process
[i
];
570 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
571 g_assert(self
->running_process
[i
] != NULL
);
575 nb_tracefile
= self
->parent
.tracefiles
->len
;
577 //g_tree_destroy(tsc->pqueue);
578 //tsc->pqueue = g_tree_new(compare_tracefile);
580 for(i
= 0 ; i
< nb_tracefile
; i
++) {
582 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
583 LttvTracefileContext
*, i
));
584 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
585 g_assert(type
== LTTV_GOBJECT
);
586 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
588 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
590 g_assert(type
== LTTV_UINT
);
591 pid
= *(value
.v_uint
);
592 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
594 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
596 g_assert(type
== LTTV_POINTER
);
597 //g_assert(*(value.v_pointer) != NULL);
598 ep
= *(value
.v_pointer
);
599 g_assert(tfcs
->parent
.t_context
!= NULL
);
601 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
602 g_tree_remove(tsc
->pqueue
, tfc
);
605 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
606 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
607 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
608 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
609 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
611 tfc
->timestamp
= ltt_time_infinite
;
617 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
619 guint i
, nb_tracefile
, nb_cpus
;
621 LttvTracefileState
*tfcs
;
623 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
625 guint
*running_process
;
627 LttvAttributeType type
;
629 LttvAttributeValue value
;
631 LttvAttributeName name
;
633 LttEventPosition
*ep
;
635 tracefiles_tree
= lttv_attribute_find_subdir(container
,
636 LTTV_STATE_TRACEFILES
);
637 g_object_ref(G_OBJECT(tracefiles_tree
));
638 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
640 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
642 g_assert(type
== LTTV_POINTER
);
643 lttv_state_free_process_table(*(value
.v_pointer
));
644 *(value
.v_pointer
) = NULL
;
645 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
647 /* Free running processes array */
648 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
649 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
651 g_assert(type
== LTTV_POINTER
);
652 running_process
= *(value
.v_pointer
);
653 g_free(running_process
);
655 nb_tracefile
= self
->parent
.tracefiles
->len
;
657 for(i
= 0 ; i
< nb_tracefile
; i
++) {
659 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
660 LttvTracefileContext
*, i
));
661 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
);
662 g_assert(type
== LTTV_GOBJECT
);
663 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
665 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
667 g_assert(type
== LTTV_POINTER
);
668 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
670 g_object_unref(G_OBJECT(tracefiles_tree
));
674 static void free_saved_state(LttvTraceState
*self
)
678 LttvAttributeType type
;
680 LttvAttributeValue value
;
682 LttvAttributeName name
;
684 LttvAttribute
*saved_states
;
686 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
687 LTTV_STATE_SAVED_STATES
);
689 nb
= lttv_attribute_get_number(saved_states
);
690 for(i
= 0 ; i
< nb
; i
++) {
691 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
);
692 g_assert(type
== LTTV_GOBJECT
);
693 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
696 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
701 create_max_time(LttvTraceState
*tcs
)
703 LttvAttributeValue v
;
705 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
707 g_assert(*(v
.v_pointer
) == NULL
);
708 *(v
.v_pointer
) = g_new(LttTime
,1);
709 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
714 get_max_time(LttvTraceState
*tcs
)
716 LttvAttributeValue v
;
718 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
720 g_assert(*(v
.v_pointer
) != NULL
);
721 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
726 free_max_time(LttvTraceState
*tcs
)
728 LttvAttributeValue v
;
730 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
732 g_free(*(v
.v_pointer
));
733 *(v
.v_pointer
) = NULL
;
737 typedef struct _LttvNameTables
{
738 // FIXME GQuark *eventtype_names;
739 GQuark
*syscall_names
;
742 GQuark
*soft_irq_names
;
747 create_name_tables(LttvTraceState
*tcs
)
751 GQuark f_name
, e_name
;
755 LttvTraceHookByFacility
*thf
;
761 GString
*fe_name
= g_string_new("");
763 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
765 LttvAttributeValue v
;
767 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
769 g_assert(*(v
.v_pointer
) == NULL
);
770 *(v
.v_pointer
) = name_tables
;
771 #if 0 // Use iteration over the facilities_by_name and then list all event
772 // types of each facility
773 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
774 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
775 for(i
= 0 ; i
< nb
; i
++) {
776 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
777 e_name
= ltt_eventtype_name(et
);
778 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
779 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
780 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
783 if(lttv_trace_find_hook(tcs
->parent
.t
,
784 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
785 LTT_FIELD_SYSCALL_ID
, 0, 0,
789 thf
= lttv_trace_hook_get_first(&h
);
791 t
= ltt_field_type(thf
->f1
);
792 nb
= ltt_type_element_number(t
);
794 lttv_trace_hook_destroy(&h
);
796 name_tables
->syscall_names
= g_new(GQuark
, nb
);
798 for(i
= 0 ; i
< nb
; i
++) {
799 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
802 //name_tables->syscall_names = g_new(GQuark, 256);
803 //for(i = 0 ; i < 256 ; i++) {
804 // g_string_printf(fe_name, "syscall %d", i);
805 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
808 if(lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
809 LTT_EVENT_TRAP_ENTRY
,
810 LTT_FIELD_TRAP_ID
, 0, 0,
814 thf
= lttv_trace_hook_get_first(&h
);
816 t
= ltt_field_type(thf
->f1
);
817 //nb = ltt_type_element_number(t);
819 lttv_trace_hook_destroy(&h
);
822 name_tables->trap_names = g_new(GQuark, nb);
823 for(i = 0 ; i < nb ; i++) {
824 name_tables->trap_names[i] = g_quark_from_string(
825 ltt_enum_string_get(t, i));
829 name_tables
->trap_names
= g_new(GQuark
, 256);
830 for(i
= 0 ; i
< 256 ; i
++) {
831 g_string_printf(fe_name
, "trap %d", i
);
832 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
835 if(lttv_trace_find_hook(tcs
->parent
.t
,
836 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
837 LTT_FIELD_IRQ_ID
, 0, 0,
841 thf
= lttv_trace_hook_get_first(&h
);
843 t
= ltt_field_type(thf
->f1
);
844 //nb = ltt_type_element_number(t);
846 lttv_trace_hook_destroy(&h
);
849 name_tables->irq_names = g_new(GQuark, nb);
850 for(i = 0 ; i < nb ; i++) {
851 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
855 name_tables
->irq_names
= g_new(GQuark
, 256);
856 for(i
= 0 ; i
< 256 ; i
++) {
857 g_string_printf(fe_name
, "irq %d", i
);
858 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
862 name_tables->soft_irq_names = g_new(GQuark, nb);
863 for(i = 0 ; i < nb ; i++) {
864 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
868 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
869 for(i
= 0 ; i
< 256 ; i
++) {
870 g_string_printf(fe_name
, "softirq %d", i
);
871 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
875 g_string_free(fe_name
, TRUE
);
880 get_name_tables(LttvTraceState
*tcs
)
882 LttvNameTables
*name_tables
;
884 LttvAttributeValue v
;
886 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
888 g_assert(*(v
.v_pointer
) != NULL
);
889 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
890 //tcs->eventtype_names = name_tables->eventtype_names;
891 tcs
->syscall_names
= name_tables
->syscall_names
;
892 tcs
->trap_names
= name_tables
->trap_names
;
893 tcs
->irq_names
= name_tables
->irq_names
;
894 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
899 free_name_tables(LttvTraceState
*tcs
)
901 LttvNameTables
*name_tables
;
903 LttvAttributeValue v
;
905 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
907 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
908 *(v
.v_pointer
) = NULL
;
910 // g_free(name_tables->eventtype_names);
911 g_free(name_tables
->syscall_names
);
912 g_free(name_tables
->trap_names
);
913 g_free(name_tables
->irq_names
);
914 g_free(name_tables
->soft_irq_names
);
918 #ifdef HASH_TABLE_DEBUG
920 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
922 LttvProcessState
*process
= (LttvProcessState
*)value
;
924 /* Test for process corruption */
925 guint stack_len
= process
->execution_stack
->len
;
928 static void hash_table_check(GHashTable
*table
)
930 g_hash_table_foreach(table
, test_process
, NULL
);
937 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
940 LttvExecutionState
*es
;
942 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
943 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
945 #ifdef HASH_TABLE_DEBUG
946 hash_table_check(ts
->processes
);
948 LttvProcessState
*process
= ts
->running_process
[cpu
];
950 guint depth
= process
->execution_stack
->len
;
952 process
->execution_stack
=
953 g_array_set_size(process
->execution_stack
, depth
+ 1);
956 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
958 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
961 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
962 es
->s
= process
->state
->s
;
967 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
969 guint cpu
= ltt_tracefile_num(tfs
->parent
.tf
);
970 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
971 LttvProcessState
*process
= ts
->running_process
[cpu
];
973 guint depth
= process
->execution_stack
->len
;
975 if(process
->state
->t
!= t
){
976 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
977 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
978 g_info("process state has %s when pop_int is %s\n",
979 g_quark_to_string(process
->state
->t
),
980 g_quark_to_string(t
));
981 g_info("{ %u, %u, %s, %s }\n",
984 g_quark_to_string(process
->name
),
985 g_quark_to_string(process
->state
->s
));
990 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
991 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
995 process
->execution_stack
=
996 g_array_set_size(process
->execution_stack
, depth
- 1);
997 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
999 process
->state
->change
= tfs
->parent
.timestamp
;
1004 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1005 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1007 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1009 LttvExecutionState
*es
;
1011 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1017 process
->name
= name
;
1018 //process->last_cpu = tfs->cpu_name;
1019 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1020 g_info("Process %u, core %p", process
->pid
, process
);
1021 g_hash_table_insert(tcs
->processes
, process
, process
);
1024 process
->ppid
= parent
->pid
;
1025 process
->creation_time
= *timestamp
;
1028 /* No parent. This process exists but we are missing all information about
1029 its creation. The birth time is set to zero but we remember the time of
1034 process
->creation_time
= ltt_time_zero
;
1037 process
->insertion_time
= *timestamp
;
1038 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1039 process
->creation_time
.tv_nsec
);
1040 process
->pid_time
= g_quark_from_string(buffer
);
1042 //process->last_cpu = tfs->cpu_name;
1043 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1044 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1045 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1046 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1047 es
= process
->state
= &g_array_index(process
->execution_stack
,
1048 LttvExecutionState
, 0);
1049 es
->t
= LTTV_STATE_USER_MODE
;
1050 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1051 es
->entry
= *timestamp
;
1052 //g_assert(timestamp->tv_sec != 0);
1053 es
->change
= *timestamp
;
1054 es
->s
= LTTV_STATE_RUN
;
1056 es
= process
->state
= &g_array_index(process
->execution_stack
,
1057 LttvExecutionState
, 1);
1058 es
->t
= LTTV_STATE_SYSCALL
;
1059 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1060 es
->entry
= *timestamp
;
1061 //g_assert(timestamp->tv_sec != 0);
1062 es
->change
= *timestamp
;
1063 es
->s
= LTTV_STATE_WAIT_FORK
;
1068 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1071 LttvProcessState key
;
1072 LttvProcessState
*process
;
1076 process
= g_hash_table_lookup(ts
->processes
, &key
);
1081 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1084 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1086 /* Put ltt_time_zero creation time for unexisting processes */
1087 if(unlikely(process
== NULL
)) process
= lttv_state_create_process(ts
,
1088 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1092 /* FIXME : this function should be called when we receive an event telling that
1093 * release_task has been called in the kernel. In happens generally when
1094 * the parent waits for its child terminaison, but may also happen in special
1095 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1096 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1097 * of a killed thread ground, but isn't the leader.
1099 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1101 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1102 LttvProcessState key
;
1104 key
.pid
= process
->pid
;
1105 key
.cpu
= process
->cpu
;
1106 g_hash_table_remove(ts
->processes
, &key
);
1107 g_array_free(process
->execution_stack
, TRUE
);
1112 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1114 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1119 static void lttv_state_free_process_table(GHashTable
*processes
)
1121 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1122 g_hash_table_destroy(processes
);
1126 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1128 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1129 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1130 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1131 LttField
*f
= thf
->f1
;
1133 LttvExecutionSubmode submode
;
1135 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1136 ltt_event_get_unsigned(e
, f
)];
1137 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1142 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1144 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1146 pop_state(s
, LTTV_STATE_SYSCALL
);
1151 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1153 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1154 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1155 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1156 LttField
*f
= thf
->f1
;
1158 LttvExecutionSubmode submode
;
1160 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1161 ltt_event_get_unsigned(e
, f
)];
1162 push_state(s
, LTTV_STATE_TRAP
, submode
);
1167 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1169 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1171 pop_state(s
, LTTV_STATE_TRAP
);
1176 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1178 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1179 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1180 guint8 fac_id
= ltt_event_facility_id(e
);
1181 guint8 ev_id
= ltt_event_eventtype_id(e
);
1182 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1183 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1184 g_assert(thf
->f1
!= NULL
);
1185 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1186 LttField
*f
= thf
->f1
;
1188 LttvExecutionSubmode submode
;
1190 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1191 ltt_event_get_unsigned(e
, f
)];
1193 /* Do something with the info about being in user or system mode when int? */
1194 push_state(s
, LTTV_STATE_IRQ
, submode
);
1199 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1201 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1203 pop_state(s
, LTTV_STATE_IRQ
);
1207 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1209 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1210 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1211 guint8 fac_id
= ltt_event_facility_id(e
);
1212 guint8 ev_id
= ltt_event_eventtype_id(e
);
1213 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1214 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1215 g_assert(thf
->f1
!= NULL
);
1216 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1217 LttField
*f
= thf
->f1
;
1219 LttvExecutionSubmode submode
;
1221 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1222 ltt_event_get_unsigned(e
, f
)];
1224 /* Do something with the info about being in user or system mode when int? */
1225 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1230 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1232 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1234 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1239 static gboolean
schedchange(void *hook_data
, void *call_data
)
1241 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1242 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1243 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1244 LttvProcessState
*process
= ts
->running_process
[cpu
];
1246 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1247 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1248 guint pid_in
, pid_out
;
1251 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1252 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1253 state_out
= ltt_event_get_int(e
, thf
->f3
);
1255 if(likely(process
!= NULL
)) {
1257 /* We could not know but it was not the idle process executing.
1258 This should only happen at the beginning, before the first schedule
1259 event, and when the initial information (current process for each CPU)
1260 is missing. It is not obvious how we could, after the fact, compensate
1261 the wrongly attributed statistics. */
1263 //This test only makes sense once the state is known and if there is no
1265 //if(unlikely(process->pid != pid_out)) {
1266 // g_assert(process->pid == 0);
1269 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1270 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1271 process
->state
->change
= s
->parent
.timestamp
;
1273 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1274 else process
->state
->s
= LTTV_STATE_WAIT
;
1275 process
->state
->change
= s
->parent
.timestamp
;
1279 exit_process(s
, process
); /* EXIT_DEAD */
1280 /* see sched.h for states */
1282 process
= ts
->running_process
[cpu
] =
1283 lttv_state_find_process_or_create(
1284 (LttvTraceState
*)s
->parent
.t_context
,
1286 &s
->parent
.timestamp
);
1287 process
->state
->s
= LTTV_STATE_RUN
;
1289 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1290 process
->state
->change
= s
->parent
.timestamp
;
1294 static gboolean
process_fork(void *hook_data
, void *call_data
)
1296 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1297 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1298 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1301 LttvProcessState
*zombie_process
;
1302 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1303 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1304 LttvProcessState
*process
= ts
->running_process
[cpu
];
1305 LttvProcessState
*child_process
;
1308 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1311 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1313 /* Mathieu : it seems like the process might have been scheduled in before the
1314 * fork, and, in a rare case, might be the current process. This might happen
1315 * in a SMP case where we don't have enough precision on the clocks.
1317 * Test reenabled after precision fixes on time. (Mathieu) */
1319 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1321 if(unlikely(zombie_process
!= NULL
)) {
1322 /* Reutilisation of PID. Only now we are sure that the old PID
1323 * has been released. FIXME : should know when release_task happens instead.
1325 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1327 for(i
=0; i
< num_cpus
; i
++) {
1328 g_assert(zombie_process
!= ts
->running_process
[i
]);
1331 exit_process(s
, zombie_process
);
1334 g_assert(process
->pid
!= child_pid
);
1335 // FIXME : Add this test in the "known state" section
1336 // g_assert(process->pid == parent_pid);
1337 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1338 if(child_process
== NULL
) {
1339 lttv_state_create_process(ts
, process
, cpu
,
1340 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1342 /* The process has already been created : due to time imprecision between
1343 * multiple CPUs : it has been scheduled in before creation. Note that we
1344 * shouldn't have this kind of imprecision.
1346 * Simply put a correct parent.
1348 g_assert(0); /* This is a problematic case : the process has been created
1349 before the fork event */
1350 child_process
->ppid
= process
->pid
;
1357 static gboolean
process_exit(void *hook_data
, void *call_data
)
1359 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1360 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1361 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1364 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1365 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1366 LttvProcessState
*process
= ts
->running_process
[cpu
];
1368 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1370 // FIXME : Add this test in the "known state" section
1371 // g_assert(process->pid == pid);
1373 if(likely(process
!= NULL
)) {
1374 process
->state
->s
= LTTV_STATE_EXIT
;
1379 static gboolean
process_free(void *hook_data
, void *call_data
)
1381 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1382 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1383 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1384 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1386 LttvProcessState
*process
;
1388 /* PID of the process to release */
1389 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1391 g_assert(release_pid
!= 0);
1393 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1395 if(likely(process
!= NULL
)) {
1396 /* release_task is happening at kernel level : we can now safely release
1397 * the data structure of the process */
1398 //This test is fun, though, as it may happen that
1399 //at time t : CPU 0 : process_free
1400 //at time t+150ns : CPU 1 : schedule out
1401 //Clearly due to time imprecision, we disable it. (Mathieu)
1402 //If this weird case happen, we have no choice but to put the
1403 //Currently running process on the cpu to 0.
1404 //I re-enable it following time precision fixes. (Mathieu)
1405 //Well, in the case where an process is freed by a process on another CPU
1406 //and still scheduled, it happens that this is the schedchange that will
1407 //drop the last reference count. Do not free it here!
1408 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1410 for(i
=0; i
< num_cpus
; i
++) {
1411 //g_assert(process != ts->running_process[i]);
1412 if(process
== ts
->running_process
[i
]) {
1413 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1417 if(i
== num_cpus
) /* process is not scheduled */
1418 exit_process(s
, process
);
1425 static gboolean
process_exec(void *hook_data
, void *call_data
)
1427 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1428 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1429 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1430 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1432 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1433 LttvProcessState
*process
= ts
->running_process
[cpu
];
1435 /* PID of the process to release */
1436 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1437 //name = ltt_event_get_string(e, thf->f1);
1438 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1440 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1441 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1442 memcpy(null_term_name
, name_begin
, name_len
);
1443 null_term_name
[name_len
] = '\0';
1445 process
->name
= g_quark_from_string(null_term_name
);
1446 g_free(null_term_name
);
1450 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1452 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1453 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1454 //It's slow : optimise later by doing this before reading trace.
1455 LttEventType
*et
= ltt_event_eventtype(e
);
1457 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1461 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1462 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1463 LttvProcessState
*process
= ts
->running_process
[cpu
];
1464 LttvProcessState
*parent_process
;
1465 LttField
*f4
, *f5
, *f6
;
1466 GQuark mode
, submode
, status
;
1469 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1472 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1475 command
= ltt_event_get_string(e
, thf
->f3
);
1478 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1479 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1480 ltt_event_get_unsigned(e
, f4
));
1483 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1484 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1485 ltt_event_get_unsigned(e
, f5
));
1488 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1489 status
= ltt_enum_string_get(ltt_field_type(f6
),
1490 ltt_event_get_unsigned(e
, f6
));
1492 /* The process might exist if a process was forked while performing the sate dump. */
1493 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1494 if(process
== NULL
) {
1495 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1496 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1497 pid
, g_quark_from_string(command
),
1498 &s
->parent
.timestamp
);
1500 /* Keep the stack bottom : a running user mode */
1502 if(mode
== LTTV_STATE_USER_MODE
) {
1503 /* Only keep the bottom */
1504 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1506 /* On top of it : */
1507 LttvExecutionState
*es
;
1508 es
= process
->state
= &g_array_index(process
->execution_stack
,
1509 LttvExecutionState
, 1);
1516 /* The process has already been created :
1517 * Probably was forked while dumping the process state or
1518 * was simply scheduled in prior to get the state dump event.
1520 process
->ppid
= parent_pid
;
1521 process
->name
= g_quark_from_string(command
);
1522 /* Don't mess around with the stack, it will eventually become
1523 * ok after the end of state dump. */
1529 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1531 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1533 lttv_state_add_event_hooks(tss
);
1538 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1540 LttvTraceset
*traceset
= self
->parent
.ts
;
1542 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1546 LttvTracefileState
*tfs
;
1550 LttvTraceHookByFacility
*thf
;
1552 LttvTraceHook
*hook
;
1554 LttvAttributeValue val
;
1558 nb_trace
= lttv_traceset_number(traceset
);
1559 for(i
= 0 ; i
< nb_trace
; i
++) {
1560 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1562 /* Find the eventtype id for the following events and register the
1563 associated by id hooks. */
1565 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 14);
1566 hooks
= g_array_set_size(hooks
, 14);
1568 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1569 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1570 LTT_FIELD_SYSCALL_ID
, 0, 0,
1571 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1574 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1575 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1577 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1580 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1581 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1582 LTT_FIELD_TRAP_ID
, 0, 0,
1583 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1586 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1587 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1589 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1592 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1593 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1594 LTT_FIELD_IRQ_ID
, 0, 0,
1595 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1598 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1599 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1601 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1604 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1605 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1606 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1607 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1610 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1611 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1613 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1616 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1617 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1618 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1619 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1622 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1623 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1624 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1625 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1628 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1629 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1630 LTT_FIELD_PID
, 0, 0,
1631 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1634 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1635 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1636 LTT_FIELD_PID
, 0, 0,
1637 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1640 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1641 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1642 LTT_FIELD_FILENAME
, 0, 0,
1643 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1646 /* statedump-related hooks */
1647 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1648 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1649 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1650 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1654 /* Add these hooks to each event_by_id hooks list */
1656 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1658 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1660 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1661 LttvTracefileContext
*, j
));
1663 for(k
= 0 ; k
< hooks
->len
; k
++) {
1664 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1665 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1666 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1668 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1675 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1676 *(val
.v_pointer
) = hooks
;
1680 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1682 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1684 lttv_state_remove_event_hooks(tss
);
1689 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1691 LttvTraceset
*traceset
= self
->parent
.ts
;
1693 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1697 LttvTracefileState
*tfs
;
1701 LttvTraceHook
*hook
;
1703 LttvTraceHookByFacility
*thf
;
1705 LttvAttributeValue val
;
1707 nb_trace
= lttv_traceset_number(traceset
);
1708 for(i
= 0 ; i
< nb_trace
; i
++) {
1709 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1710 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1711 hooks
= *(val
.v_pointer
);
1713 /* Remove these hooks from each event_by_id hooks list */
1715 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1717 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1719 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1720 LttvTracefileContext
*, j
));
1722 for(k
= 0 ; k
< hooks
->len
; k
++) {
1723 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1724 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1725 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1727 lttv_hooks_remove_data(
1728 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1734 for(k
= 0 ; k
< hooks
->len
; k
++)
1735 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1736 g_array_free(hooks
, TRUE
);
1740 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1742 guint
*event_count
= (guint
*)hook_data
;
1744 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1745 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1750 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1752 LttvTracefileState
*tfcs
;
1754 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1756 LttEventPosition
*ep
;
1762 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1764 LttvAttributeValue value
;
1766 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1767 LTTV_STATE_SAVED_STATES
);
1768 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1769 value
= lttv_attribute_add(saved_states_tree
,
1770 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1771 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1772 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1773 *(value
.v_time
) = self
->parent
.timestamp
;
1774 lttv_state_save(tcs
, saved_state_tree
);
1775 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1776 self
->parent
.timestamp
.tv_nsec
);
1778 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1783 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1785 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1787 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1793 static gboolean
block_start(void *hook_data
, void *call_data
)
1795 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1797 LttvTracefileState
*tfcs
;
1799 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1801 LttEventPosition
*ep
;
1803 guint i
, nb_block
, nb_event
, nb_tracefile
;
1807 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1809 LttvAttributeValue value
;
1811 ep
= ltt_event_position_new();
1813 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1815 /* Count the number of events added since the last block end in any
1818 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1820 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1821 LttvTracefileContext
, i
));
1822 ltt_event_position(tfcs
->parent
.e
, ep
);
1823 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1824 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1825 tfcs
->saved_position
= nb_event
;
1829 if(tcs
->nb_event
>= tcs
->save_interval
) {
1830 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1831 LTTV_STATE_SAVED_STATES
);
1832 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1833 value
= lttv_attribute_add(saved_states_tree
,
1834 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1835 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1836 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1837 *(value
.v_time
) = self
->parent
.timestamp
;
1838 lttv_state_save(tcs
, saved_state_tree
);
1840 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1841 self
->parent
.timestamp
.tv_nsec
);
1843 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1849 static gboolean
block_end(void *hook_data
, void *call_data
)
1851 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1853 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1857 LttEventPosition
*ep
;
1859 guint nb_block
, nb_event
;
1861 ep
= ltt_event_position_new();
1862 ltt_event_position(self
->parent
.e
, ep
);
1863 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1864 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1865 self
->saved_position
= 0;
1866 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1873 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1875 LttvTraceset
*traceset
= self
->parent
.ts
;
1877 guint i
, j
, nb_trace
, nb_tracefile
;
1881 LttvTracefileState
*tfs
;
1883 LttvTraceHook hook_start
, hook_end
;
1885 nb_trace
= lttv_traceset_number(traceset
);
1886 for(i
= 0 ; i
< nb_trace
; i
++) {
1887 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1889 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1890 NULL
, NULL
, block_start
, &hook_start
);
1891 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1892 NULL
, NULL
, block_end
, &hook_end
);
1894 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1896 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1898 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1899 LttvTracefileContext
, j
));
1900 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1901 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1902 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1903 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1909 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1911 LttvTraceset
*traceset
= self
->parent
.ts
;
1913 guint i
, j
, nb_trace
, nb_tracefile
;
1917 LttvTracefileState
*tfs
;
1920 nb_trace
= lttv_traceset_number(traceset
);
1921 for(i
= 0 ; i
< nb_trace
; i
++) {
1923 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1924 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1926 guint
*event_count
= g_new(guint
, 1);
1929 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1931 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1932 LttvTracefileContext
*, j
));
1933 lttv_hooks_add(tfs
->parent
.event
,
1934 state_save_event_hook
,
1941 lttv_process_traceset_begin(&self
->parent
,
1942 NULL
, NULL
, NULL
, NULL
, NULL
);
1946 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1948 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1950 lttv_state_save_add_event_hooks(tss
);
1957 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1959 LttvTraceset
*traceset
= self
->parent
.ts
;
1961 guint i
, j
, nb_trace
, nb_tracefile
;
1965 LttvTracefileState
*tfs
;
1967 LttvTraceHook hook_start
, hook_end
;
1969 nb_trace
= lttv_traceset_number(traceset
);
1970 for(i
= 0 ; i
< nb_trace
; i
++) {
1971 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1973 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1974 NULL
, NULL
, block_start
, &hook_start
);
1976 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1977 NULL
, NULL
, block_end
, &hook_end
);
1979 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1981 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1983 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1984 LttvTracefileContext
, j
));
1985 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1986 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
1987 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1988 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
1994 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1996 LttvTraceset
*traceset
= self
->parent
.ts
;
1998 guint i
, j
, nb_trace
, nb_tracefile
;
2002 LttvTracefileState
*tfs
;
2004 LttvHooks
*after_trace
= lttv_hooks_new();
2006 lttv_hooks_add(after_trace
,
2007 state_save_after_trace_hook
,
2012 lttv_process_traceset_end(&self
->parent
,
2013 NULL
, after_trace
, NULL
, NULL
, NULL
);
2015 lttv_hooks_destroy(after_trace
);
2017 nb_trace
= lttv_traceset_number(traceset
);
2018 for(i
= 0 ; i
< nb_trace
; i
++) {
2020 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2021 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2023 guint
*event_count
= NULL
;
2025 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2027 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2028 LttvTracefileContext
*, j
));
2029 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2030 state_save_event_hook
);
2032 if(event_count
) g_free(event_count
);
2036 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2038 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2040 lttv_state_save_remove_event_hooks(tss
);
2045 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2047 LttvTraceset
*traceset
= self
->parent
.ts
;
2051 int min_pos
, mid_pos
, max_pos
;
2053 guint call_rest
= 0;
2055 LttvTraceState
*tcs
;
2057 LttvAttributeValue value
;
2059 LttvAttributeType type
;
2061 LttvAttributeName name
;
2063 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2065 //g_tree_destroy(self->parent.pqueue);
2066 //self->parent.pqueue = g_tree_new(compare_tracefile);
2068 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2070 nb_trace
= lttv_traceset_number(traceset
);
2071 for(i
= 0 ; i
< nb_trace
; i
++) {
2072 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2074 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2075 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2076 LTTV_STATE_SAVED_STATES
);
2079 if(saved_states_tree
) {
2080 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2081 mid_pos
= max_pos
/ 2;
2082 while(min_pos
< max_pos
) {
2083 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2084 g_assert(type
== LTTV_GOBJECT
);
2085 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2086 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2088 g_assert(type
== LTTV_TIME
);
2089 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2091 closest_tree
= saved_state_tree
;
2093 else max_pos
= mid_pos
- 1;
2095 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2099 /* restore the closest earlier saved state */
2101 lttv_state_restore(tcs
, closest_tree
);
2105 /* There is no saved state, yet we want to have it. Restart at T0 */
2107 restore_init_state(tcs
);
2108 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2111 /* We want to seek quickly without restoring/updating the state */
2113 restore_init_state(tcs
);
2114 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2117 if(!call_rest
) g_info("NOT Calling restore");
2122 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2128 traceset_state_finalize (LttvTracesetState
*self
)
2130 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2131 finalize(G_OBJECT(self
));
2136 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2138 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2140 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2141 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2142 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2143 klass
->new_traceset_context
= new_traceset_context
;
2144 klass
->new_trace_context
= new_trace_context
;
2145 klass
->new_tracefile_context
= new_tracefile_context
;
2150 lttv_traceset_state_get_type(void)
2152 static GType type
= 0;
2154 static const GTypeInfo info
= {
2155 sizeof (LttvTracesetStateClass
),
2156 NULL
, /* base_init */
2157 NULL
, /* base_finalize */
2158 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2159 NULL
, /* class_finalize */
2160 NULL
, /* class_data */
2161 sizeof (LttvTracesetState
),
2162 0, /* n_preallocs */
2163 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2164 NULL
/* value handling */
2167 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2175 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2181 trace_state_finalize (LttvTraceState
*self
)
2183 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2184 finalize(G_OBJECT(self
));
2189 trace_state_class_init (LttvTraceStateClass
*klass
)
2191 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2193 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2194 klass
->state_save
= state_save
;
2195 klass
->state_restore
= state_restore
;
2196 klass
->state_saved_free
= state_saved_free
;
2201 lttv_trace_state_get_type(void)
2203 static GType type
= 0;
2205 static const GTypeInfo info
= {
2206 sizeof (LttvTraceStateClass
),
2207 NULL
, /* base_init */
2208 NULL
, /* base_finalize */
2209 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2210 NULL
, /* class_finalize */
2211 NULL
, /* class_data */
2212 sizeof (LttvTraceState
),
2213 0, /* n_preallocs */
2214 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2215 NULL
/* value handling */
2218 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2219 "LttvTraceStateType", &info
, 0);
2226 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2232 tracefile_state_finalize (LttvTracefileState
*self
)
2234 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2235 finalize(G_OBJECT(self
));
2240 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2242 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2244 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2249 lttv_tracefile_state_get_type(void)
2251 static GType type
= 0;
2253 static const GTypeInfo info
= {
2254 sizeof (LttvTracefileStateClass
),
2255 NULL
, /* base_init */
2256 NULL
, /* base_finalize */
2257 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2258 NULL
, /* class_finalize */
2259 NULL
, /* class_data */
2260 sizeof (LttvTracefileState
),
2261 0, /* n_preallocs */
2262 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2263 NULL
/* value handling */
2266 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2267 "LttvTracefileStateType", &info
, 0);
2273 static void module_init()
2275 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2276 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2277 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2278 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2279 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2280 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2281 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2282 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2283 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2284 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2285 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2286 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2287 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2288 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2289 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2290 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2291 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2292 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2293 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2294 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2295 LTTV_STATE_EVENT
= g_quark_from_string("event");
2296 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2297 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2298 LTTV_STATE_TIME
= g_quark_from_string("time");
2299 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2300 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2301 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2302 g_quark_from_string("trace_state_use_count");
2305 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2306 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2307 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2308 LTT_FACILITY_FS
= g_quark_from_string("fs");
2309 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2312 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2313 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2314 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2315 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2316 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2317 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2318 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2319 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2320 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2321 LTT_EVENT_FORK
= g_quark_from_string("fork");
2322 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2323 LTT_EVENT_FREE
= g_quark_from_string("free");
2324 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2325 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2328 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2329 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2330 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2331 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2332 LTT_FIELD_OUT
= g_quark_from_string("out");
2333 LTT_FIELD_IN
= g_quark_from_string("in");
2334 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2335 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2336 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2337 LTT_FIELD_PID
= g_quark_from_string("pid");
2338 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2339 LTT_FIELD_NAME
= g_quark_from_string("name");
2340 LTT_FIELD_MODE
= g_quark_from_string("mode");
2341 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2342 LTT_FIELD_STATUS
= g_quark_from_string("status");
2346 static void module_destroy()
2351 LTTV_MODULE("state", "State computation", \
2352 "Update the system state, possibly saving it at intervals", \
2353 module_init
, module_destroy
)