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 child_process
= 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
;
1352 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1353 child_process
->name
= process
->name
;
1359 static gboolean
process_exit(void *hook_data
, void *call_data
)
1361 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1362 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1363 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1366 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1367 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1368 LttvProcessState
*process
= ts
->running_process
[cpu
];
1370 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1372 // FIXME : Add this test in the "known state" section
1373 // g_assert(process->pid == pid);
1375 if(likely(process
!= NULL
)) {
1376 process
->state
->s
= LTTV_STATE_EXIT
;
1381 static gboolean
process_free(void *hook_data
, void *call_data
)
1383 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1384 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1385 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1386 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1388 LttvProcessState
*process
;
1390 /* PID of the process to release */
1391 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1393 g_assert(release_pid
!= 0);
1395 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1397 if(likely(process
!= NULL
)) {
1398 /* release_task is happening at kernel level : we can now safely release
1399 * the data structure of the process */
1400 //This test is fun, though, as it may happen that
1401 //at time t : CPU 0 : process_free
1402 //at time t+150ns : CPU 1 : schedule out
1403 //Clearly due to time imprecision, we disable it. (Mathieu)
1404 //If this weird case happen, we have no choice but to put the
1405 //Currently running process on the cpu to 0.
1406 //I re-enable it following time precision fixes. (Mathieu)
1407 //Well, in the case where an process is freed by a process on another CPU
1408 //and still scheduled, it happens that this is the schedchange that will
1409 //drop the last reference count. Do not free it here!
1410 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1412 for(i
=0; i
< num_cpus
; i
++) {
1413 //g_assert(process != ts->running_process[i]);
1414 if(process
== ts
->running_process
[i
]) {
1415 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1419 if(i
== num_cpus
) /* process is not scheduled */
1420 exit_process(s
, process
);
1427 static gboolean
process_exec(void *hook_data
, void *call_data
)
1429 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1430 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1431 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1432 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1434 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1435 LttvProcessState
*process
= ts
->running_process
[cpu
];
1437 /* PID of the process to release */
1438 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1439 //name = ltt_event_get_string(e, thf->f1);
1440 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1442 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1443 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1444 memcpy(null_term_name
, name_begin
, name_len
);
1445 null_term_name
[name_len
] = '\0';
1447 process
->name
= g_quark_from_string(null_term_name
);
1448 g_free(null_term_name
);
1452 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1454 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1455 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1456 //It's slow : optimise later by doing this before reading trace.
1457 LttEventType
*et
= ltt_event_eventtype(e
);
1459 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1463 guint cpu
= ltt_tracefile_num(s
->parent
.tf
);
1464 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1465 LttvProcessState
*process
= ts
->running_process
[cpu
];
1466 LttvProcessState
*parent_process
;
1467 LttField
*f4
, *f5
, *f6
;
1468 GQuark mode
, submode
, status
;
1471 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1474 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1477 command
= ltt_event_get_string(e
, thf
->f3
);
1480 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1481 mode
= ltt_enum_string_get(ltt_field_type(f4
),
1482 ltt_event_get_unsigned(e
, f4
));
1485 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1486 submode
= ltt_enum_string_get(ltt_field_type(f5
),
1487 ltt_event_get_unsigned(e
, f5
));
1490 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1491 status
= ltt_enum_string_get(ltt_field_type(f6
),
1492 ltt_event_get_unsigned(e
, f6
));
1494 /* The process might exist if a process was forked while performing the sate dump. */
1495 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1496 if(process
== NULL
) {
1497 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1498 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1499 pid
, g_quark_from_string(command
),
1500 &s
->parent
.timestamp
);
1502 /* Keep the stack bottom : a running user mode */
1504 /* Disabled because of inconsistencies in the current statedump states. */
1505 if(mode
== LTTV_STATE_USER_MODE
) {
1506 /* Only keep the bottom */
1507 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1509 /* On top of it : */
1510 LttvExecutionState
*es
;
1511 es
= process
->state
= &g_array_index(process
->execution_stack
,
1512 LttvExecutionState
, 1);
1521 LttvExecutionState
*es
;
1522 es
= process
->state
= &g_array_index(process
->execution_stack
,
1523 LttvExecutionState
, 1);
1524 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1525 es
->s
= LTTV_STATE_UNNAMED
;
1526 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1529 /* The process has already been created :
1530 * Probably was forked while dumping the process state or
1531 * was simply scheduled in prior to get the state dump event.
1533 process
->ppid
= parent_pid
;
1534 process
->name
= g_quark_from_string(command
);
1535 /* Don't mess around with the stack, it will eventually become
1536 * ok after the end of state dump. */
1542 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1544 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1546 lttv_state_add_event_hooks(tss
);
1551 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1553 LttvTraceset
*traceset
= self
->parent
.ts
;
1555 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1559 LttvTracefileState
*tfs
;
1563 LttvTraceHookByFacility
*thf
;
1565 LttvTraceHook
*hook
;
1567 LttvAttributeValue val
;
1571 nb_trace
= lttv_traceset_number(traceset
);
1572 for(i
= 0 ; i
< nb_trace
; i
++) {
1573 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1575 /* Find the eventtype id for the following events and register the
1576 associated by id hooks. */
1578 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 14);
1579 hooks
= g_array_set_size(hooks
, 14);
1581 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1582 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1583 LTT_FIELD_SYSCALL_ID
, 0, 0,
1584 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 0));
1587 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1588 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1590 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 1));
1593 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1594 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1595 LTT_FIELD_TRAP_ID
, 0, 0,
1596 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 2));
1599 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1600 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1602 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 3));
1605 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1606 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1607 LTT_FIELD_IRQ_ID
, 0, 0,
1608 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 4));
1611 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1612 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1614 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 5));
1617 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1618 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1619 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1620 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 6));
1623 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1624 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1626 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 7));
1629 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1630 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1631 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1632 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 8));
1635 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1636 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1637 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1638 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 9));
1641 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1642 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1643 LTT_FIELD_PID
, 0, 0,
1644 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 10));
1647 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1648 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1649 LTT_FIELD_PID
, 0, 0,
1650 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 11));
1653 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1654 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1655 LTT_FIELD_FILENAME
, 0, 0,
1656 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 12));
1659 /* statedump-related hooks */
1660 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1661 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1662 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1663 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, 13));
1667 /* Add these hooks to each event_by_id hooks list */
1669 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1671 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1673 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1674 LttvTracefileContext
*, j
));
1676 for(k
= 0 ; k
< hooks
->len
; k
++) {
1677 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1678 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1679 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1681 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1688 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1689 *(val
.v_pointer
) = hooks
;
1693 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
1695 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1697 lttv_state_remove_event_hooks(tss
);
1702 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
1704 LttvTraceset
*traceset
= self
->parent
.ts
;
1706 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1710 LttvTracefileState
*tfs
;
1714 LttvTraceHook
*hook
;
1716 LttvTraceHookByFacility
*thf
;
1718 LttvAttributeValue val
;
1720 nb_trace
= lttv_traceset_number(traceset
);
1721 for(i
= 0 ; i
< nb_trace
; i
++) {
1722 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1723 lttv_attribute_find(self
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
1724 hooks
= *(val
.v_pointer
);
1726 /* Remove these hooks from each event_by_id hooks list */
1728 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1730 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1732 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1733 LttvTracefileContext
*, j
));
1735 for(k
= 0 ; k
< hooks
->len
; k
++) {
1736 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
1737 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
1738 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
1740 lttv_hooks_remove_data(
1741 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
1747 for(k
= 0 ; k
< hooks
->len
; k
++)
1748 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
1749 g_array_free(hooks
, TRUE
);
1753 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
1755 guint
*event_count
= (guint
*)hook_data
;
1757 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1758 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
1763 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1765 LttvTracefileState
*tfcs
;
1767 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1769 LttEventPosition
*ep
;
1775 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1777 LttvAttributeValue value
;
1779 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1780 LTTV_STATE_SAVED_STATES
);
1781 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1782 value
= lttv_attribute_add(saved_states_tree
,
1783 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1784 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1785 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1786 *(value
.v_time
) = self
->parent
.timestamp
;
1787 lttv_state_save(tcs
, saved_state_tree
);
1788 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1789 self
->parent
.timestamp
.tv_nsec
);
1791 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1796 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
1798 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
1800 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1806 static gboolean
block_start(void *hook_data
, void *call_data
)
1808 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1810 LttvTracefileState
*tfcs
;
1812 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1814 LttEventPosition
*ep
;
1816 guint i
, nb_block
, nb_event
, nb_tracefile
;
1820 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
1822 LttvAttributeValue value
;
1824 ep
= ltt_event_position_new();
1826 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
1828 /* Count the number of events added since the last block end in any
1831 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1833 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
1834 LttvTracefileContext
, i
));
1835 ltt_event_position(tfcs
->parent
.e
, ep
);
1836 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1837 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
1838 tfcs
->saved_position
= nb_event
;
1842 if(tcs
->nb_event
>= tcs
->save_interval
) {
1843 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
1844 LTTV_STATE_SAVED_STATES
);
1845 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1846 value
= lttv_attribute_add(saved_states_tree
,
1847 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1848 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1849 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1850 *(value
.v_time
) = self
->parent
.timestamp
;
1851 lttv_state_save(tcs
, saved_state_tree
);
1853 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
1854 self
->parent
.timestamp
.tv_nsec
);
1856 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1862 static gboolean
block_end(void *hook_data
, void *call_data
)
1864 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
1866 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
1870 LttEventPosition
*ep
;
1872 guint nb_block
, nb_event
;
1874 ep
= ltt_event_position_new();
1875 ltt_event_position(self
->parent
.e
, ep
);
1876 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
1877 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
1878 self
->saved_position
= 0;
1879 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
1886 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1888 LttvTraceset
*traceset
= self
->parent
.ts
;
1890 guint i
, j
, nb_trace
, nb_tracefile
;
1894 LttvTracefileState
*tfs
;
1896 LttvTraceHook hook_start
, hook_end
;
1898 nb_trace
= lttv_traceset_number(traceset
);
1899 for(i
= 0 ; i
< nb_trace
; i
++) {
1900 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1902 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1903 NULL
, NULL
, block_start
, &hook_start
);
1904 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1905 NULL
, NULL
, block_end
, &hook_end
);
1907 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1909 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1911 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1912 LttvTracefileContext
, j
));
1913 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1914 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
1915 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
1916 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
1922 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
1924 LttvTraceset
*traceset
= self
->parent
.ts
;
1926 guint i
, j
, nb_trace
, nb_tracefile
;
1930 LttvTracefileState
*tfs
;
1933 nb_trace
= lttv_traceset_number(traceset
);
1934 for(i
= 0 ; i
< nb_trace
; i
++) {
1936 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1937 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1939 guint
*event_count
= g_new(guint
, 1);
1942 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1944 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
1945 LttvTracefileContext
*, j
));
1946 lttv_hooks_add(tfs
->parent
.event
,
1947 state_save_event_hook
,
1954 lttv_process_traceset_begin(&self
->parent
,
1955 NULL
, NULL
, NULL
, NULL
, NULL
);
1959 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
1961 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1963 lttv_state_save_add_event_hooks(tss
);
1970 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
1972 LttvTraceset
*traceset
= self
->parent
.ts
;
1974 guint i
, j
, nb_trace
, nb_tracefile
;
1978 LttvTracefileState
*tfs
;
1980 LttvTraceHook hook_start
, hook_end
;
1982 nb_trace
= lttv_traceset_number(traceset
);
1983 for(i
= 0 ; i
< nb_trace
; i
++) {
1984 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
1986 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
1987 NULL
, NULL
, block_start
, &hook_start
);
1989 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
1990 NULL
, NULL
, block_end
, &hook_end
);
1992 nb_tracefile
= ts
->parent
.tracefiles
->len
;
1994 for(j
= 0 ; j
< nb_tracefile
; j
++) {
1996 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
1997 LttvTracefileContext
, j
));
1998 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1999 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2000 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2001 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2007 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2009 LttvTraceset
*traceset
= self
->parent
.ts
;
2011 guint i
, j
, nb_trace
, nb_tracefile
;
2015 LttvTracefileState
*tfs
;
2017 LttvHooks
*after_trace
= lttv_hooks_new();
2019 lttv_hooks_add(after_trace
,
2020 state_save_after_trace_hook
,
2025 lttv_process_traceset_end(&self
->parent
,
2026 NULL
, after_trace
, NULL
, NULL
, NULL
);
2028 lttv_hooks_destroy(after_trace
);
2030 nb_trace
= lttv_traceset_number(traceset
);
2031 for(i
= 0 ; i
< nb_trace
; i
++) {
2033 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2034 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2036 guint
*event_count
= NULL
;
2038 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2040 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2041 LttvTracefileContext
*, j
));
2042 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2043 state_save_event_hook
);
2045 if(event_count
) g_free(event_count
);
2049 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2051 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2053 lttv_state_save_remove_event_hooks(tss
);
2058 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2060 LttvTraceset
*traceset
= self
->parent
.ts
;
2064 int min_pos
, mid_pos
, max_pos
;
2066 guint call_rest
= 0;
2068 LttvTraceState
*tcs
;
2070 LttvAttributeValue value
;
2072 LttvAttributeType type
;
2074 LttvAttributeName name
;
2076 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2078 //g_tree_destroy(self->parent.pqueue);
2079 //self->parent.pqueue = g_tree_new(compare_tracefile);
2081 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2083 nb_trace
= lttv_traceset_number(traceset
);
2084 for(i
= 0 ; i
< nb_trace
; i
++) {
2085 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2087 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2088 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2089 LTTV_STATE_SAVED_STATES
);
2092 if(saved_states_tree
) {
2093 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2094 mid_pos
= max_pos
/ 2;
2095 while(min_pos
< max_pos
) {
2096 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
);
2097 g_assert(type
== LTTV_GOBJECT
);
2098 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2099 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2101 g_assert(type
== LTTV_TIME
);
2102 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2104 closest_tree
= saved_state_tree
;
2106 else max_pos
= mid_pos
- 1;
2108 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2112 /* restore the closest earlier saved state */
2114 lttv_state_restore(tcs
, closest_tree
);
2118 /* There is no saved state, yet we want to have it. Restart at T0 */
2120 restore_init_state(tcs
);
2121 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2124 /* We want to seek quickly without restoring/updating the state */
2126 restore_init_state(tcs
);
2127 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2130 if(!call_rest
) g_info("NOT Calling restore");
2135 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2141 traceset_state_finalize (LttvTracesetState
*self
)
2143 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2144 finalize(G_OBJECT(self
));
2149 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2151 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2153 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2154 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2155 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2156 klass
->new_traceset_context
= new_traceset_context
;
2157 klass
->new_trace_context
= new_trace_context
;
2158 klass
->new_tracefile_context
= new_tracefile_context
;
2163 lttv_traceset_state_get_type(void)
2165 static GType type
= 0;
2167 static const GTypeInfo info
= {
2168 sizeof (LttvTracesetStateClass
),
2169 NULL
, /* base_init */
2170 NULL
, /* base_finalize */
2171 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2172 NULL
, /* class_finalize */
2173 NULL
, /* class_data */
2174 sizeof (LttvTracesetState
),
2175 0, /* n_preallocs */
2176 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2177 NULL
/* value handling */
2180 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2188 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2194 trace_state_finalize (LttvTraceState
*self
)
2196 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2197 finalize(G_OBJECT(self
));
2202 trace_state_class_init (LttvTraceStateClass
*klass
)
2204 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2206 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2207 klass
->state_save
= state_save
;
2208 klass
->state_restore
= state_restore
;
2209 klass
->state_saved_free
= state_saved_free
;
2214 lttv_trace_state_get_type(void)
2216 static GType type
= 0;
2218 static const GTypeInfo info
= {
2219 sizeof (LttvTraceStateClass
),
2220 NULL
, /* base_init */
2221 NULL
, /* base_finalize */
2222 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2223 NULL
, /* class_finalize */
2224 NULL
, /* class_data */
2225 sizeof (LttvTraceState
),
2226 0, /* n_preallocs */
2227 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2228 NULL
/* value handling */
2231 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2232 "LttvTraceStateType", &info
, 0);
2239 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2245 tracefile_state_finalize (LttvTracefileState
*self
)
2247 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2248 finalize(G_OBJECT(self
));
2253 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2255 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2257 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2262 lttv_tracefile_state_get_type(void)
2264 static GType type
= 0;
2266 static const GTypeInfo info
= {
2267 sizeof (LttvTracefileStateClass
),
2268 NULL
, /* base_init */
2269 NULL
, /* base_finalize */
2270 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2271 NULL
, /* class_finalize */
2272 NULL
, /* class_data */
2273 sizeof (LttvTracefileState
),
2274 0, /* n_preallocs */
2275 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2276 NULL
/* value handling */
2279 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2280 "LttvTracefileStateType", &info
, 0);
2286 static void module_init()
2288 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2289 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2290 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2291 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2292 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2293 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2294 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2295 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2296 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2297 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2298 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2299 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2300 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2301 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2302 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2303 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2304 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2305 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2306 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2307 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2308 LTTV_STATE_EVENT
= g_quark_from_string("event");
2309 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2310 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2311 LTTV_STATE_TIME
= g_quark_from_string("time");
2312 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2313 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2314 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2315 g_quark_from_string("trace_state_use_count");
2318 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2319 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2320 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2321 LTT_FACILITY_FS
= g_quark_from_string("fs");
2322 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2325 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2326 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2327 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2328 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2329 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2330 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2331 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2332 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2333 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2334 LTT_EVENT_FORK
= g_quark_from_string("fork");
2335 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2336 LTT_EVENT_FREE
= g_quark_from_string("free");
2337 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2338 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2341 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2342 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2343 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2344 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2345 LTT_FIELD_OUT
= g_quark_from_string("out");
2346 LTT_FIELD_IN
= g_quark_from_string("in");
2347 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2348 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2349 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2350 LTT_FIELD_PID
= g_quark_from_string("pid");
2351 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2352 LTT_FIELD_NAME
= g_quark_from_string("name");
2353 LTT_FIELD_MODE
= g_quark_from_string("mode");
2354 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2355 LTT_FIELD_STATUS
= g_quark_from_string("status");
2359 static void module_destroy()
2364 LTTV_MODULE("state", "State computation", \
2365 "Update the system state, possibly saving it at intervals", \
2366 module_init
, module_destroy
)