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 LttTime start_time
, end_time
;
209 /* Free the process tables */
210 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
211 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
212 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
213 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
216 /* Seek time to beginning */
217 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
218 // closest. It's the tracecontext job to seek the trace to the beginning
219 // anyway : the init state might be used at the middle of the trace as well...
220 //g_tree_destroy(self->parent.ts_context->pqueue);
221 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
223 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
225 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
227 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
229 /* Put the per cpu running_process to beginning state : process 0. */
230 for(i
=0; i
< nb_cpus
; i
++) {
231 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0,
232 LTTV_STATE_UNNAMED
, &start_time
);
233 self
->running_process
[i
]->state
->s
= LTTV_STATE_RUN
;
234 self
->running_process
[i
]->cpu
= i
;
238 nb_tracefile
= self
->parent
.tracefiles
->len
;
240 for(i
= 0 ; i
< nb_tracefile
; i
++) {
242 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
243 LttvTracefileContext
*, i
));
244 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
245 // tfcs->saved_position = 0;
246 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
247 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
248 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
249 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
254 //static LttTime time_zero = {0,0};
256 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
259 const LttTime
*t1
= (const LttTime
*)a
;
260 const LttTime
*t2
= (const LttTime
*)b
;
262 return ltt_time_compare(*t1
, *t2
);
265 static void free_usertrace_key(gpointer data
)
271 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
273 guint i
, j
, nb_trace
, nb_tracefile
;
275 LttvTraceContext
*tc
;
279 LttvTracefileState
*tfcs
;
281 LttvAttributeValue v
;
283 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
284 init((LttvTracesetContext
*)self
, ts
);
286 nb_trace
= lttv_traceset_number(ts
);
287 for(i
= 0 ; i
< nb_trace
; i
++) {
288 tc
= self
->parent
.traces
[i
];
289 tcs
= LTTV_TRACE_STATE(tc
);
290 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
291 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
295 if(*(v
.v_uint
) == 1) {
296 create_name_tables(tcs
);
297 create_max_time(tcs
);
299 get_name_tables(tcs
);
302 nb_tracefile
= tc
->tracefiles
->len
;
303 tcs
->processes
= NULL
;
304 tcs
->usertraces
= NULL
;
305 tcs
->running_process
= g_new(LttvProcessState
*,
306 ltt_trace_get_num_cpu(tc
->t
));
307 restore_init_state(tcs
);
308 for(j
= 0 ; j
< nb_tracefile
; j
++) {
310 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
311 LttvTracefileContext
*, j
));
312 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
313 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
315 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
316 /* It's a Usertrace */
317 LttvProcessState
*process
;
319 ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
320 ltt_tracefile_creation(tfcs
->parent
.tf
));
321 process
= lttv_state_find_process_or_create(
323 0, ltt_tracefile_tid(tfcs
->parent
.tf
),
325 process
->usertrace
= tfcs
;
329 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
330 /* It's a Usertrace */
331 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
332 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
334 if(!usertrace_tree
) {
335 usertrace_tree
= g_tree_new_full(compare_usertraces
,
336 NULL
, free_usertrace_key
, NULL
);
337 g_hash_table_insert(tcs
->usertraces
,
338 (gpointer
)tid
, usertrace_tree
);
340 LttTime
*timestamp
= g_new(LttTime
, 1);
341 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
342 ltt_tracefile_creation(tfcs
->parent
.tf
));
343 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
351 fini(LttvTracesetState
*self
)
357 LttvTracefileState
*tfcs
;
359 LttvAttributeValue v
;
361 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
362 for(i
= 0 ; i
< nb_trace
; i
++) {
363 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
364 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
367 g_assert(*(v
.v_uint
) != 0);
370 if(*(v
.v_uint
) == 0) {
371 free_name_tables(tcs
);
373 free_saved_state(tcs
);
375 g_free(tcs
->running_process
);
376 tcs
->running_process
= NULL
;
377 lttv_state_free_process_table(tcs
->processes
);
378 lttv_state_free_usertraces(tcs
->usertraces
);
379 tcs
->processes
= NULL
;
380 tcs
->usertraces
= NULL
;
382 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
383 fini((LttvTracesetContext
*)self
);
387 static LttvTracesetContext
*
388 new_traceset_context(LttvTracesetContext
*self
)
390 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
394 static LttvTraceContext
*
395 new_trace_context(LttvTracesetContext
*self
)
397 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
401 static LttvTracefileContext
*
402 new_tracefile_context(LttvTracesetContext
*self
)
404 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
408 /* Write the process state of the trace */
410 static void write_process_state(gpointer key
, gpointer value
,
413 LttvProcessState
*process
;
415 LttvExecutionState
*es
;
417 FILE *fp
= (FILE *)user_data
;
421 process
= (LttvProcessState
*)value
;
423 " <PROCESS CORE=%p PID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
424 process
, process
->pid
, process
->ppid
, g_quark_to_string(process
->type
),
425 process
->creation_time
.tv_sec
,
426 process
->creation_time
.tv_nsec
, g_quark_to_string(process
->name
),
429 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
430 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
431 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
432 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
433 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
434 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
435 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
437 fprintf(fp
, " </PROCESS>\n");
441 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
443 guint i
, nb_tracefile
, nb_block
, offset
;
446 LttvTracefileState
*tfcs
;
450 LttEventPosition
*ep
;
454 ep
= ltt_event_position_new();
456 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
458 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
460 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
461 for(i
=0;i
<nb_cpus
;i
++) {
462 fprintf(fp
,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
463 i
, self
->running_process
[i
]->pid
);
466 nb_tracefile
= self
->parent
.tracefiles
->len
;
468 for(i
= 0 ; i
< nb_tracefile
; i
++) {
470 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
471 LttvTracefileContext
*, i
));
472 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
473 tfcs
->parent
.timestamp
.tv_sec
,
474 tfcs
->parent
.timestamp
.tv_nsec
);
475 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
476 if(e
== NULL
) fprintf(fp
,"/>\n");
478 ltt_event_position(e
, ep
);
479 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
480 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
485 fprintf(fp
,"</PROCESS_STATE>");
489 /* Copy each process from an existing hash table to a new one */
491 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
493 LttvProcessState
*process
, *new_process
;
495 GHashTable
*new_processes
= (GHashTable
*)user_data
;
499 process
= (LttvProcessState
*)value
;
500 new_process
= g_new(LttvProcessState
, 1);
501 *new_process
= *process
;
502 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
503 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
504 new_process
->execution_stack
=
505 g_array_set_size(new_process
->execution_stack
,
506 process
->execution_stack
->len
);
507 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
508 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
509 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
511 new_process
->state
= &g_array_index(new_process
->execution_stack
,
512 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
513 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
515 new_process
->user_stack
=
516 g_array_set_size(new_process
->user_stack
,
517 process
->user_stack
->len
);
518 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
519 g_array_index(new_process
->user_stack
, guint64
, i
) =
520 g_array_index(process
->user_stack
, guint64
, i
);
522 new_process
->current_function
= process
->current_function
;
523 g_hash_table_insert(new_processes
, new_process
, new_process
);
527 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
529 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
531 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
532 return new_processes
;
536 /* The saved state for each trace contains a member "processes", which
537 stores a copy of the process table, and a member "tracefiles" with
538 one entry per tracefile. Each tracefile has a "process" member pointing
539 to the current process and a "position" member storing the tracefile
540 position (needed to seek to the current "next" event. */
542 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
544 guint i
, nb_tracefile
, nb_cpus
;
546 LttvTracefileState
*tfcs
;
548 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
550 guint
*running_process
;
552 LttvAttributeType type
;
554 LttvAttributeValue value
;
556 LttvAttributeName name
;
558 LttEventPosition
*ep
;
560 tracefiles_tree
= lttv_attribute_find_subdir(container
,
561 LTTV_STATE_TRACEFILES
);
563 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
565 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
567 /* Add the currently running processes array */
568 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
569 running_process
= g_new(guint
, nb_cpus
);
570 for(i
=0;i
<nb_cpus
;i
++) {
571 running_process
[i
] = self
->running_process
[i
]->pid
;
573 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
575 *(value
.v_pointer
) = running_process
;
577 g_info("State save");
579 nb_tracefile
= self
->parent
.tracefiles
->len
;
581 for(i
= 0 ; i
< nb_tracefile
; i
++) {
583 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
584 LttvTracefileContext
*, i
));
585 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
586 value
= lttv_attribute_add(tracefiles_tree
, i
,
588 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
590 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
592 *(value
.v_uint
) = tfcs
->process
->pid
;
594 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
596 /* Only save the position if the tfs has not infinite time. */
597 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
598 // && current_tfcs != tfcs) {
599 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
600 *(value
.v_pointer
) = NULL
;
602 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
603 ep
= ltt_event_position_new();
604 ltt_event_position(e
, ep
);
605 *(value
.v_pointer
) = ep
;
607 guint nb_block
, offset
;
610 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
611 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
613 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
619 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
621 guint i
, nb_tracefile
, pid
, nb_cpus
;
623 LttvTracefileState
*tfcs
;
625 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
627 guint
*running_process
;
629 LttvAttributeType type
;
631 LttvAttributeValue value
;
633 LttvAttributeName name
;
637 LttEventPosition
*ep
;
639 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
641 tracefiles_tree
= lttv_attribute_find_subdir(container
,
642 LTTV_STATE_TRACEFILES
);
644 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
646 g_assert(type
== LTTV_POINTER
);
647 lttv_state_free_process_table(self
->processes
);
648 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
650 /* Add the currently running processes array */
651 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
652 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
654 g_assert(type
== LTTV_POINTER
);
655 running_process
= *(value
.v_pointer
);
656 for(i
=0;i
<nb_cpus
;i
++) {
657 pid
= running_process
[i
];
658 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
659 g_assert(self
->running_process
[i
] != NULL
);
663 nb_tracefile
= self
->parent
.tracefiles
->len
;
665 //g_tree_destroy(tsc->pqueue);
666 //tsc->pqueue = g_tree_new(compare_tracefile);
668 for(i
= 0 ; i
< nb_tracefile
; i
++) {
670 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
671 LttvTracefileContext
*, i
));
672 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
673 g_assert(type
== LTTV_GOBJECT
);
674 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
676 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
678 g_assert(type
== LTTV_UINT
);
679 pid
= *(value
.v_uint
);
680 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
682 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
684 g_assert(type
== LTTV_POINTER
);
685 //g_assert(*(value.v_pointer) != NULL);
686 ep
= *(value
.v_pointer
);
687 g_assert(tfcs
->parent
.t_context
!= NULL
);
689 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
690 g_tree_remove(tsc
->pqueue
, tfc
);
693 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
694 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
695 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
696 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
697 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
699 tfc
->timestamp
= ltt_time_infinite
;
705 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
707 guint i
, nb_tracefile
, nb_cpus
;
709 LttvTracefileState
*tfcs
;
711 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
713 guint
*running_process
;
715 LttvAttributeType type
;
717 LttvAttributeValue value
;
719 LttvAttributeName name
;
723 LttEventPosition
*ep
;
725 tracefiles_tree
= lttv_attribute_find_subdir(container
,
726 LTTV_STATE_TRACEFILES
);
727 g_object_ref(G_OBJECT(tracefiles_tree
));
728 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
730 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
732 g_assert(type
== LTTV_POINTER
);
733 lttv_state_free_process_table(*(value
.v_pointer
));
734 *(value
.v_pointer
) = NULL
;
735 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
737 /* Free running processes array */
738 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
739 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
741 g_assert(type
== LTTV_POINTER
);
742 running_process
= *(value
.v_pointer
);
743 g_free(running_process
);
745 nb_tracefile
= self
->parent
.tracefiles
->len
;
747 for(i
= 0 ; i
< nb_tracefile
; i
++) {
749 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
750 LttvTracefileContext
*, i
));
751 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
752 g_assert(type
== LTTV_GOBJECT
);
753 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
755 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
757 g_assert(type
== LTTV_POINTER
);
758 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
760 g_object_unref(G_OBJECT(tracefiles_tree
));
764 static void free_saved_state(LttvTraceState
*self
)
768 LttvAttributeType type
;
770 LttvAttributeValue value
;
772 LttvAttributeName name
;
776 LttvAttribute
*saved_states
;
778 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
779 LTTV_STATE_SAVED_STATES
);
781 nb
= lttv_attribute_get_number(saved_states
);
782 for(i
= 0 ; i
< nb
; i
++) {
783 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
784 g_assert(type
== LTTV_GOBJECT
);
785 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
788 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
793 create_max_time(LttvTraceState
*tcs
)
795 LttvAttributeValue v
;
797 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
799 g_assert(*(v
.v_pointer
) == NULL
);
800 *(v
.v_pointer
) = g_new(LttTime
,1);
801 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
806 get_max_time(LttvTraceState
*tcs
)
808 LttvAttributeValue v
;
810 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
812 g_assert(*(v
.v_pointer
) != NULL
);
813 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
818 free_max_time(LttvTraceState
*tcs
)
820 LttvAttributeValue v
;
822 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
824 g_free(*(v
.v_pointer
));
825 *(v
.v_pointer
) = NULL
;
829 typedef struct _LttvNameTables
{
830 // FIXME GQuark *eventtype_names;
831 GQuark
*syscall_names
;
836 GQuark
*soft_irq_names
;
841 create_name_tables(LttvTraceState
*tcs
)
845 GQuark f_name
, e_name
;
849 LttvTraceHookByFacility
*thf
;
855 GString
*fe_name
= g_string_new("");
857 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
859 LttvAttributeValue v
;
861 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
863 g_assert(*(v
.v_pointer
) == NULL
);
864 *(v
.v_pointer
) = name_tables
;
865 #if 0 // Use iteration over the facilities_by_name and then list all event
866 // types of each facility
867 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
868 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
869 for(i
= 0 ; i
< nb
; i
++) {
870 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
871 e_name
= ltt_eventtype_name(et
);
872 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
873 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
874 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
877 if(!lttv_trace_find_hook(tcs
->parent
.t
,
878 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
879 LTT_FIELD_SYSCALL_ID
, 0, 0,
882 thf
= lttv_trace_hook_get_first(&h
);
884 t
= ltt_field_type(thf
->f1
);
885 nb
= ltt_type_element_number(t
);
887 lttv_trace_hook_destroy(&h
);
889 name_tables
->syscall_names
= g_new(GQuark
, nb
);
890 name_tables
->nb_syscalls
= nb
;
892 for(i
= 0 ; i
< nb
; i
++) {
893 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
896 //name_tables->syscall_names = g_new(GQuark, 256);
897 //for(i = 0 ; i < 256 ; i++) {
898 // g_string_printf(fe_name, "syscall %d", i);
899 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
902 name_tables
->syscall_names
= NULL
;
903 name_tables
->nb_syscalls
= 0;
906 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL
,
907 LTT_EVENT_TRAP_ENTRY
,
908 LTT_FIELD_TRAP_ID
, 0, 0,
911 thf
= lttv_trace_hook_get_first(&h
);
913 t
= ltt_field_type(thf
->f1
);
914 //nb = ltt_type_element_number(t);
916 lttv_trace_hook_destroy(&h
);
919 name_tables->trap_names = g_new(GQuark, nb);
920 for(i = 0 ; i < nb ; i++) {
921 name_tables->trap_names[i] = g_quark_from_string(
922 ltt_enum_string_get(t, i));
925 name_tables
->nb_traps
= 256;
926 name_tables
->trap_names
= g_new(GQuark
, 256);
927 for(i
= 0 ; i
< 256 ; i
++) {
928 g_string_printf(fe_name
, "trap %d", i
);
929 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
932 name_tables
->trap_names
= NULL
;
933 name_tables
->nb_traps
= 0;
936 if(!lttv_trace_find_hook(tcs
->parent
.t
,
937 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
938 LTT_FIELD_IRQ_ID
, 0, 0,
941 thf
= lttv_trace_hook_get_first(&h
);
943 t
= ltt_field_type(thf
->f1
);
944 //nb = ltt_type_element_number(t);
946 lttv_trace_hook_destroy(&h
);
949 name_tables->irq_names = g_new(GQuark, nb);
950 for(i = 0 ; i < nb ; i++) {
951 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
955 name_tables
->irq_names
= g_new(GQuark
, 256);
956 for(i
= 0 ; i
< 256 ; i
++) {
957 g_string_printf(fe_name
, "irq %d", i
);
958 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
961 name_tables
->irq_names
= NULL
;
964 name_tables->soft_irq_names = g_new(GQuark, nb);
965 for(i = 0 ; i < nb ; i++) {
966 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
970 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
971 for(i
= 0 ; i
< 256 ; i
++) {
972 g_string_printf(fe_name
, "softirq %d", i
);
973 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
977 g_string_free(fe_name
, TRUE
);
982 get_name_tables(LttvTraceState
*tcs
)
984 LttvNameTables
*name_tables
;
986 LttvAttributeValue v
;
988 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
990 g_assert(*(v
.v_pointer
) != NULL
);
991 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
992 //tcs->eventtype_names = name_tables->eventtype_names;
993 tcs
->syscall_names
= name_tables
->syscall_names
;
994 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
995 tcs
->trap_names
= name_tables
->trap_names
;
996 tcs
->nb_traps
= name_tables
->nb_traps
;
997 tcs
->irq_names
= name_tables
->irq_names
;
998 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1003 free_name_tables(LttvTraceState
*tcs
)
1005 LttvNameTables
*name_tables
;
1007 LttvAttributeValue v
;
1009 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1011 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1012 *(v
.v_pointer
) = NULL
;
1014 // g_free(name_tables->eventtype_names);
1015 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1016 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1017 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1018 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1019 if(name_tables
) g_free(name_tables
);
1022 #ifdef HASH_TABLE_DEBUG
1024 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1026 LttvProcessState
*process
= (LttvProcessState
*)value
;
1028 /* Test for process corruption */
1029 guint stack_len
= process
->execution_stack
->len
;
1032 static void hash_table_check(GHashTable
*table
)
1034 g_hash_table_foreach(table
, test_process
, NULL
);
1041 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1044 LttvExecutionState
*es
;
1046 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1047 guint cpu
= tfs
->cpu
;
1049 #ifdef HASH_TABLE_DEBUG
1050 hash_table_check(ts
->processes
);
1052 LttvProcessState
*process
= ts
->running_process
[cpu
];
1054 guint depth
= process
->execution_stack
->len
;
1056 process
->execution_stack
=
1057 g_array_set_size(process
->execution_stack
, depth
+ 1);
1060 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1062 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1065 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1066 es
->cum_cpu_time
= ltt_time_zero
;
1067 es
->s
= process
->state
->s
;
1068 process
->state
= es
;
1072 * return 1 when empty, else 0 */
1073 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1074 LttvTracefileState
*tfs
)
1076 guint cpu
= tfs
->cpu
;
1077 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1079 guint depth
= process
->execution_stack
->len
;
1085 process
->execution_stack
=
1086 g_array_set_size(process
->execution_stack
, depth
- 1);
1087 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1089 process
->state
->change
= tfs
->parent
.timestamp
;
1094 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1096 guint cpu
= tfs
->cpu
;
1097 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1098 LttvProcessState
*process
= ts
->running_process
[cpu
];
1100 guint depth
= process
->execution_stack
->len
;
1102 if(process
->state
->t
!= t
){
1103 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1104 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1105 g_info("process state has %s when pop_int is %s\n",
1106 g_quark_to_string(process
->state
->t
),
1107 g_quark_to_string(t
));
1108 g_info("{ %u, %u, %s, %s }\n",
1111 g_quark_to_string(process
->name
),
1112 g_quark_to_string(process
->state
->s
));
1117 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1118 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1122 process
->execution_stack
=
1123 g_array_set_size(process
->execution_stack
, depth
- 1);
1124 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1126 process
->state
->change
= tfs
->parent
.timestamp
;
1129 struct search_result
{
1130 const LttTime
*time
; /* Requested time */
1131 LttTime
*best
; /* Best result */
1134 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1136 const LttTime
*elem_time
= (const LttTime
*)a
;
1137 /* Explicit non const cast */
1138 struct search_result
*res
= (struct search_result
*)b
;
1140 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1141 /* The usertrace was created before the schedchange */
1142 /* Get larger keys */
1144 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1145 /* The usertrace was created after the schedchange time */
1146 /* Get smaller keys */
1148 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1149 res
->best
= elem_time
;
1152 res
->best
= elem_time
;
1159 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1160 guint pid
, const LttTime
*timestamp
)
1162 LttvTracefileState
*tfs
= NULL
;
1163 struct search_result res
;
1164 /* Find the usertrace associated with a pid and time interval.
1165 * Search in the usertraces by PID (within a hash) and then, for each
1166 * corresponding element of the array, find the first one with creation
1167 * timestamp the lowest, but higher or equal to "timestamp". */
1168 res
.time
= timestamp
;
1170 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1171 if(usertrace_tree
) {
1172 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1174 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1182 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1183 guint cpu
, guint pid
, GQuark name
, const LttTime
*timestamp
)
1185 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1187 LttvExecutionState
*es
;
1189 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1195 process
->name
= name
;
1196 //process->last_cpu = tfs->cpu_name;
1197 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1198 process
->type
= LTTV_STATE_USER_THREAD
;
1199 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1200 process
->current_function
= 0; //function 0x0 by default.
1202 g_info("Process %u, core %p", process
->pid
, process
);
1203 g_hash_table_insert(tcs
->processes
, process
, process
);
1206 process
->ppid
= parent
->pid
;
1207 process
->creation_time
= *timestamp
;
1210 /* No parent. This process exists but we are missing all information about
1211 its creation. The birth time is set to zero but we remember the time of
1216 process
->creation_time
= ltt_time_zero
;
1219 process
->insertion_time
= *timestamp
;
1220 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1221 process
->creation_time
.tv_nsec
);
1222 process
->pid_time
= g_quark_from_string(buffer
);
1224 //process->last_cpu = tfs->cpu_name;
1225 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1226 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1227 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1228 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1229 es
= process
->state
= &g_array_index(process
->execution_stack
,
1230 LttvExecutionState
, 0);
1231 es
->t
= LTTV_STATE_USER_MODE
;
1232 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1233 es
->entry
= *timestamp
;
1234 //g_assert(timestamp->tv_sec != 0);
1235 es
->change
= *timestamp
;
1236 es
->cum_cpu_time
= ltt_time_zero
;
1237 es
->s
= LTTV_STATE_RUN
;
1239 es
= process
->state
= &g_array_index(process
->execution_stack
,
1240 LttvExecutionState
, 1);
1241 es
->t
= LTTV_STATE_SYSCALL
;
1242 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1243 es
->entry
= *timestamp
;
1244 //g_assert(timestamp->tv_sec != 0);
1245 es
->change
= *timestamp
;
1246 es
->cum_cpu_time
= ltt_time_zero
;
1247 es
->s
= LTTV_STATE_WAIT_FORK
;
1249 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1250 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1251 sizeof(guint64
), 0);
1256 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1259 LttvProcessState key
;
1260 LttvProcessState
*process
;
1264 process
= g_hash_table_lookup(ts
->processes
, &key
);
1269 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1272 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1273 LttvExecutionState
*es
;
1275 /* Put ltt_time_zero creation time for unexisting processes */
1276 if(unlikely(process
== NULL
)) {
1277 process
= lttv_state_create_process(ts
,
1278 NULL
, cpu
, pid
, LTTV_STATE_UNNAMED
, timestamp
);
1279 /* We are not sure is it's a kernel thread or normal thread, put the
1280 * bottom stack state to unknown */
1281 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1282 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1287 /* FIXME : this function should be called when we receive an event telling that
1288 * release_task has been called in the kernel. In happens generally when
1289 * the parent waits for its child terminaison, but may also happen in special
1290 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1291 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1292 * of a killed thread ground, but isn't the leader.
1294 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
1296 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
1297 LttvProcessState key
;
1299 key
.pid
= process
->pid
;
1300 key
.cpu
= process
->cpu
;
1301 g_hash_table_remove(ts
->processes
, &key
);
1302 g_array_free(process
->execution_stack
, TRUE
);
1303 g_array_free(process
->user_stack
, TRUE
);
1308 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1310 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
1311 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
1316 static void lttv_state_free_process_table(GHashTable
*processes
)
1318 g_hash_table_foreach(processes
, free_process_state
, NULL
);
1319 g_hash_table_destroy(processes
);
1323 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
1325 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1326 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1327 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1328 LttField
*f
= thf
->f1
;
1330 LttvExecutionSubmode submode
;
1332 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
1333 guint syscall
= ltt_event_get_unsigned(e
, f
);
1335 if(syscall
< nb_syscalls
) {
1336 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
1339 /* Fixup an incomplete syscall table */
1340 GString
*string
= g_string_new("");
1341 g_string_printf(string
, "syscall %u", syscall
);
1342 submode
= g_quark_from_string(string
->str
);
1343 g_string_free(string
, TRUE
);
1345 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
1350 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
1352 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1354 pop_state(s
, LTTV_STATE_SYSCALL
);
1359 static gboolean
trap_entry(void *hook_data
, void *call_data
)
1361 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1362 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1363 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1364 LttField
*f
= thf
->f1
;
1366 LttvExecutionSubmode submode
;
1368 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
1369 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
1371 if(trap
< nb_traps
) {
1372 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
1374 /* Fixup an incomplete trap table */
1375 GString
*string
= g_string_new("");
1376 g_string_printf(string
, "trap %u", trap
);
1377 submode
= g_quark_from_string(string
->str
);
1378 g_string_free(string
, TRUE
);
1381 push_state(s
, LTTV_STATE_TRAP
, submode
);
1386 static gboolean
trap_exit(void *hook_data
, void *call_data
)
1388 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1390 pop_state(s
, LTTV_STATE_TRAP
);
1395 static gboolean
irq_entry(void *hook_data
, void *call_data
)
1397 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1398 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1399 guint8 fac_id
= ltt_event_facility_id(e
);
1400 guint8 ev_id
= ltt_event_eventtype_id(e
);
1401 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1402 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1403 g_assert(thf
->f1
!= NULL
);
1404 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1405 LttField
*f
= thf
->f1
;
1407 LttvExecutionSubmode submode
;
1409 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[
1410 ltt_event_get_unsigned(e
, f
)];
1412 /* Do something with the info about being in user or system mode when int? */
1413 push_state(s
, LTTV_STATE_IRQ
, submode
);
1417 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
1419 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1421 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
1427 static gboolean
irq_exit(void *hook_data
, void *call_data
)
1429 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1431 pop_state(s
, LTTV_STATE_IRQ
);
1435 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
1437 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1438 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1439 guint8 fac_id
= ltt_event_facility_id(e
);
1440 guint8 ev_id
= ltt_event_eventtype_id(e
);
1441 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1442 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1443 g_assert(thf
->f1
!= NULL
);
1444 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1445 LttField
*f
= thf
->f1
;
1447 LttvExecutionSubmode submode
;
1449 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[
1450 ltt_event_get_long_unsigned(e
, f
)];
1452 /* Do something with the info about being in user or system mode when int? */
1453 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
1457 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1461 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1462 guint cpu
= tfs
->cpu
;
1463 LttvProcessState
*process
= ts
->running_process
[cpu
];
1465 guint depth
= process
->user_stack
->len
;
1467 process
->user_stack
=
1468 g_array_set_size(process
->user_stack
, depth
+ 1);
1470 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
1471 *new_func
= funcptr
;
1472 process
->current_function
= funcptr
;
1475 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
1477 guint cpu
= tfs
->cpu
;
1478 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1479 LttvProcessState
*process
= ts
->running_process
[cpu
];
1481 if(process
->current_function
!= funcptr
){
1482 g_info("Different functions (%lu.%09lu): ignore it\n",
1483 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1484 g_info("process state has %llu when pop_function is %llu\n",
1485 process
->current_function
, funcptr
);
1486 g_info("{ %u, %u, %s, %s }\n",
1489 g_quark_to_string(process
->name
),
1490 g_quark_to_string(process
->state
->s
));
1493 guint depth
= process
->user_stack
->len
;
1496 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1497 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1501 process
->user_stack
=
1502 g_array_set_size(process
->user_stack
, depth
- 1);
1503 process
->current_function
=
1504 g_array_index(process
->user_stack
, guint64
, depth
- 2);
1508 static gboolean
function_entry(void *hook_data
, void *call_data
)
1510 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1511 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1512 guint8 fac_id
= ltt_event_facility_id(e
);
1513 guint8 ev_id
= ltt_event_eventtype_id(e
);
1514 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1515 g_assert(thf
->f1
!= NULL
);
1516 LttField
*f
= thf
->f1
;
1517 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1519 push_function(s
, funcptr
);
1523 static gboolean
function_exit(void *hook_data
, void *call_data
)
1525 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1526 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1527 guint8 fac_id
= ltt_event_facility_id(e
);
1528 guint8 ev_id
= ltt_event_eventtype_id(e
);
1529 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1530 g_assert(thf
->f1
!= NULL
);
1531 LttField
*f
= thf
->f1
;
1532 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
1534 LttvExecutionSubmode submode
;
1536 pop_function(s
, funcptr
);
1540 static gboolean
schedchange(void *hook_data
, void *call_data
)
1542 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1544 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1545 LttvProcessState
*process
= ts
->running_process
[cpu
];
1546 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
1548 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1549 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1550 guint pid_in
, pid_out
;
1553 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
1554 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
1555 state_out
= ltt_event_get_int(e
, thf
->f3
);
1557 if(likely(process
!= NULL
)) {
1559 /* We could not know but it was not the idle process executing.
1560 This should only happen at the beginning, before the first schedule
1561 event, and when the initial information (current process for each CPU)
1562 is missing. It is not obvious how we could, after the fact, compensate
1563 the wrongly attributed statistics. */
1565 //This test only makes sense once the state is known and if there is no
1566 //missing events. We need to silently ignore schedchange coming after a
1567 //process_free, or it causes glitches. (FIXME)
1568 //if(unlikely(process->pid != pid_out)) {
1569 // g_assert(process->pid == 0);
1572 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
1573 process
->state
->s
= LTTV_STATE_ZOMBIE
;
1574 process
->state
->change
= s
->parent
.timestamp
;
1576 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
1577 else process
->state
->s
= LTTV_STATE_WAIT
;
1578 process
->state
->change
= s
->parent
.timestamp
;
1582 exit_process(s
, process
); /* EXIT_DEAD */
1583 /* see sched.h for states */
1585 process
= ts
->running_process
[cpu
] =
1586 lttv_state_find_process_or_create(
1587 (LttvTraceState
*)s
->parent
.t_context
,
1589 &s
->parent
.timestamp
);
1590 process
->state
->s
= LTTV_STATE_RUN
;
1592 if(process
->usertrace
)
1593 process
->usertrace
->cpu
= cpu
;
1594 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1595 process
->state
->change
= s
->parent
.timestamp
;
1599 static gboolean
process_fork(void *hook_data
, void *call_data
)
1601 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1602 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1603 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1606 LttvProcessState
*zombie_process
;
1608 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1609 LttvProcessState
*process
= ts
->running_process
[cpu
];
1610 LttvProcessState
*child_process
;
1613 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1616 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1618 /* Mathieu : it seems like the process might have been scheduled in before the
1619 * fork, and, in a rare case, might be the current process. This might happen
1620 * in a SMP case where we don't have enough precision on the clocks.
1622 * Test reenabled after precision fixes on time. (Mathieu) */
1624 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1626 if(unlikely(zombie_process
!= NULL
)) {
1627 /* Reutilisation of PID. Only now we are sure that the old PID
1628 * has been released. FIXME : should know when release_task happens instead.
1630 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1632 for(i
=0; i
< num_cpus
; i
++) {
1633 g_assert(zombie_process
!= ts
->running_process
[i
]);
1636 exit_process(s
, zombie_process
);
1639 g_assert(process
->pid
!= child_pid
);
1640 // FIXME : Add this test in the "known state" section
1641 // g_assert(process->pid == parent_pid);
1642 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1643 if(child_process
== NULL
) {
1644 child_process
= lttv_state_create_process(ts
, process
, cpu
,
1645 child_pid
, LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
1647 /* The process has already been created : due to time imprecision between
1648 * multiple CPUs : it has been scheduled in before creation. Note that we
1649 * shouldn't have this kind of imprecision.
1651 * Simply put a correct parent.
1653 g_assert(0); /* This is a problematic case : the process has been created
1654 before the fork event */
1655 child_process
->ppid
= process
->pid
;
1657 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
1658 child_process
->name
= process
->name
;
1663 /* We stamp a newly created process as kernel_thread */
1664 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
1666 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1667 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1668 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1671 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1672 LttvProcessState
*process
;
1673 LttvExecutionState
*es
;
1676 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1678 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1679 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1680 es
->t
= LTTV_STATE_SYSCALL
;
1681 process
->type
= LTTV_STATE_KERNEL_THREAD
;
1686 static gboolean
process_exit(void *hook_data
, void *call_data
)
1688 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1689 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1690 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1694 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1695 LttvProcessState
*process
= ts
->running_process
[cpu
];
1697 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1699 // FIXME : Add this test in the "known state" section
1700 // g_assert(process->pid == pid);
1702 if(likely(process
!= NULL
)) {
1703 process
->state
->s
= LTTV_STATE_EXIT
;
1708 static gboolean
process_free(void *hook_data
, void *call_data
)
1710 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1711 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1712 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1713 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1715 LttvProcessState
*process
;
1717 /* PID of the process to release */
1718 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1720 g_assert(release_pid
!= 0);
1722 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
1724 if(likely(process
!= NULL
)) {
1725 /* release_task is happening at kernel level : we can now safely release
1726 * the data structure of the process */
1727 //This test is fun, though, as it may happen that
1728 //at time t : CPU 0 : process_free
1729 //at time t+150ns : CPU 1 : schedule out
1730 //Clearly due to time imprecision, we disable it. (Mathieu)
1731 //If this weird case happen, we have no choice but to put the
1732 //Currently running process on the cpu to 0.
1733 //I re-enable it following time precision fixes. (Mathieu)
1734 //Well, in the case where an process is freed by a process on another CPU
1735 //and still scheduled, it happens that this is the schedchange that will
1736 //drop the last reference count. Do not free it here!
1737 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1739 for(i
=0; i
< num_cpus
; i
++) {
1740 //g_assert(process != ts->running_process[i]);
1741 if(process
== ts
->running_process
[i
]) {
1742 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1746 //if(i == num_cpus) /* process is not scheduled */
1747 //exit_process(s, process); // do nothing : wait for the schedchange to
1748 //delete the process.
1755 static gboolean
process_exec(void *hook_data
, void *call_data
)
1757 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1758 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1759 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1760 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1763 LttvProcessState
*process
= ts
->running_process
[cpu
];
1765 /* PID of the process to release */
1766 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
1767 //name = ltt_event_get_string(e, thf->f1);
1768 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
1770 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
1771 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
1772 memcpy(null_term_name
, name_begin
, name_len
);
1773 null_term_name
[name_len
] = '\0';
1775 process
->name
= g_quark_from_string(null_term_name
);
1776 g_free(null_term_name
);
1780 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
1782 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
1783 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
1784 //It's slow : optimise later by doing this before reading trace.
1785 LttEventType
*et
= ltt_event_eventtype(e
);
1787 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1792 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
1793 LttvProcessState
*process
= ts
->running_process
[cpu
];
1794 LttvProcessState
*parent_process
;
1795 LttField
*f4
, *f5
, *f6
, *f7
;
1796 GQuark type
, mode
, submode
, status
;
1797 LttvExecutionState
*es
;
1800 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
1803 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
1806 command
= ltt_event_get_string(e
, thf
->f3
);
1809 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
1810 type
= ltt_enum_string_get(ltt_field_type(f4
),
1811 ltt_event_get_unsigned(e
, f4
));
1814 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
1815 mode
= ltt_enum_string_get(ltt_field_type(f5
),
1816 ltt_event_get_unsigned(e
, f5
));
1819 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
1820 submode
= ltt_enum_string_get(ltt_field_type(f6
),
1821 ltt_event_get_unsigned(e
, f6
));
1824 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
1825 status
= ltt_enum_string_get(ltt_field_type(f7
),
1826 ltt_event_get_unsigned(e
, f7
));
1828 /* The process might exist if a process was forked while performing the sate dump. */
1829 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1830 if(process
== NULL
) {
1831 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
1832 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
1833 pid
, g_quark_from_string(command
),
1834 &s
->parent
.timestamp
);
1836 /* Keep the stack bottom : a running user mode */
1837 /* Disabled because of inconsistencies in the current statedump states. */
1838 if(type
== LTTV_STATE_KERNEL_THREAD
) {
1839 /* Only keep the bottom */
1840 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
1841 es
= process
->state
= &g_array_index(process
->execution_stack
,
1842 LttvExecutionState
, 0);
1843 es
->t
= LTTV_STATE_SYSCALL
;
1847 /* On top of it : */
1848 es
= process
->state
= &g_array_index(process
->execution_stack
,
1849 LttvExecutionState
, 1);
1850 es
->t
= LTTV_STATE_USER_MODE
;
1857 es
= process
->state
= &g_array_index(process
->execution_stack
,
1858 LttvExecutionState
, 1);
1859 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1860 es
->s
= LTTV_STATE_UNNAMED
;
1861 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
1865 /* The process has already been created :
1866 * Probably was forked while dumping the process state or
1867 * was simply scheduled in prior to get the state dump event.
1868 * We know for sure if it is a user space thread.
1870 process
->ppid
= parent_pid
;
1871 process
->name
= g_quark_from_string(command
);
1872 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1873 if(type
!= LTTV_STATE_KERNEL_THREAD
)
1874 es
->t
= LTTV_STATE_USER_MODE
;
1875 /* Don't mess around with the stack, it will eventually become
1876 * ok after the end of state dump. */
1882 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
1884 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
1886 lttv_state_add_event_hooks(tss
);
1891 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
1893 LttvTraceset
*traceset
= self
->parent
.ts
;
1895 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
1899 LttvTracefileState
*tfs
;
1903 LttvTraceHookByFacility
*thf
;
1905 LttvTraceHook
*hook
;
1907 LttvAttributeValue val
;
1912 nb_trace
= lttv_traceset_number(traceset
);
1913 for(i
= 0 ; i
< nb_trace
; i
++) {
1914 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
1916 /* Find the eventtype id for the following events and register the
1917 associated by id hooks. */
1919 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 17);
1920 hooks
= g_array_set_size(hooks
, 17); // Max possible number of hooks.
1923 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1924 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1925 LTT_FIELD_SYSCALL_ID
, 0, 0,
1926 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1929 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1930 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
1932 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1935 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1936 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_ENTRY
,
1937 LTT_FIELD_TRAP_ID
, 0, 0,
1938 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1941 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1942 LTT_FACILITY_KERNEL
, LTT_EVENT_TRAP_EXIT
,
1944 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1947 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1948 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1949 LTT_FIELD_IRQ_ID
, 0, 0,
1950 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1953 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1954 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
1956 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1959 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1960 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
1961 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
1962 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1965 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1966 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
1968 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1971 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1972 LTT_FACILITY_PROCESS
, LTT_EVENT_SCHEDCHANGE
,
1973 LTT_FIELD_OUT
, LTT_FIELD_IN
, LTT_FIELD_OUT_STATE
,
1974 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1977 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1978 LTT_FACILITY_PROCESS
, LTT_EVENT_FORK
,
1979 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, 0,
1980 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1983 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1984 LTT_FACILITY_PROCESS
, LTT_EVENT_KERNEL_THREAD
,
1985 LTT_FIELD_PID
, 0, 0,
1986 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
1990 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1991 LTT_FACILITY_PROCESS
, LTT_EVENT_EXIT
,
1992 LTT_FIELD_PID
, 0, 0,
1993 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
1996 ret
= lttv_trace_find_hook(ts
->parent
.t
,
1997 LTT_FACILITY_PROCESS
, LTT_EVENT_FREE
,
1998 LTT_FIELD_PID
, 0, 0,
1999 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2002 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2003 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
2004 LTT_FIELD_FILENAME
, 0, 0,
2005 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2008 /* statedump-related hooks */
2009 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2010 LTT_FACILITY_STATEDUMP
, LTT_EVENT_ENUM_PROCESS_STATE
,
2011 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
2012 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2015 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2016 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
2017 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2018 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2021 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2022 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
2023 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
2024 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2027 hooks
= g_array_set_size(hooks
, hn
);
2029 /* Add these hooks to each event_by_id hooks list */
2031 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2033 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2035 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2036 LttvTracefileContext
*, j
));
2038 for(k
= 0 ; k
< hooks
->len
; k
++) {
2039 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2040 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2041 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2043 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2050 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2051 *(val
.v_pointer
) = hooks
;
2055 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2057 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2059 lttv_state_remove_event_hooks(tss
);
2064 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
2066 LttvTraceset
*traceset
= self
->parent
.ts
;
2068 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2072 LttvTracefileState
*tfs
;
2076 LttvTraceHook
*hook
;
2078 LttvTraceHookByFacility
*thf
;
2080 LttvAttributeValue val
;
2082 nb_trace
= lttv_traceset_number(traceset
);
2083 for(i
= 0 ; i
< nb_trace
; i
++) {
2084 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2085 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
2086 hooks
= *(val
.v_pointer
);
2088 /* Remove these hooks from each event_by_id hooks list */
2090 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2092 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2094 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2095 LttvTracefileContext
*, j
));
2097 for(k
= 0 ; k
< hooks
->len
; k
++) {
2098 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
2099 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
2100 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
2102 lttv_hooks_remove_data(
2103 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
2109 for(k
= 0 ; k
< hooks
->len
; k
++)
2110 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
2111 g_array_free(hooks
, TRUE
);
2115 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
2117 guint
*event_count
= (guint
*)hook_data
;
2119 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2120 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
2125 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2127 LttvTracefileState
*tfcs
;
2129 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2131 LttEventPosition
*ep
;
2137 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2139 LttvAttributeValue value
;
2141 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2142 LTTV_STATE_SAVED_STATES
);
2143 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2144 value
= lttv_attribute_add(saved_states_tree
,
2145 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2146 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2147 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2148 *(value
.v_time
) = self
->parent
.timestamp
;
2149 lttv_state_save(tcs
, saved_state_tree
);
2150 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2151 self
->parent
.timestamp
.tv_nsec
);
2153 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2158 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
2160 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
2162 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
2167 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
2175 static gboolean
block_start(void *hook_data
, void *call_data
)
2177 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2179 LttvTracefileState
*tfcs
;
2181 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2183 LttEventPosition
*ep
;
2185 guint i
, nb_block
, nb_event
, nb_tracefile
;
2189 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
2191 LttvAttributeValue value
;
2193 ep
= ltt_event_position_new();
2195 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
2197 /* Count the number of events added since the last block end in any
2200 for(i
= 0 ; i
< nb_tracefile
; i
++) {
2202 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
2203 LttvTracefileContext
, i
));
2204 ltt_event_position(tfcs
->parent
.e
, ep
);
2205 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2206 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
2207 tfcs
->saved_position
= nb_event
;
2211 if(tcs
->nb_event
>= tcs
->save_interval
) {
2212 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2213 LTTV_STATE_SAVED_STATES
);
2214 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
2215 value
= lttv_attribute_add(saved_states_tree
,
2216 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
2217 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
2218 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
2219 *(value
.v_time
) = self
->parent
.timestamp
;
2220 lttv_state_save(tcs
, saved_state_tree
);
2222 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
2223 self
->parent
.timestamp
.tv_nsec
);
2225 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2231 static gboolean
block_end(void *hook_data
, void *call_data
)
2233 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
2235 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
2239 LttEventPosition
*ep
;
2241 guint nb_block
, nb_event
;
2243 ep
= ltt_event_position_new();
2244 ltt_event_position(self
->parent
.e
, ep
);
2245 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
2246 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
2247 self
->saved_position
= 0;
2248 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
2255 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2257 LttvTraceset
*traceset
= self
->parent
.ts
;
2259 guint i
, j
, nb_trace
, nb_tracefile
;
2263 LttvTracefileState
*tfs
;
2265 LttvTraceHook hook_start
, hook_end
;
2267 nb_trace
= lttv_traceset_number(traceset
);
2268 for(i
= 0 ; i
< nb_trace
; i
++) {
2269 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2271 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2272 NULL
, NULL
, block_start
, &hook_start
);
2273 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2274 NULL
, NULL
, block_end
, &hook_end
);
2276 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2278 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2280 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2281 LttvTracefileContext
, j
));
2282 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2283 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
2284 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
2285 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
2291 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
2293 LttvTraceset
*traceset
= self
->parent
.ts
;
2295 guint i
, j
, nb_trace
, nb_tracefile
;
2299 LttvTracefileState
*tfs
;
2302 nb_trace
= lttv_traceset_number(traceset
);
2303 for(i
= 0 ; i
< nb_trace
; i
++) {
2305 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2306 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2308 guint
*event_count
= g_new(guint
, 1);
2311 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2313 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2314 LttvTracefileContext
*, j
));
2315 lttv_hooks_add(tfs
->parent
.event
,
2316 state_save_event_hook
,
2323 lttv_process_traceset_begin(&self
->parent
,
2324 NULL
, NULL
, NULL
, NULL
, NULL
);
2328 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
2330 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2332 lttv_state_save_add_event_hooks(tss
);
2339 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2341 LttvTraceset
*traceset
= self
->parent
.ts
;
2343 guint i
, j
, nb_trace
, nb_tracefile
;
2347 LttvTracefileState
*tfs
;
2349 LttvTraceHook hook_start
, hook_end
;
2351 nb_trace
= lttv_traceset_number(traceset
);
2352 for(i
= 0 ; i
< nb_trace
; i
++) {
2353 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
2355 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
2356 NULL
, NULL
, block_start
, &hook_start
);
2358 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
2359 NULL
, NULL
, block_end
, &hook_end
);
2361 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2363 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2365 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
2366 LttvTracefileContext
, j
));
2367 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2368 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
2369 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2370 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
2376 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
2378 LttvTraceset
*traceset
= self
->parent
.ts
;
2380 guint i
, j
, nb_trace
, nb_tracefile
;
2384 LttvTracefileState
*tfs
;
2386 LttvHooks
*after_trace
= lttv_hooks_new();
2388 lttv_hooks_add(after_trace
,
2389 state_save_after_trace_hook
,
2394 lttv_process_traceset_end(&self
->parent
,
2395 NULL
, after_trace
, NULL
, NULL
, NULL
);
2397 lttv_hooks_destroy(after_trace
);
2399 nb_trace
= lttv_traceset_number(traceset
);
2400 for(i
= 0 ; i
< nb_trace
; i
++) {
2402 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2403 nb_tracefile
= ts
->parent
.tracefiles
->len
;
2405 guint
*event_count
= NULL
;
2407 for(j
= 0 ; j
< nb_tracefile
; j
++) {
2409 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
2410 LttvTracefileContext
*, j
));
2411 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
2412 state_save_event_hook
);
2414 if(event_count
) g_free(event_count
);
2418 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
2420 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2422 lttv_state_save_remove_event_hooks(tss
);
2427 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
2429 LttvTraceset
*traceset
= self
->parent
.ts
;
2433 int min_pos
, mid_pos
, max_pos
;
2435 guint call_rest
= 0;
2437 LttvTraceState
*tcs
;
2439 LttvAttributeValue value
;
2441 LttvAttributeType type
;
2443 LttvAttributeName name
;
2447 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
2449 //g_tree_destroy(self->parent.pqueue);
2450 //self->parent.pqueue = g_tree_new(compare_tracefile);
2452 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
2454 nb_trace
= lttv_traceset_number(traceset
);
2455 for(i
= 0 ; i
< nb_trace
; i
++) {
2456 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
2458 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
2459 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
2460 LTTV_STATE_SAVED_STATES
);
2463 if(saved_states_tree
) {
2464 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
2465 mid_pos
= max_pos
/ 2;
2466 while(min_pos
< max_pos
) {
2467 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
2469 g_assert(type
== LTTV_GOBJECT
);
2470 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
2471 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
2473 g_assert(type
== LTTV_TIME
);
2474 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
2476 closest_tree
= saved_state_tree
;
2478 else max_pos
= mid_pos
- 1;
2480 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
2484 /* restore the closest earlier saved state */
2486 lttv_state_restore(tcs
, closest_tree
);
2490 /* There is no saved state, yet we want to have it. Restart at T0 */
2492 restore_init_state(tcs
);
2493 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
2496 /* We want to seek quickly without restoring/updating the state */
2498 restore_init_state(tcs
);
2499 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
2502 if(!call_rest
) g_info("NOT Calling restore");
2507 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2513 traceset_state_finalize (LttvTracesetState
*self
)
2515 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
2516 finalize(G_OBJECT(self
));
2521 traceset_state_class_init (LttvTracesetContextClass
*klass
)
2523 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2525 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
2526 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
2527 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
2528 klass
->new_traceset_context
= new_traceset_context
;
2529 klass
->new_trace_context
= new_trace_context
;
2530 klass
->new_tracefile_context
= new_tracefile_context
;
2535 lttv_traceset_state_get_type(void)
2537 static GType type
= 0;
2539 static const GTypeInfo info
= {
2540 sizeof (LttvTracesetStateClass
),
2541 NULL
, /* base_init */
2542 NULL
, /* base_finalize */
2543 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
2544 NULL
, /* class_finalize */
2545 NULL
, /* class_data */
2546 sizeof (LttvTracesetState
),
2547 0, /* n_preallocs */
2548 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
2549 NULL
/* value handling */
2552 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
2560 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2566 trace_state_finalize (LttvTraceState
*self
)
2568 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
2569 finalize(G_OBJECT(self
));
2574 trace_state_class_init (LttvTraceStateClass
*klass
)
2576 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2578 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
2579 klass
->state_save
= state_save
;
2580 klass
->state_restore
= state_restore
;
2581 klass
->state_saved_free
= state_saved_free
;
2586 lttv_trace_state_get_type(void)
2588 static GType type
= 0;
2590 static const GTypeInfo info
= {
2591 sizeof (LttvTraceStateClass
),
2592 NULL
, /* base_init */
2593 NULL
, /* base_finalize */
2594 (GClassInitFunc
) trace_state_class_init
, /* class_init */
2595 NULL
, /* class_finalize */
2596 NULL
, /* class_data */
2597 sizeof (LttvTraceState
),
2598 0, /* n_preallocs */
2599 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
2600 NULL
/* value handling */
2603 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
2604 "LttvTraceStateType", &info
, 0);
2611 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
2617 tracefile_state_finalize (LttvTracefileState
*self
)
2619 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
2620 finalize(G_OBJECT(self
));
2625 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
2627 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
2629 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
2634 lttv_tracefile_state_get_type(void)
2636 static GType type
= 0;
2638 static const GTypeInfo info
= {
2639 sizeof (LttvTracefileStateClass
),
2640 NULL
, /* base_init */
2641 NULL
, /* base_finalize */
2642 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
2643 NULL
, /* class_finalize */
2644 NULL
, /* class_data */
2645 sizeof (LttvTracefileState
),
2646 0, /* n_preallocs */
2647 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
2648 NULL
/* value handling */
2651 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
2652 "LttvTracefileStateType", &info
, 0);
2658 static void module_init()
2660 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
2661 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
2662 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
2663 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
2664 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
2665 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
2666 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
2667 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
2668 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
2669 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
2670 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
2671 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
2672 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
2673 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
2674 LTTV_STATE_RUN
= g_quark_from_string("RUN");
2675 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
2676 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
2677 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
2678 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
2679 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
2680 LTTV_STATE_PROCESS
= g_quark_from_string("process");
2681 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
2682 LTTV_STATE_EVENT
= g_quark_from_string("event");
2683 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
2684 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
2685 LTTV_STATE_TIME
= g_quark_from_string("time");
2686 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
2687 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
2688 LTTV_STATE_TRACE_STATE_USE_COUNT
=
2689 g_quark_from_string("trace_state_use_count");
2692 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
2693 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
2694 LTT_FACILITY_PROCESS
= g_quark_from_string("process");
2695 LTT_FACILITY_FS
= g_quark_from_string("fs");
2696 LTT_FACILITY_STATEDUMP
= g_quark_from_string("statedump");
2697 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
2700 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
2701 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
2702 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
2703 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
2704 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
2705 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
2706 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
2707 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
2708 LTT_EVENT_SCHEDCHANGE
= g_quark_from_string("schedchange");
2709 LTT_EVENT_FORK
= g_quark_from_string("fork");
2710 LTT_EVENT_KERNEL_THREAD
= g_quark_from_string("kernel_thread");
2711 LTT_EVENT_EXIT
= g_quark_from_string("exit");
2712 LTT_EVENT_FREE
= g_quark_from_string("free");
2713 LTT_EVENT_EXEC
= g_quark_from_string("exec");
2714 LTT_EVENT_ENUM_PROCESS_STATE
= g_quark_from_string("enumerate_process_state");
2715 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
2716 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
2719 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
2720 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
2721 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
2722 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
2723 LTT_FIELD_OUT
= g_quark_from_string("out");
2724 LTT_FIELD_IN
= g_quark_from_string("in");
2725 LTT_FIELD_OUT_STATE
= g_quark_from_string("out_state");
2726 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
2727 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
2728 LTT_FIELD_PID
= g_quark_from_string("pid");
2729 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
2730 LTT_FIELD_NAME
= g_quark_from_string("name");
2731 LTT_FIELD_TYPE
= g_quark_from_string("type");
2732 LTT_FIELD_MODE
= g_quark_from_string("mode");
2733 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
2734 LTT_FIELD_STATUS
= g_quark_from_string("status");
2735 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
2736 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
2740 static void module_destroy()
2745 LTTV_MODULE("state", "State computation", \
2746 "Update the system state, possibly saving it at intervals", \
2747 module_init
, module_destroy
)