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>
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
43 #define PREALLOCATED_EXECUTION_STACK 10
45 /* Facilities Quarks */
49 LTT_FACILITY_KERNEL_ARCH
,
52 LTT_FACILITY_USER_GENERIC
,
58 LTT_EVENT_SYSCALL_ENTRY
,
59 LTT_EVENT_SYSCALL_EXIT
,
64 LTT_EVENT_SOFT_IRQ_ENTRY
,
65 LTT_EVENT_SOFT_IRQ_EXIT
,
66 LTT_EVENT_SCHED_SCHEDULE
,
67 LTT_EVENT_PROCESS_FORK
,
68 LTT_EVENT_KTHREAD_CREATE
,
69 LTT_EVENT_PROCESS_EXIT
,
70 LTT_EVENT_PROCESS_FREE
,
72 LTT_EVENT_PROCESS_STATE
,
73 LTT_EVENT_STATEDUMP_END
,
74 LTT_EVENT_FUNCTION_ENTRY
,
75 LTT_EVENT_FUNCTION_EXIT
,
76 LTT_EVENT_THREAD_BRAND
,
77 LTT_EVENT_REQUEST_ISSUE
,
78 LTT_EVENT_REQUEST_COMPLETE
;
86 LTT_FIELD_SOFT_IRQ_ID
,
108 LTTV_STATE_MODE_UNKNOWN
,
109 LTTV_STATE_USER_MODE
,
116 LTTV_STATE_SUBMODE_UNKNOWN
,
117 LTTV_STATE_SUBMODE_NONE
;
121 LTTV_STATE_WAIT_FORK
,
130 LTTV_STATE_UNBRANDED
;
133 LTTV_STATE_USER_THREAD
,
134 LTTV_STATE_KERNEL_THREAD
;
151 LTTV_BDEV_BUSY_READING
,
152 LTTV_BDEV_BUSY_WRITING
;
155 LTTV_STATE_TRACEFILES
,
156 LTTV_STATE_PROCESSES
,
158 LTTV_STATE_RUNNING_PROCESS
,
160 LTTV_STATE_SAVED_STATES
,
161 LTTV_STATE_SAVED_STATES_TIME
,
164 LTTV_STATE_NAME_TABLES
,
165 LTTV_STATE_TRACE_STATE_USE_COUNT
,
166 LTTV_STATE_RESOURCE_CPUS
;
168 static void create_max_time(LttvTraceState
*tcs
);
170 static void get_max_time(LttvTraceState
*tcs
);
172 static void free_max_time(LttvTraceState
*tcs
);
174 static void create_name_tables(LttvTraceState
*tcs
);
176 static void get_name_tables(LttvTraceState
*tcs
);
178 static void free_name_tables(LttvTraceState
*tcs
);
180 static void free_saved_state(LttvTraceState
*tcs
);
182 static void lttv_state_free_process_table(GHashTable
*processes
);
184 static void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
185 GPtrArray
*quarktable
);
187 void lttv_state_save(LttvTraceState
*self
, LttvAttribute
*container
)
189 LTTV_TRACE_STATE_GET_CLASS(self
)->state_save(self
, container
);
193 void lttv_state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
195 LTTV_TRACE_STATE_GET_CLASS(self
)->state_restore(self
, container
);
199 void lttv_state_state_saved_free(LttvTraceState
*self
,
200 LttvAttribute
*container
)
202 LTTV_TRACE_STATE_GET_CLASS(self
)->state_saved_free(self
, container
);
206 guint
process_hash(gconstpointer key
)
208 guint pid
= ((const LttvProcessState
*)key
)->pid
;
209 return (pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ;
213 /* If the hash table hash function is well distributed,
214 * the process_equal should compare different pid */
215 gboolean
process_equal(gconstpointer a
, gconstpointer b
)
217 const LttvProcessState
*process_a
, *process_b
;
220 process_a
= (const LttvProcessState
*)a
;
221 process_b
= (const LttvProcessState
*)b
;
223 if(likely(process_a
->pid
!= process_b
->pid
)) ret
= FALSE
;
224 else if(likely(process_a
->pid
== 0 &&
225 process_a
->cpu
!= process_b
->cpu
)) ret
= FALSE
;
230 static void delete_usertrace(gpointer key
, gpointer value
, gpointer user_data
)
232 g_tree_destroy((GTree
*)value
);
235 static void lttv_state_free_usertraces(GHashTable
*usertraces
)
237 g_hash_table_foreach(usertraces
, delete_usertrace
, NULL
);
238 g_hash_table_destroy(usertraces
);
244 restore_init_state(LttvTraceState
*self
)
246 guint i
, nb_cpus
, nb_irqs
;
248 LttvTracefileState
*tfcs
;
250 LttTime start_time
, end_time
;
252 /* Free the process tables */
253 if(self
->processes
!= NULL
) lttv_state_free_process_table(self
->processes
);
254 if(self
->usertraces
!= NULL
) lttv_state_free_usertraces(self
->usertraces
);
255 self
->processes
= g_hash_table_new(process_hash
, process_equal
);
256 self
->usertraces
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
259 /* Seek time to beginning */
260 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
261 // closest. It's the tracecontext job to seek the trace to the beginning
262 // anyway : the init state might be used at the middle of the trace as well...
263 //g_tree_destroy(self->parent.ts_context->pqueue);
264 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
266 ltt_trace_time_span_get(self
->parent
.t
, &start_time
, &end_time
);
268 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
270 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
271 nb_irqs
= self
->nb_irqs
;
273 /* Put the per cpu running_process to beginning state : process 0. */
274 for(i
=0; i
< nb_cpus
; i
++) {
275 LttvExecutionState
*es
;
276 self
->running_process
[i
] = lttv_state_create_process(self
, NULL
, i
, 0, 0,
277 LTTV_STATE_UNNAMED
, &start_time
);
278 /* We are not sure is it's a kernel thread or normal thread, put the
279 * bottom stack state to unknown */
280 self
->running_process
[i
]->execution_stack
=
281 g_array_set_size(self
->running_process
[i
]->execution_stack
, 1);
282 es
= self
->running_process
[i
]->state
=
283 &g_array_index(self
->running_process
[i
]->execution_stack
,
284 LttvExecutionState
, 0);
285 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
286 es
->s
= LTTV_STATE_UNNAMED
;
288 //self->running_process[i]->state->s = LTTV_STATE_RUN;
289 self
->running_process
[i
]->cpu
= i
;
291 /* reset cpu states */
292 if(self
->cpu_states
[i
].mode_stack
->len
> 0)
293 g_array_remove_range(self
->cpu_states
[i
].mode_stack
, 0, self
->cpu_states
[i
].mode_stack
->len
);
296 for(i
=0; i
<nb_irqs
; i
++) {
297 if(self
->irq_states
[i
].mode_stack
->len
> 0)
298 g_array_remove_range(self
->irq_states
[i
].mode_stack
, 0, self
->irq_states
[i
].mode_stack
->len
);
302 nb_tracefile
= self
->parent
.tracefiles
->len
;
304 for(i
= 0 ; i
< nb_tracefile
; i
++) {
306 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
307 LttvTracefileContext
*, i
));
308 ltt_trace_time_span_get(self
->parent
.t
, &tfcs
->parent
.timestamp
, NULL
);
309 // tfcs->saved_position = 0;
310 tfcs
->process
= lttv_state_create_process(tfcs
, NULL
,0);
311 tfcs
->process
->state
->s
= LTTV_STATE_RUN
;
312 tfcs
->process
->last_cpu
= tfcs
->cpu_name
;
313 tfcs
->process
->last_cpu_index
= ltt_tracefile_num(((LttvTracefileContext
*)tfcs
)->tf
);
318 //static LttTime time_zero = {0,0};
320 static gint
compare_usertraces(gconstpointer a
, gconstpointer b
,
323 const LttTime
*t1
= (const LttTime
*)a
;
324 const LttTime
*t2
= (const LttTime
*)b
;
326 return ltt_time_compare(*t1
, *t2
);
329 static void free_usertrace_key(gpointer data
)
334 #define MAX_STRING_LEN 4096
337 state_load_saved_states(LttvTraceState
*tcs
)
340 GPtrArray
*quarktable
;
345 tcs
->has_precomputed_states
= FALSE
;
349 gchar buf
[MAX_STRING_LEN
];
352 trace_path
= g_quark_to_string(ltt_trace_name(tcs
->parent
.t
));
353 strncpy(path
, trace_path
, PATH_MAX
-1);
354 count
= strnlen(trace_path
, PATH_MAX
-1);
355 // quarktable : open, test
356 strncat(path
, "/precomputed/quarktable", PATH_MAX
-count
-1);
357 fp
= fopen(path
, "r");
359 quarktable
= g_ptr_array_sized_new(4096);
361 /* Index 0 is null */
363 if(hdr
== EOF
) return;
364 g_assert(hdr
== HDR_QUARKS
);
368 if(hdr
== EOF
) break;
369 g_assert(hdr
== HDR_QUARK
);
370 g_ptr_array_set_size(quarktable
, q
+1);
373 fread(&buf
[i
], sizeof(gchar
), 1, fp
);
374 if(buf
[i
] == '\0' || feof(fp
)) break;
377 len
= strnlen(buf
, MAX_STRING_LEN
-1);
378 g_ptr_array_index (quarktable
, q
) = g_new(gchar
, len
+1);
379 strncpy(g_ptr_array_index (quarktable
, q
), buf
, len
+1);
385 // saved_states : open, test
386 strncpy(path
, trace_path
, PATH_MAX
-1);
387 count
= strnlen(trace_path
, PATH_MAX
-1);
388 strncat(path
, "/precomputed/states", PATH_MAX
-count
-1);
389 fp
= fopen(path
, "r");
393 if(hdr
!= HDR_TRACE
) goto end
;
395 lttv_trace_states_read_raw(tcs
, fp
, quarktable
);
397 tcs
->has_precomputed_states
= TRUE
;
402 /* Free the quarktable */
403 for(i
=0; i
<quarktable
->len
; i
++) {
404 string
= g_ptr_array_index (quarktable
, i
);
407 g_ptr_array_free(quarktable
, TRUE
);
412 init(LttvTracesetState
*self
, LttvTraceset
*ts
)
414 guint i
, j
, nb_trace
, nb_tracefile
, nb_cpu
;
417 LttvTraceContext
*tc
;
421 LttvTracefileState
*tfcs
;
423 LttvAttributeValue v
;
425 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
426 init((LttvTracesetContext
*)self
, ts
);
428 nb_trace
= lttv_traceset_number(ts
);
429 for(i
= 0 ; i
< nb_trace
; i
++) {
430 tc
= self
->parent
.traces
[i
];
431 tcs
= LTTV_TRACE_STATE(tc
);
432 tcs
->save_interval
= LTTV_STATE_SAVE_INTERVAL
;
433 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
437 if(*(v
.v_uint
) == 1) {
438 create_name_tables(tcs
);
439 create_max_time(tcs
);
441 get_name_tables(tcs
);
444 nb_tracefile
= tc
->tracefiles
->len
;
445 nb_cpu
= ltt_trace_get_num_cpu(tc
->t
);
446 nb_irq
= tcs
->nb_irqs
;
447 tcs
->processes
= NULL
;
448 tcs
->usertraces
= NULL
;
449 tcs
->running_process
= g_new(LttvProcessState
*, nb_cpu
);
451 /* init cpu resource stuff */
452 tcs
->cpu_states
= g_new(LttvCPUState
, nb_cpu
);
453 for(j
= 0; j
<nb_cpu
; j
++) {
454 tcs
->cpu_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
455 g_assert(tcs
->cpu_states
[j
].mode_stack
!= NULL
);
458 /* init irq resource stuff */
459 tcs
->irq_states
= g_new(LttvIRQState
, nb_irq
);
460 for(j
= 0; j
<nb_irq
; j
++) {
461 tcs
->irq_states
[j
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvIRQMode
));
462 g_assert(tcs
->irq_states
[j
].mode_stack
!= NULL
);
465 /* init bdev resource stuff */
466 tcs
->bdev_states
= g_hash_table_new(g_int_hash
, g_int_equal
);
468 restore_init_state(tcs
);
469 for(j
= 0 ; j
< nb_tracefile
; j
++) {
471 LTTV_TRACEFILE_STATE(g_array_index(tc
->tracefiles
,
472 LttvTracefileContext
*, j
));
473 tfcs
->tracefile_name
= ltt_tracefile_name(tfcs
->parent
.tf
);
474 tfcs
->cpu
= ltt_tracefile_cpu(tfcs
->parent
.tf
);
475 tfcs
->cpu_state
= &(tcs
->cpu_states
[tfcs
->cpu
]);
476 if(ltt_tracefile_tid(tfcs
->parent
.tf
) != 0) {
477 /* It's a Usertrace */
478 guint tid
= ltt_tracefile_tid(tfcs
->parent
.tf
);
479 GTree
*usertrace_tree
= (GTree
*)g_hash_table_lookup(tcs
->usertraces
,
481 if(!usertrace_tree
) {
482 usertrace_tree
= g_tree_new_full(compare_usertraces
,
483 NULL
, free_usertrace_key
, NULL
);
484 g_hash_table_insert(tcs
->usertraces
,
485 (gpointer
)tid
, usertrace_tree
);
487 LttTime
*timestamp
= g_new(LttTime
, 1);
488 *timestamp
= ltt_interpolate_time_from_tsc(tfcs
->parent
.tf
,
489 ltt_tracefile_creation(tfcs
->parent
.tf
));
490 g_tree_insert(usertrace_tree
, timestamp
, tfcs
);
494 /* See if the trace has saved states */
495 state_load_saved_states(tcs
);
500 fini(LttvTracesetState
*self
)
506 LttvTracefileState
*tfcs
;
508 LttvAttributeValue v
;
510 nb_trace
= lttv_traceset_number(LTTV_TRACESET_CONTEXT(self
)->ts
);
511 for(i
= 0 ; i
< nb_trace
; i
++) {
512 tcs
= (LttvTraceState
*)(LTTV_TRACESET_CONTEXT(self
)->traces
[i
]);
513 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_TRACE_STATE_USE_COUNT
,
516 g_assert(*(v
.v_uint
) != 0);
519 if(*(v
.v_uint
) == 0) {
520 free_name_tables(tcs
);
522 free_saved_state(tcs
);
524 g_free(tcs
->running_process
);
525 tcs
->running_process
= NULL
;
526 lttv_state_free_process_table(tcs
->processes
);
527 lttv_state_free_usertraces(tcs
->usertraces
);
528 tcs
->processes
= NULL
;
529 tcs
->usertraces
= NULL
;
531 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
532 fini((LttvTracesetContext
*)self
);
536 static LttvTracesetContext
*
537 new_traceset_context(LttvTracesetContext
*self
)
539 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE
, NULL
));
543 static LttvTraceContext
*
544 new_trace_context(LttvTracesetContext
*self
)
546 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE
, NULL
));
550 static LttvTracefileContext
*
551 new_tracefile_context(LttvTracesetContext
*self
)
553 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE
, NULL
));
557 /* Write the process state of the trace */
559 static void write_process_state(gpointer key
, gpointer value
,
562 LttvProcessState
*process
;
564 LttvExecutionState
*es
;
566 FILE *fp
= (FILE *)user_data
;
571 process
= (LttvProcessState
*)value
;
573 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
574 process
, process
->pid
, process
->tgid
, process
->ppid
,
575 g_quark_to_string(process
->type
),
576 process
->creation_time
.tv_sec
,
577 process
->creation_time
.tv_nsec
,
578 process
->insertion_time
.tv_sec
,
579 process
->insertion_time
.tv_nsec
,
580 g_quark_to_string(process
->name
),
581 g_quark_to_string(process
->brand
),
584 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
585 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
586 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
587 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
588 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
589 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
590 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
593 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
594 address
= &g_array_index(process
->user_stack
, guint64
, i
);
595 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
599 if(process
->usertrace
) {
600 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
601 g_quark_to_string(process
->usertrace
->tracefile_name
),
602 process
->usertrace
->cpu
);
606 fprintf(fp
, " </PROCESS>\n");
610 void lttv_state_write(LttvTraceState
*self
, LttTime t
, FILE *fp
)
612 guint i
, nb_tracefile
, nb_block
, offset
;
615 LttvTracefileState
*tfcs
;
619 LttEventPosition
*ep
;
623 ep
= ltt_event_position_new();
625 fprintf(fp
,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t
.tv_sec
, t
.tv_nsec
);
627 g_hash_table_foreach(self
->processes
, write_process_state
, fp
);
629 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
630 for(i
=0;i
<nb_cpus
;i
++) {
631 fprintf(fp
," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
632 i
, self
->running_process
[i
]->pid
);
635 nb_tracefile
= self
->parent
.tracefiles
->len
;
637 for(i
= 0 ; i
< nb_tracefile
; i
++) {
639 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
640 LttvTracefileContext
*, i
));
641 fprintf(fp
, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
642 tfcs
->parent
.timestamp
.tv_sec
,
643 tfcs
->parent
.timestamp
.tv_nsec
);
644 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
645 if(e
== NULL
) fprintf(fp
,"/>\n");
647 ltt_event_position(e
, ep
);
648 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
649 fprintf(fp
, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block
, offset
,
654 fprintf(fp
,"</PROCESS_STATE>\n");
658 static void write_process_state_raw(gpointer key
, gpointer value
,
661 LttvProcessState
*process
;
663 LttvExecutionState
*es
;
665 FILE *fp
= (FILE *)user_data
;
670 process
= (LttvProcessState
*)value
;
671 fputc(HDR_PROCESS
, fp
);
672 //fwrite(&header, sizeof(header), 1, fp);
673 //fprintf(fp, "%s", g_quark_to_string(process->type));
675 fwrite(&process
->type
, sizeof(process
->type
), 1, fp
);
676 //fprintf(fp, "%s", g_quark_to_string(process->name));
678 fwrite(&process
->name
, sizeof(process
->name
), 1, fp
);
679 //fprintf(fp, "%s", g_quark_to_string(process->brand));
681 fwrite(&process
->brand
, sizeof(process
->brand
), 1, fp
);
682 fwrite(&process
->pid
, sizeof(process
->pid
), 1, fp
);
683 fwrite(&process
->tgid
, sizeof(process
->tgid
), 1, fp
);
684 fwrite(&process
->ppid
, sizeof(process
->ppid
), 1, fp
);
685 fwrite(&process
->cpu
, sizeof(process
->cpu
), 1, fp
);
686 fwrite(&process
->creation_time
, sizeof(process
->creation_time
), 1, fp
);
687 fwrite(&process
->insertion_time
, sizeof(process
->insertion_time
), 1, fp
);
691 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
692 process
, process
->pid
, process
->tgid
, process
->ppid
,
693 g_quark_to_string(process
->type
),
694 process
->creation_time
.tv_sec
,
695 process
->creation_time
.tv_nsec
,
696 process
->insertion_time
.tv_sec
,
697 process
->insertion_time
.tv_nsec
,
698 g_quark_to_string(process
->name
),
699 g_quark_to_string(process
->brand
),
703 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
704 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
707 //fprintf(fp, "%s", g_quark_to_string(es->t));
709 fwrite(&es
->t
, sizeof(es
->t
), 1, fp
);
710 //fprintf(fp, "%s", g_quark_to_string(es->n));
712 fwrite(&es
->n
, sizeof(es
->n
), 1, fp
);
713 //fprintf(fp, "%s", g_quark_to_string(es->s));
715 fwrite(&es
->s
, sizeof(es
->s
), 1, fp
);
716 fwrite(&es
->entry
, sizeof(es
->entry
), 1, fp
);
717 fwrite(&es
->change
, sizeof(es
->change
), 1, fp
);
718 fwrite(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
720 fprintf(fp
, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
721 g_quark_to_string(es
->t
), g_quark_to_string(es
->n
),
722 es
->entry
.tv_sec
, es
->entry
.tv_nsec
);
723 fprintf(fp
, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
724 es
->change
.tv_sec
, es
->change
.tv_nsec
, g_quark_to_string(es
->s
));
728 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
729 address
= &g_array_index(process
->user_stack
, guint64
, i
);
730 fputc(HDR_USER_STACK
, fp
);
731 fwrite(&address
, sizeof(address
), 1, fp
);
733 fprintf(fp
, " <USER_STACK ADDRESS=\"%llu\"/>\n",
738 if(process
->usertrace
) {
739 fputc(HDR_USERTRACE
, fp
);
740 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
742 fwrite(&process
->usertrace
->tracefile_name
,
743 sizeof(process
->usertrace
->tracefile_name
), 1, fp
);
744 fwrite(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
746 fprintf(fp
, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
747 g_quark_to_string(process
->usertrace
->tracefile_name
),
748 process
->usertrace
->cpu
);
755 void lttv_state_write_raw(LttvTraceState
*self
, LttTime t
, FILE *fp
)
757 guint i
, nb_tracefile
, nb_block
, offset
;
760 LttvTracefileState
*tfcs
;
764 LttEventPosition
*ep
;
768 ep
= ltt_event_position_new();
770 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
771 fputc(HDR_PROCESS_STATE
, fp
);
772 fwrite(&t
, sizeof(t
), 1, fp
);
774 g_hash_table_foreach(self
->processes
, write_process_state_raw
, fp
);
776 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
777 for(i
=0;i
<nb_cpus
;i
++) {
779 fwrite(&i
, sizeof(i
), 1, fp
); /* cpu number */
780 fwrite(&self
->running_process
[i
]->pid
,
781 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
782 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
783 // i, self->running_process[i]->pid);
786 nb_tracefile
= self
->parent
.tracefiles
->len
;
788 for(i
= 0 ; i
< nb_tracefile
; i
++) {
790 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
791 LttvTracefileContext
*, i
));
792 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
793 // tfcs->parent.timestamp.tv_sec,
794 // tfcs->parent.timestamp.tv_nsec);
795 fputc(HDR_TRACEFILE
, fp
);
796 fwrite(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
797 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
798 * position following : end of trace */
799 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
801 ltt_event_position(e
, ep
);
802 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
803 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
805 fwrite(&nb_block
, sizeof(nb_block
), 1, fp
);
806 fwrite(&offset
, sizeof(offset
), 1, fp
);
807 fwrite(&tsc
, sizeof(tsc
), 1, fp
);
814 /* Read process state from a file */
816 /* Called because a HDR_PROCESS was found */
817 static void read_process_state_raw(LttvTraceState
*self
, FILE *fp
,
818 GPtrArray
*quarktable
)
820 LttvExecutionState
*es
;
821 LttvProcessState
*process
, *parent_process
;
822 LttvProcessState tmp
;
829 /* TODO : check return value */
830 fread(&tmp
.type
, sizeof(tmp
.type
), 1, fp
);
831 fread(&tmp
.name
, sizeof(tmp
.name
), 1, fp
);
832 fread(&tmp
.brand
, sizeof(tmp
.brand
), 1, fp
);
833 fread(&tmp
.pid
, sizeof(tmp
.pid
), 1, fp
);
834 fread(&tmp
.tgid
, sizeof(tmp
.tgid
), 1, fp
);
835 fread(&tmp
.ppid
, sizeof(tmp
.ppid
), 1, fp
);
836 fread(&tmp
.cpu
, sizeof(tmp
.cpu
), 1, fp
);
837 fread(&tmp
.creation_time
, sizeof(tmp
.creation_time
), 1, fp
);
838 fread(&tmp
.insertion_time
, sizeof(tmp
.insertion_time
), 1, fp
);
841 process
= lttv_state_find_process(self
, tmp
.cpu
, tmp
.pid
);
843 /* We must link to the parent */
844 parent_process
= lttv_state_find_process_or_create(self
, ANY_CPU
, tmp
.ppid
,
846 process
= lttv_state_find_process(self
, ANY_CPU
, tmp
.pid
);
847 if(process
== NULL
) {
848 process
= lttv_state_create_process(self
, parent_process
, tmp
.cpu
,
850 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
)),
854 process
->insertion_time
= tmp
.insertion_time
;
855 process
->creation_time
= tmp
.creation_time
;
856 process
->type
= g_quark_from_string(
857 (gchar
*)g_ptr_array_index(quarktable
, tmp
.type
));
858 process
->tgid
= tmp
.tgid
;
859 process
->ppid
= tmp
.ppid
;
860 process
->brand
= g_quark_from_string(
861 (gchar
*)g_ptr_array_index(quarktable
, tmp
.brand
));
863 g_quark_from_string((gchar
*)g_ptr_array_index(quarktable
, tmp
.name
));
867 if(feof(fp
) || ferror(fp
)) goto end_loop
;
869 gint hdr
= fgetc(fp
);
870 if(hdr
== EOF
) goto end_loop
;
874 process
->execution_stack
=
875 g_array_set_size(process
->execution_stack
,
876 process
->execution_stack
->len
+ 1);
877 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
878 process
->execution_stack
->len
-1);
881 fread(&es
->t
, sizeof(es
->t
), 1, fp
);
882 es
->t
= g_quark_from_string(
883 (gchar
*)g_ptr_array_index(quarktable
, es
->t
));
884 fread(&es
->n
, sizeof(es
->n
), 1, fp
);
885 es
->n
= g_quark_from_string(
886 (gchar
*)g_ptr_array_index(quarktable
, es
->n
));
887 fread(&es
->s
, sizeof(es
->s
), 1, fp
);
888 es
->s
= g_quark_from_string(
889 (gchar
*)g_ptr_array_index(quarktable
, es
->s
));
890 fread(&es
->entry
, sizeof(es
->entry
), 1, fp
);
891 fread(&es
->change
, sizeof(es
->change
), 1, fp
);
892 fread(&es
->cum_cpu_time
, sizeof(es
->cum_cpu_time
), 1, fp
);
895 process
->user_stack
= g_array_set_size(process
->user_stack
,
896 process
->user_stack
->len
+ 1);
897 address
= &g_array_index(process
->user_stack
, guint64
,
898 process
->user_stack
->len
-1);
899 fread(address
, sizeof(address
), 1, fp
);
900 process
->current_function
= *address
;
903 fread(&tmpq
, sizeof(tmpq
), 1, fp
);
904 fread(&process
->usertrace
->cpu
, sizeof(process
->usertrace
->cpu
), 1, fp
);
916 /* Called because a HDR_PROCESS_STATE was found */
917 /* Append a saved state to the trace states */
918 void lttv_state_read_raw(LttvTraceState
*self
, FILE *fp
, GPtrArray
*quarktable
)
920 guint i
, nb_tracefile
, nb_block
, offset
;
922 LttvTracefileState
*tfcs
;
924 LttEventPosition
*ep
;
932 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
934 LttvAttributeValue value
;
935 GTree
*pqueue
= self
->parent
.ts_context
->pqueue
;
936 ep
= ltt_event_position_new();
938 restore_init_state(self
);
940 fread(&t
, sizeof(t
), 1, fp
);
943 if(feof(fp
) || ferror(fp
)) goto end_loop
;
945 if(hdr
== EOF
) goto end_loop
;
949 /* Call read_process_state_raw */
950 read_process_state_raw(self
, fp
, quarktable
);
960 case HDR_PROCESS_STATE
:
966 g_error("Error while parsing saved state file : unknown data header %d",
972 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
973 for(i
=0;i
<nb_cpus
;i
++) {
976 g_assert(hdr
== HDR_CPU
);
977 fread(&cpu_num
, sizeof(cpu_num
), 1, fp
); /* cpu number */
978 g_assert(i
== cpu_num
);
979 fread(&self
->running_process
[i
]->pid
,
980 sizeof(self
->running_process
[i
]->pid
), 1, fp
);
983 nb_tracefile
= self
->parent
.tracefiles
->len
;
985 for(i
= 0 ; i
< nb_tracefile
; i
++) {
987 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
988 LttvTracefileContext
*, i
));
989 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
990 // tfcs->parent.timestamp.tv_sec,
991 // tfcs->parent.timestamp.tv_nsec);
992 g_tree_remove(pqueue
, &tfcs
->parent
);
994 g_assert(hdr
== HDR_TRACEFILE
);
995 fread(&tfcs
->parent
.timestamp
, sizeof(tfcs
->parent
.timestamp
), 1, fp
);
996 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
997 * position following : end of trace */
998 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) != 0) {
999 fread(&nb_block
, sizeof(nb_block
), 1, fp
);
1000 fread(&offset
, sizeof(offset
), 1, fp
);
1001 fread(&tsc
, sizeof(tsc
), 1, fp
);
1002 ltt_event_position_set(ep
, tfcs
->parent
.tf
, nb_block
, offset
, tsc
);
1003 gint ret
= ltt_tracefile_seek_position(tfcs
->parent
.tf
, ep
);
1005 g_tree_insert(pqueue
, &tfcs
->parent
, &tfcs
->parent
);
1010 saved_states_tree
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1011 LTTV_STATE_SAVED_STATES
);
1012 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1013 value
= lttv_attribute_add(saved_states_tree
,
1014 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
1015 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
1016 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
1017 *(value
.v_time
) = t
;
1018 lttv_state_save(self
, saved_state_tree
);
1019 g_debug("Saving state at time %lu.%lu", t
.tv_sec
,
1022 *(self
->max_time_state_recomputed_in_seek
) = t
;
1026 /* Called when a HDR_TRACE is found */
1027 void lttv_trace_states_read_raw(LttvTraceState
*tcs
, FILE *fp
,
1028 GPtrArray
*quarktable
)
1033 if(feof(fp
) || ferror(fp
)) goto end_loop
;
1035 if(hdr
== EOF
) goto end_loop
;
1038 case HDR_PROCESS_STATE
:
1039 /* Call read_process_state_raw */
1040 lttv_state_read_raw(tcs
, fp
, quarktable
);
1048 case HDR_USER_STACK
:
1052 g_error("Error while parsing saved state file :"
1053 " unexpected data header %d",
1057 g_error("Error while parsing saved state file : unknown data header %d",
1062 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
1063 restore_init_state(tcs
);
1064 lttv_process_trace_seek_time(tcs
, ltt_time_zero
);
1070 /* Copy each process from an existing hash table to a new one */
1072 static void copy_process_state(gpointer key
, gpointer value
,gpointer user_data
)
1074 LttvProcessState
*process
, *new_process
;
1076 GHashTable
*new_processes
= (GHashTable
*)user_data
;
1080 process
= (LttvProcessState
*)value
;
1081 new_process
= g_new(LttvProcessState
, 1);
1082 *new_process
= *process
;
1083 new_process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1084 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1085 new_process
->execution_stack
=
1086 g_array_set_size(new_process
->execution_stack
,
1087 process
->execution_stack
->len
);
1088 for(i
= 0 ; i
< process
->execution_stack
->len
; i
++) {
1089 g_array_index(new_process
->execution_stack
, LttvExecutionState
, i
) =
1090 g_array_index(process
->execution_stack
, LttvExecutionState
, i
);
1092 new_process
->state
= &g_array_index(new_process
->execution_stack
,
1093 LttvExecutionState
, new_process
->execution_stack
->len
- 1);
1094 new_process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1095 sizeof(guint64
), 0);
1096 new_process
->user_stack
=
1097 g_array_set_size(new_process
->user_stack
,
1098 process
->user_stack
->len
);
1099 for(i
= 0 ; i
< process
->user_stack
->len
; i
++) {
1100 g_array_index(new_process
->user_stack
, guint64
, i
) =
1101 g_array_index(process
->user_stack
, guint64
, i
);
1103 new_process
->current_function
= process
->current_function
;
1104 g_hash_table_insert(new_processes
, new_process
, new_process
);
1108 static GHashTable
*lttv_state_copy_process_table(GHashTable
*processes
)
1110 GHashTable
*new_processes
= g_hash_table_new(process_hash
, process_equal
);
1112 g_hash_table_foreach(processes
, copy_process_state
, new_processes
);
1113 return new_processes
;
1116 static LttvCPUState
*lttv_state_copy_cpu_states(LttvCPUState
*states
, guint n
)
1119 LttvCPUState
*retval
;
1121 retval
= g_malloc(n
*sizeof(LttvCPUState
));
1123 for(i
=0; i
<n
; i
++) {
1124 retval
[i
].mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(LttvCPUMode
));
1125 retval
[i
].last_irq
= states
[i
].last_irq
;
1126 g_array_set_size(retval
[i
].mode_stack
, states
[i
].mode_stack
->len
);
1127 for(j
=0; j
<states
[i
].mode_stack
->len
; j
++) {
1128 g_array_index(retval
[i
].mode_stack
, GQuark
, j
) = g_array_index(states
[i
].mode_stack
, GQuark
, j
);
1135 static void lttv_state_free_cpu_states(LttvCPUState
*states
, guint n
)
1139 for(i
=0; i
<n
; i
++) {
1140 g_array_free(states
[i
].mode_stack
, FALSE
);
1146 /* The saved state for each trace contains a member "processes", which
1147 stores a copy of the process table, and a member "tracefiles" with
1148 one entry per tracefile. Each tracefile has a "process" member pointing
1149 to the current process and a "position" member storing the tracefile
1150 position (needed to seek to the current "next" event. */
1152 static void state_save(LttvTraceState
*self
, LttvAttribute
*container
)
1154 guint i
, nb_tracefile
, nb_cpus
;
1156 LttvTracefileState
*tfcs
;
1158 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1160 guint
*running_process
;
1162 LttvAttributeType type
;
1164 LttvAttributeValue value
;
1166 LttvAttributeName name
;
1168 LttEventPosition
*ep
;
1170 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1171 LTTV_STATE_TRACEFILES
);
1173 value
= lttv_attribute_add(container
, LTTV_STATE_PROCESSES
,
1175 *(value
.v_pointer
) = lttv_state_copy_process_table(self
->processes
);
1177 /* Add the currently running processes array */
1178 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1179 running_process
= g_new(guint
, nb_cpus
);
1180 for(i
=0;i
<nb_cpus
;i
++) {
1181 running_process
[i
] = self
->running_process
[i
]->pid
;
1183 value
= lttv_attribute_add(container
, LTTV_STATE_RUNNING_PROCESS
,
1185 *(value
.v_pointer
) = running_process
;
1187 g_info("State save");
1189 nb_tracefile
= self
->parent
.tracefiles
->len
;
1191 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1193 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1194 LttvTracefileContext
*, i
));
1195 tracefile_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
1196 value
= lttv_attribute_add(tracefiles_tree
, i
,
1198 *(value
.v_gobject
) = (GObject
*)tracefile_tree
;
1200 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_PROCESS
,
1202 *(value
.v_uint
) = tfcs
->process
->pid
;
1204 value
= lttv_attribute_add(tracefile_tree
, LTTV_STATE_EVENT
,
1206 /* Only save the position if the tfs has not infinite time. */
1207 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1208 // && current_tfcs != tfcs) {
1209 if(ltt_time_compare(tfcs
->parent
.timestamp
, ltt_time_infinite
) == 0) {
1210 *(value
.v_pointer
) = NULL
;
1212 LttEvent
*e
= ltt_tracefile_get_event(tfcs
->parent
.tf
);
1213 ep
= ltt_event_position_new();
1214 ltt_event_position(e
, ep
);
1215 *(value
.v_pointer
) = ep
;
1217 guint nb_block
, offset
;
1220 ltt_event_position_get(ep
, &tf
, &nb_block
, &offset
, &tsc
);
1221 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block
, offset
,
1223 tfcs
->parent
.timestamp
.tv_sec
, tfcs
->parent
.timestamp
.tv_nsec
);
1227 value
= lttv_attribute_add(container
, LTTV_STATE_RESOURCE_CPUS
,
1229 guint size
= sizeof(LttvCPUState
)*nb_cpus
;
1230 *(value
.v_pointer
) = lttv_state_copy_cpu_states(self
->cpu_states
, nb_cpus
);
1234 static void state_restore(LttvTraceState
*self
, LttvAttribute
*container
)
1236 guint i
, nb_tracefile
, pid
, nb_cpus
;
1238 LttvTracefileState
*tfcs
;
1240 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1242 guint
*running_process
;
1244 LttvAttributeType type
;
1246 LttvAttributeValue value
;
1248 LttvAttributeName name
;
1252 LttEventPosition
*ep
;
1254 LttvTracesetContext
*tsc
= self
->parent
.ts_context
;
1256 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1257 LTTV_STATE_TRACEFILES
);
1259 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1261 g_assert(type
== LTTV_POINTER
);
1262 lttv_state_free_process_table(self
->processes
);
1263 self
->processes
= lttv_state_copy_process_table(*(value
.v_pointer
));
1265 /* Add the currently running processes array */
1266 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1267 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1269 g_assert(type
== LTTV_POINTER
);
1270 running_process
= *(value
.v_pointer
);
1271 for(i
=0;i
<nb_cpus
;i
++) {
1272 pid
= running_process
[i
];
1273 self
->running_process
[i
] = lttv_state_find_process(self
, i
, pid
);
1274 g_assert(self
->running_process
[i
] != NULL
);
1277 printf("state restore\n");
1279 nb_tracefile
= self
->parent
.tracefiles
->len
;
1281 //g_tree_destroy(tsc->pqueue);
1282 //tsc->pqueue = g_tree_new(compare_tracefile);
1284 /* restore cpu resource states */
1285 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RESOURCE_CPUS
, &value
);
1286 g_assert(type
== LTTV_POINTER
);
1287 lttv_state_free_cpu_states(self
->cpu_states
, nb_cpus
);
1288 self
->cpu_states
= lttv_state_copy_cpu_states(*(value
.v_pointer
), nb_cpus
);
1290 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1292 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1293 LttvTracefileContext
*, i
));
1294 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1295 g_assert(type
== LTTV_GOBJECT
);
1296 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1298 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_PROCESS
,
1300 g_assert(type
== LTTV_UINT
);
1301 pid
= *(value
.v_uint
);
1302 tfcs
->process
= lttv_state_find_process_or_create(tfcs
, pid
);
1304 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1306 g_assert(type
== LTTV_POINTER
);
1307 //g_assert(*(value.v_pointer) != NULL);
1308 ep
= *(value
.v_pointer
);
1309 g_assert(tfcs
->parent
.t_context
!= NULL
);
1311 tfcs
->cpu_state
= &self
->cpu_states
[tfcs
->cpu
];
1313 LttvTracefileContext
*tfc
= LTTV_TRACEFILE_CONTEXT(tfcs
);
1314 g_tree_remove(tsc
->pqueue
, tfc
);
1317 g_assert(ltt_tracefile_seek_position(tfc
->tf
, ep
) == 0);
1318 tfc
->timestamp
= ltt_event_time(ltt_tracefile_get_event(tfc
->tf
));
1319 g_assert(ltt_time_compare(tfc
->timestamp
, ltt_time_infinite
) != 0);
1320 g_tree_insert(tsc
->pqueue
, tfc
, tfc
);
1321 g_info("Restoring state for a tf at time %lu.%lu", tfc
->timestamp
.tv_sec
, tfc
->timestamp
.tv_nsec
);
1323 tfc
->timestamp
= ltt_time_infinite
;
1329 static void state_saved_free(LttvTraceState
*self
, LttvAttribute
*container
)
1331 guint i
, nb_tracefile
, nb_cpus
;
1333 LttvTracefileState
*tfcs
;
1335 LttvAttribute
*tracefiles_tree
, *tracefile_tree
;
1337 guint
*running_process
;
1339 LttvAttributeType type
;
1341 LttvAttributeValue value
;
1343 LttvAttributeName name
;
1347 LttEventPosition
*ep
;
1349 tracefiles_tree
= lttv_attribute_find_subdir(container
,
1350 LTTV_STATE_TRACEFILES
);
1351 g_object_ref(G_OBJECT(tracefiles_tree
));
1352 lttv_attribute_remove_by_name(container
, LTTV_STATE_TRACEFILES
);
1354 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_PROCESSES
,
1356 g_assert(type
== LTTV_POINTER
);
1357 lttv_state_free_process_table(*(value
.v_pointer
));
1358 *(value
.v_pointer
) = NULL
;
1359 lttv_attribute_remove_by_name(container
, LTTV_STATE_PROCESSES
);
1361 /* Free running processes array */
1362 nb_cpus
= ltt_trace_get_num_cpu(self
->parent
.t
);
1363 type
= lttv_attribute_get_by_name(container
, LTTV_STATE_RUNNING_PROCESS
,
1365 g_assert(type
== LTTV_POINTER
);
1366 running_process
= *(value
.v_pointer
);
1367 g_free(running_process
);
1369 nb_tracefile
= self
->parent
.tracefiles
->len
;
1371 for(i
= 0 ; i
< nb_tracefile
; i
++) {
1373 LTTV_TRACEFILE_STATE(g_array_index(self
->parent
.tracefiles
,
1374 LttvTracefileContext
*, i
));
1375 type
= lttv_attribute_get(tracefiles_tree
, i
, &name
, &value
, &is_named
);
1376 g_assert(type
== LTTV_GOBJECT
);
1377 tracefile_tree
= *((LttvAttribute
**)(value
.v_gobject
));
1379 type
= lttv_attribute_get_by_name(tracefile_tree
, LTTV_STATE_EVENT
,
1381 g_assert(type
== LTTV_POINTER
);
1382 if(*(value
.v_pointer
) != NULL
) g_free(*(value
.v_pointer
));
1384 g_object_unref(G_OBJECT(tracefiles_tree
));
1388 static void free_saved_state(LttvTraceState
*self
)
1392 LttvAttributeType type
;
1394 LttvAttributeValue value
;
1396 LttvAttributeName name
;
1400 LttvAttribute
*saved_states
;
1402 saved_states
= lttv_attribute_find_subdir(self
->parent
.t_a
,
1403 LTTV_STATE_SAVED_STATES
);
1405 nb
= lttv_attribute_get_number(saved_states
);
1406 for(i
= 0 ; i
< nb
; i
++) {
1407 type
= lttv_attribute_get(saved_states
, i
, &name
, &value
, &is_named
);
1408 g_assert(type
== LTTV_GOBJECT
);
1409 state_saved_free(self
, *((LttvAttribute
**)value
.v_gobject
));
1412 lttv_attribute_remove_by_name(self
->parent
.t_a
, LTTV_STATE_SAVED_STATES
);
1417 create_max_time(LttvTraceState
*tcs
)
1419 LttvAttributeValue v
;
1421 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1423 g_assert(*(v
.v_pointer
) == NULL
);
1424 *(v
.v_pointer
) = g_new(LttTime
,1);
1425 *((LttTime
*)*(v
.v_pointer
)) = ltt_time_zero
;
1430 get_max_time(LttvTraceState
*tcs
)
1432 LttvAttributeValue v
;
1434 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1436 g_assert(*(v
.v_pointer
) != NULL
);
1437 tcs
->max_time_state_recomputed_in_seek
= (LttTime
*)*(v
.v_pointer
);
1442 free_max_time(LttvTraceState
*tcs
)
1444 LttvAttributeValue v
;
1446 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_SAVED_STATES_TIME
,
1448 g_free(*(v
.v_pointer
));
1449 *(v
.v_pointer
) = NULL
;
1453 typedef struct _LttvNameTables
{
1454 // FIXME GQuark *eventtype_names;
1455 GQuark
*syscall_names
;
1461 GQuark
*soft_irq_names
;
1467 create_name_tables(LttvTraceState
*tcs
)
1471 GQuark f_name
, e_name
;
1475 LttvTraceHookByFacility
*thf
;
1481 GString
*fe_name
= g_string_new("");
1483 LttvNameTables
*name_tables
= g_new(LttvNameTables
, 1);
1485 LttvAttributeValue v
;
1487 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1489 g_assert(*(v
.v_pointer
) == NULL
);
1490 *(v
.v_pointer
) = name_tables
;
1491 #if 0 // Use iteration over the facilities_by_name and then list all event
1492 // types of each facility
1493 nb
= ltt_trace_eventtype_number(tcs
->parent
.t
);
1494 name_tables
->eventtype_names
= g_new(GQuark
, nb
);
1495 for(i
= 0 ; i
< nb
; i
++) {
1496 et
= ltt_trace_eventtype_get(tcs
->parent
.t
, i
);
1497 e_name
= ltt_eventtype_name(et
);
1498 f_name
= ltt_facility_name(ltt_eventtype_facility(et
));
1499 g_string_printf(fe_name
, "%s.%s", f_name
, e_name
);
1500 name_tables
->eventtype_names
[i
] = g_quark_from_string(fe_name
->str
);
1503 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1504 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
1505 LTT_FIELD_SYSCALL_ID
, 0, 0,
1508 thf
= lttv_trace_hook_get_first(&h
);
1510 t
= ltt_field_type(thf
->f1
);
1511 nb
= ltt_type_element_number(t
);
1513 lttv_trace_hook_destroy(&h
);
1515 name_tables
->syscall_names
= g_new(GQuark
, nb
);
1516 name_tables
->nb_syscalls
= nb
;
1518 for(i
= 0 ; i
< nb
; i
++) {
1519 name_tables
->syscall_names
[i
] = ltt_enum_string_get(t
, i
);
1520 if(!name_tables
->syscall_names
[i
]) {
1521 GString
*string
= g_string_new("");
1522 g_string_printf(string
, "syscall %u", i
);
1523 name_tables
->syscall_names
[i
] = g_quark_from_string(string
->str
);
1524 g_string_free(string
, TRUE
);
1528 //name_tables->syscall_names = g_new(GQuark, 256);
1529 //for(i = 0 ; i < 256 ; i++) {
1530 // g_string_printf(fe_name, "syscall %d", i);
1531 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1534 name_tables
->syscall_names
= NULL
;
1535 name_tables
->nb_syscalls
= 0;
1538 if(!lttv_trace_find_hook(tcs
->parent
.t
, LTT_FACILITY_KERNEL_ARCH
,
1539 LTT_EVENT_TRAP_ENTRY
,
1540 LTT_FIELD_TRAP_ID
, 0, 0,
1543 thf
= lttv_trace_hook_get_first(&h
);
1545 t
= ltt_field_type(thf
->f1
);
1546 //nb = ltt_type_element_number(t);
1548 lttv_trace_hook_destroy(&h
);
1551 name_tables->trap_names = g_new(GQuark, nb);
1552 for(i = 0 ; i < nb ; i++) {
1553 name_tables->trap_names[i] = g_quark_from_string(
1554 ltt_enum_string_get(t, i));
1557 name_tables
->nb_traps
= 256;
1558 name_tables
->trap_names
= g_new(GQuark
, 256);
1559 for(i
= 0 ; i
< 256 ; i
++) {
1560 g_string_printf(fe_name
, "trap %d", i
);
1561 name_tables
->trap_names
[i
] = g_quark_from_string(fe_name
->str
);
1564 name_tables
->trap_names
= NULL
;
1565 name_tables
->nb_traps
= 0;
1568 if(!lttv_trace_find_hook(tcs
->parent
.t
,
1569 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
1570 LTT_FIELD_IRQ_ID
, 0, 0,
1573 thf
= lttv_trace_hook_get_first(&h
);
1575 t
= ltt_field_type(thf
->f1
);
1576 //nb = ltt_type_element_number(t);
1578 lttv_trace_hook_destroy(&h
);
1581 name_tables->irq_names = g_new(GQuark, nb);
1582 for(i = 0 ; i < nb ; i++) {
1583 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1587 name_tables
->nb_irqs
= 256;
1588 name_tables
->irq_names
= g_new(GQuark
, 256);
1589 for(i
= 0 ; i
< 256 ; i
++) {
1590 g_string_printf(fe_name
, "irq %d", i
);
1591 name_tables
->irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1594 name_tables
->nb_irqs
= 0;
1595 name_tables
->irq_names
= NULL
;
1598 name_tables->soft_irq_names = g_new(GQuark, nb);
1599 for(i = 0 ; i < nb ; i++) {
1600 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1604 name_tables
->nb_softirqs
= 256;
1605 name_tables
->soft_irq_names
= g_new(GQuark
, 256);
1606 for(i
= 0 ; i
< 256 ; i
++) {
1607 g_string_printf(fe_name
, "softirq %d", i
);
1608 name_tables
->soft_irq_names
[i
] = g_quark_from_string(fe_name
->str
);
1612 g_string_free(fe_name
, TRUE
);
1617 get_name_tables(LttvTraceState
*tcs
)
1619 LttvNameTables
*name_tables
;
1621 LttvAttributeValue v
;
1623 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1625 g_assert(*(v
.v_pointer
) != NULL
);
1626 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1627 //tcs->eventtype_names = name_tables->eventtype_names;
1628 tcs
->syscall_names
= name_tables
->syscall_names
;
1629 tcs
->nb_syscalls
= name_tables
->nb_syscalls
;
1630 tcs
->trap_names
= name_tables
->trap_names
;
1631 tcs
->nb_traps
= name_tables
->nb_traps
;
1632 tcs
->irq_names
= name_tables
->irq_names
;
1633 tcs
->soft_irq_names
= name_tables
->soft_irq_names
;
1634 tcs
->nb_irqs
= name_tables
->nb_irqs
;
1635 tcs
->nb_softirqs
= name_tables
->nb_softirqs
;
1640 free_name_tables(LttvTraceState
*tcs
)
1642 LttvNameTables
*name_tables
;
1644 LttvAttributeValue v
;
1646 lttv_attribute_find(tcs
->parent
.t_a
, LTTV_STATE_NAME_TABLES
,
1648 name_tables
= (LttvNameTables
*)*(v
.v_pointer
);
1649 *(v
.v_pointer
) = NULL
;
1651 // g_free(name_tables->eventtype_names);
1652 if(name_tables
->syscall_names
) g_free(name_tables
->syscall_names
);
1653 if(name_tables
->trap_names
) g_free(name_tables
->trap_names
);
1654 if(name_tables
->irq_names
) g_free(name_tables
->irq_names
);
1655 if(name_tables
->soft_irq_names
) g_free(name_tables
->soft_irq_names
);
1656 if(name_tables
) g_free(name_tables
);
1659 #ifdef HASH_TABLE_DEBUG
1661 static void test_process(gpointer key
, gpointer value
, gpointer user_data
)
1663 LttvProcessState
*process
= (LttvProcessState
*)value
;
1665 /* Test for process corruption */
1666 guint stack_len
= process
->execution_stack
->len
;
1669 static void hash_table_check(GHashTable
*table
)
1671 g_hash_table_foreach(table
, test_process
, NULL
);
1677 /* clears the stack and sets the state passed as argument */
1678 static void cpu_set_base_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1680 g_array_set_size(cpust
->mode_stack
, 1);
1681 ((GQuark
*)cpust
->mode_stack
->data
)[0] = state
;
1684 static void cpu_push_mode(LttvCPUState
*cpust
, LttvCPUMode state
)
1686 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
+ 1);
1687 ((GQuark
*)cpust
->mode_stack
->data
)[cpust
->mode_stack
->len
- 1] = state
;
1690 static void cpu_pop_mode(LttvCPUState
*cpust
)
1692 if(cpust
->mode_stack
->len
== 1)
1693 cpu_set_base_mode(cpust
, LTTV_CPU_UNKNOWN
);
1695 g_array_set_size(cpust
->mode_stack
, cpust
->mode_stack
->len
- 1);
1698 /* clears the stack and sets the state passed as argument */
1699 static void bdev_set_base_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1701 g_array_set_size(bdevst
->mode_stack
, 1);
1702 ((GQuark
*)bdevst
->mode_stack
->data
)[0] = state
;
1705 static void bdev_push_mode(LttvBdevState
*bdevst
, LttvBdevMode state
)
1707 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
+ 1);
1708 ((GQuark
*)bdevst
->mode_stack
->data
)[bdevst
->mode_stack
->len
- 1] = state
;
1711 static void bdev_pop_mode(LttvBdevState
*bdevst
)
1713 if(bdevst
->mode_stack
->len
== 1)
1714 bdev_set_base_mode(bdevst
, LTTV_BDEV_UNKNOWN
);
1716 g_array_set_size(bdevst
->mode_stack
, bdevst
->mode_stack
->len
- 1);
1719 static void irq_set_base_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1721 g_array_set_size(irqst
->mode_stack
, 1);
1722 ((GQuark
*)irqst
->mode_stack
->data
)[0] = state
;
1725 static void irq_push_mode(LttvIRQState
*irqst
, LttvIRQMode state
)
1727 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
+ 1);
1728 ((GQuark
*)irqst
->mode_stack
->data
)[irqst
->mode_stack
->len
- 1] = state
;
1731 static void irq_pop_mode(LttvIRQState
*irqst
)
1733 if(irqst
->mode_stack
->len
== 1)
1734 irq_set_base_mode(irqst
, LTTV_IRQ_UNKNOWN
);
1736 g_array_set_size(irqst
->mode_stack
, irqst
->mode_stack
->len
- 1);
1739 static void push_state(LttvTracefileState
*tfs
, LttvExecutionMode t
,
1742 LttvExecutionState
*es
;
1744 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1745 guint cpu
= tfs
->cpu
;
1747 #ifdef HASH_TABLE_DEBUG
1748 hash_table_check(ts
->processes
);
1750 LttvProcessState
*process
= ts
->running_process
[cpu
];
1752 guint depth
= process
->execution_stack
->len
;
1754 process
->execution_stack
=
1755 g_array_set_size(process
->execution_stack
, depth
+ 1);
1758 &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
- 1);
1760 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, depth
);
1763 es
->entry
= es
->change
= tfs
->parent
.timestamp
;
1764 es
->cum_cpu_time
= ltt_time_zero
;
1765 es
->s
= process
->state
->s
;
1766 process
->state
= es
;
1770 * return 1 when empty, else 0 */
1771 int lttv_state_pop_state_cleanup(LttvProcessState
*process
,
1772 LttvTracefileState
*tfs
)
1774 guint cpu
= tfs
->cpu
;
1775 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1777 guint depth
= process
->execution_stack
->len
;
1783 process
->execution_stack
=
1784 g_array_set_size(process
->execution_stack
, depth
- 1);
1785 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1787 process
->state
->change
= tfs
->parent
.timestamp
;
1792 static void pop_state(LttvTracefileState
*tfs
, LttvExecutionMode t
)
1794 guint cpu
= tfs
->cpu
;
1795 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
1796 LttvProcessState
*process
= ts
->running_process
[cpu
];
1798 guint depth
= process
->execution_stack
->len
;
1800 if(process
->state
->t
!= t
){
1801 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1802 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1803 g_info("process state has %s when pop_int is %s\n",
1804 g_quark_to_string(process
->state
->t
),
1805 g_quark_to_string(t
));
1806 g_info("{ %u, %u, %s, %s, %s }\n",
1809 g_quark_to_string(process
->name
),
1810 g_quark_to_string(process
->brand
),
1811 g_quark_to_string(process
->state
->s
));
1816 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1817 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
1821 process
->execution_stack
=
1822 g_array_set_size(process
->execution_stack
, depth
- 1);
1823 process
->state
= &g_array_index(process
->execution_stack
, LttvExecutionState
,
1825 process
->state
->change
= tfs
->parent
.timestamp
;
1828 struct search_result
{
1829 const LttTime
*time
; /* Requested time */
1830 LttTime
*best
; /* Best result */
1833 static gint
search_usertrace(gconstpointer a
, gconstpointer b
)
1835 const LttTime
*elem_time
= (const LttTime
*)a
;
1836 /* Explicit non const cast */
1837 struct search_result
*res
= (struct search_result
*)b
;
1839 if(ltt_time_compare(*elem_time
, *(res
->time
)) < 0) {
1840 /* The usertrace was created before the schedchange */
1841 /* Get larger keys */
1843 } else if(ltt_time_compare(*elem_time
, *(res
->time
)) >= 0) {
1844 /* The usertrace was created after the schedchange time */
1845 /* Get smaller keys */
1847 if(ltt_time_compare(*elem_time
, *res
->best
) < 0) {
1848 res
->best
= elem_time
;
1851 res
->best
= elem_time
;
1858 static LttvTracefileState
*ltt_state_usertrace_find(LttvTraceState
*tcs
,
1859 guint pid
, const LttTime
*timestamp
)
1861 LttvTracefileState
*tfs
= NULL
;
1862 struct search_result res
;
1863 /* Find the usertrace associated with a pid and time interval.
1864 * Search in the usertraces by PID (within a hash) and then, for each
1865 * corresponding element of the array, find the first one with creation
1866 * timestamp the lowest, but higher or equal to "timestamp". */
1867 res
.time
= timestamp
;
1869 GTree
*usertrace_tree
= g_hash_table_lookup(tcs
->usertraces
, (gpointer
)pid
);
1870 if(usertrace_tree
) {
1871 g_tree_search(usertrace_tree
, search_usertrace
, &res
);
1873 tfs
= g_tree_lookup(usertrace_tree
, res
.best
);
1881 lttv_state_create_process(LttvTraceState
*tcs
, LttvProcessState
*parent
,
1882 guint cpu
, guint pid
, guint tgid
, GQuark name
, const LttTime
*timestamp
)
1884 LttvProcessState
*process
= g_new(LttvProcessState
, 1);
1886 LttvExecutionState
*es
;
1888 LttvTraceContext
*tc
= (LttvTraceContext
*)tcs
;
1893 process
->tgid
= tgid
;
1895 process
->name
= name
;
1896 process
->brand
= LTTV_STATE_UNBRANDED
;
1897 //process->last_cpu = tfs->cpu_name;
1898 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1899 process
->type
= LTTV_STATE_USER_THREAD
;
1900 process
->usertrace
= ltt_state_usertrace_find(tcs
, pid
, timestamp
);
1901 process
->current_function
= 0; //function 0x0 by default.
1903 g_info("Process %u, core %p", process
->pid
, process
);
1904 g_hash_table_insert(tcs
->processes
, process
, process
);
1907 process
->ppid
= parent
->pid
;
1908 process
->creation_time
= *timestamp
;
1911 /* No parent. This process exists but we are missing all information about
1912 its creation. The birth time is set to zero but we remember the time of
1917 process
->creation_time
= ltt_time_zero
;
1920 process
->insertion_time
= *timestamp
;
1921 sprintf(buffer
,"%d-%lu.%lu",pid
, process
->creation_time
.tv_sec
,
1922 process
->creation_time
.tv_nsec
);
1923 process
->pid_time
= g_quark_from_string(buffer
);
1925 //process->last_cpu = tfs->cpu_name;
1926 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1927 process
->execution_stack
= g_array_sized_new(FALSE
, FALSE
,
1928 sizeof(LttvExecutionState
), PREALLOCATED_EXECUTION_STACK
);
1929 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 2);
1930 es
= process
->state
= &g_array_index(process
->execution_stack
,
1931 LttvExecutionState
, 0);
1932 es
->t
= LTTV_STATE_USER_MODE
;
1933 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1934 es
->entry
= *timestamp
;
1935 //g_assert(timestamp->tv_sec != 0);
1936 es
->change
= *timestamp
;
1937 es
->cum_cpu_time
= ltt_time_zero
;
1938 es
->s
= LTTV_STATE_RUN
;
1940 es
= process
->state
= &g_array_index(process
->execution_stack
,
1941 LttvExecutionState
, 1);
1942 es
->t
= LTTV_STATE_SYSCALL
;
1943 es
->n
= LTTV_STATE_SUBMODE_NONE
;
1944 es
->entry
= *timestamp
;
1945 //g_assert(timestamp->tv_sec != 0);
1946 es
->change
= *timestamp
;
1947 es
->cum_cpu_time
= ltt_time_zero
;
1948 es
->s
= LTTV_STATE_WAIT_FORK
;
1950 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1951 process
->user_stack
= g_array_sized_new(FALSE
, FALSE
,
1952 sizeof(guint64
), 0);
1957 LttvProcessState
*lttv_state_find_process(LttvTraceState
*ts
, guint cpu
,
1960 LttvProcessState key
;
1961 LttvProcessState
*process
;
1965 process
= g_hash_table_lookup(ts
->processes
, &key
);
1970 lttv_state_find_process_or_create(LttvTraceState
*ts
, guint cpu
, guint pid
,
1971 const LttTime
*timestamp
)
1973 LttvProcessState
*process
= lttv_state_find_process(ts
, cpu
, pid
);
1974 LttvExecutionState
*es
;
1976 /* Put ltt_time_zero creation time for unexisting processes */
1977 if(unlikely(process
== NULL
)) {
1978 process
= lttv_state_create_process(ts
,
1979 NULL
, cpu
, pid
, 0, LTTV_STATE_UNNAMED
, timestamp
);
1980 /* We are not sure is it's a kernel thread or normal thread, put the
1981 * bottom stack state to unknown */
1982 process
->execution_stack
=
1983 g_array_set_size(process
->execution_stack
, 1);
1984 process
->state
= es
=
1985 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
1986 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
1987 es
->s
= LTTV_STATE_UNNAMED
;
1992 /* FIXME : this function should be called when we receive an event telling that
1993 * release_task has been called in the kernel. In happens generally when
1994 * the parent waits for its child terminaison, but may also happen in special
1995 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1996 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1997 * of a killed thread ground, but isn't the leader.
1999 static void exit_process(LttvTracefileState
*tfs
, LttvProcessState
*process
)
2001 LttvTraceState
*ts
= LTTV_TRACE_STATE(tfs
->parent
.t_context
);
2002 LttvProcessState key
;
2004 key
.pid
= process
->pid
;
2005 key
.cpu
= process
->cpu
;
2006 g_hash_table_remove(ts
->processes
, &key
);
2007 g_array_free(process
->execution_stack
, TRUE
);
2008 g_array_free(process
->user_stack
, TRUE
);
2013 static void free_process_state(gpointer key
, gpointer value
,gpointer user_data
)
2015 g_array_free(((LttvProcessState
*)value
)->execution_stack
, TRUE
);
2016 g_array_free(((LttvProcessState
*)value
)->user_stack
, TRUE
);
2021 static void lttv_state_free_process_table(GHashTable
*processes
)
2023 g_hash_table_foreach(processes
, free_process_state
, NULL
);
2024 g_hash_table_destroy(processes
);
2028 static gboolean
syscall_entry(void *hook_data
, void *call_data
)
2030 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2032 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2033 LttvProcessState
*process
= ts
->running_process
[cpu
];
2034 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2035 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2036 LttField
*f
= thf
->f1
;
2038 LttvExecutionSubmode submode
;
2040 guint nb_syscalls
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_syscalls
;
2041 guint syscall
= ltt_event_get_unsigned(e
, f
);
2043 if(syscall
< nb_syscalls
) {
2044 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->syscall_names
[
2047 /* Fixup an incomplete syscall table */
2048 GString
*string
= g_string_new("");
2049 g_string_printf(string
, "syscall %u", syscall
);
2050 submode
= g_quark_from_string(string
->str
);
2051 g_string_free(string
, TRUE
);
2053 /* There can be no system call from PID 0 : unknown state */
2054 if(process
->pid
!= 0)
2055 push_state(s
, LTTV_STATE_SYSCALL
, submode
);
2060 static gboolean
syscall_exit(void *hook_data
, void *call_data
)
2062 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2064 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2065 LttvProcessState
*process
= ts
->running_process
[cpu
];
2067 /* There can be no system call from PID 0 : unknown state */
2068 if(process
->pid
!= 0)
2069 pop_state(s
, LTTV_STATE_SYSCALL
);
2074 static gboolean
trap_entry(void *hook_data
, void *call_data
)
2076 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2077 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2078 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2079 LttField
*f
= thf
->f1
;
2081 LttvExecutionSubmode submode
;
2083 guint64 nb_traps
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_traps
;
2084 guint64 trap
= ltt_event_get_long_unsigned(e
, f
);
2086 if(trap
< nb_traps
) {
2087 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->trap_names
[trap
];
2089 /* Fixup an incomplete trap table */
2090 GString
*string
= g_string_new("");
2091 g_string_printf(string
, "trap %llu", trap
);
2092 submode
= g_quark_from_string(string
->str
);
2093 g_string_free(string
, TRUE
);
2096 push_state(s
, LTTV_STATE_TRAP
, submode
);
2098 /* update cpu status */
2099 cpu_push_mode(s
->cpu_state
, LTTV_CPU_TRAP
);
2104 static gboolean
trap_exit(void *hook_data
, void *call_data
)
2106 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2108 pop_state(s
, LTTV_STATE_TRAP
);
2110 /* update cpu status */
2111 cpu_pop_mode(s
->cpu_state
);
2116 static gboolean
irq_entry(void *hook_data
, void *call_data
)
2118 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2119 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2120 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2121 guint8 fac_id
= ltt_event_facility_id(e
);
2122 guint8 ev_id
= ltt_event_eventtype_id(e
);
2123 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2124 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2125 g_assert(thf
->f1
!= NULL
);
2126 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2127 LttField
*f
= thf
->f1
;
2129 LttvExecutionSubmode submode
;
2130 guint64 irq
= ltt_event_get_long_unsigned(e
, f
);
2131 guint64 nb_irqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_irqs
;
2135 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->irq_names
[irq
];
2137 /* Fixup an incomplete irq table */
2138 GString
*string
= g_string_new("");
2139 g_string_printf(string
, "irq %llu", irq
);
2140 submode
= g_quark_from_string(string
->str
);
2141 g_string_free(string
, TRUE
);
2144 /* Do something with the info about being in user or system mode when int? */
2145 push_state(s
, LTTV_STATE_IRQ
, submode
);
2147 /* update cpu status */
2148 cpu_push_mode(s
->cpu_state
, LTTV_CPU_IRQ
);
2150 /* update irq status */
2151 s
->cpu_state
->last_irq
= irq
;
2152 irq_push_mode(&ts
->irq_states
[irq
], LTTV_IRQ_BUSY
);
2157 static gboolean
soft_irq_exit(void *hook_data
, void *call_data
)
2159 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2161 pop_state(s
, LTTV_STATE_SOFT_IRQ
);
2167 static gboolean
irq_exit(void *hook_data
, void *call_data
)
2169 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2170 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2172 pop_state(s
, LTTV_STATE_IRQ
);
2174 /* update cpu status */
2175 cpu_pop_mode(s
->cpu_state
);
2177 /* update irq status */
2178 irq_pop_mode(&ts
->irq_states
[s
->cpu_state
->last_irq
]);
2183 static gboolean
soft_irq_entry(void *hook_data
, void *call_data
)
2185 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2186 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2187 guint8 fac_id
= ltt_event_facility_id(e
);
2188 guint8 ev_id
= ltt_event_eventtype_id(e
);
2189 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2190 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2191 g_assert(thf
->f1
!= NULL
);
2192 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2193 LttField
*f
= thf
->f1
;
2195 LttvExecutionSubmode submode
;
2196 guint64 softirq
= ltt_event_get_long_unsigned(e
, f
);
2197 guint64 nb_softirqs
= ((LttvTraceState
*)(s
->parent
.t_context
))->nb_softirqs
;
2200 if(softirq
< nb_softirqs
) {
2201 submode
= ((LttvTraceState
*)(s
->parent
.t_context
))->soft_irq_names
[softirq
];
2203 /* Fixup an incomplete irq table */
2204 GString
*string
= g_string_new("");
2205 g_string_printf(string
, "softirq %llu", softirq
);
2206 submode
= g_quark_from_string(string
->str
);
2207 g_string_free(string
, TRUE
);
2210 /* Do something with the info about being in user or system mode when int? */
2211 push_state(s
, LTTV_STATE_SOFT_IRQ
, submode
);
2215 LttvBdevState
*bdev_state_get(LttvTraceState
*ts
, guint16 devcode
)
2217 gint devcode_gint
= devcode
;
2218 gpointer bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2220 LttvBdevState
*bdevstate
= g_malloc(sizeof(LttvBdevState
));
2221 bdevstate
->mode_stack
= g_array_new(FALSE
, FALSE
, sizeof(GQuark
));
2223 gint
* key
= g_malloc(sizeof(gint
));
2225 g_hash_table_insert(ts
->bdev_states
, key
, bdevstate
);
2226 printf("adding key %u to hash table\n", *key
);
2234 static gboolean
bdev_request_issue(void *hook_data
, void *call_data
)
2236 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2237 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2238 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2239 guint8 fac_id
= ltt_event_facility_id(e
);
2240 guint8 ev_id
= ltt_event_eventtype_id(e
);
2241 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2243 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2244 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2245 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2246 guint16 devcode
= MKDEV(major
,minor
);
2248 /* have we seen this block device before? */
2249 gpointer bdev
= bdev_state_get(ts
, devcode
);
2252 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_READING
);
2254 bdev_push_mode(bdev
, LTTV_BDEV_BUSY_WRITING
);
2259 static gboolean
bdev_request_complete(void *hook_data
, void *call_data
)
2261 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2262 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2263 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2264 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2266 guint major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
2267 guint minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
2268 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
2269 guint16 devcode
= MKDEV(major
,minor
);
2271 /* have we seen this block device before? */
2272 gpointer bdev
= bdev_state_get(ts
, devcode
);
2274 /* update block device */
2275 bdev_pop_mode(bdev
);
2280 static void push_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2284 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2285 guint cpu
= tfs
->cpu
;
2286 LttvProcessState
*process
= ts
->running_process
[cpu
];
2288 guint depth
= process
->user_stack
->len
;
2290 process
->user_stack
=
2291 g_array_set_size(process
->user_stack
, depth
+ 1);
2293 new_func
= &g_array_index(process
->user_stack
, guint64
, depth
);
2294 *new_func
= funcptr
;
2295 process
->current_function
= funcptr
;
2298 static void pop_function(LttvTracefileState
*tfs
, guint64 funcptr
)
2300 guint cpu
= tfs
->cpu
;
2301 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
2302 LttvProcessState
*process
= ts
->running_process
[cpu
];
2304 if(process
->current_function
!= funcptr
){
2305 g_info("Different functions (%lu.%09lu): ignore it\n",
2306 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2307 g_info("process state has %llu when pop_function is %llu\n",
2308 process
->current_function
, funcptr
);
2309 g_info("{ %u, %u, %s, %s, %s }\n",
2312 g_quark_to_string(process
->name
),
2313 g_quark_to_string(process
->brand
),
2314 g_quark_to_string(process
->state
->s
));
2317 guint depth
= process
->user_stack
->len
;
2320 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2321 tfs
->parent
.timestamp
.tv_sec
, tfs
->parent
.timestamp
.tv_nsec
);
2325 process
->user_stack
=
2326 g_array_set_size(process
->user_stack
, depth
- 1);
2327 process
->current_function
=
2328 g_array_index(process
->user_stack
, guint64
, depth
- 2);
2332 static gboolean
function_entry(void *hook_data
, void *call_data
)
2334 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2335 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2336 guint8 fac_id
= ltt_event_facility_id(e
);
2337 guint8 ev_id
= ltt_event_eventtype_id(e
);
2338 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2339 g_assert(thf
->f1
!= NULL
);
2340 LttField
*f
= thf
->f1
;
2341 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2343 push_function(s
, funcptr
);
2347 static gboolean
function_exit(void *hook_data
, void *call_data
)
2349 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2350 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2351 guint8 fac_id
= ltt_event_facility_id(e
);
2352 guint8 ev_id
= ltt_event_eventtype_id(e
);
2353 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2354 g_assert(thf
->f1
!= NULL
);
2355 LttField
*f
= thf
->f1
;
2356 guint64 funcptr
= ltt_event_get_long_unsigned(e
, f
);
2358 LttvExecutionSubmode submode
;
2360 pop_function(s
, funcptr
);
2364 static gboolean
schedchange(void *hook_data
, void *call_data
)
2366 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2368 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2369 LttvProcessState
*process
= ts
->running_process
[cpu
];
2370 LttvProcessState
*old_process
= ts
->running_process
[cpu
];
2372 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2373 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2374 guint pid_in
, pid_out
;
2377 pid_out
= ltt_event_get_unsigned(e
, thf
->f1
);
2378 pid_in
= ltt_event_get_unsigned(e
, thf
->f2
);
2379 state_out
= ltt_event_get_long_int(e
, thf
->f3
);
2381 if(likely(process
!= NULL
)) {
2383 /* We could not know but it was not the idle process executing.
2384 This should only happen at the beginning, before the first schedule
2385 event, and when the initial information (current process for each CPU)
2386 is missing. It is not obvious how we could, after the fact, compensate
2387 the wrongly attributed statistics. */
2389 //This test only makes sense once the state is known and if there is no
2390 //missing events. We need to silently ignore schedchange coming after a
2391 //process_free, or it causes glitches. (FIXME)
2392 //if(unlikely(process->pid != pid_out)) {
2393 // g_assert(process->pid == 0);
2395 if(process
->pid
== 0
2396 && process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2398 /* Scheduling out of pid 0 at beginning of the trace :
2399 * we know for sure it is in syscall mode at this point. */
2400 g_assert(process
->execution_stack
->len
== 1);
2401 process
->state
->t
= LTTV_STATE_SYSCALL
;
2402 process
->state
->s
= LTTV_STATE_WAIT
;
2403 process
->state
->change
= s
->parent
.timestamp
;
2404 process
->state
->entry
= s
->parent
.timestamp
;
2407 if(unlikely(process
->state
->s
== LTTV_STATE_EXIT
)) {
2408 process
->state
->s
= LTTV_STATE_ZOMBIE
;
2409 process
->state
->change
= s
->parent
.timestamp
;
2411 if(unlikely(state_out
== 0)) process
->state
->s
= LTTV_STATE_WAIT_CPU
;
2412 else process
->state
->s
= LTTV_STATE_WAIT
;
2413 process
->state
->change
= s
->parent
.timestamp
;
2416 if(state_out
== 32 || state_out
== 128)
2417 exit_process(s
, process
); /* EXIT_DEAD || TASK_DEAD */
2418 /* see sched.h for states */
2421 process
= ts
->running_process
[cpu
] =
2422 lttv_state_find_process_or_create(
2423 (LttvTraceState
*)s
->parent
.t_context
,
2425 &s
->parent
.timestamp
);
2426 process
->state
->s
= LTTV_STATE_RUN
;
2428 if(process
->usertrace
)
2429 process
->usertrace
->cpu
= cpu
;
2430 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2431 process
->state
->change
= s
->parent
.timestamp
;
2433 /* update cpu status */
2435 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_IDLE
);
2437 cpu_set_base_mode(s
->cpu_state
, LTTV_CPU_BUSY
);
2442 static gboolean
process_fork(void *hook_data
, void *call_data
)
2444 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2445 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2446 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2448 guint child_pid
; /* In the Linux Kernel, there is one PID per thread. */
2449 guint child_tgid
; /* tgid in the Linux kernel is the "real" POSIX PID. */
2450 LttvProcessState
*zombie_process
;
2452 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2453 LttvProcessState
*process
= ts
->running_process
[cpu
];
2454 LttvProcessState
*child_process
;
2457 parent_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2460 child_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2461 s
->parent
.target_pid
= child_pid
;
2464 if(thf
->f3
) child_tgid
= ltt_event_get_unsigned(e
, thf
->f3
);
2465 else child_tgid
= 0;
2467 /* Mathieu : it seems like the process might have been scheduled in before the
2468 * fork, and, in a rare case, might be the current process. This might happen
2469 * in a SMP case where we don't have enough precision on the clocks.
2471 * Test reenabled after precision fixes on time. (Mathieu) */
2473 zombie_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2475 if(unlikely(zombie_process
!= NULL
)) {
2476 /* Reutilisation of PID. Only now we are sure that the old PID
2477 * has been released. FIXME : should know when release_task happens instead.
2479 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2481 for(i
=0; i
< num_cpus
; i
++) {
2482 g_assert(zombie_process
!= ts
->running_process
[i
]);
2485 exit_process(s
, zombie_process
);
2488 g_assert(process
->pid
!= child_pid
);
2489 // FIXME : Add this test in the "known state" section
2490 // g_assert(process->pid == parent_pid);
2491 child_process
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
2492 if(child_process
== NULL
) {
2493 child_process
= lttv_state_create_process(ts
, process
, cpu
,
2494 child_pid
, child_tgid
,
2495 LTTV_STATE_UNNAMED
, &s
->parent
.timestamp
);
2497 /* The process has already been created : due to time imprecision between
2498 * multiple CPUs : it has been scheduled in before creation. Note that we
2499 * shouldn't have this kind of imprecision.
2501 * Simply put a correct parent.
2503 g_assert(0); /* This is a problematic case : the process has been created
2504 before the fork event */
2505 child_process
->ppid
= process
->pid
;
2506 child_process
->tgid
= child_tgid
;
2508 g_assert(child_process
->name
== LTTV_STATE_UNNAMED
);
2509 child_process
->name
= process
->name
;
2510 child_process
->brand
= process
->brand
;
2515 /* We stamp a newly created process as kernel_thread.
2516 * The thread should not be running yet. */
2517 static gboolean
process_kernel_thread(void *hook_data
, void *call_data
)
2519 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2520 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2521 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2524 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2525 LttvProcessState
*process
;
2526 LttvExecutionState
*es
;
2529 pid
= (guint
)ltt_event_get_long_unsigned(e
, thf
->f1
);
2530 s
->parent
.target_pid
= pid
;
2532 process
= lttv_state_find_process_or_create(ts
, ANY_CPU
, pid
,
2534 process
->execution_stack
=
2535 g_array_set_size(process
->execution_stack
, 1);
2536 es
= process
->state
=
2537 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2538 es
->t
= LTTV_STATE_SYSCALL
;
2539 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2544 static gboolean
process_exit(void *hook_data
, void *call_data
)
2546 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2547 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2548 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2552 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2553 LttvProcessState
*process
; // = ts->running_process[cpu];
2555 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2556 s
->parent
.target_pid
= pid
;
2558 // FIXME : Add this test in the "known state" section
2559 // g_assert(process->pid == pid);
2561 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2562 if(likely(process
!= NULL
)) {
2563 process
->state
->s
= LTTV_STATE_EXIT
;
2568 static gboolean
process_free(void *hook_data
, void *call_data
)
2570 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2571 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2572 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2573 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2575 LttvProcessState
*process
;
2577 /* PID of the process to release */
2578 release_pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2579 s
->parent
.target_pid
= release_pid
;
2581 g_assert(release_pid
!= 0);
2583 process
= lttv_state_find_process(ts
, ANY_CPU
, release_pid
);
2585 if(likely(process
!= NULL
)) {
2586 /* release_task is happening at kernel level : we can now safely release
2587 * the data structure of the process */
2588 //This test is fun, though, as it may happen that
2589 //at time t : CPU 0 : process_free
2590 //at time t+150ns : CPU 1 : schedule out
2591 //Clearly due to time imprecision, we disable it. (Mathieu)
2592 //If this weird case happen, we have no choice but to put the
2593 //Currently running process on the cpu to 0.
2594 //I re-enable it following time precision fixes. (Mathieu)
2595 //Well, in the case where an process is freed by a process on another CPU
2596 //and still scheduled, it happens that this is the schedchange that will
2597 //drop the last reference count. Do not free it here!
2598 guint num_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2600 for(i
=0; i
< num_cpus
; i
++) {
2601 //g_assert(process != ts->running_process[i]);
2602 if(process
== ts
->running_process
[i
]) {
2603 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2607 if(i
== num_cpus
) /* process is not scheduled */
2608 exit_process(s
, process
);
2615 static gboolean
process_exec(void *hook_data
, void *call_data
)
2617 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2618 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2619 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2620 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2623 LttvProcessState
*process
= ts
->running_process
[cpu
];
2625 #if 0//how to use a sequence that must be transformed in a string
2626 /* PID of the process to release */
2627 guint64 name_len
= ltt_event_field_element_number(e
, thf
->f1
);
2628 //name = ltt_event_get_string(e, thf->f1);
2629 LttField
*child
= ltt_event_field_element_select(e
, thf
->f1
, 0);
2631 (gchar
*)(ltt_event_data(e
)+ltt_event_field_offset(e
, child
));
2632 gchar
*null_term_name
= g_new(gchar
, name_len
+1);
2633 memcpy(null_term_name
, name_begin
, name_len
);
2634 null_term_name
[name_len
] = '\0';
2635 process
->name
= g_quark_from_string(null_term_name
);
2638 process
->name
= g_quark_from_string(ltt_event_get_string(e
, thf
->f1
));
2639 process
->brand
= LTTV_STATE_UNBRANDED
;
2640 //g_free(null_term_name);
2644 static gboolean
thread_brand(void *hook_data
, void *call_data
)
2646 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2647 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2648 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2649 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2652 LttvProcessState
*process
= ts
->running_process
[cpu
];
2654 name
= ltt_event_get_string(e
, thf
->f1
);
2655 process
->brand
= g_quark_from_string(name
);
2660 static void fix_process(gpointer key
, gpointer value
,
2663 LttvProcessState
*process
;
2664 LttvExecutionState
*es
;
2665 process
= (LttvProcessState
*)value
;
2666 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)user_data
;
2667 LttTime
*timestamp
= (LttTime
*)user_data
;
2669 if(process
->type
== LTTV_STATE_KERNEL_THREAD
) {
2670 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2671 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2672 es
->t
= LTTV_STATE_SYSCALL
;
2673 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2674 es
->entry
= *timestamp
;
2675 es
->change
= *timestamp
;
2676 es
->cum_cpu_time
= ltt_time_zero
;
2677 if(es
->s
== LTTV_STATE_UNNAMED
)
2678 es
->s
= LTTV_STATE_WAIT
;
2681 es
= &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2682 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2683 es
->t
= LTTV_STATE_USER_MODE
;
2684 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2685 es
->entry
= *timestamp
;
2686 //g_assert(timestamp->tv_sec != 0);
2687 es
->change
= *timestamp
;
2688 es
->cum_cpu_time
= ltt_time_zero
;
2689 if(es
->s
== LTTV_STATE_UNNAMED
)
2690 es
->s
= LTTV_STATE_RUN
;
2692 if(process
->execution_stack
->len
== 1) {
2693 /* Still in bottom unknown mode, means never did a system call
2694 * May be either in user mode, syscall mode, running or waiting.*/
2695 /* FIXME : we may be tagging syscall mode when being user mode */
2696 process
->execution_stack
=
2697 g_array_set_size(process
->execution_stack
, 2);
2698 es
= process
->state
= &g_array_index(process
->execution_stack
,
2699 LttvExecutionState
, 1);
2700 es
->t
= LTTV_STATE_SYSCALL
;
2701 es
->n
= LTTV_STATE_SUBMODE_NONE
;
2702 es
->entry
= *timestamp
;
2703 //g_assert(timestamp->tv_sec != 0);
2704 es
->change
= *timestamp
;
2705 es
->cum_cpu_time
= ltt_time_zero
;
2706 if(es
->s
== LTTV_STATE_WAIT_FORK
)
2707 es
->s
= LTTV_STATE_WAIT
;
2713 static gboolean
statedump_end(void *hook_data
, void *call_data
)
2715 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2716 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2717 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2718 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2719 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2721 /* For all processes */
2722 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2723 /* else, if stack[0] is unknown, set to user mode, running */
2725 g_hash_table_foreach(ts
->processes
, fix_process
, &tfc
->timestamp
);
2728 static gboolean
enum_process_state(void *hook_data
, void *call_data
)
2730 LttvTracefileState
*s
= (LttvTracefileState
*)call_data
;
2731 LttEvent
*e
= ltt_tracefile_get_event(s
->parent
.tf
);
2732 //It's slow : optimise later by doing this before reading trace.
2733 LttEventType
*et
= ltt_event_eventtype(e
);
2735 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2741 LttvTraceState
*ts
= (LttvTraceState
*)s
->parent
.t_context
;
2742 LttvProcessState
*process
= ts
->running_process
[cpu
];
2743 LttvProcessState
*parent_process
;
2744 LttField
*f4
, *f5
, *f6
, *f7
, *f8
;
2745 GQuark type
, mode
, submode
, status
;
2746 LttvExecutionState
*es
;
2750 pid
= ltt_event_get_unsigned(e
, thf
->f1
);
2751 s
->parent
.target_pid
= pid
;
2754 parent_pid
= ltt_event_get_unsigned(e
, thf
->f2
);
2757 command
= ltt_event_get_string(e
, thf
->f3
);
2760 f4
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TYPE
);
2761 type
= ltt_enum_string_get(ltt_field_type(f4
),
2762 ltt_event_get_unsigned(e
, f4
));
2765 f5
= ltt_eventtype_field_by_name(et
, LTT_FIELD_MODE
);
2766 mode
= ltt_enum_string_get(ltt_field_type(f5
),
2767 ltt_event_get_unsigned(e
, f5
));
2770 f6
= ltt_eventtype_field_by_name(et
, LTT_FIELD_SUBMODE
);
2771 submode
= ltt_enum_string_get(ltt_field_type(f6
),
2772 ltt_event_get_unsigned(e
, f6
));
2775 f7
= ltt_eventtype_field_by_name(et
, LTT_FIELD_STATUS
);
2776 status
= ltt_enum_string_get(ltt_field_type(f7
),
2777 ltt_event_get_unsigned(e
, f7
));
2780 f8
= ltt_eventtype_field_by_name(et
, LTT_FIELD_TGID
);
2781 if(f8
) tgid
= ltt_event_get_unsigned(e
, f8
);
2786 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2787 for(i
=0; i
<nb_cpus
; i
++) {
2788 process
= lttv_state_find_process(ts
, i
, pid
);
2789 g_assert(process
!= NULL
);
2791 process
->ppid
= parent_pid
;
2792 process
->tgid
= tgid
;
2793 process
->name
= g_quark_from_string(command
);
2795 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2796 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2800 /* The process might exist if a process was forked while performing the
2802 process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
2803 if(process
== NULL
) {
2804 parent_process
= lttv_state_find_process(ts
, ANY_CPU
, parent_pid
);
2805 process
= lttv_state_create_process(ts
, parent_process
, cpu
,
2806 pid
, tgid
, g_quark_from_string(command
),
2807 &s
->parent
.timestamp
);
2809 /* Keep the stack bottom : a running user mode */
2810 /* Disabled because of inconsistencies in the current statedump states. */
2811 if(type
== LTTV_STATE_KERNEL_THREAD
) {
2812 /* Only keep the bottom
2813 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2814 /* Will cause expected trap when in fact being syscall (even after end of
2816 * Will cause expected interrupt when being syscall. (only before end of
2817 * statedump event) */
2818 // This will cause a "popping last state on stack, ignoring it."
2819 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2820 es
= process
->state
= &g_array_index(process
->execution_stack
,
2821 LttvExecutionState
, 0);
2822 process
->type
= LTTV_STATE_KERNEL_THREAD
;
2823 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2824 es
->s
= LTTV_STATE_UNNAMED
;
2825 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2827 es
->t
= LTTV_STATE_SYSCALL
;
2832 /* User space process :
2833 * bottom : user mode
2834 * either currently running or scheduled out.
2835 * can be scheduled out because interrupted in (user mode or in syscall)
2836 * or because of an explicit call to the scheduler in syscall. Note that
2837 * the scheduler call comes after the irq_exit, so never in interrupt
2839 // temp workaround : set size to 1 : only have user mode bottom of stack.
2840 // will cause g_info message of expected syscall mode when in fact being
2841 // in user mode. Can also cause expected trap when in fact being user
2842 // mode in the event of a page fault reenabling interrupts in the handler.
2843 // Expected syscall and trap can also happen after the end of statedump
2844 // This will cause a "popping last state on stack, ignoring it."
2845 process
->execution_stack
= g_array_set_size(process
->execution_stack
, 1);
2846 es
= process
->state
= &g_array_index(process
->execution_stack
,
2847 LttvExecutionState
, 0);
2848 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2849 es
->s
= LTTV_STATE_UNNAMED
;
2850 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2852 es
->t
= LTTV_STATE_USER_MODE
;
2860 es
= process
->state
= &g_array_index(process
->execution_stack
,
2861 LttvExecutionState
, 1);
2862 es
->t
= LTTV_STATE_MODE_UNKNOWN
;
2863 es
->s
= LTTV_STATE_UNNAMED
;
2864 es
->n
= LTTV_STATE_SUBMODE_UNKNOWN
;
2868 /* The process has already been created :
2869 * Probably was forked while dumping the process state or
2870 * was simply scheduled in prior to get the state dump event.
2872 process
->ppid
= parent_pid
;
2873 process
->tgid
= tgid
;
2874 process
->name
= g_quark_from_string(command
);
2875 process
->type
= type
;
2877 &g_array_index(process
->execution_stack
, LttvExecutionState
, 0);
2879 if(es
->t
== LTTV_STATE_MODE_UNKNOWN
) {
2880 if(type
== LTTV_STATE_KERNEL_THREAD
)
2881 es
->t
= LTTV_STATE_SYSCALL
;
2883 es
->t
= LTTV_STATE_USER_MODE
;
2886 /* Don't mess around with the stack, it will eventually become
2887 * ok after the end of state dump. */
2894 gint
lttv_state_hook_add_event_hooks(void *hook_data
, void *call_data
)
2896 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
2898 lttv_state_add_event_hooks(tss
);
2903 void lttv_state_add_event_hooks(LttvTracesetState
*self
)
2905 LttvTraceset
*traceset
= self
->parent
.ts
;
2907 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
2911 LttvTracefileState
*tfs
;
2915 LttvTraceHookByFacility
*thf
;
2917 LttvTraceHook
*hook
;
2919 LttvAttributeValue val
;
2924 nb_trace
= lttv_traceset_number(traceset
);
2925 for(i
= 0 ; i
< nb_trace
; i
++) {
2926 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
2928 /* Find the eventtype id for the following events and register the
2929 associated by id hooks. */
2931 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 19);
2932 hooks
= g_array_set_size(hooks
, 19); // Max possible number of hooks.
2935 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2936 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_ENTRY
,
2937 LTT_FIELD_SYSCALL_ID
, 0, 0,
2938 syscall_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2941 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2942 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_SYSCALL_EXIT
,
2944 syscall_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2947 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2948 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_ENTRY
,
2949 LTT_FIELD_TRAP_ID
, 0, 0,
2950 trap_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2953 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2954 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_TRAP_EXIT
,
2956 trap_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2959 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2960 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
2961 LTT_FIELD_IRQ_ID
, 0, 0,
2962 irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2965 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2966 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
2968 irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2971 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2972 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_ENTRY
,
2973 LTT_FIELD_SOFT_IRQ_ID
, 0, 0,
2974 soft_irq_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2977 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2978 LTT_FACILITY_KERNEL
, LTT_EVENT_SOFT_IRQ_EXIT
,
2980 soft_irq_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2983 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2984 LTT_FACILITY_KERNEL
, LTT_EVENT_SCHED_SCHEDULE
,
2985 LTT_FIELD_PREV_PID
, LTT_FIELD_NEXT_PID
, LTT_FIELD_PREV_STATE
,
2986 schedchange
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2989 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2990 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FORK
,
2991 LTT_FIELD_PARENT_PID
, LTT_FIELD_CHILD_PID
, LTT_FIELD_CHILD_TGID
,
2992 process_fork
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
2995 ret
= lttv_trace_find_hook(ts
->parent
.t
,
2996 LTT_FACILITY_KERNEL_ARCH
, LTT_EVENT_KTHREAD_CREATE
,
2997 LTT_FIELD_PID
, 0, 0,
2998 process_kernel_thread
, NULL
, &g_array_index(hooks
, LttvTraceHook
,
3002 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3003 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_EXIT
,
3004 LTT_FIELD_PID
, 0, 0,
3005 process_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3008 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3009 LTT_FACILITY_KERNEL
, LTT_EVENT_PROCESS_FREE
,
3010 LTT_FIELD_PID
, 0, 0,
3011 process_free
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3014 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3015 LTT_FACILITY_FS
, LTT_EVENT_EXEC
,
3016 LTT_FIELD_FILENAME
, 0, 0,
3017 process_exec
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3020 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3021 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_THREAD_BRAND
,
3022 LTT_FIELD_NAME
, 0, 0,
3023 thread_brand
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3026 /* statedump-related hooks */
3027 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3028 LTT_FACILITY_LIST
, LTT_EVENT_PROCESS_STATE
,
3029 LTT_FIELD_PID
, LTT_FIELD_PARENT_PID
, LTT_FIELD_NAME
,
3030 enum_process_state
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3033 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3034 LTT_FACILITY_LIST
, LTT_EVENT_STATEDUMP_END
,
3036 statedump_end
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3039 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3040 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_ISSUE
,
3041 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3042 bdev_request_issue
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3045 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3046 LTT_FACILITY_BLOCK
, LTT_EVENT_REQUEST_COMPLETE
,
3047 LTT_FIELD_MAJOR
, LTT_FIELD_MINOR
, LTT_FIELD_OPERATION
,
3048 bdev_request_complete
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3051 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3052 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_ENTRY
,
3053 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3054 function_entry
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3057 ret
= lttv_trace_find_hook(ts
->parent
.t
,
3058 LTT_FACILITY_USER_GENERIC
, LTT_EVENT_FUNCTION_EXIT
,
3059 LTT_FIELD_THIS_FN
, LTT_FIELD_CALL_SITE
, 0,
3060 function_exit
, NULL
, &g_array_index(hooks
, LttvTraceHook
, hn
++));
3063 hooks
= g_array_set_size(hooks
, hn
);
3065 /* Add these hooks to each event_by_id hooks list */
3067 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3069 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3071 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3072 LttvTracefileContext
*, j
));
3074 for(k
= 0 ; k
< hooks
->len
; k
++) {
3075 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3076 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3077 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3079 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3086 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3087 *(val
.v_pointer
) = hooks
;
3091 gint
lttv_state_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3093 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3095 lttv_state_remove_event_hooks(tss
);
3100 void lttv_state_remove_event_hooks(LttvTracesetState
*self
)
3102 LttvTraceset
*traceset
= self
->parent
.ts
;
3104 guint i
, j
, k
, l
, nb_trace
, nb_tracefile
;
3108 LttvTracefileState
*tfs
;
3112 LttvTraceHook
*hook
;
3114 LttvTraceHookByFacility
*thf
;
3116 LttvAttributeValue val
;
3118 nb_trace
= lttv_traceset_number(traceset
);
3119 for(i
= 0 ; i
< nb_trace
; i
++) {
3120 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3122 lttv_attribute_find(ts
->parent
.a
, LTTV_STATE_HOOKS
, LTTV_POINTER
, &val
);
3123 hooks
= *(val
.v_pointer
);
3125 /* Remove these hooks from each event_by_id hooks list */
3127 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3129 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3131 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3132 LttvTracefileContext
*, j
));
3134 for(k
= 0 ; k
< hooks
->len
; k
++) {
3135 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
3136 for(l
=0;l
<hook
->fac_list
->len
;l
++) {
3137 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
3139 lttv_hooks_remove_data(
3140 lttv_hooks_by_id_find(tfs
->parent
.event_by_id
, thf
->id
),
3146 for(k
= 0 ; k
< hooks
->len
; k
++)
3147 lttv_trace_hook_destroy(&g_array_index(hooks
, LttvTraceHook
, k
));
3148 g_array_free(hooks
, TRUE
);
3152 static gboolean
state_save_event_hook(void *hook_data
, void *call_data
)
3154 guint
*event_count
= (guint
*)hook_data
;
3156 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3157 if(likely((*event_count
)++ < LTTV_STATE_SAVE_INTERVAL
))
3162 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3164 LttvTracefileState
*tfcs
;
3166 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3168 LttEventPosition
*ep
;
3174 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3176 LttvAttributeValue value
;
3178 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3179 LTTV_STATE_SAVED_STATES
);
3180 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3181 value
= lttv_attribute_add(saved_states_tree
,
3182 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3183 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3184 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3185 *(value
.v_time
) = self
->parent
.timestamp
;
3186 lttv_state_save(tcs
, saved_state_tree
);
3187 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3188 self
->parent
.timestamp
.tv_nsec
);
3190 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3195 static gboolean
state_save_after_trace_hook(void *hook_data
, void *call_data
)
3197 LttvTraceState
*tcs
= (LttvTraceState
*)(call_data
);
3199 *(tcs
->max_time_state_recomputed_in_seek
) = tcs
->parent
.time_span
.end_time
;
3204 guint
lttv_state_current_cpu(LttvTracefileState
*tfs
)
3212 static gboolean
block_start(void *hook_data
, void *call_data
)
3214 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3216 LttvTracefileState
*tfcs
;
3218 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3220 LttEventPosition
*ep
;
3222 guint i
, nb_block
, nb_event
, nb_tracefile
;
3226 LttvAttribute
*saved_states_tree
, *saved_state_tree
;
3228 LttvAttributeValue value
;
3230 ep
= ltt_event_position_new();
3232 nb_tracefile
= tcs
->parent
.tracefiles
->len
;
3234 /* Count the number of events added since the last block end in any
3237 for(i
= 0 ; i
< nb_tracefile
; i
++) {
3239 LTTV_TRACEFILE_STATE(&g_array_index(tcs
->parent
.tracefiles
,
3240 LttvTracefileContext
, i
));
3241 ltt_event_position(tfcs
->parent
.e
, ep
);
3242 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3243 tcs
->nb_event
+= nb_event
- tfcs
->saved_position
;
3244 tfcs
->saved_position
= nb_event
;
3248 if(tcs
->nb_event
>= tcs
->save_interval
) {
3249 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3250 LTTV_STATE_SAVED_STATES
);
3251 saved_state_tree
= g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
3252 value
= lttv_attribute_add(saved_states_tree
,
3253 lttv_attribute_get_number(saved_states_tree
), LTTV_GOBJECT
);
3254 *(value
.v_gobject
) = (GObject
*)saved_state_tree
;
3255 value
= lttv_attribute_add(saved_state_tree
, LTTV_STATE_TIME
, LTTV_TIME
);
3256 *(value
.v_time
) = self
->parent
.timestamp
;
3257 lttv_state_save(tcs
, saved_state_tree
);
3259 g_debug("Saving state at time %lu.%lu", self
->parent
.timestamp
.tv_sec
,
3260 self
->parent
.timestamp
.tv_nsec
);
3262 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3268 static gboolean
block_end(void *hook_data
, void *call_data
)
3270 LttvTracefileState
*self
= (LttvTracefileState
*)call_data
;
3272 LttvTraceState
*tcs
= (LttvTraceState
*)(self
->parent
.t_context
);
3276 LttEventPosition
*ep
;
3278 guint nb_block
, nb_event
;
3280 ep
= ltt_event_position_new();
3281 ltt_event_position(self
->parent
.e
, ep
);
3282 ltt_event_position_get(ep
, &nb_block
, &nb_event
, &tf
);
3283 tcs
->nb_event
+= nb_event
- self
->saved_position
+ 1;
3284 self
->saved_position
= 0;
3285 *(tcs
->max_time_state_recomputed_in_seek
) = self
->parent
.timestamp
;
3292 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3294 LttvTraceset
*traceset
= self
->parent
.ts
;
3296 guint i
, j
, nb_trace
, nb_tracefile
;
3300 LttvTracefileState
*tfs
;
3302 LttvTraceHook hook_start
, hook_end
;
3304 nb_trace
= lttv_traceset_number(traceset
);
3305 for(i
= 0 ; i
< nb_trace
; i
++) {
3306 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3308 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3309 NULL
, NULL
, block_start
, &hook_start
);
3310 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3311 NULL
, NULL
, block_end
, &hook_end
);
3313 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3315 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3317 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3318 LttvTracefileContext
, j
));
3319 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3320 hook_start
.id
), hook_start
.h
, NULL
, LTTV_PRIO_STATE
);
3321 lttv_hooks_add(lttv_hooks_by_id_find(tfs
->parent
.event_by_id
,
3322 hook_end
.id
), hook_end
.h
, NULL
, LTTV_PRIO_STATE
);
3328 void lttv_state_save_add_event_hooks(LttvTracesetState
*self
)
3330 LttvTraceset
*traceset
= self
->parent
.ts
;
3332 guint i
, j
, nb_trace
, nb_tracefile
;
3336 LttvTracefileState
*tfs
;
3339 nb_trace
= lttv_traceset_number(traceset
);
3340 for(i
= 0 ; i
< nb_trace
; i
++) {
3342 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3343 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3345 if(ts
->has_precomputed_states
) continue;
3347 guint
*event_count
= g_new(guint
, 1);
3350 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3352 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3353 LttvTracefileContext
*, j
));
3354 lttv_hooks_add(tfs
->parent
.event
,
3355 state_save_event_hook
,
3362 lttv_process_traceset_begin(&self
->parent
,
3363 NULL
, NULL
, NULL
, NULL
, NULL
);
3367 gint
lttv_state_save_hook_add_event_hooks(void *hook_data
, void *call_data
)
3369 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3371 lttv_state_save_add_event_hooks(tss
);
3378 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3380 LttvTraceset
*traceset
= self
->parent
.ts
;
3382 guint i
, j
, nb_trace
, nb_tracefile
;
3386 LttvTracefileState
*tfs
;
3388 LttvTraceHook hook_start
, hook_end
;
3390 nb_trace
= lttv_traceset_number(traceset
);
3391 for(i
= 0 ; i
< nb_trace
; i
++) {
3392 ts
= LTTV_TRACE_STATE(self
->parent
.traces
[i
]);
3394 lttv_trace_find_hook(ts
->parent
.t
, "core","block_start",NULL
,
3395 NULL
, NULL
, block_start
, &hook_start
);
3397 lttv_trace_find_hook(ts
->parent
.t
, "core","block_end",NULL
,
3398 NULL
, NULL
, block_end
, &hook_end
);
3400 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3402 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3404 LTTV_TRACEFILE_STATE(&g_array_index(ts
->parent
.tracefiles
,
3405 LttvTracefileContext
, j
));
3406 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3407 tfs
->parent
.event_by_id
, hook_start
.id
), hook_start
.h
, NULL
);
3408 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3409 tfs
->parent
.event_by_id
, hook_end
.id
), hook_end
.h
, NULL
);
3415 void lttv_state_save_remove_event_hooks(LttvTracesetState
*self
)
3417 LttvTraceset
*traceset
= self
->parent
.ts
;
3419 guint i
, j
, nb_trace
, nb_tracefile
;
3423 LttvTracefileState
*tfs
;
3425 LttvHooks
*after_trace
= lttv_hooks_new();
3427 lttv_hooks_add(after_trace
,
3428 state_save_after_trace_hook
,
3433 lttv_process_traceset_end(&self
->parent
,
3434 NULL
, after_trace
, NULL
, NULL
, NULL
);
3436 lttv_hooks_destroy(after_trace
);
3438 nb_trace
= lttv_traceset_number(traceset
);
3439 for(i
= 0 ; i
< nb_trace
; i
++) {
3441 ts
= (LttvTraceState
*)self
->parent
.traces
[i
];
3442 nb_tracefile
= ts
->parent
.tracefiles
->len
;
3444 if(ts
->has_precomputed_states
) continue;
3446 guint
*event_count
= NULL
;
3448 for(j
= 0 ; j
< nb_tracefile
; j
++) {
3450 LTTV_TRACEFILE_STATE(g_array_index(ts
->parent
.tracefiles
,
3451 LttvTracefileContext
*, j
));
3452 event_count
= lttv_hooks_remove(tfs
->parent
.event
,
3453 state_save_event_hook
);
3455 if(event_count
) g_free(event_count
);
3459 gint
lttv_state_save_hook_remove_event_hooks(void *hook_data
, void *call_data
)
3461 LttvTracesetState
*tss
= (LttvTracesetState
*)(call_data
);
3463 lttv_state_save_remove_event_hooks(tss
);
3468 void lttv_state_traceset_seek_time_closest(LttvTracesetState
*self
, LttTime t
)
3470 LttvTraceset
*traceset
= self
->parent
.ts
;
3474 int min_pos
, mid_pos
, max_pos
;
3476 guint call_rest
= 0;
3478 LttvTraceState
*tcs
;
3480 LttvAttributeValue value
;
3482 LttvAttributeType type
;
3484 LttvAttributeName name
;
3488 LttvAttribute
*saved_states_tree
, *saved_state_tree
, *closest_tree
;
3490 //g_tree_destroy(self->parent.pqueue);
3491 //self->parent.pqueue = g_tree_new(compare_tracefile);
3493 g_info("Entering seek_time_closest for time %lu.%lu", t
.tv_sec
, t
.tv_nsec
);
3495 nb_trace
= lttv_traceset_number(traceset
);
3496 for(i
= 0 ; i
< nb_trace
; i
++) {
3497 tcs
= (LttvTraceState
*)self
->parent
.traces
[i
];
3499 if(ltt_time_compare(t
, *(tcs
->max_time_state_recomputed_in_seek
)) < 0) {
3500 saved_states_tree
= lttv_attribute_find_subdir(tcs
->parent
.t_a
,
3501 LTTV_STATE_SAVED_STATES
);
3504 if(saved_states_tree
) {
3505 max_pos
= lttv_attribute_get_number(saved_states_tree
) - 1;
3506 mid_pos
= max_pos
/ 2;
3507 while(min_pos
< max_pos
) {
3508 type
= lttv_attribute_get(saved_states_tree
, mid_pos
, &name
, &value
,
3510 g_assert(type
== LTTV_GOBJECT
);
3511 saved_state_tree
= *((LttvAttribute
**)(value
.v_gobject
));
3512 type
= lttv_attribute_get_by_name(saved_state_tree
, LTTV_STATE_TIME
,
3514 g_assert(type
== LTTV_TIME
);
3515 if(ltt_time_compare(*(value
.v_time
), t
) < 0) {
3517 closest_tree
= saved_state_tree
;
3519 else max_pos
= mid_pos
- 1;
3521 mid_pos
= (min_pos
+ max_pos
+ 1) / 2;
3525 /* restore the closest earlier saved state */
3527 lttv_state_restore(tcs
, closest_tree
);
3531 /* There is no saved state, yet we want to have it. Restart at T0 */
3533 restore_init_state(tcs
);
3534 lttv_process_trace_seek_time(&(tcs
->parent
), ltt_time_zero
);
3537 /* We want to seek quickly without restoring/updating the state */
3539 restore_init_state(tcs
);
3540 lttv_process_trace_seek_time(&(tcs
->parent
), t
);
3543 if(!call_rest
) g_info("NOT Calling restore");
3548 traceset_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3554 traceset_state_finalize (LttvTracesetState
*self
)
3556 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE
))->
3557 finalize(G_OBJECT(self
));
3562 traceset_state_class_init (LttvTracesetContextClass
*klass
)
3564 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3566 gobject_class
->finalize
= (void (*)(GObject
*self
)) traceset_state_finalize
;
3567 klass
->init
= (void (*)(LttvTracesetContext
*self
, LttvTraceset
*ts
))init
;
3568 klass
->fini
= (void (*)(LttvTracesetContext
*self
))fini
;
3569 klass
->new_traceset_context
= new_traceset_context
;
3570 klass
->new_trace_context
= new_trace_context
;
3571 klass
->new_tracefile_context
= new_tracefile_context
;
3576 lttv_traceset_state_get_type(void)
3578 static GType type
= 0;
3580 static const GTypeInfo info
= {
3581 sizeof (LttvTracesetStateClass
),
3582 NULL
, /* base_init */
3583 NULL
, /* base_finalize */
3584 (GClassInitFunc
) traceset_state_class_init
, /* class_init */
3585 NULL
, /* class_finalize */
3586 NULL
, /* class_data */
3587 sizeof (LttvTracesetState
),
3588 0, /* n_preallocs */
3589 (GInstanceInitFunc
) traceset_state_instance_init
, /* instance_init */
3590 NULL
/* value handling */
3593 type
= g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE
, "LttvTracesetStateType",
3601 trace_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3607 trace_state_finalize (LttvTraceState
*self
)
3609 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE
))->
3610 finalize(G_OBJECT(self
));
3615 trace_state_class_init (LttvTraceStateClass
*klass
)
3617 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3619 gobject_class
->finalize
= (void (*)(GObject
*self
)) trace_state_finalize
;
3620 klass
->state_save
= state_save
;
3621 klass
->state_restore
= state_restore
;
3622 klass
->state_saved_free
= state_saved_free
;
3627 lttv_trace_state_get_type(void)
3629 static GType type
= 0;
3631 static const GTypeInfo info
= {
3632 sizeof (LttvTraceStateClass
),
3633 NULL
, /* base_init */
3634 NULL
, /* base_finalize */
3635 (GClassInitFunc
) trace_state_class_init
, /* class_init */
3636 NULL
, /* class_finalize */
3637 NULL
, /* class_data */
3638 sizeof (LttvTraceState
),
3639 0, /* n_preallocs */
3640 (GInstanceInitFunc
) trace_state_instance_init
, /* instance_init */
3641 NULL
/* value handling */
3644 type
= g_type_register_static (LTTV_TRACE_CONTEXT_TYPE
,
3645 "LttvTraceStateType", &info
, 0);
3652 tracefile_state_instance_init (GTypeInstance
*instance
, gpointer g_class
)
3658 tracefile_state_finalize (LttvTracefileState
*self
)
3660 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE
))->
3661 finalize(G_OBJECT(self
));
3666 tracefile_state_class_init (LttvTracefileStateClass
*klass
)
3668 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
3670 gobject_class
->finalize
= (void (*)(GObject
*self
)) tracefile_state_finalize
;
3675 lttv_tracefile_state_get_type(void)
3677 static GType type
= 0;
3679 static const GTypeInfo info
= {
3680 sizeof (LttvTracefileStateClass
),
3681 NULL
, /* base_init */
3682 NULL
, /* base_finalize */
3683 (GClassInitFunc
) tracefile_state_class_init
, /* class_init */
3684 NULL
, /* class_finalize */
3685 NULL
, /* class_data */
3686 sizeof (LttvTracefileState
),
3687 0, /* n_preallocs */
3688 (GInstanceInitFunc
) tracefile_state_instance_init
, /* instance_init */
3689 NULL
/* value handling */
3692 type
= g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE
,
3693 "LttvTracefileStateType", &info
, 0);
3699 static void module_init()
3701 LTTV_STATE_UNNAMED
= g_quark_from_string("UNNAMED");
3702 LTTV_STATE_UNBRANDED
= g_quark_from_string("UNBRANDED");
3703 LTTV_STATE_MODE_UNKNOWN
= g_quark_from_string("MODE_UNKNOWN");
3704 LTTV_STATE_USER_MODE
= g_quark_from_string("USER_MODE");
3705 LTTV_STATE_SYSCALL
= g_quark_from_string("SYSCALL");
3706 LTTV_STATE_TRAP
= g_quark_from_string("TRAP");
3707 LTTV_STATE_IRQ
= g_quark_from_string("IRQ");
3708 LTTV_STATE_SOFT_IRQ
= g_quark_from_string("SOFTIRQ");
3709 LTTV_STATE_SUBMODE_UNKNOWN
= g_quark_from_string("UNKNOWN");
3710 LTTV_STATE_SUBMODE_NONE
= g_quark_from_string("NONE");
3711 LTTV_STATE_WAIT_FORK
= g_quark_from_string("WAIT_FORK");
3712 LTTV_STATE_WAIT_CPU
= g_quark_from_string("WAIT_CPU");
3713 LTTV_STATE_EXIT
= g_quark_from_string("EXIT");
3714 LTTV_STATE_ZOMBIE
= g_quark_from_string("ZOMBIE");
3715 LTTV_STATE_WAIT
= g_quark_from_string("WAIT");
3716 LTTV_STATE_RUN
= g_quark_from_string("RUN");
3717 LTTV_STATE_DEAD
= g_quark_from_string("DEAD");
3718 LTTV_STATE_USER_THREAD
= g_quark_from_string("USER_THREAD");
3719 LTTV_STATE_KERNEL_THREAD
= g_quark_from_string("KERNEL_THREAD");
3720 LTTV_STATE_TRACEFILES
= g_quark_from_string("tracefiles");
3721 LTTV_STATE_PROCESSES
= g_quark_from_string("processes");
3722 LTTV_STATE_PROCESS
= g_quark_from_string("process");
3723 LTTV_STATE_RUNNING_PROCESS
= g_quark_from_string("running_process");
3724 LTTV_STATE_EVENT
= g_quark_from_string("event");
3725 LTTV_STATE_SAVED_STATES
= g_quark_from_string("saved states");
3726 LTTV_STATE_SAVED_STATES_TIME
= g_quark_from_string("saved states time");
3727 LTTV_STATE_TIME
= g_quark_from_string("time");
3728 LTTV_STATE_HOOKS
= g_quark_from_string("saved state hooks");
3729 LTTV_STATE_NAME_TABLES
= g_quark_from_string("name tables");
3730 LTTV_STATE_TRACE_STATE_USE_COUNT
=
3731 g_quark_from_string("trace_state_use_count");
3732 LTTV_STATE_RESOURCE_CPUS
= g_quark_from_string("cpu resource states");
3735 LTT_FACILITY_KERNEL
= g_quark_from_string("kernel");
3736 LTT_FACILITY_KERNEL_ARCH
= g_quark_from_string("kernel_arch");
3737 LTT_FACILITY_FS
= g_quark_from_string("fs");
3738 LTT_FACILITY_LIST
= g_quark_from_string("list");
3739 LTT_FACILITY_USER_GENERIC
= g_quark_from_string("user_generic");
3740 LTT_FACILITY_BLOCK
= g_quark_from_string("block");
3743 LTT_EVENT_SYSCALL_ENTRY
= g_quark_from_string("syscall_entry");
3744 LTT_EVENT_SYSCALL_EXIT
= g_quark_from_string("syscall_exit");
3745 LTT_EVENT_TRAP_ENTRY
= g_quark_from_string("trap_entry");
3746 LTT_EVENT_TRAP_EXIT
= g_quark_from_string("trap_exit");
3747 LTT_EVENT_IRQ_ENTRY
= g_quark_from_string("irq_entry");
3748 LTT_EVENT_IRQ_EXIT
= g_quark_from_string("irq_exit");
3749 LTT_EVENT_SOFT_IRQ_ENTRY
= g_quark_from_string("soft_irq_entry");
3750 LTT_EVENT_SOFT_IRQ_EXIT
= g_quark_from_string("soft_irq_exit");
3751 LTT_EVENT_SCHED_SCHEDULE
= g_quark_from_string("sched_schedule");
3752 LTT_EVENT_PROCESS_FORK
= g_quark_from_string("process_fork");
3753 LTT_EVENT_KTHREAD_CREATE
= g_quark_from_string("kthread_create");
3754 LTT_EVENT_PROCESS_EXIT
= g_quark_from_string("process_exit");
3755 LTT_EVENT_PROCESS_FREE
= g_quark_from_string("process_free");
3756 LTT_EVENT_EXEC
= g_quark_from_string("exec");
3757 LTT_EVENT_PROCESS_STATE
= g_quark_from_string("process_state");
3758 LTT_EVENT_STATEDUMP_END
= g_quark_from_string("statedump_end");
3759 LTT_EVENT_FUNCTION_ENTRY
= g_quark_from_string("function_entry");
3760 LTT_EVENT_FUNCTION_EXIT
= g_quark_from_string("function_exit");
3761 LTT_EVENT_THREAD_BRAND
= g_quark_from_string("thread_brand");
3762 LTT_EVENT_REQUEST_ISSUE
= g_quark_from_string("_blk_request_issue");
3763 LTT_EVENT_REQUEST_COMPLETE
= g_quark_from_string("_blk_request_complete");
3766 LTT_FIELD_SYSCALL_ID
= g_quark_from_string("syscall_id");
3767 LTT_FIELD_TRAP_ID
= g_quark_from_string("trap_id");
3768 LTT_FIELD_IRQ_ID
= g_quark_from_string("irq_id");
3769 LTT_FIELD_SOFT_IRQ_ID
= g_quark_from_string("softirq_id");
3770 LTT_FIELD_PREV_PID
= g_quark_from_string("prev_pid");
3771 LTT_FIELD_NEXT_PID
= g_quark_from_string("next_pid");
3772 LTT_FIELD_PREV_STATE
= g_quark_from_string("prev_state");
3773 LTT_FIELD_PARENT_PID
= g_quark_from_string("parent_pid");
3774 LTT_FIELD_CHILD_PID
= g_quark_from_string("child_pid");
3775 LTT_FIELD_PID
= g_quark_from_string("pid");
3776 LTT_FIELD_TGID
= g_quark_from_string("tgid");
3777 LTT_FIELD_CHILD_TGID
= g_quark_from_string("child_tgid");
3778 LTT_FIELD_FILENAME
= g_quark_from_string("filename");
3779 LTT_FIELD_NAME
= g_quark_from_string("name");
3780 LTT_FIELD_TYPE
= g_quark_from_string("type");
3781 LTT_FIELD_MODE
= g_quark_from_string("mode");
3782 LTT_FIELD_SUBMODE
= g_quark_from_string("submode");
3783 LTT_FIELD_STATUS
= g_quark_from_string("status");
3784 LTT_FIELD_THIS_FN
= g_quark_from_string("this_fn");
3785 LTT_FIELD_CALL_SITE
= g_quark_from_string("call_site");
3786 LTT_FIELD_MAJOR
= g_quark_from_string("major");
3787 LTT_FIELD_MINOR
= g_quark_from_string("minor");
3788 LTT_FIELD_OPERATION
= g_quark_from_string("direction");
3790 LTTV_CPU_UNKNOWN
= g_quark_from_string("unknown");
3791 LTTV_CPU_IDLE
= g_quark_from_string("idle");
3792 LTTV_CPU_BUSY
= g_quark_from_string("busy");
3793 LTTV_CPU_IRQ
= g_quark_from_string("irq");
3794 LTTV_CPU_TRAP
= g_quark_from_string("trap");
3796 LTTV_IRQ_UNKNOWN
= g_quark_from_string("unknown");
3797 LTTV_IRQ_IDLE
= g_quark_from_string("idle");
3798 LTTV_IRQ_BUSY
= g_quark_from_string("busy");
3800 LTTV_BDEV_UNKNOWN
= g_quark_from_string("unknown");
3801 LTTV_BDEV_IDLE
= g_quark_from_string("idle");
3802 LTTV_BDEV_BUSY_READING
= g_quark_from_string("busy_reading");
3803 LTTV_BDEV_BUSY_WRITING
= g_quark_from_string("busy_writing");
3806 static void module_destroy()
3811 LTTV_MODULE("state", "State computation", \
3812 "Update the system state, possibly saving it at intervals", \
3813 module_init
, module_destroy
)