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
,
43 LTT_FACILITY_USER_GENERIC
;
48 LTT_EVENT_SYSCALL_ENTRY
,
49 LTT_EVENT_SYSCALL_EXIT
,
54 LTT_EVENT_SOFT_IRQ_ENTRY
,
55 LTT_EVENT_SOFT_IRQ_EXIT
,
56 LTT_EVENT_SCHEDCHANGE
,
58 LTT_EVENT_KERNEL_THREAD
,
62 LTT_EVENT_ENUM_PROCESS_STATE
,
63 LTT_EVENT_FUNCTION_ENTRY
,
64 LTT_EVENT_FUNCTION_EXIT
;
72 LTT_FIELD_SOFT_IRQ_ID
,
89 LTTV_STATE_MODE_UNKNOWN
,
97 LTTV_STATE_SUBMODE_UNKNOWN
,
98 LTTV_STATE_SUBMODE_NONE
;
102 LTTV_STATE_WAIT_FORK
,
111 LTTV_STATE_USER_THREAD
,
112 LTTV_STATE_KERNEL_THREAD
;
115 LTTV_STATE_TRACEFILES
,
116 LTTV_STATE_PROCESSES
,
118 LTTV_STATE_RUNNING_PROCESS
,
120 LTTV_STATE_SAVED_STATES
,
121 LTTV_STATE_SAVED_STATES_TIME
,
124 LTTV_STATE_NAME_TABLES
,
125 LTTV_STATE_TRACE_STATE_USE_COUNT
;
127 static void create_max_time(LttvTraceState
*tcs
);
129 static void get_max_time(LttvTraceState
*tcs
);
131 static void free_max_time(LttvTraceState
*tcs
);
133 static void create_name_tables(LttvTraceState
*tcs
);
135 static void get_name_tables(LttvTraceState
*tcs
);
137 static void free_name_tables(LttvTraceState
*tcs
);
139 static void free_saved_state(LttvTraceState
*tcs
);
141 static void lttv_state_free_process_table(GHashTable
*processes
);
144 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
146 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
150 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
152 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
156 void lttv_state_state_saved_free(LttvTraceState
*self
,
157 LttvAttribute
*container
)
159 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
163 guint
process_hash(gconstpointer key
)
165 guint pid
= ((const LttvProcessState
*)key
)->pid
;
166 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
170 /* If the hash table hash function is well distributed,
171 * the process_equal should compare different pid */
172 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
174 const LttvProcessState
*process_a
, *process_b
;
177 process_a
= (const LttvProcessState
*)a
;
178 process_b
= (const LttvProcessState
*)b
;
180 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
181 else if(likely(process_a
->pid
== 0 &&
182 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
187 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
189 g_tree_destroy((GTree
*)value
);
192 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
194 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
195 g_hash_table_destroy(usertraces
);
201 restore_init_state(LttvTraceState
*self
)
205 LttvTracefileState
*tfcs
;
207 /* Free the process tables */
208 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
209 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
210 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
211 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
214 /* Seek time to beginning */
215 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
216 // closest. It's the tracecontext job to seek the trace to the beginning
217 // anyway : the init state might be used at the middle of the trace as well...
218 //g_tree_destroy(self->parent.ts_context->pqueue);
219 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
222 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
224 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
226 /* Put the per cpu running_process to beginning state : process 0. */
227 for(i
=0; i
< nb_cpus
; i
++) {
228 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
229 LTTV_STATE_UNNAMED
, <t_time_zero
);
230 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
231 self
->running_process
[i
]->cpu
= i
;
235 nb_tracefile
= self
->parent
.tracefiles
->len
;
237 for(i
= 0 ; i
< nb_tracefile
; i
++) {
239 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
240 LttvTracefileContext
*, i
));
241 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
242 // tfcs->saved_position = 0;
243 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
244 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
245 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
246 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
251 //static LttTime time_zero = {0,0};
253 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
256 const LttTime
*t1
= (const LttTime
*)a
;
257 const LttTime
*t2
= (const LttTime
*)b
;
259 return ltt_time_compare(*t1
, *t2
);
262 static void free_usertrace_key(gpointer data
)
268 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
270 guint i
, j
, nb_trace
, nb_tracefile
;
272 LttvTraceContext
*tc
;
276 LttvTracefileState
*tfcs
;
278 LttvAttributeValue v
;
280 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
281 init((LttvTracesetContext
*)self
, ts
);
283 nb_trace
= lttv_traceset_number(ts
);
284 for(i
= 0 ; i
< nb_trace
; i
++) {
285 tc
= self
->parent
.traces
[i
];
286 tcs
= LTTV_TRACE_STATE(tc
);
287 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
288 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
292 if(*(v
.v_uint
) == 1) {
293 create_name_tables(tcs
);
294 create_max_time(tcs
);
296 get_name_tables(tcs
);
299 nb_tracefile
= tc
->tracefiles
->len
;
300 tcs
->processes
= NULL
;
301 tcs
->usertraces
= NULL
;
302 tcs
->running_process
= g_new(LttvProcessState
*,
303 ltt_trace_get_num_cpu(tc
->t
));
304 restore_init_state(tcs
);
305 for(j
= 0 ; j
< nb_tracefile
; j
++) {
307 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
308 LttvTracefileContext
*, j
));
309 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
310 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
312 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
313 /* It's a Usertrace */
314 LttvProcessState
*process
;
316 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
317 ltt_tracefile_creation(tfcs
->parent
.tf
));
318 process
= lttv_state_find_process_or_create(
320 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
322 process
->usertrace
= tfcs
;
326 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
327 /* It's a Usertrace */
328 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
329 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
331 if(!usertrace_tree
) {
332 usertrace_tree
= g_tree_new_full(compare_usertraces
,
333 NULL
, free_usertrace_key
, NULL
);
334 g_hash_table_insert(tcs
->usertraces
,
335 (gpointer
)tid
, usertrace_tree
);
337 LttTime
*timestamp
= g_new(LttTime
, 1);
338 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
339 ltt_tracefile_creation(tfcs
->parent
.tf
));
340 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
348 fini(LttvTracesetState
*self
)
354 LttvTracefileState
*tfcs
;
356 LttvAttributeValue v
;
358 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
359 for(i
= 0 ; i
< nb_trace
; i
++) {
360 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
361 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
364 g_assert(*(v
.v_uint
) != 0);
367 if(*(v
.v_uint
) == 0) {
368 free_name_tables(tcs
);
370 free_saved_state(tcs
);
372 g_free(tcs
->running_process
);
373 tcs
->running_process
= NULL
;
374 lttv_state_free_process_table(tcs
->processes
);
375 lttv_state_free_usertraces(tcs
->usertraces
);
376 tcs
->processes
= NULL
;
377 tcs
->usertraces
= NULL
;
379 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
380 fini((LttvTracesetContext
*)self
);
384 static LttvTracesetContext
*
385 new_traceset_context(LttvTracesetContext
*self
)
387 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
391 static LttvTraceContext
*
392 new_trace_context(LttvTracesetContext
*self
)
394 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
398 static LttvTracefileContext
*
399 new_tracefile_context(LttvTracesetContext
*self
)
401 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
405 /* Write the process state of the trace */
407 static void write_process_state(gpointer key
, gpointer value
,
410 LttvProcessState
*process
;
412 LttvExecutionState
*es
;
414 FILE *fp
= (FILE *)user_data
;
418 process
= (LttvProcessState
*)value
;
420 " <PROCESS CORE=%p PID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
421 process
, process
->pid
, process
->ppid
, g_quark_to_string(process
->type
),
422 process
->creation_time
.tv_sec
,
423 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
426 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
427 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
428 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
429 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
430 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
431 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
432 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
434 fprintf(fp
, " </PROCESS>\n");
438 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
440 guint i
, nb_tracefile
, nb_block
, offset
;
443 LttvTracefileState
*tfcs
;
447 LttEventPosition
*ep
;
451 ep
= ltt_event_position_new();
453 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
455 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
457 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
458 for(i
=0;i
<nb_cpus
;i
++) {
459 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
460 i
, self
->running_process
[i
]->pid
);
463 nb_tracefile
= self
->parent
.tracefiles
->len
;
465 for(i
= 0 ; i
< nb_tracefile
; i
++) {
467 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
468 LttvTracefileContext
*, i
));
469 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
470 tfcs
->parent
.timestamp
.tv_sec
,
471 tfcs
->parent
.timestamp
.tv_nsec
);
472 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
473 if(e
== NULL
) fprintf(fp
,"/>\n");
475 ltt_event_position(e
, ep
);
476 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
477 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
482 fprintf(fp
,"</PROCESS_STATE>");
486 /* Copy each process from an existing hash table to a new one */
488 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
490 LttvProcessState
*process
, *new_process
;
492 GHashTable
*new_processes
= (GHashTable
*)user_data
;
496 process
= (LttvProcessState
*)value
;
497 new_process
= g_new(LttvProcessState
, 1);
498 *new_process
= *process
;
499 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
500 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
501 new_process
->execution_stack
=
502 g_array_set_size(new_process
->execution_stack
,
503 process
->execution_stack
->len
);
504 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
505 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
506 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
508 new_process
->state
= &g_array_index(new_process
->execution_stack
,
509 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
510 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
512 new_process
->user_stack
=
513 g_array_set_size(new_process
->user_stack
,
514 process
->user_stack
->len
);
515 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
516 g_array_index(new_process
->user_stack
, guint64
, i
) =
517 g_array_index(process
->user_stack
, guint64
, i
);
519 new_process
->current_function
= process
->current_function
;
520 g_hash_table_insert(new_processes
, new_process
, new_process
);
524 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
526 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
528 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
529 return new_processes
;
533 /* The saved state for each trace contains a member "processes", which
534 stores a copy of the process table, and a member "tracefiles" with
535 one entry per tracefile. Each tracefile has a "process" member pointing
536 to the current process and a "position" member storing the tracefile
537 position (needed to seek to the current "next" event. */
539 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
541 guint i
, nb_tracefile
, nb_cpus
;
543 LttvTracefileState
*tfcs
;
545 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
547 guint
*running_process
;
549 LttvAttributeType type
;
551 LttvAttributeValue value
;
553 LttvAttributeName name
;
555 LttEventPosition
*ep
;
557 tracefiles_tree
= lttv_attribute_find_subdir(container
,
558 LTTV_STATE_TRACEFILES
);
560 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
562 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
564 /* Add the currently running processes array */
565 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
566 running_process
= g_new(guint
, nb_cpus
);
567 for(i
=0;i
<nb_cpus
;i
++) {
568 running_process
[i
] = self
->running_process
[i
]->pid
;
570 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
572 *(value
.v_pointer
) = running_process
;
574 g_info("State save");
576 nb_tracefile
= self
->parent
.tracefiles
->len
;
578 for(i
= 0 ; i
< nb_tracefile
; i
++) {
580 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
581 LttvTracefileContext
*, i
));
582 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
583 value
= lttv_attribute_add(tracefiles_tree
, i
,
585 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
587 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
589 *(value
.v_uint
) = tfcs
->process
->pid
;
591 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
593 /* Only save the position if the tfs has not infinite time. */
594 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
595 // && current_tfcs != tfcs) {
596 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
597 *(value
.v_pointer
) = NULL
;
599 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
600 ep
= ltt_event_position_new();
601 ltt_event_position(e
, ep
);
602 *(value
.v_pointer
) = ep
;
604 guint nb_block
, offset
;
607 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
608 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
610 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
616 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
618 guint i
, nb_tracefile
, pid
, nb_cpus
;
620 LttvTracefileState
*tfcs
;
622 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
624 guint
*running_process
;
626 LttvAttributeType type
;
628 LttvAttributeValue value
;
630 LttvAttributeName name
;
634 LttEventPosition
*ep
;
636 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
638 tracefiles_tree
= lttv_attribute_find_subdir(container
,
639 LTTV_STATE_TRACEFILES
);
641 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
643 g_assert(type
== LTTV_POINTER
);
644 lttv_state_free_process_table(self
->processes
);
645 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
647 /* Add the currently 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 for(i
=0;i
<nb_cpus
;i
++) {
654 pid
= running_process
[i
];
655 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
656 g_assert(self
->running_process
[i
] != NULL
);
660 nb_tracefile
= self
->parent
.tracefiles
->len
;
662 //g_tree_destroy(tsc->pqueue);
663 //tsc->pqueue = g_tree_new(compare_tracefile);
665 for(i
= 0 ; i
< nb_tracefile
; i
++) {
667 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
668 LttvTracefileContext
*, i
));
669 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
670 g_assert(type
== LTTV_GOBJECT
);
671 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
673 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
675 g_assert(type
== LTTV_UINT
);
676 pid
= *(value
.v_uint
);
677 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
679 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
681 g_assert(type
== LTTV_POINTER
);
682 //g_assert(*(value.v_pointer) != NULL);
683 ep
= *(value
.v_pointer
);
684 g_assert(tfcs
->parent
.t_context
!= NULL
);
686 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
687 g_tree_remove(tsc
->pqueue
, tfc
);
690 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
691 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
692 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
693 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
694 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
696 tfc
->timestamp
= ltt_time_infinite
;
702 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
704 guint i
, nb_tracefile
, nb_cpus
;
706 LttvTracefileState
*tfcs
;
708 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
710 guint
*running_process
;
712 LttvAttributeType type
;
714 LttvAttributeValue value
;
716 LttvAttributeName name
;
720 LttEventPosition
*ep
;
722 tracefiles_tree
= lttv_attribute_find_subdir(container
,
723 LTTV_STATE_TRACEFILES
);
724 g_object_ref(G_OBJECT(tracefiles_tree
));
725 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
727 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
729 g_assert(type
== LTTV_POINTER
);
730 lttv_state_free_process_table(*(value
.v_pointer
));
731 *(value
.v_pointer
) = NULL
;
732 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
734 /* Free running processes array */
735 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
736 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
738 g_assert(type
== LTTV_POINTER
);
739 running_process
= *(value
.v_pointer
);
740 g_free(running_process
);
742 nb_tracefile
= self
->parent
.tracefiles
->len
;
744 for(i
= 0 ; i
< nb_tracefile
; i
++) {
746 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
747 LttvTracefileContext
*, i
));
748 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
749 g_assert(type
== LTTV_GOBJECT
);
750 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
752 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
754 g_assert(type
== LTTV_POINTER
);
755 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
757 g_object_unref(G_OBJECT(tracefiles_tree
));
761 static void free_saved_state(LttvTraceState
*self
)
765 LttvAttributeType type
;
767 LttvAttributeValue value
;
769 LttvAttributeName name
;
773 LttvAttribute
*saved_states
;
775 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
776 LTTV_STATE_SAVED_STATES
);
778 nb
= lttv_attribute_get_number(saved_states
);
779 for(i
= 0 ; i
< nb
; i
++) {
780 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
781 g_assert(type
== LTTV_GOBJECT
);
782 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
785 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
790 create_max_time(LttvTraceState
*tcs
)
792 LttvAttributeValue v
;
794 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
796 g_assert(*(v
.v_pointer
) == NULL
);
797 *(v
.v_pointer
) = g_new(LttTime
,1);
798 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
803 get_max_time(LttvTraceState
*tcs
)
805 LttvAttributeValue v
;
807 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
809 g_assert(*(v
.v_pointer
) != NULL
);
810 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
815 free_max_time(LttvTraceState
*tcs
)
817 LttvAttributeValue v
;
819 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
821 g_free(*(v
.v_pointer
));
822 *(v
.v_pointer
) = NULL
;
826 typedef struct _LttvNameTables
{
827 // FIXME GQuark *eventtype_names;
828 GQuark
*syscall_names
;
832 GQuark
*soft_irq_names
;
837 create_name_tables(LttvTraceState
*tcs
)
841 GQuark f_name
, e_name
;
845 LttvTraceHookByFacility
*thf
;
851 GString
*fe_name
= g_string_new("");
853 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
855 LttvAttributeValue v
;
857 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
859 g_assert(*(v
.v_pointer
) == NULL
);
860 *(v
.v_pointer
) = name_tables
;
861 #if 0 // Use iteration over the facilities_by_name and then list all event
862 // types of each facility
863 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
864 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
865 for(i
= 0 ; i
< nb
; i
++) {
866 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
867 e_name
= ltt_eventtype_name(et
);
868 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
869 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
870 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
873 if(!lttv_trace_find_hook(tcs
->parent
.t
,
874 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
875 LTT_FIELD_SYSCALL_ID
, 0, 0,
878 thf
= lttv_trace_hook_get_first(&h
);
880 t
= ltt_field_type(thf
->f1
);
881 nb
= ltt_type_element_number(t
);
883 lttv_trace_hook_destroy(&h
);
885 name_tables
->syscall_names
= g_new(GQuark
, nb
);
886 name_tables
->nb_syscalls
= nb
;
888 for(i
= 0 ; i
< nb
; i
++) {
889 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
892 //name_tables->syscall_names = g_new(GQuark, 256);
893 //for(i = 0 ; i < 256 ; i++) {
894 // g_string_printf(fe_name, "syscall %d", i);
895 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
898 name_tables
->syscall_names
= NULL
;
899 name_tables
->nb_syscalls
= 0;
902 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
903 LTT_EVENT_TRAP_ENTRY
,
904 LTT_FIELD_TRAP_ID
, 0, 0,
907 thf
= lttv_trace_hook_get_first(&h
);
909 t
= ltt_field_type(thf
->f1
);
910 //nb = ltt_type_element_number(t);
912 lttv_trace_hook_destroy(&h
);
915 name_tables->trap_names = g_new(GQuark, nb);
916 for(i = 0 ; i < nb ; i++) {
917 name_tables->trap_names[i] = g_quark_from_string(
918 ltt_enum_string_get(t, i));
922 name_tables
->trap_names
= g_new(GQuark
, 256);
923 for(i
= 0 ; i
< 256 ; i
++) {
924 g_string_printf(fe_name
, "trap %d", i
);
925 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
928 name_tables
->trap_names
= NULL
;
931 if(!lttv_trace_find_hook(tcs
->parent
.t
,
932 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
933 LTT_FIELD_IRQ_ID
, 0, 0,
936 thf
= lttv_trace_hook_get_first(&h
);
938 t
= ltt_field_type(thf
->f1
);
939 //nb = ltt_type_element_number(t);
941 lttv_trace_hook_destroy(&h
);
944 name_tables->irq_names = g_new(GQuark, nb);
945 for(i = 0 ; i < nb ; i++) {
946 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
950 name_tables
->irq_names
= g_new(GQuark
, 256);
951 for(i
= 0 ; i
< 256 ; i
++) {
952 g_string_printf(fe_name
, "irq %d", i
);
953 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
956 name_tables
->irq_names
= NULL
;
959 name_tables->soft_irq_names = g_new(GQuark, nb);
960 for(i = 0 ; i < nb ; i++) {
961 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
965 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
966 for(i
= 0 ; i
< 256 ; i
++) {
967 g_string_printf(fe_name
, "softirq %d", i
);
968 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
972 g_string_free(fe_name
, TRUE
);
977 get_name_tables(LttvTraceState
*tcs
)
979 LttvNameTables
*name_tables
;
981 LttvAttributeValue v
;
983 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
985 g_assert(*(v
.v_pointer
) != NULL
);
986 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
987 //tcs->eventtype_names = name_tables->eventtype_names;
988 tcs
->syscall_names
= name_tables
->syscall_names
;
989 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
990 tcs
->trap_names
= name_tables
->trap_names
;
991 tcs
->irq_names
= name_tables
->irq_names
;
992 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
997 free_name_tables(LttvTraceState
*tcs
)
999 LttvNameTables
*name_tables
;
1001 LttvAttributeValue v
;
1003 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1005 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1006 *(v
.v_pointer
) = NULL
;
1008 // g_free(name_tables->eventtype_names);
1009 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1010 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1011 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1012 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1013 if(name_tables
) g_free(name_tables
);
1016 #ifdef HASH_TABLE_DEBUG
1018 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1020 LttvProcessState
*process
= (LttvProcessState
*)value
;
1022 /* Test for process corruption */
1023 guint stack_len
= process
->execution_stack
->len
;
1026 static void hash_table_check(GHashTable
*table
)
1028 g_hash_table_foreach(table
, test_process
, NULL
);
1035 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1038 LttvExecutionState
*es
;
1040 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1041 guint cpu
= tfs
->cpu
;
1043 #ifdef HASH_TABLE_DEBUG
1044 hash_table_check(ts
->processes
);
1046 LttvProcessState
*process
= ts
->running_process
[cpu
];
1048 guint depth
= process
->execution_stack
->len
;
1050 process
->execution_stack
=
1051 g_array_set_size(process
->execution_stack
, depth
+ 1);
1054 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1056 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1059 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1060 es
->cum_cpu_time
= ltt_time_zero
;
1061 es
->s
= process
->state
->s
;
1062 process
->state
= es
;
1066 * return 1 when empty, else 0 */
1067 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1068 LttvTracefileState
*tfs
)
1070 guint cpu
= tfs
->cpu
;
1071 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1073 guint depth
= process
->execution_stack
->len
;
1079 process
->execution_stack
=
1080 g_array_set_size(process
->execution_stack
, depth
- 1);
1081 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1083 process
->state
->change
= tfs
->parent
.timestamp
;
1088 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1090 guint cpu
= tfs
->cpu
;
1091 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1092 LttvProcessState
*process
= ts
->running_process
[cpu
];
1094 guint depth
= process
->execution_stack
->len
;
1096 if(process
->state
->t
!= t
){
1097 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1098 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1099 g_info("process state has %s when pop_int is %s\n",
1100 g_quark_to_string(process
->state
->t
),
1101 g_quark_to_string(t
));
1102 g_info("{ %u, %u, %s, %s }\n",
1105 g_quark_to_string(process
->name
),
1106 g_quark_to_string(process
->state
->s
));
1111 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1112 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1116 process
->execution_stack
=
1117 g_array_set_size(process
->execution_stack
, depth
- 1);
1118 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1120 process
->state
->change
= tfs
->parent
.timestamp
;
1123 struct search_result
{
1124 const LttTime
*time
; /* Requested time */
1125 LttTime
*best
; /* Best result */
1128 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1130 const LttTime
*elem_time
= (const LttTime
*)a
;
1131 /* Explicit non const cast */
1132 struct search_result
*res
= (struct search_result
*)b
;
1134 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1135 /* The usertrace was created before the schedchange */
1136 /* Get larger keys */
1138 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1139 /* The usertrace was created after the schedchange time */
1140 /* Get smaller keys */
1142 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1143 res
->best
= elem_time
;
1146 res
->best
= elem_time
;
1153 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1154 guint pid
, const LttTime
*timestamp
)
1156 LttvTracefileState
*tfs
= NULL
;
1157 struct search_result res
;
1158 /* Find the usertrace associated with a pid and time interval.
1159 * Search in the usertraces by PID (within a hash) and then, for each
1160 * corresponding element of the array, find the first one with creation
1161 * timestamp the lowest, but higher or equal to "timestamp". */
1162 res
.time
= timestamp
;
1164 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1165 if(usertrace_tree
) {
1166 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1168 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1176 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1177 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1179 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1181 LttvExecutionState
*es
;
1183 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1189 process
->name
= name
;
1190 //process->last_cpu = tfs->cpu_name;
1191 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1192 process
->type
= LTTV_STATE_USER_THREAD
;
1193 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1194 process
->current_function
= 0; //function 0x0 by default.
1196 g_info("Process %u, core %p", process
->pid
, process
);
1197 g_hash_table_insert(tcs
->processes
, process
, process
);
1200 process
->ppid
= parent
->pid
;
1201 process
->creation_time
= *timestamp
;
1204 /* No parent. This process exists but we are missing all information about
1205 its creation. The birth time is set to zero but we remember the time of
1210 process
->creation_time
= ltt_time_zero
;
1213 process
->insertion_time
= *timestamp
;
1214 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1215 process
->creation_time
.tv_nsec
);
1216 process
->pid_time
= g_quark_from_string(buffer
);
1218 //process->last_cpu = tfs->cpu_name;
1219 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1220 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1221 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1222 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1223 es
= process
->state
= &g_array_index(process
->execution_stack
,
1224 LttvExecutionState
, 0);
1225 es
->t
= LTTV_STATE_USER_MODE
;
1226 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1227 es
->entry
= *timestamp
;
1228 //g_assert(timestamp->tv_sec != 0);
1229 es
->change
= *timestamp
;
1230 es
->cum_cpu_time
= ltt_time_zero
;
1231 es
->s
= LTTV_STATE_RUN
;
1233 es
= process
->state
= &g_array_index(process
->execution_stack
,
1234 LttvExecutionState
, 1);
1235 es
->t
= LTTV_STATE_SYSCALL
;
1236 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1237 es
->entry
= *timestamp
;
1238 //g_assert(timestamp->tv_sec != 0);
1239 es
->change
= *timestamp
;
1240 es
->cum_cpu_time
= ltt_time_zero
;
1241 es
->s
= LTTV_STATE_WAIT_FORK
;
1243 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1244 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1245 sizeof(guint64
), 0);
1250 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1253 LttvProcessState key
;
1254 LttvProcessState
*process
;
1258 process
= g_hash_table_lookup(ts
->processes
, &key
);
1263 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1266 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1267 LttvExecutionState
*es
;
1269 /* Put ltt_time_zero creation time for unexisting processes */
1270 if(unlikely(process
== NULL
)) {
1271 process
= lttv_state_create_process(ts
,
1272 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1273 /* We are not sure is it's a kernel thread or normal thread, put the
1274 * bottom stack state to unknown */
1275 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1276 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1281 /* FIXME : this function should be called when we receive an event telling that
1282 * release_task has been called in the kernel. In happens generally when
1283 * the parent waits for its child terminaison, but may also happen in special
1284 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1285 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1286 * of a killed thread ground, but isn't the leader.
1288 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1290 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1291 LttvProcessState key
;
1293 key
.pid
= process
->pid
;
1294 key
.cpu
= process
->cpu
;
1295 g_hash_table_remove(ts
->processes
, &key
);
1296 g_array_free(process
->execution_stack
, TRUE
);
1297 g_array_free(process
->user_stack
, TRUE
);
1302 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1304 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1305 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1310 static void lttv_state_free_process_table(GHashTable
*processes
)
1312 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1313 g_hash_table_destroy(processes
);
1317 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1319 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1320 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1321 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1322 LttField
*f
= thf
->f1
;
1324 LttvExecutionSubmode submode
;
1326 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1327 guint syscall
= ltt_event_get_unsigned(e
, f
);
1329 if(syscall
< nb_syscalls
) {
1330 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1333 /* Fixup an incomplete syscall table */
1334 GString
*string
= g_string_new("");
1335 g_string_printf(string
, "syscall %u", syscall
);
1336 submode
= g_quark_from_string(string
->str
);
1337 g_string_free(string
, TRUE
);
1339 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1344 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1346 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1348 pop_state(s
, LTTV_STATE_SYSCALL
);
1353 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1355 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1356 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1357 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1358 LttField
*f
= thf
->f1
;
1360 LttvExecutionSubmode submode
;
1362 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[
1363 ltt_event_get_unsigned(e
, f
)];
1364 push_state(s
, LTTV_STATE_TRAP
, submode
);
1369 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1371 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1373 pop_state(s
, LTTV_STATE_TRAP
);
1378 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1380 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1381 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1382 guint8 fac_id
= ltt_event_facility_id(e
);
1383 guint8 ev_id
= ltt_event_eventtype_id(e
);
1384 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1385 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1386 g_assert(thf
->f1
!= NULL
);
1387 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1388 LttField
*f
= thf
->f1
;
1390 LttvExecutionSubmode submode
;
1392 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1393 ltt_event_get_unsigned(e
, f
)];
1395 /* Do something with the info about being in user or system mode when int? */
1396 push_state(s
, LTTV_STATE_IRQ
, submode
);
1400 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1402 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1404 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1410 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1412 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1414 pop_state(s
, LTTV_STATE_IRQ
);
1418 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1420 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1421 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1422 guint8 fac_id
= ltt_event_facility_id(e
);
1423 guint8 ev_id
= ltt_event_eventtype_id(e
);
1424 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1425 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1426 g_assert(thf
->f1
!= NULL
);
1427 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1428 LttField
*f
= thf
->f1
;
1430 LttvExecutionSubmode submode
;
1432 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1433 ltt_event_get_unsigned(e
, f
)];
1435 /* Do something with the info about being in user or system mode when int? */
1436 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1440 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1444 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1445 guint cpu
= tfs
->cpu
;
1446 LttvProcessState
*process
= ts
->running_process
[cpu
];
1448 guint depth
= process
->user_stack
->len
;
1450 process
->user_stack
=
1451 g_array_set_size(process
->user_stack
, depth
+ 1);
1453 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1454 *new_func
= funcptr
;
1455 process
->current_function
= funcptr
;
1458 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1460 guint cpu
= tfs
->cpu
;
1461 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1462 LttvProcessState
*process
= ts
->running_process
[cpu
];
1464 if(process
->current_function
!= funcptr
){
1465 g_info("Different functions (%lu.%09lu): ignore it\n",
1466 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1467 g_info("process state has %llu when pop_function is %llu\n",
1468 process
->current_function
, funcptr
);
1469 g_info("{ %u, %u, %s, %s }\n",
1472 g_quark_to_string(process
->name
),
1473 g_quark_to_string(process
->state
->s
));
1476 guint depth
= process
->user_stack
->len
;
1479 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1480 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1484 process
->user_stack
=
1485 g_array_set_size(process
->user_stack
, depth
- 1);
1486 process
->current_function
=
1487 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1491 static gboolean
function_entry(void *hook_data
, void *call_data
)
1493 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1494 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1495 guint8 fac_id
= ltt_event_facility_id(e
);
1496 guint8 ev_id
= ltt_event_eventtype_id(e
);
1497 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1498 g_assert(thf
->f1
!= NULL
);
1499 LttField
*f
= thf
->f1
;
1500 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1502 push_function(s
, funcptr
);
1506 static gboolean
function_exit(void *hook_data
, void *call_data
)
1508 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1509 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1510 guint8 fac_id
= ltt_event_facility_id(e
);
1511 guint8 ev_id
= ltt_event_eventtype_id(e
);
1512 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1513 g_assert(thf
->f1
!= NULL
);
1514 LttField
*f
= thf
->f1
;
1515 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1517 LttvExecutionSubmode submode
;
1519 pop_function(s
, funcptr
);
1523 static gboolean
schedchange(void *hook_data
, void *call_data
)
1525 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1527 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1528 LttvProcessState
*process
= ts
->running_process
[cpu
];
1529 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1531 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1532 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1533 guint pid_in
, pid_out
;
1536 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1537 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1538 state_out
= ltt_event_get_int(e
, thf
->f3
);
1540 if(likely(process
!= NULL
)) {
1542 /* We could not know but it was not the idle process executing.
1543 This should only happen at the beginning, before the first schedule
1544 event, and when the initial information (current process for each CPU)
1545 is missing. It is not obvious how we could, after the fact, compensate
1546 the wrongly attributed statistics. */
1548 //This test only makes sense once the state is known and if there is no
1549 //missing events. We need to silently ignore schedchange coming after a
1550 //process_free, or it causes glitches. (FIXME)
1551 //if(unlikely(process->pid != pid_out)) {
1552 // g_assert(process->pid == 0);
1555 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1556 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1557 process
->state
->change
= s
->parent
.timestamp
;
1559 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1560 else process
->state
->s
= LTTV_STATE_WAIT
;
1561 process
->state
->change
= s
->parent
.timestamp
;
1565 exit_process(s
, process
); /* EXIT_DEAD */
1566 /* see sched.h for states */
1568 process
= ts
->running_process
[cpu
] =
1569 lttv_state_find_process_or_create(
1570 (LttvTraceState
*)s
->parent
.t_context
,
1572 &s
->parent
.timestamp
);
1573 process
->state
->s
= LTTV_STATE_RUN
;
1575 if(process
->usertrace
)
1576 process
->usertrace
->cpu
= cpu
;
1577 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1578 process
->state
->change
= s
->parent
.timestamp
;
1582 static gboolean
process_fork(void *hook_data
, void *call_data
)
1584 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1585 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1586 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1589 LttvProcessState
*zombie_process
;
1591 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1592 LttvProcessState
*process
= ts
->running_process
[cpu
];
1593 LttvProcessState
*child_process
;
1596 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1599 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1601 /* Mathieu : it seems like the process might have been scheduled in before the
1602 * fork, and, in a rare case, might be the current process. This might happen
1603 * in a SMP case where we don't have enough precision on the clocks.
1605 * Test reenabled after precision fixes on time. (Mathieu) */
1607 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1609 if(unlikely(zombie_process
!= NULL
)) {
1610 /* Reutilisation of PID. Only now we are sure that the old PID
1611 * has been released. FIXME : should know when release_task happens instead.
1613 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1615 for(i
=0; i
< num_cpus
; i
++) {
1616 g_assert(zombie_process
!= ts
->running_process
[i
]);
1619 exit_process(s
, zombie_process
);
1622 g_assert(process
->pid
!= child_pid
);
1623 // FIXME : Add this test in the "known state" section
1624 // g_assert(process->pid == parent_pid);
1625 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1626 if(child_process
== NULL
) {
1627 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1628 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1630 /* The process has already been created : due to time imprecision between
1631 * multiple CPUs : it has been scheduled in before creation. Note that we
1632 * shouldn't have this kind of imprecision.
1634 * Simply put a correct parent.
1636 g_assert(0); /* This is a problematic case : the process has been created
1637 before the fork event */
1638 child_process
->ppid
= process
->pid
;
1640 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1641 child_process
->name
= process
->name
;
1646 /* We stamp a newly created process as kernel_thread */
1647 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1649 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1650 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1651 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1654 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1655 LttvProcessState
*process
;
1656 LttvExecutionState
*es
;
1659 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1661 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1662 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1663 es
->t
= LTTV_STATE_SYSCALL
;
1664 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1669 static gboolean
process_exit(void *hook_data
, void *call_data
)
1671 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1672 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1673 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1677 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1678 LttvProcessState
*process
= ts
->running_process
[cpu
];
1680 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1682 // FIXME : Add this test in the "known state" section
1683 // g_assert(process->pid == pid);
1685 if(likely(process
!= NULL
)) {
1686 process
->state
->s
= LTTV_STATE_EXIT
;
1691 static gboolean
process_free(void *hook_data
, void *call_data
)
1693 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1694 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1695 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1696 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1698 LttvProcessState
*process
;
1700 /* PID of the process to release */
1701 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1703 g_assert(release_pid
!= 0);
1705 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1707 if(likely(process
!= NULL
)) {
1708 /* release_task is happening at kernel level : we can now safely release
1709 * the data structure of the process */
1710 //This test is fun, though, as it may happen that
1711 //at time t : CPU 0 : process_free
1712 //at time t+150ns : CPU 1 : schedule out
1713 //Clearly due to time imprecision, we disable it. (Mathieu)
1714 //If this weird case happen, we have no choice but to put the
1715 //Currently running process on the cpu to 0.
1716 //I re-enable it following time precision fixes. (Mathieu)
1717 //Well, in the case where an process is freed by a process on another CPU
1718 //and still scheduled, it happens that this is the schedchange that will
1719 //drop the last reference count. Do not free it here!
1720 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1722 for(i
=0; i
< num_cpus
; i
++) {
1723 //g_assert(process != ts->running_process[i]);
1724 if(process
== ts
->running_process
[i
]) {
1725 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1729 //if(i == num_cpus) /* process is not scheduled */
1730 //exit_process(s, process); // do nothing : wait for the schedchange to
1731 //delete the process.
1738 static gboolean
process_exec(void *hook_data
, void *call_data
)
1740 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1741 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1742 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1743 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1746 LttvProcessState
*process
= ts
->running_process
[cpu
];
1748 /* PID of the process to release */
1749 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1750 //name = ltt_event_get_string(e, thf->f1);
1751 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1753 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1754 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1755 memcpy(null_term_name
, name_begin
, name_len
);
1756 null_term_name
[name_len
] = '\0';
1758 process
->name
= g_quark_from_string(null_term_name
);
1759 g_free(null_term_name
);
1763 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1765 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1766 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1767 //It's slow : optimise later by doing this before reading trace.
1768 LttEventType
*et
= ltt_event_eventtype(e
);
1770 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1775 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1776 LttvProcessState
*process
= ts
->running_process
[cpu
];
1777 LttvProcessState
*parent_process
;
1778 LttField
*f4
, *f5
, *f6
, *f7
;
1779 GQuark type
, mode
, submode
, status
;
1780 LttvExecutionState
*es
;
1783 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1786 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1789 command
= ltt_event_get_string(e
, thf
->f3
);
1792 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1793 type
= ltt_enum_string_get(ltt_field_type(f4
),
1794 ltt_event_get_unsigned(e
, f4
));
1797 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1798 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1799 ltt_event_get_unsigned(e
, f5
));
1802 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1803 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1804 ltt_event_get_unsigned(e
, f6
));
1807 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1808 status
= ltt_enum_string_get(ltt_field_type(f7
),
1809 ltt_event_get_unsigned(e
, f7
));
1811 /* The process might exist if a process was forked while performing the sate dump. */
1812 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1813 if(process
== NULL
) {
1814 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1815 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1816 pid
, g_quark_from_string(command
),
1817 &s
->parent
.timestamp
);
1819 /* Keep the stack bottom : a running user mode */
1820 /* Disabled because of inconsistencies in the current statedump states. */
1821 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1822 /* Only keep the bottom */
1823 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1824 es
= process
->state
= &g_array_index(process
->execution_stack
,
1825 LttvExecutionState
, 0);
1826 es
->t
= LTTV_STATE_SYSCALL
;
1830 /* On top of it : */
1831 es
= process
->state
= &g_array_index(process
->execution_stack
,
1832 LttvExecutionState
, 1);
1833 es
->t
= LTTV_STATE_USER_MODE
;
1840 es
= process
->state
= &g_array_index(process
->execution_stack
,
1841 LttvExecutionState
, 1);
1842 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1843 es
->s
= LTTV_STATE_UNNAMED
;
1844 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1848 /* The process has already been created :
1849 * Probably was forked while dumping the process state or
1850 * was simply scheduled in prior to get the state dump event.
1851 * We know for sure if it is a user space thread.
1853 process
->ppid
= parent_pid
;
1854 process
->name
= g_quark_from_string(command
);
1855 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1856 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1857 es
->t
= LTTV_STATE_USER_MODE
;
1858 /* Don't mess around with the stack, it will eventually become
1859 * ok after the end of state dump. */
1865 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1867 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1869 lttv_state_add_event_hooks(tss
);
1874 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1876 LttvTraceset
*traceset
= self
->parent
.ts
;
1878 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1882 LttvTracefileState
*tfs
;
1886 LttvTraceHookByFacility
*thf
;
1888 LttvTraceHook
*hook
;
1890 LttvAttributeValue val
;
1895 nb_trace
= lttv_traceset_number(traceset
);
1896 for(i
= 0 ; i
< nb_trace
; i
++) {
1897 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1899 /* Find the eventtype id for the following events and register the
1900 associated by id hooks. */
1902 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1903 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1906 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1907 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1908 LTT_FIELD_SYSCALL_ID
, 0, 0,
1909 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1912 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1913 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1915 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1918 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1919 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1920 LTT_FIELD_TRAP_ID
, 0, 0,
1921 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1924 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1925 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1927 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1930 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1931 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1932 LTT_FIELD_IRQ_ID
, 0, 0,
1933 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1936 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1937 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1939 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1942 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1943 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1944 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1945 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1948 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1949 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1951 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1954 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1955 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1956 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1957 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1960 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1961 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1962 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1963 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1966 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1967 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1968 LTT_FIELD_PID
, 0, 0,
1969 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1973 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1974 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1975 LTT_FIELD_PID
, 0, 0,
1976 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1979 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1980 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1981 LTT_FIELD_PID
, 0, 0,
1982 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1985 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1986 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
1987 LTT_FIELD_FILENAME
, 0, 0,
1988 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1991 /* statedump-related hooks */
1992 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1993 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
1994 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
1995 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1998 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1999 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2000 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2001 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2004 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2005 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2006 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2007 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2010 hooks
= g_array_set_size(hooks
, hn
);
2012 /* Add these hooks to each event_by_id hooks list */
2014 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2016 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2018 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2019 LttvTracefileContext
*, j
));
2021 for(k
= 0 ; k
< hooks
->len
; k
++) {
2022 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2023 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2024 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2026 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2033 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2034 *(val
.v_pointer
) = hooks
;
2038 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2040 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2042 lttv_state_remove_event_hooks(tss
);
2047 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2049 LttvTraceset
*traceset
= self
->parent
.ts
;
2051 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2055 LttvTracefileState
*tfs
;
2059 LttvTraceHook
*hook
;
2061 LttvTraceHookByFacility
*thf
;
2063 LttvAttributeValue val
;
2065 nb_trace
= lttv_traceset_number(traceset
);
2066 for(i
= 0 ; i
< nb_trace
; i
++) {
2067 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2068 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2069 hooks
= *(val
.v_pointer
);
2071 /* Remove these hooks from each event_by_id hooks list */
2073 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2075 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2077 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2078 LttvTracefileContext
*, j
));
2080 for(k
= 0 ; k
< hooks
->len
; k
++) {
2081 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2082 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2083 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2085 lttv_hooks_remove_data(
2086 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2092 for(k
= 0 ; k
< hooks
->len
; k
++)
2093 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2094 g_array_free(hooks
, TRUE
);
2098 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2100 guint
*event_count
= (guint
*)hook_data
;
2102 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2103 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2108 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2110 LttvTracefileState
*tfcs
;
2112 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2114 LttEventPosition
*ep
;
2120 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2122 LttvAttributeValue value
;
2124 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2125 LTTV_STATE_SAVED_STATES
);
2126 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2127 value
= lttv_attribute_add(saved_states_tree
,
2128 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2129 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2130 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2131 *(value
.v_time
) = self
->parent
.timestamp
;
2132 lttv_state_save(tcs
, saved_state_tree
);
2133 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2134 self
->parent
.timestamp
.tv_nsec
);
2136 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2141 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2143 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2145 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2150 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2158 static gboolean
block_start(void *hook_data
, void *call_data
)
2160 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2162 LttvTracefileState
*tfcs
;
2164 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2166 LttEventPosition
*ep
;
2168 guint i
, nb_block
, nb_event
, nb_tracefile
;
2172 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2174 LttvAttributeValue value
;
2176 ep
= ltt_event_position_new();
2178 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2180 /* Count the number of events added since the last block end in any
2183 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2185 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2186 LttvTracefileContext
, i
));
2187 ltt_event_position(tfcs
->parent
.e
, ep
);
2188 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2189 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2190 tfcs
->saved_position
= nb_event
;
2194 if(tcs
->nb_event
>= tcs
->save_interval
) {
2195 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2196 LTTV_STATE_SAVED_STATES
);
2197 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2198 value
= lttv_attribute_add(saved_states_tree
,
2199 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2200 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2201 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2202 *(value
.v_time
) = self
->parent
.timestamp
;
2203 lttv_state_save(tcs
, saved_state_tree
);
2205 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2206 self
->parent
.timestamp
.tv_nsec
);
2208 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2214 static gboolean
block_end(void *hook_data
, void *call_data
)
2216 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2218 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2222 LttEventPosition
*ep
;
2224 guint nb_block
, nb_event
;
2226 ep
= ltt_event_position_new();
2227 ltt_event_position(self
->parent
.e
, ep
);
2228 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2229 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2230 self
->saved_position
= 0;
2231 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2238 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2240 LttvTraceset
*traceset
= self
->parent
.ts
;
2242 guint i
, j
, nb_trace
, nb_tracefile
;
2246 LttvTracefileState
*tfs
;
2248 LttvTraceHook hook_start
, hook_end
;
2250 nb_trace
= lttv_traceset_number(traceset
);
2251 for(i
= 0 ; i
< nb_trace
; i
++) {
2252 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2254 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2255 NULL
, NULL
, block_start
, &hook_start
);
2256 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2257 NULL
, NULL
, block_end
, &hook_end
);
2259 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2261 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2263 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2264 LttvTracefileContext
, j
));
2265 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2266 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2267 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2268 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2274 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2276 LttvTraceset
*traceset
= self
->parent
.ts
;
2278 guint i
, j
, nb_trace
, nb_tracefile
;
2282 LttvTracefileState
*tfs
;
2285 nb_trace
= lttv_traceset_number(traceset
);
2286 for(i
= 0 ; i
< nb_trace
; i
++) {
2288 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2289 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2291 guint
*event_count
= g_new(guint
, 1);
2294 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2296 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2297 LttvTracefileContext
*, j
));
2298 lttv_hooks_add(tfs
->parent
.event
,
2299 state_save_event_hook
,
2306 lttv_process_traceset_begin(&self
->parent
,
2307 NULL
, NULL
, NULL
, NULL
, NULL
);
2311 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2313 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2315 lttv_state_save_add_event_hooks(tss
);
2322 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2324 LttvTraceset
*traceset
= self
->parent
.ts
;
2326 guint i
, j
, nb_trace
, nb_tracefile
;
2330 LttvTracefileState
*tfs
;
2332 LttvTraceHook hook_start
, hook_end
;
2334 nb_trace
= lttv_traceset_number(traceset
);
2335 for(i
= 0 ; i
< nb_trace
; i
++) {
2336 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2338 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2339 NULL
, NULL
, block_start
, &hook_start
);
2341 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2342 NULL
, NULL
, block_end
, &hook_end
);
2344 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2346 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2348 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2349 LttvTracefileContext
, j
));
2350 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2351 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2352 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2353 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2359 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2361 LttvTraceset
*traceset
= self
->parent
.ts
;
2363 guint i
, j
, nb_trace
, nb_tracefile
;
2367 LttvTracefileState
*tfs
;
2369 LttvHooks
*after_trace
= lttv_hooks_new();
2371 lttv_hooks_add(after_trace
,
2372 state_save_after_trace_hook
,
2377 lttv_process_traceset_end(&self
->parent
,
2378 NULL
, after_trace
, NULL
, NULL
, NULL
);
2380 lttv_hooks_destroy(after_trace
);
2382 nb_trace
= lttv_traceset_number(traceset
);
2383 for(i
= 0 ; i
< nb_trace
; i
++) {
2385 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2386 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2388 guint
*event_count
= NULL
;
2390 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2392 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2393 LttvTracefileContext
*, j
));
2394 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2395 state_save_event_hook
);
2397 if(event_count
) g_free(event_count
);
2401 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2403 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2405 lttv_state_save_remove_event_hooks(tss
);
2410 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2412 LttvTraceset
*traceset
= self
->parent
.ts
;
2416 int min_pos
, mid_pos
, max_pos
;
2418 guint call_rest
= 0;
2420 LttvTraceState
*tcs
;
2422 LttvAttributeValue value
;
2424 LttvAttributeType type
;
2426 LttvAttributeName name
;
2430 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2432 //g_tree_destroy(self->parent.pqueue);
2433 //self->parent.pqueue = g_tree_new(compare_tracefile);
2435 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2437 nb_trace
= lttv_traceset_number(traceset
);
2438 for(i
= 0 ; i
< nb_trace
; i
++) {
2439 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2441 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2442 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2443 LTTV_STATE_SAVED_STATES
);
2446 if(saved_states_tree
) {
2447 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2448 mid_pos
= max_pos
/ 2;
2449 while(min_pos
< max_pos
) {
2450 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2452 g_assert(type
== LTTV_GOBJECT
);
2453 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2454 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2456 g_assert(type
== LTTV_TIME
);
2457 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2459 closest_tree
= saved_state_tree
;
2461 else max_pos
= mid_pos
- 1;
2463 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2467 /* restore the closest earlier saved state */
2469 lttv_state_restore(tcs
, closest_tree
);
2473 /* There is no saved state, yet we want to have it. Restart at T0 */
2475 restore_init_state(tcs
);
2476 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2479 /* We want to seek quickly without restoring/updating the state */
2481 restore_init_state(tcs
);
2482 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2485 if(!call_rest
) g_info("NOT Calling restore");
2490 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2496 traceset_state_finalize (LttvTracesetState
*self
)
2498 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2499 finalize(G_OBJECT(self
));
2504 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2506 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2508 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2509 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2510 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2511 klass
->new_traceset_context
= new_traceset_context
;
2512 klass
->new_trace_context
= new_trace_context
;
2513 klass
->new_tracefile_context
= new_tracefile_context
;
2518 lttv_traceset_state_get_type(void)
2520 static GType type
= 0;
2522 static const GTypeInfo info
= {
2523 sizeof (LttvTracesetStateClass
),
2524 NULL
, /* base_init */
2525 NULL
, /* base_finalize */
2526 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2527 NULL
, /* class_finalize */
2528 NULL
, /* class_data */
2529 sizeof (LttvTracesetState
),
2530 0, /* n_preallocs */
2531 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2532 NULL
/* value handling */
2535 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2543 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2549 trace_state_finalize (LttvTraceState
*self
)
2551 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2552 finalize(G_OBJECT(self
));
2557 trace_state_class_init (LttvTraceStateClass
*klass
)
2559 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2561 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2562 klass
->state_save
= state_save
;
2563 klass
->state_restore
= state_restore
;
2564 klass
->state_saved_free
= state_saved_free
;
2569 lttv_trace_state_get_type(void)
2571 static GType type
= 0;
2573 static const GTypeInfo info
= {
2574 sizeof (LttvTraceStateClass
),
2575 NULL
, /* base_init */
2576 NULL
, /* base_finalize */
2577 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2578 NULL
, /* class_finalize */
2579 NULL
, /* class_data */
2580 sizeof (LttvTraceState
),
2581 0, /* n_preallocs */
2582 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2583 NULL
/* value handling */
2586 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2587 "LttvTraceStateType", &info
, 0);
2594 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2600 tracefile_state_finalize (LttvTracefileState
*self
)
2602 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2603 finalize(G_OBJECT(self
));
2608 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2610 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2612 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2617 lttv_tracefile_state_get_type(void)
2619 static GType type
= 0;
2621 static const GTypeInfo info
= {
2622 sizeof (LttvTracefileStateClass
),
2623 NULL
, /* base_init */
2624 NULL
, /* base_finalize */
2625 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2626 NULL
, /* class_finalize */
2627 NULL
, /* class_data */
2628 sizeof (LttvTracefileState
),
2629 0, /* n_preallocs */
2630 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2631 NULL
/* value handling */
2634 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2635 "LttvTracefileStateType", &info
, 0);
2641 static void module_init()
2643 LTTV_STATE_UNNAMED
= g_quark_from_string("unnamed");
2644 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2645 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2646 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2647 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2648 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2649 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2650 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2651 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2652 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2653 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2654 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2655 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2656 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2657 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2658 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2659 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2660 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2661 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2662 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2663 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2664 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2665 LTTV_STATE_EVENT
= g_quark_from_string("event");
2666 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2667 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2668 LTTV_STATE_TIME
= g_quark_from_string("time");
2669 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2670 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2671 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2672 g_quark_from_string("trace_state_use_count");
2675 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2676 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2677 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2678 LTT_FACILITY_FS
= g_quark_from_string("fs");
2679 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2680 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2683 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2684 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2685 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2686 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2687 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2688 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2689 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2690 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2691 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2692 LTT_EVENT_FORK
= g_quark_from_string("fork");
2693 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2694 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2695 LTT_EVENT_FREE
= g_quark_from_string("free");
2696 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2697 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2698 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2699 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2702 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2703 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2704 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2705 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2706 LTT_FIELD_OUT
= g_quark_from_string("out");
2707 LTT_FIELD_IN
= g_quark_from_string("in");
2708 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2709 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2710 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2711 LTT_FIELD_PID
= g_quark_from_string("pid");
2712 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2713 LTT_FIELD_NAME
= g_quark_from_string("name");
2714 LTT_FIELD_TYPE
= g_quark_from_string("type");
2715 LTT_FIELD_MODE
= g_quark_from_string("mode");
2716 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2717 LTT_FIELD_STATUS
= g_quark_from_string("status");
2718 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2719 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2723 static void module_destroy()
2728 LTTV_MODULE("state", "State computation", \
2729 "Update the system state, possibly saving it at intervals", \
2730 module_init
, module_destroy
)