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
;
833 GQuark
*soft_irq_names
;
838 create_name_tables(LttvTraceState
*tcs
)
842 GQuark f_name
, e_name
;
846 LttvTraceHookByFacility
*thf
;
852 GString
*fe_name
= g_string_new("");
854 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
856 LttvAttributeValue v
;
858 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
860 g_assert(*(v
.v_pointer
) == NULL
);
861 *(v
.v_pointer
) = name_tables
;
862 #if 0 // Use iteration over the facilities_by_name and then list all event
863 // types of each facility
864 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
865 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
866 for(i
= 0 ; i
< nb
; i
++) {
867 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
868 e_name
= ltt_eventtype_name(et
);
869 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
870 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
871 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
874 if(!lttv_trace_find_hook(tcs
->parent
.t
,
875 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
876 LTT_FIELD_SYSCALL_ID
, 0, 0,
879 thf
= lttv_trace_hook_get_first(&h
);
881 t
= ltt_field_type(thf
->f1
);
882 nb
= ltt_type_element_number(t
);
884 lttv_trace_hook_destroy(&h
);
886 name_tables
->syscall_names
= g_new(GQuark
, nb
);
887 name_tables
->nb_syscalls
= nb
;
889 for(i
= 0 ; i
< nb
; i
++) {
890 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
893 //name_tables->syscall_names = g_new(GQuark, 256);
894 //for(i = 0 ; i < 256 ; i++) {
895 // g_string_printf(fe_name, "syscall %d", i);
896 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
899 name_tables
->syscall_names
= NULL
;
900 name_tables
->nb_syscalls
= 0;
903 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
904 LTT_EVENT_TRAP_ENTRY
,
905 LTT_FIELD_TRAP_ID
, 0, 0,
908 thf
= lttv_trace_hook_get_first(&h
);
910 t
= ltt_field_type(thf
->f1
);
911 //nb = ltt_type_element_number(t);
913 lttv_trace_hook_destroy(&h
);
916 name_tables->trap_names = g_new(GQuark, nb);
917 for(i = 0 ; i < nb ; i++) {
918 name_tables->trap_names[i] = g_quark_from_string(
919 ltt_enum_string_get(t, i));
922 name_tables
->nb_traps
= 256;
923 name_tables
->trap_names
= g_new(GQuark
, 256);
924 for(i
= 0 ; i
< 256 ; i
++) {
925 g_string_printf(fe_name
, "trap %d", i
);
926 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
929 name_tables
->trap_names
= NULL
;
930 name_tables
->nb_traps
= 0;
933 if(!lttv_trace_find_hook(tcs
->parent
.t
,
934 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
935 LTT_FIELD_IRQ_ID
, 0, 0,
938 thf
= lttv_trace_hook_get_first(&h
);
940 t
= ltt_field_type(thf
->f1
);
941 //nb = ltt_type_element_number(t);
943 lttv_trace_hook_destroy(&h
);
946 name_tables->irq_names = g_new(GQuark, nb);
947 for(i = 0 ; i < nb ; i++) {
948 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
952 name_tables
->irq_names
= g_new(GQuark
, 256);
953 for(i
= 0 ; i
< 256 ; i
++) {
954 g_string_printf(fe_name
, "irq %d", i
);
955 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
958 name_tables
->irq_names
= NULL
;
961 name_tables->soft_irq_names = g_new(GQuark, nb);
962 for(i = 0 ; i < nb ; i++) {
963 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
967 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
968 for(i
= 0 ; i
< 256 ; i
++) {
969 g_string_printf(fe_name
, "softirq %d", i
);
970 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
974 g_string_free(fe_name
, TRUE
);
979 get_name_tables(LttvTraceState
*tcs
)
981 LttvNameTables
*name_tables
;
983 LttvAttributeValue v
;
985 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
987 g_assert(*(v
.v_pointer
) != NULL
);
988 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
989 //tcs->eventtype_names = name_tables->eventtype_names;
990 tcs
->syscall_names
= name_tables
->syscall_names
;
991 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
992 tcs
->trap_names
= name_tables
->trap_names
;
993 tcs
->nb_traps
= name_tables
->nb_traps
;
994 tcs
->irq_names
= name_tables
->irq_names
;
995 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1000 free_name_tables(LttvTraceState
*tcs
)
1002 LttvNameTables
*name_tables
;
1004 LttvAttributeValue v
;
1006 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1008 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1009 *(v
.v_pointer
) = NULL
;
1011 // g_free(name_tables->eventtype_names);
1012 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1013 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1014 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1015 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1016 if(name_tables
) g_free(name_tables
);
1019 #ifdef HASH_TABLE_DEBUG
1021 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1023 LttvProcessState
*process
= (LttvProcessState
*)value
;
1025 /* Test for process corruption */
1026 guint stack_len
= process
->execution_stack
->len
;
1029 static void hash_table_check(GHashTable
*table
)
1031 g_hash_table_foreach(table
, test_process
, NULL
);
1038 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1041 LttvExecutionState
*es
;
1043 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1044 guint cpu
= tfs
->cpu
;
1046 #ifdef HASH_TABLE_DEBUG
1047 hash_table_check(ts
->processes
);
1049 LttvProcessState
*process
= ts
->running_process
[cpu
];
1051 guint depth
= process
->execution_stack
->len
;
1053 process
->execution_stack
=
1054 g_array_set_size(process
->execution_stack
, depth
+ 1);
1057 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1059 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1062 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1063 es
->cum_cpu_time
= ltt_time_zero
;
1064 es
->s
= process
->state
->s
;
1065 process
->state
= es
;
1069 * return 1 when empty, else 0 */
1070 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1071 LttvTracefileState
*tfs
)
1073 guint cpu
= tfs
->cpu
;
1074 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1076 guint depth
= process
->execution_stack
->len
;
1082 process
->execution_stack
=
1083 g_array_set_size(process
->execution_stack
, depth
- 1);
1084 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1086 process
->state
->change
= tfs
->parent
.timestamp
;
1091 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1093 guint cpu
= tfs
->cpu
;
1094 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1095 LttvProcessState
*process
= ts
->running_process
[cpu
];
1097 guint depth
= process
->execution_stack
->len
;
1099 if(process
->state
->t
!= t
){
1100 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1101 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1102 g_info("process state has %s when pop_int is %s\n",
1103 g_quark_to_string(process
->state
->t
),
1104 g_quark_to_string(t
));
1105 g_info("{ %u, %u, %s, %s }\n",
1108 g_quark_to_string(process
->name
),
1109 g_quark_to_string(process
->state
->s
));
1114 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1115 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1119 process
->execution_stack
=
1120 g_array_set_size(process
->execution_stack
, depth
- 1);
1121 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1123 process
->state
->change
= tfs
->parent
.timestamp
;
1126 struct search_result
{
1127 const LttTime
*time
; /* Requested time */
1128 LttTime
*best
; /* Best result */
1131 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1133 const LttTime
*elem_time
= (const LttTime
*)a
;
1134 /* Explicit non const cast */
1135 struct search_result
*res
= (struct search_result
*)b
;
1137 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1138 /* The usertrace was created before the schedchange */
1139 /* Get larger keys */
1141 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1142 /* The usertrace was created after the schedchange time */
1143 /* Get smaller keys */
1145 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1146 res
->best
= elem_time
;
1149 res
->best
= elem_time
;
1156 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1157 guint pid
, const LttTime
*timestamp
)
1159 LttvTracefileState
*tfs
= NULL
;
1160 struct search_result res
;
1161 /* Find the usertrace associated with a pid and time interval.
1162 * Search in the usertraces by PID (within a hash) and then, for each
1163 * corresponding element of the array, find the first one with creation
1164 * timestamp the lowest, but higher or equal to "timestamp". */
1165 res
.time
= timestamp
;
1167 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1168 if(usertrace_tree
) {
1169 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1171 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1179 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1180 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1182 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1184 LttvExecutionState
*es
;
1186 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1192 process
->name
= name
;
1193 //process->last_cpu = tfs->cpu_name;
1194 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1195 process
->type
= LTTV_STATE_USER_THREAD
;
1196 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1197 process
->current_function
= 0; //function 0x0 by default.
1199 g_info("Process %u, core %p", process
->pid
, process
);
1200 g_hash_table_insert(tcs
->processes
, process
, process
);
1203 process
->ppid
= parent
->pid
;
1204 process
->creation_time
= *timestamp
;
1207 /* No parent. This process exists but we are missing all information about
1208 its creation. The birth time is set to zero but we remember the time of
1213 process
->creation_time
= ltt_time_zero
;
1216 process
->insertion_time
= *timestamp
;
1217 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1218 process
->creation_time
.tv_nsec
);
1219 process
->pid_time
= g_quark_from_string(buffer
);
1221 //process->last_cpu = tfs->cpu_name;
1222 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1223 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1224 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1225 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1226 es
= process
->state
= &g_array_index(process
->execution_stack
,
1227 LttvExecutionState
, 0);
1228 es
->t
= LTTV_STATE_USER_MODE
;
1229 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1230 es
->entry
= *timestamp
;
1231 //g_assert(timestamp->tv_sec != 0);
1232 es
->change
= *timestamp
;
1233 es
->cum_cpu_time
= ltt_time_zero
;
1234 es
->s
= LTTV_STATE_RUN
;
1236 es
= process
->state
= &g_array_index(process
->execution_stack
,
1237 LttvExecutionState
, 1);
1238 es
->t
= LTTV_STATE_SYSCALL
;
1239 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1240 es
->entry
= *timestamp
;
1241 //g_assert(timestamp->tv_sec != 0);
1242 es
->change
= *timestamp
;
1243 es
->cum_cpu_time
= ltt_time_zero
;
1244 es
->s
= LTTV_STATE_WAIT_FORK
;
1246 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1247 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1248 sizeof(guint64
), 0);
1253 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1256 LttvProcessState key
;
1257 LttvProcessState
*process
;
1261 process
= g_hash_table_lookup(ts
->processes
, &key
);
1266 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1269 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1270 LttvExecutionState
*es
;
1272 /* Put ltt_time_zero creation time for unexisting processes */
1273 if(unlikely(process
== NULL
)) {
1274 process
= lttv_state_create_process(ts
,
1275 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1276 /* We are not sure is it's a kernel thread or normal thread, put the
1277 * bottom stack state to unknown */
1278 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1279 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1284 /* FIXME : this function should be called when we receive an event telling that
1285 * release_task has been called in the kernel. In happens generally when
1286 * the parent waits for its child terminaison, but may also happen in special
1287 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1288 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1289 * of a killed thread ground, but isn't the leader.
1291 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1293 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1294 LttvProcessState key
;
1296 key
.pid
= process
->pid
;
1297 key
.cpu
= process
->cpu
;
1298 g_hash_table_remove(ts
->processes
, &key
);
1299 g_array_free(process
->execution_stack
, TRUE
);
1300 g_array_free(process
->user_stack
, TRUE
);
1305 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1307 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1308 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1313 static void lttv_state_free_process_table(GHashTable
*processes
)
1315 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1316 g_hash_table_destroy(processes
);
1320 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1322 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1323 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1324 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1325 LttField
*f
= thf
->f1
;
1327 LttvExecutionSubmode submode
;
1329 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1330 guint syscall
= ltt_event_get_unsigned(e
, f
);
1332 if(syscall
< nb_syscalls
) {
1333 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1336 /* Fixup an incomplete syscall table */
1337 GString
*string
= g_string_new("");
1338 g_string_printf(string
, "syscall %u", syscall
);
1339 submode
= g_quark_from_string(string
->str
);
1340 g_string_free(string
, TRUE
);
1342 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1347 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1349 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1351 pop_state(s
, LTTV_STATE_SYSCALL
);
1356 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1358 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1359 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1360 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1361 LttField
*f
= thf
->f1
;
1363 LttvExecutionSubmode submode
;
1365 guint nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1366 guint trap
= ltt_event_get_unsigned(e
, f
);
1368 if(trap
< nb_traps
) {
1369 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1371 /* Fixup an incomplete trap table */
1372 GString
*string
= g_string_new("");
1373 g_string_printf(string
, "trap %u", trap
);
1374 submode
= g_quark_from_string(string
->str
);
1375 g_string_free(string
, TRUE
);
1378 push_state(s
, LTTV_STATE_TRAP
, submode
);
1383 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1385 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1387 pop_state(s
, LTTV_STATE_TRAP
);
1392 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1394 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1395 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1396 guint8 fac_id
= ltt_event_facility_id(e
);
1397 guint8 ev_id
= ltt_event_eventtype_id(e
);
1398 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1399 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1400 g_assert(thf
->f1
!= NULL
);
1401 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1402 LttField
*f
= thf
->f1
;
1404 LttvExecutionSubmode submode
;
1406 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1407 ltt_event_get_unsigned(e
, f
)];
1409 /* Do something with the info about being in user or system mode when int? */
1410 push_state(s
, LTTV_STATE_IRQ
, submode
);
1414 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1416 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1418 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1424 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1426 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1428 pop_state(s
, LTTV_STATE_IRQ
);
1432 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1434 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1435 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1436 guint8 fac_id
= ltt_event_facility_id(e
);
1437 guint8 ev_id
= ltt_event_eventtype_id(e
);
1438 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1439 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1440 g_assert(thf
->f1
!= NULL
);
1441 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1442 LttField
*f
= thf
->f1
;
1444 LttvExecutionSubmode submode
;
1446 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1447 ltt_event_get_unsigned(e
, f
)];
1449 /* Do something with the info about being in user or system mode when int? */
1450 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1454 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1458 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1459 guint cpu
= tfs
->cpu
;
1460 LttvProcessState
*process
= ts
->running_process
[cpu
];
1462 guint depth
= process
->user_stack
->len
;
1464 process
->user_stack
=
1465 g_array_set_size(process
->user_stack
, depth
+ 1);
1467 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1468 *new_func
= funcptr
;
1469 process
->current_function
= funcptr
;
1472 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1474 guint cpu
= tfs
->cpu
;
1475 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1476 LttvProcessState
*process
= ts
->running_process
[cpu
];
1478 if(process
->current_function
!= funcptr
){
1479 g_info("Different functions (%lu.%09lu): ignore it\n",
1480 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1481 g_info("process state has %llu when pop_function is %llu\n",
1482 process
->current_function
, funcptr
);
1483 g_info("{ %u, %u, %s, %s }\n",
1486 g_quark_to_string(process
->name
),
1487 g_quark_to_string(process
->state
->s
));
1490 guint depth
= process
->user_stack
->len
;
1493 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1494 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1498 process
->user_stack
=
1499 g_array_set_size(process
->user_stack
, depth
- 1);
1500 process
->current_function
=
1501 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1505 static gboolean
function_entry(void *hook_data
, void *call_data
)
1507 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1508 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1509 guint8 fac_id
= ltt_event_facility_id(e
);
1510 guint8 ev_id
= ltt_event_eventtype_id(e
);
1511 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1512 g_assert(thf
->f1
!= NULL
);
1513 LttField
*f
= thf
->f1
;
1514 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1516 push_function(s
, funcptr
);
1520 static gboolean
function_exit(void *hook_data
, void *call_data
)
1522 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1523 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1524 guint8 fac_id
= ltt_event_facility_id(e
);
1525 guint8 ev_id
= ltt_event_eventtype_id(e
);
1526 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1527 g_assert(thf
->f1
!= NULL
);
1528 LttField
*f
= thf
->f1
;
1529 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1531 LttvExecutionSubmode submode
;
1533 pop_function(s
, funcptr
);
1537 static gboolean
schedchange(void *hook_data
, void *call_data
)
1539 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1541 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1542 LttvProcessState
*process
= ts
->running_process
[cpu
];
1543 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1545 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1546 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1547 guint pid_in
, pid_out
;
1550 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1551 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1552 state_out
= ltt_event_get_int(e
, thf
->f3
);
1554 if(likely(process
!= NULL
)) {
1556 /* We could not know but it was not the idle process executing.
1557 This should only happen at the beginning, before the first schedule
1558 event, and when the initial information (current process for each CPU)
1559 is missing. It is not obvious how we could, after the fact, compensate
1560 the wrongly attributed statistics. */
1562 //This test only makes sense once the state is known and if there is no
1563 //missing events. We need to silently ignore schedchange coming after a
1564 //process_free, or it causes glitches. (FIXME)
1565 //if(unlikely(process->pid != pid_out)) {
1566 // g_assert(process->pid == 0);
1569 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1570 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1571 process
->state
->change
= s
->parent
.timestamp
;
1573 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1574 else process
->state
->s
= LTTV_STATE_WAIT
;
1575 process
->state
->change
= s
->parent
.timestamp
;
1579 exit_process(s
, process
); /* EXIT_DEAD */
1580 /* see sched.h for states */
1582 process
= ts
->running_process
[cpu
] =
1583 lttv_state_find_process_or_create(
1584 (LttvTraceState
*)s
->parent
.t_context
,
1586 &s
->parent
.timestamp
);
1587 process
->state
->s
= LTTV_STATE_RUN
;
1589 if(process
->usertrace
)
1590 process
->usertrace
->cpu
= cpu
;
1591 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1592 process
->state
->change
= s
->parent
.timestamp
;
1596 static gboolean
process_fork(void *hook_data
, void *call_data
)
1598 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1599 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1600 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1603 LttvProcessState
*zombie_process
;
1605 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1606 LttvProcessState
*process
= ts
->running_process
[cpu
];
1607 LttvProcessState
*child_process
;
1610 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1613 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1615 /* Mathieu : it seems like the process might have been scheduled in before the
1616 * fork, and, in a rare case, might be the current process. This might happen
1617 * in a SMP case where we don't have enough precision on the clocks.
1619 * Test reenabled after precision fixes on time. (Mathieu) */
1621 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1623 if(unlikely(zombie_process
!= NULL
)) {
1624 /* Reutilisation of PID. Only now we are sure that the old PID
1625 * has been released. FIXME : should know when release_task happens instead.
1627 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1629 for(i
=0; i
< num_cpus
; i
++) {
1630 g_assert(zombie_process
!= ts
->running_process
[i
]);
1633 exit_process(s
, zombie_process
);
1636 g_assert(process
->pid
!= child_pid
);
1637 // FIXME : Add this test in the "known state" section
1638 // g_assert(process->pid == parent_pid);
1639 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1640 if(child_process
== NULL
) {
1641 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1642 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1644 /* The process has already been created : due to time imprecision between
1645 * multiple CPUs : it has been scheduled in before creation. Note that we
1646 * shouldn't have this kind of imprecision.
1648 * Simply put a correct parent.
1650 g_assert(0); /* This is a problematic case : the process has been created
1651 before the fork event */
1652 child_process
->ppid
= process
->pid
;
1654 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1655 child_process
->name
= process
->name
;
1660 /* We stamp a newly created process as kernel_thread */
1661 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1663 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1664 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1665 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1668 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1669 LttvProcessState
*process
;
1670 LttvExecutionState
*es
;
1673 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1675 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1676 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1677 es
->t
= LTTV_STATE_SYSCALL
;
1678 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1683 static gboolean
process_exit(void *hook_data
, void *call_data
)
1685 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1686 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1687 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1691 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1692 LttvProcessState
*process
= ts
->running_process
[cpu
];
1694 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1696 // FIXME : Add this test in the "known state" section
1697 // g_assert(process->pid == pid);
1699 if(likely(process
!= NULL
)) {
1700 process
->state
->s
= LTTV_STATE_EXIT
;
1705 static gboolean
process_free(void *hook_data
, void *call_data
)
1707 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1708 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1709 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1710 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1712 LttvProcessState
*process
;
1714 /* PID of the process to release */
1715 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1717 g_assert(release_pid
!= 0);
1719 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1721 if(likely(process
!= NULL
)) {
1722 /* release_task is happening at kernel level : we can now safely release
1723 * the data structure of the process */
1724 //This test is fun, though, as it may happen that
1725 //at time t : CPU 0 : process_free
1726 //at time t+150ns : CPU 1 : schedule out
1727 //Clearly due to time imprecision, we disable it. (Mathieu)
1728 //If this weird case happen, we have no choice but to put the
1729 //Currently running process on the cpu to 0.
1730 //I re-enable it following time precision fixes. (Mathieu)
1731 //Well, in the case where an process is freed by a process on another CPU
1732 //and still scheduled, it happens that this is the schedchange that will
1733 //drop the last reference count. Do not free it here!
1734 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1736 for(i
=0; i
< num_cpus
; i
++) {
1737 //g_assert(process != ts->running_process[i]);
1738 if(process
== ts
->running_process
[i
]) {
1739 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1743 //if(i == num_cpus) /* process is not scheduled */
1744 //exit_process(s, process); // do nothing : wait for the schedchange to
1745 //delete the process.
1752 static gboolean
process_exec(void *hook_data
, void *call_data
)
1754 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1755 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1756 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1757 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1760 LttvProcessState
*process
= ts
->running_process
[cpu
];
1762 /* PID of the process to release */
1763 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1764 //name = ltt_event_get_string(e, thf->f1);
1765 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1767 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1768 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1769 memcpy(null_term_name
, name_begin
, name_len
);
1770 null_term_name
[name_len
] = '\0';
1772 process
->name
= g_quark_from_string(null_term_name
);
1773 g_free(null_term_name
);
1777 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1779 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1780 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1781 //It's slow : optimise later by doing this before reading trace.
1782 LttEventType
*et
= ltt_event_eventtype(e
);
1784 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1789 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1790 LttvProcessState
*process
= ts
->running_process
[cpu
];
1791 LttvProcessState
*parent_process
;
1792 LttField
*f4
, *f5
, *f6
, *f7
;
1793 GQuark type
, mode
, submode
, status
;
1794 LttvExecutionState
*es
;
1797 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1800 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1803 command
= ltt_event_get_string(e
, thf
->f3
);
1806 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1807 type
= ltt_enum_string_get(ltt_field_type(f4
),
1808 ltt_event_get_unsigned(e
, f4
));
1811 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1812 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1813 ltt_event_get_unsigned(e
, f5
));
1816 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1817 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1818 ltt_event_get_unsigned(e
, f6
));
1821 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1822 status
= ltt_enum_string_get(ltt_field_type(f7
),
1823 ltt_event_get_unsigned(e
, f7
));
1825 /* The process might exist if a process was forked while performing the sate dump. */
1826 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1827 if(process
== NULL
) {
1828 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1829 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1830 pid
, g_quark_from_string(command
),
1831 &s
->parent
.timestamp
);
1833 /* Keep the stack bottom : a running user mode */
1834 /* Disabled because of inconsistencies in the current statedump states. */
1835 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1836 /* Only keep the bottom */
1837 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1838 es
= process
->state
= &g_array_index(process
->execution_stack
,
1839 LttvExecutionState
, 0);
1840 es
->t
= LTTV_STATE_SYSCALL
;
1844 /* On top of it : */
1845 es
= process
->state
= &g_array_index(process
->execution_stack
,
1846 LttvExecutionState
, 1);
1847 es
->t
= LTTV_STATE_USER_MODE
;
1854 es
= process
->state
= &g_array_index(process
->execution_stack
,
1855 LttvExecutionState
, 1);
1856 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1857 es
->s
= LTTV_STATE_UNNAMED
;
1858 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1862 /* The process has already been created :
1863 * Probably was forked while dumping the process state or
1864 * was simply scheduled in prior to get the state dump event.
1865 * We know for sure if it is a user space thread.
1867 process
->ppid
= parent_pid
;
1868 process
->name
= g_quark_from_string(command
);
1869 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1870 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1871 es
->t
= LTTV_STATE_USER_MODE
;
1872 /* Don't mess around with the stack, it will eventually become
1873 * ok after the end of state dump. */
1879 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1881 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1883 lttv_state_add_event_hooks(tss
);
1888 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1890 LttvTraceset
*traceset
= self
->parent
.ts
;
1892 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1896 LttvTracefileState
*tfs
;
1900 LttvTraceHookByFacility
*thf
;
1902 LttvTraceHook
*hook
;
1904 LttvAttributeValue val
;
1909 nb_trace
= lttv_traceset_number(traceset
);
1910 for(i
= 0 ; i
< nb_trace
; i
++) {
1911 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1913 /* Find the eventtype id for the following events and register the
1914 associated by id hooks. */
1916 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1917 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1920 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1921 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1922 LTT_FIELD_SYSCALL_ID
, 0, 0,
1923 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1926 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1927 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1929 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1932 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1933 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1934 LTT_FIELD_TRAP_ID
, 0, 0,
1935 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1938 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1939 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1941 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1944 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1945 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1946 LTT_FIELD_IRQ_ID
, 0, 0,
1947 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1950 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1951 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1953 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1956 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1957 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1958 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1959 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1962 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1963 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1965 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1968 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1969 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1970 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1971 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1974 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1975 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1976 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1977 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1980 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1981 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1982 LTT_FIELD_PID
, 0, 0,
1983 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1987 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1988 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1989 LTT_FIELD_PID
, 0, 0,
1990 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1993 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1994 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1995 LTT_FIELD_PID
, 0, 0,
1996 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1999 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2000 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2001 LTT_FIELD_FILENAME
, 0, 0,
2002 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2005 /* statedump-related hooks */
2006 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2007 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2008 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2009 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2012 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2013 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2014 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2015 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2018 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2019 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2020 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2021 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2024 hooks
= g_array_set_size(hooks
, hn
);
2026 /* Add these hooks to each event_by_id hooks list */
2028 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2030 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2032 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2033 LttvTracefileContext
*, j
));
2035 for(k
= 0 ; k
< hooks
->len
; k
++) {
2036 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2037 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2038 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2040 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2047 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2048 *(val
.v_pointer
) = hooks
;
2052 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2054 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2056 lttv_state_remove_event_hooks(tss
);
2061 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2063 LttvTraceset
*traceset
= self
->parent
.ts
;
2065 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2069 LttvTracefileState
*tfs
;
2073 LttvTraceHook
*hook
;
2075 LttvTraceHookByFacility
*thf
;
2077 LttvAttributeValue val
;
2079 nb_trace
= lttv_traceset_number(traceset
);
2080 for(i
= 0 ; i
< nb_trace
; i
++) {
2081 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2082 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2083 hooks
= *(val
.v_pointer
);
2085 /* Remove these hooks from each event_by_id hooks list */
2087 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2089 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2091 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2092 LttvTracefileContext
*, j
));
2094 for(k
= 0 ; k
< hooks
->len
; k
++) {
2095 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2096 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2097 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2099 lttv_hooks_remove_data(
2100 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2106 for(k
= 0 ; k
< hooks
->len
; k
++)
2107 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2108 g_array_free(hooks
, TRUE
);
2112 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2114 guint
*event_count
= (guint
*)hook_data
;
2116 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2117 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2122 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2124 LttvTracefileState
*tfcs
;
2126 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2128 LttEventPosition
*ep
;
2134 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2136 LttvAttributeValue value
;
2138 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2139 LTTV_STATE_SAVED_STATES
);
2140 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2141 value
= lttv_attribute_add(saved_states_tree
,
2142 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2143 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2144 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2145 *(value
.v_time
) = self
->parent
.timestamp
;
2146 lttv_state_save(tcs
, saved_state_tree
);
2147 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2148 self
->parent
.timestamp
.tv_nsec
);
2150 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2155 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2157 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2159 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2164 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2172 static gboolean
block_start(void *hook_data
, void *call_data
)
2174 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2176 LttvTracefileState
*tfcs
;
2178 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2180 LttEventPosition
*ep
;
2182 guint i
, nb_block
, nb_event
, nb_tracefile
;
2186 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2188 LttvAttributeValue value
;
2190 ep
= ltt_event_position_new();
2192 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2194 /* Count the number of events added since the last block end in any
2197 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2199 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2200 LttvTracefileContext
, i
));
2201 ltt_event_position(tfcs
->parent
.e
, ep
);
2202 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2203 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2204 tfcs
->saved_position
= nb_event
;
2208 if(tcs
->nb_event
>= tcs
->save_interval
) {
2209 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2210 LTTV_STATE_SAVED_STATES
);
2211 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2212 value
= lttv_attribute_add(saved_states_tree
,
2213 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2214 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2215 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2216 *(value
.v_time
) = self
->parent
.timestamp
;
2217 lttv_state_save(tcs
, saved_state_tree
);
2219 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2220 self
->parent
.timestamp
.tv_nsec
);
2222 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2228 static gboolean
block_end(void *hook_data
, void *call_data
)
2230 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2232 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2236 LttEventPosition
*ep
;
2238 guint nb_block
, nb_event
;
2240 ep
= ltt_event_position_new();
2241 ltt_event_position(self
->parent
.e
, ep
);
2242 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2243 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2244 self
->saved_position
= 0;
2245 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2252 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2254 LttvTraceset
*traceset
= self
->parent
.ts
;
2256 guint i
, j
, nb_trace
, nb_tracefile
;
2260 LttvTracefileState
*tfs
;
2262 LttvTraceHook hook_start
, hook_end
;
2264 nb_trace
= lttv_traceset_number(traceset
);
2265 for(i
= 0 ; i
< nb_trace
; i
++) {
2266 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2268 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2269 NULL
, NULL
, block_start
, &hook_start
);
2270 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2271 NULL
, NULL
, block_end
, &hook_end
);
2273 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2275 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2277 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2278 LttvTracefileContext
, j
));
2279 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2280 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2281 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2282 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2288 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2290 LttvTraceset
*traceset
= self
->parent
.ts
;
2292 guint i
, j
, nb_trace
, nb_tracefile
;
2296 LttvTracefileState
*tfs
;
2299 nb_trace
= lttv_traceset_number(traceset
);
2300 for(i
= 0 ; i
< nb_trace
; i
++) {
2302 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2303 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2305 guint
*event_count
= g_new(guint
, 1);
2308 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2310 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2311 LttvTracefileContext
*, j
));
2312 lttv_hooks_add(tfs
->parent
.event
,
2313 state_save_event_hook
,
2320 lttv_process_traceset_begin(&self
->parent
,
2321 NULL
, NULL
, NULL
, NULL
, NULL
);
2325 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2327 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2329 lttv_state_save_add_event_hooks(tss
);
2336 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2338 LttvTraceset
*traceset
= self
->parent
.ts
;
2340 guint i
, j
, nb_trace
, nb_tracefile
;
2344 LttvTracefileState
*tfs
;
2346 LttvTraceHook hook_start
, hook_end
;
2348 nb_trace
= lttv_traceset_number(traceset
);
2349 for(i
= 0 ; i
< nb_trace
; i
++) {
2350 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2352 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2353 NULL
, NULL
, block_start
, &hook_start
);
2355 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2356 NULL
, NULL
, block_end
, &hook_end
);
2358 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2360 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2362 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2363 LttvTracefileContext
, j
));
2364 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2365 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2366 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2367 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2373 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2375 LttvTraceset
*traceset
= self
->parent
.ts
;
2377 guint i
, j
, nb_trace
, nb_tracefile
;
2381 LttvTracefileState
*tfs
;
2383 LttvHooks
*after_trace
= lttv_hooks_new();
2385 lttv_hooks_add(after_trace
,
2386 state_save_after_trace_hook
,
2391 lttv_process_traceset_end(&self
->parent
,
2392 NULL
, after_trace
, NULL
, NULL
, NULL
);
2394 lttv_hooks_destroy(after_trace
);
2396 nb_trace
= lttv_traceset_number(traceset
);
2397 for(i
= 0 ; i
< nb_trace
; i
++) {
2399 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2400 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2402 guint
*event_count
= NULL
;
2404 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2406 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2407 LttvTracefileContext
*, j
));
2408 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2409 state_save_event_hook
);
2411 if(event_count
) g_free(event_count
);
2415 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2417 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2419 lttv_state_save_remove_event_hooks(tss
);
2424 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2426 LttvTraceset
*traceset
= self
->parent
.ts
;
2430 int min_pos
, mid_pos
, max_pos
;
2432 guint call_rest
= 0;
2434 LttvTraceState
*tcs
;
2436 LttvAttributeValue value
;
2438 LttvAttributeType type
;
2440 LttvAttributeName name
;
2444 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2446 //g_tree_destroy(self->parent.pqueue);
2447 //self->parent.pqueue = g_tree_new(compare_tracefile);
2449 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2451 nb_trace
= lttv_traceset_number(traceset
);
2452 for(i
= 0 ; i
< nb_trace
; i
++) {
2453 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2455 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2456 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2457 LTTV_STATE_SAVED_STATES
);
2460 if(saved_states_tree
) {
2461 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2462 mid_pos
= max_pos
/ 2;
2463 while(min_pos
< max_pos
) {
2464 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2466 g_assert(type
== LTTV_GOBJECT
);
2467 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2468 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2470 g_assert(type
== LTTV_TIME
);
2471 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2473 closest_tree
= saved_state_tree
;
2475 else max_pos
= mid_pos
- 1;
2477 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2481 /* restore the closest earlier saved state */
2483 lttv_state_restore(tcs
, closest_tree
);
2487 /* There is no saved state, yet we want to have it. Restart at T0 */
2489 restore_init_state(tcs
);
2490 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2493 /* We want to seek quickly without restoring/updating the state */
2495 restore_init_state(tcs
);
2496 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2499 if(!call_rest
) g_info("NOT Calling restore");
2504 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2510 traceset_state_finalize (LttvTracesetState
*self
)
2512 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2513 finalize(G_OBJECT(self
));
2518 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2520 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2522 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2523 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2524 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2525 klass
->new_traceset_context
= new_traceset_context
;
2526 klass
->new_trace_context
= new_trace_context
;
2527 klass
->new_tracefile_context
= new_tracefile_context
;
2532 lttv_traceset_state_get_type(void)
2534 static GType type
= 0;
2536 static const GTypeInfo info
= {
2537 sizeof (LttvTracesetStateClass
),
2538 NULL
, /* base_init */
2539 NULL
, /* base_finalize */
2540 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2541 NULL
, /* class_finalize */
2542 NULL
, /* class_data */
2543 sizeof (LttvTracesetState
),
2544 0, /* n_preallocs */
2545 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2546 NULL
/* value handling */
2549 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2557 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2563 trace_state_finalize (LttvTraceState
*self
)
2565 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2566 finalize(G_OBJECT(self
));
2571 trace_state_class_init (LttvTraceStateClass
*klass
)
2573 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2575 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2576 klass
->state_save
= state_save
;
2577 klass
->state_restore
= state_restore
;
2578 klass
->state_saved_free
= state_saved_free
;
2583 lttv_trace_state_get_type(void)
2585 static GType type
= 0;
2587 static const GTypeInfo info
= {
2588 sizeof (LttvTraceStateClass
),
2589 NULL
, /* base_init */
2590 NULL
, /* base_finalize */
2591 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2592 NULL
, /* class_finalize */
2593 NULL
, /* class_data */
2594 sizeof (LttvTraceState
),
2595 0, /* n_preallocs */
2596 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2597 NULL
/* value handling */
2600 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2601 "LttvTraceStateType", &info
, 0);
2608 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2614 tracefile_state_finalize (LttvTracefileState
*self
)
2616 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2617 finalize(G_OBJECT(self
));
2622 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2624 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2626 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2631 lttv_tracefile_state_get_type(void)
2633 static GType type
= 0;
2635 static const GTypeInfo info
= {
2636 sizeof (LttvTracefileStateClass
),
2637 NULL
, /* base_init */
2638 NULL
, /* base_finalize */
2639 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2640 NULL
, /* class_finalize */
2641 NULL
, /* class_data */
2642 sizeof (LttvTracefileState
),
2643 0, /* n_preallocs */
2644 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2645 NULL
/* value handling */
2648 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2649 "LttvTracefileStateType", &info
, 0);
2655 static void module_init()
2657 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2658 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2659 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2660 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2661 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2662 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2663 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2664 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2665 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2666 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2667 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2668 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2669 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2670 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2671 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2672 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2673 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2674 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2675 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2676 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2677 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2678 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2679 LTTV_STATE_EVENT
= g_quark_from_string("event");
2680 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2681 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2682 LTTV_STATE_TIME
= g_quark_from_string("time");
2683 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2684 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2685 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2686 g_quark_from_string("trace_state_use_count");
2689 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2690 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2691 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2692 LTT_FACILITY_FS
= g_quark_from_string("fs");
2693 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2694 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2697 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2698 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2699 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2700 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2701 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2702 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2703 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2704 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2705 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2706 LTT_EVENT_FORK
= g_quark_from_string("fork");
2707 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2708 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2709 LTT_EVENT_FREE
= g_quark_from_string("free");
2710 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2711 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2712 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2713 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2716 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2717 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2718 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2719 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2720 LTT_FIELD_OUT
= g_quark_from_string("out");
2721 LTT_FIELD_IN
= g_quark_from_string("in");
2722 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2723 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2724 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2725 LTT_FIELD_PID
= g_quark_from_string("pid");
2726 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2727 LTT_FIELD_NAME
= g_quark_from_string("name");
2728 LTT_FIELD_TYPE
= g_quark_from_string("type");
2729 LTT_FIELD_MODE
= g_quark_from_string("mode");
2730 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2731 LTT_FIELD_STATUS
= g_quark_from_string("status");
2732 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2733 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2737 static void module_destroy()
2742 LTTV_MODULE("state", "State computation", \
2743 "Update the system state, possibly saving it at intervals", \
2744 module_init
, module_destroy
)