use ltt_time_infinite
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
... / ...
CommitLineData
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19
20#include <lttv/lttv.h>
21#include <lttv/module.h>
22#include <lttv/state.h>
23#include <ltt/facility.h>
24#include <ltt/trace.h>
25#include <ltt/event.h>
26#include <ltt/type.h>
27#include <stdio.h>
28
29LttvExecutionMode
30 LTTV_STATE_MODE_UNKNOWN,
31 LTTV_STATE_USER_MODE,
32 LTTV_STATE_SYSCALL,
33 LTTV_STATE_TRAP,
34 LTTV_STATE_IRQ;
35
36LttvExecutionSubmode
37 LTTV_STATE_SUBMODE_UNKNOWN,
38 LTTV_STATE_SUBMODE_NONE;
39
40LttvProcessStatus
41 LTTV_STATE_UNNAMED,
42 LTTV_STATE_WAIT_FORK,
43 LTTV_STATE_WAIT_CPU,
44 LTTV_STATE_EXIT,
45 LTTV_STATE_ZOMBIE,
46 LTTV_STATE_WAIT,
47 LTTV_STATE_RUN;
48
49static GQuark
50 LTTV_STATE_TRACEFILES,
51 LTTV_STATE_PROCESSES,
52 LTTV_STATE_PROCESS,
53 LTTV_STATE_EVENT,
54 LTTV_STATE_SAVED_STATES,
55 LTTV_STATE_SAVED_STATES_TIME,
56 LTTV_STATE_TIME,
57 LTTV_STATE_HOOKS,
58 LTTV_STATE_NAME_TABLES,
59 LTTV_STATE_TRACE_STATE_USE_COUNT;
60
61
62static void create_max_time(LttvTraceState *tcs);
63
64static void get_max_time(LttvTraceState *tcs);
65
66static void free_max_time(LttvTraceState *tcs);
67
68static void create_name_tables(LttvTraceState *tcs);
69
70static void get_name_tables(LttvTraceState *tcs);
71
72static void free_name_tables(LttvTraceState *tcs);
73
74static void free_saved_state(LttvTraceState *tcs);
75
76static void lttv_state_free_process_table(GHashTable *processes);
77
78
79void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
80{
81 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
82}
83
84
85void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
86{
87 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
88}
89
90
91void lttv_state_state_saved_free(LttvTraceState *self,
92 LttvAttribute *container)
93{
94 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
95}
96
97
98guint process_hash(gconstpointer key)
99{
100 guint pid = ((const LttvProcessState *)key)->pid;
101 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
102}
103
104
105gboolean process_equal(gconstpointer a, gconstpointer b)
106{
107 const LttvProcessState *process_a, *process_b;
108
109 process_a = (const LttvProcessState *)a;
110 process_b = (const LttvProcessState *)b;
111
112 if(process_a->pid != process_b->pid) return FALSE;
113 if(process_a->pid == 0 &&
114 process_a->last_cpu != process_b->last_cpu) return FALSE;
115 return TRUE;
116}
117
118
119static void
120restore_init_state(LttvTraceState *self)
121{
122 guint i, nb_tracefile;
123
124 LttvTracefileState *tfcs;
125
126 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
127 self->processes = g_hash_table_new(process_hash, process_equal);
128 self->nb_event = 0;
129
130 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
131 ltt_trace_per_cpu_tracefile_number(self->parent.t);
132
133 for(i = 0 ; i < nb_tracefile ; i++) {
134 tfcs = LTTV_TRACEFILE_STATE(self->parent.tracefiles[i]);
135 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
136 tfcs->saved_position = 0;
137 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
138 tfcs->process->state->s = LTTV_STATE_RUN;
139 tfcs->process->last_cpu = tfcs->cpu_name;
140 }
141}
142
143static LttTime time_zero = {0,0};
144
145static void
146init(LttvTracesetState *self, LttvTraceset *ts)
147{
148 guint i, j, nb_trace, nb_tracefile;
149
150 LttvTraceContext *tc;
151
152 LttvTraceState *tcs;
153
154 LttvTracefileState *tfcs;
155
156 LttvAttributeValue v;
157
158 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
159 init((LttvTracesetContext *)self, ts);
160
161 nb_trace = lttv_traceset_number(ts);
162 for(i = 0 ; i < nb_trace ; i++) {
163 tc = self->parent.traces[i];
164 tcs = (LttvTraceState *)tc;
165 tcs->save_interval = 50000;
166 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
167 LTTV_UINT, &v);
168 (*v.v_uint)++;
169
170 if(*(v.v_uint) == 1) {
171 create_name_tables(tcs);
172 create_max_time(tcs);
173 }
174 get_name_tables(tcs);
175 get_max_time(tcs);
176
177 nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
178 ltt_trace_per_cpu_tracefile_number(tc->t);
179
180 for(j = 0 ; j < nb_tracefile ; j++) {
181 tfcs = LTTV_TRACEFILE_STATE(tc->tracefiles[j]);
182 tfcs->cpu_name= g_quark_from_string(ltt_tracefile_name(tfcs->parent.tf));
183 }
184 tcs->processes = NULL;
185 restore_init_state(tcs);
186 }
187}
188
189
190static void
191fini(LttvTracesetState *self)
192{
193 guint i, nb_trace;
194
195 LttvTraceState *tcs;
196
197 LttvTracefileState *tfcs;
198
199 LttvAttributeValue v;
200
201 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
202 for(i = 0 ; i < nb_trace ; i++) {
203 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
204 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
205 LTTV_UINT, &v);
206
207 g_assert(*(v.v_uint) != 0);
208 (*v.v_uint)--;
209
210 if(*(v.v_uint) == 0) {
211 free_name_tables(tcs);
212 free_max_time(tcs);
213 free_saved_state(tcs);
214 }
215 lttv_state_free_process_table(tcs->processes);
216 tcs->processes = NULL;
217 }
218 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
219 fini((LttvTracesetContext *)self);
220}
221
222
223static LttvTracesetContext *
224new_traceset_context(LttvTracesetContext *self)
225{
226 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
227}
228
229
230static LttvTraceContext *
231new_trace_context(LttvTracesetContext *self)
232{
233 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
234}
235
236
237static LttvTracefileContext *
238new_tracefile_context(LttvTracesetContext *self)
239{
240 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
241}
242
243
244/* Write the process state of the trace */
245
246static void write_process_state(gpointer key, gpointer value,
247 gpointer user_data)
248{
249 LttvProcessState *process;
250
251 LttvExecutionState *es;
252
253 FILE *fp = (FILE *)user_data;
254
255 guint i;
256
257 process = (LttvProcessState *)value;
258 fprintf(fp,
259" <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
260 process, process->pid, process->ppid, process->creation_time.tv_sec,
261 process->creation_time.tv_nsec, g_quark_to_string(process->name),
262 g_quark_to_string(process->last_cpu));
263
264 for(i = 0 ; i < process->execution_stack->len; i++) {
265 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
266 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
267 g_quark_to_string(es->t), g_quark_to_string(es->n),
268 es->entry.tv_sec, es->entry.tv_nsec);
269 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
270 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
271 }
272 fprintf(fp, " </PROCESS>\n");
273}
274
275
276void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
277{
278 guint i, nb_tracefile, nb_block, nb_event;
279
280 LttvTracefileState *tfcs;
281
282 LttTracefile *tf;
283
284 LttEventPosition *ep;
285
286 ep = ltt_event_position_new();
287
288 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
289
290 g_hash_table_foreach(self->processes, write_process_state, fp);
291
292 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
293 ltt_trace_per_cpu_tracefile_number(self->parent.t);
294
295 for(i = 0 ; i < nb_tracefile ; i++) {
296 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
297 fprintf(fp, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
298 tfcs->process->pid, tfcs->parent.timestamp.tv_sec,
299 tfcs->parent.timestamp.tv_nsec);
300 if(tfcs->parent.e == NULL) fprintf(fp,"/>\n");
301 else {
302 ltt_event_position(tfcs->parent.e, ep);
303 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
304 fprintf(fp, " BLOCK=%u EVENT=%u/>\n", nb_block, nb_event);
305 }
306 }
307 g_free(ep);
308 fprintf(fp,"</PROCESS_STATE>");
309}
310
311
312/* Copy each process from an existing hash table to a new one */
313
314static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
315{
316 LttvProcessState *process, *new_process;
317
318 GHashTable *new_processes = (GHashTable *)user_data;
319
320 guint i;
321
322 process = (LttvProcessState *)value;
323 new_process = g_new(LttvProcessState, 1);
324 *new_process = *process;
325 new_process->execution_stack = g_array_new(FALSE, FALSE,
326 sizeof(LttvExecutionState));
327 g_array_set_size(new_process->execution_stack,process->execution_stack->len);
328 for(i = 0 ; i < process->execution_stack->len; i++) {
329 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
330 g_array_index(process->execution_stack, LttvExecutionState, i);
331 }
332 new_process->state = &g_array_index(new_process->execution_stack,
333 LttvExecutionState, new_process->execution_stack->len - 1);
334 g_hash_table_insert(new_processes, new_process, new_process);
335}
336
337
338static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
339{
340 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
341
342 g_hash_table_foreach(processes, copy_process_state, new_processes);
343 return new_processes;
344}
345
346
347/* The saved state for each trace contains a member "processes", which
348 stores a copy of the process table, and a member "tracefiles" with
349 one entry per tracefile. Each tracefile has a "process" member pointing
350 to the current process and a "position" member storing the tracefile
351 position (needed to seek to the current "next" event. */
352
353static void state_save(LttvTraceState *self, LttvAttribute *container)
354{
355 guint i, nb_tracefile;
356
357 LttvTracefileState *tfcs;
358
359 LttvAttribute *tracefiles_tree, *tracefile_tree;
360
361 LttvAttributeType type;
362
363 LttvAttributeValue value;
364
365 LttvAttributeName name;
366
367 LttEventPosition *ep;
368
369 tracefiles_tree = lttv_attribute_find_subdir(container,
370 LTTV_STATE_TRACEFILES);
371
372 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
373 LTTV_POINTER);
374 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
375
376 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
377 ltt_trace_per_cpu_tracefile_number(self->parent.t);
378
379 for(i = 0 ; i < nb_tracefile ; i++) {
380 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
381 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
382 value = lttv_attribute_add(tracefiles_tree, i,
383 LTTV_GOBJECT);
384 *(value.v_gobject) = (GObject *)tracefile_tree;
385 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
386 LTTV_UINT);
387 *(value.v_uint) = tfcs->process->pid;
388 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
389 LTTV_POINTER);
390 if(tfcs->parent.e == NULL) *(value.v_pointer) = NULL;
391 else {
392 ep = ltt_event_position_new();
393 ltt_event_position(tfcs->parent.e, ep);
394 *(value.v_pointer) = ep;
395
396 guint nb_block, nb_event;
397 LttTracefile *tf;
398 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
399 g_debug("Block %u event %u time %lu.%lu", nb_block, nb_event,
400 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
401 }
402 }
403}
404
405
406static void state_restore(LttvTraceState *self, LttvAttribute *container)
407{
408 guint i, nb_tracefile, pid;
409
410 LttvTracefileState *tfcs;
411
412 LttvAttribute *tracefiles_tree, *tracefile_tree;
413
414 LttvAttributeType type;
415
416 LttvAttributeValue value;
417
418 LttvAttributeName name;
419
420 LttEventPosition *ep;
421
422 tracefiles_tree = lttv_attribute_find_subdir(container,
423 LTTV_STATE_TRACEFILES);
424
425 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
426 &value);
427 g_assert(type == LTTV_POINTER);
428 lttv_state_free_process_table(self->processes);
429 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
430
431 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
432 ltt_trace_per_cpu_tracefile_number(self->parent.t);
433
434 for(i = 0 ; i < nb_tracefile ; i++) {
435 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
436 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
437 g_assert(type == LTTV_GOBJECT);
438 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
439
440 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
441 &value);
442 g_assert(type == LTTV_UINT);
443 pid = *(value.v_uint);
444 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
445
446 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
447 &value);
448 g_assert(type == LTTV_POINTER);
449 if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL;
450 else {
451 ep = *(value.v_pointer);
452 g_assert(tfcs->parent.t_context != NULL);
453 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep);
454 }
455 }
456}
457
458
459static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
460{
461 guint i, nb_tracefile;
462
463 LttvTracefileState *tfcs;
464
465 LttvAttribute *tracefiles_tree, *tracefile_tree;
466
467 LttvAttributeType type;
468
469 LttvAttributeValue value;
470
471 LttvAttributeName name;
472
473 LttEventPosition *ep;
474
475 tracefiles_tree = lttv_attribute_find_subdir(container,
476 LTTV_STATE_TRACEFILES);
477 g_object_ref(G_OBJECT(tracefiles_tree));
478 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
479
480 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
481 &value);
482 g_assert(type == LTTV_POINTER);
483 lttv_state_free_process_table(*(value.v_pointer));
484 *(value.v_pointer) = NULL;
485 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
486
487 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
488 ltt_trace_per_cpu_tracefile_number(self->parent.t);
489
490 for(i = 0 ; i < nb_tracefile ; i++) {
491 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
492 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
493 g_assert(type == LTTV_GOBJECT);
494 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
495
496 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
497 &value);
498 g_assert(type == LTTV_POINTER);
499 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
500 }
501 g_object_unref(G_OBJECT(tracefiles_tree));
502}
503
504
505static void free_saved_state(LttvTraceState *self)
506{
507 guint i, nb;
508
509 LttvAttributeType type;
510
511 LttvAttributeValue value;
512
513 LttvAttributeName name;
514
515 LttvAttribute *saved_states;
516
517 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
518 LTTV_STATE_SAVED_STATES);
519
520 nb = lttv_attribute_get_number(saved_states);
521 for(i = 0 ; i < nb ; i++) {
522 type = lttv_attribute_get(saved_states, i, &name, &value);
523 g_assert(type == LTTV_GOBJECT);
524 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
525 }
526
527 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
528}
529
530
531static void
532create_max_time(LttvTraceState *tcs)
533{
534 LttvAttributeValue v;
535
536 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
537 LTTV_POINTER, &v);
538 g_assert(*(v.v_pointer) == NULL);
539 *(v.v_pointer) = g_new(LttTime,1);
540 *((LttTime *)*(v.v_pointer)) = time_zero;
541}
542
543
544static void
545get_max_time(LttvTraceState *tcs)
546{
547 LttvAttributeValue v;
548
549 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
550 LTTV_POINTER, &v);
551 g_assert(*(v.v_pointer) != NULL);
552 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
553}
554
555
556static void
557free_max_time(LttvTraceState *tcs)
558{
559 LttvAttributeValue v;
560
561 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
562 LTTV_POINTER, &v);
563 g_free(*(v.v_pointer));
564 *(v.v_pointer) = NULL;
565}
566
567
568typedef struct _LttvNameTables {
569 GQuark *eventtype_names;
570 GQuark *syscall_names;
571 GQuark *trap_names;
572 GQuark *irq_names;
573} LttvNameTables;
574
575
576static void
577create_name_tables(LttvTraceState *tcs)
578{
579 int i, nb;
580
581 char *f_name, *e_name;
582
583 LttvTraceHook h;
584
585 LttEventType *et;
586
587 LttType *t;
588
589 GString *fe_name = g_string_new("");
590
591 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
592
593 LttvAttributeValue v;
594
595 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
596 LTTV_POINTER, &v);
597 g_assert(*(v.v_pointer) == NULL);
598 *(v.v_pointer) = name_tables;
599
600 nb = ltt_trace_eventtype_number(tcs->parent.t);
601 name_tables->eventtype_names = g_new(GQuark, nb);
602 for(i = 0 ; i < nb ; i++) {
603 et = ltt_trace_eventtype_get(tcs->parent.t, i);
604 e_name = ltt_eventtype_name(et);
605 f_name = ltt_facility_name(ltt_eventtype_facility(et));
606 g_string_printf(fe_name, "%s.%s", f_name, e_name);
607 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
608 }
609
610 lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry",
611 "syscall_id", NULL, NULL, NULL, &h);
612 t = ltt_field_type(h.f1);
613 nb = ltt_type_element_number(t);
614
615 /* CHECK syscalls should be an emun but currently are not!
616 name_tables->syscall_names = g_new(GQuark, nb);
617
618 for(i = 0 ; i < nb ; i++) {
619 name_tables->syscall_names[i] = g_quark_from_string(
620 ltt_enum_string_get(t, i));
621 }
622 */
623
624 name_tables->syscall_names = g_new(GQuark, 256);
625 for(i = 0 ; i < 256 ; i++) {
626 g_string_printf(fe_name, "syscall %d", i);
627 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
628 }
629
630 lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry",
631 "trap_id", NULL, NULL, NULL, &h);
632 t = ltt_field_type(h.f1);
633 nb = ltt_type_element_number(t);
634
635 /*
636 name_tables->trap_names = g_new(GQuark, nb);
637 for(i = 0 ; i < nb ; i++) {
638 name_tables->trap_names[i] = g_quark_from_string(
639 ltt_enum_string_get(t, i));
640 }
641 */
642
643 name_tables->trap_names = g_new(GQuark, 256);
644 for(i = 0 ; i < 256 ; i++) {
645 g_string_printf(fe_name, "trap %d", i);
646 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
647 }
648
649 lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry",
650 "irq_id", NULL, NULL, NULL, &h);
651 t = ltt_field_type(h.f1);
652 nb = ltt_type_element_number(t);
653
654 /*
655 name_tables->irq_names = g_new(GQuark, nb);
656 for(i = 0 ; i < nb ; i++) {
657 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
658 }
659 */
660
661 name_tables->irq_names = g_new(GQuark, 256);
662 for(i = 0 ; i < 256 ; i++) {
663 g_string_printf(fe_name, "irq %d", i);
664 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
665 }
666
667 g_string_free(fe_name, TRUE);
668}
669
670
671static void
672get_name_tables(LttvTraceState *tcs)
673{
674 LttvNameTables *name_tables;
675
676 LttvAttributeValue v;
677
678 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
679 LTTV_POINTER, &v);
680 g_assert(*(v.v_pointer) != NULL);
681 name_tables = (LttvNameTables *)*(v.v_pointer);
682 tcs->eventtype_names = name_tables->eventtype_names;
683 tcs->syscall_names = name_tables->syscall_names;
684 tcs->trap_names = name_tables->trap_names;
685 tcs->irq_names = name_tables->irq_names;
686}
687
688
689static void
690free_name_tables(LttvTraceState *tcs)
691{
692 LttvNameTables *name_tables;
693
694 LttvAttributeValue v;
695
696 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
697 LTTV_POINTER, &v);
698 name_tables = (LttvNameTables *)*(v.v_pointer);
699 *(v.v_pointer) = NULL;
700
701 g_free(name_tables->eventtype_names);
702 g_free(name_tables->syscall_names);
703 g_free(name_tables->trap_names);
704 g_free(name_tables->irq_names);
705 g_free(name_tables);
706}
707
708
709static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
710 guint state_id)
711{
712 LttvExecutionState *es;
713
714 LttvProcessState *process = tfs->process;
715
716 guint depth = process->execution_stack->len;
717
718 g_array_set_size(process->execution_stack, depth + 1);
719 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
720 es->t = t;
721 es->n = state_id;
722 es->entry = es->change = tfs->parent.timestamp;
723 es->s = process->state->s;
724 process->state = es;
725}
726
727
728static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
729{
730 LttvProcessState *process = tfs->process;
731
732 guint depth = process->execution_stack->len;
733
734 if(process->state->t != t){
735 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
736 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
737 g_info("process state has %s when pop_int is %s\n",
738 g_quark_to_string(process->state->t),
739 g_quark_to_string(t));
740 g_info("{ %u, %u, %s, %s }\n",
741 process->pid,
742 process->ppid,
743 g_quark_to_string(process->name),
744 g_quark_to_string(process->state->s));
745 return;
746 }
747
748 if(depth == 1){
749 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
750 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
751 return;
752 }
753
754 g_array_set_size(process->execution_stack, depth - 1);
755 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
756 depth - 2);
757 process->state->change = tfs->parent.timestamp;
758}
759
760
761LttvProcessState *
762lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
763 guint pid)
764{
765 LttvProcessState *process = g_new(LttvProcessState, 1);
766
767 LttvExecutionState *es;
768
769 LttvTraceContext *tc;
770
771 LttvTraceState *tcs;
772
773 char buffer[128];
774
775 tc = tfs->parent.t_context;
776 tcs = (LttvTraceState *)tc;
777
778 process->pid = pid;
779 process->last_cpu = tfs->cpu_name;
780 g_warning("Process %u, core %p", process->pid, process);
781 g_hash_table_insert(tcs->processes, process, process);
782
783 if(parent) {
784 process->ppid = parent->pid;
785 process->name = parent->name;
786 process->creation_time = tfs->parent.timestamp;
787 }
788
789 /* No parent. This process exists but we are missing all information about
790 its creation. The birth time is set to zero but we remember the time of
791 insertion */
792
793 else {
794 process->ppid = 0;
795 process->name = LTTV_STATE_UNNAMED;
796 process->creation_time = ltt_time_zero;
797 }
798
799 process->insertion_time = tfs->parent.timestamp;
800 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
801 process->creation_time.tv_nsec);
802 process->pid_time = g_quark_from_string(buffer);
803 process->last_cpu = tfs->cpu_name;
804 process->execution_stack = g_array_new(FALSE, FALSE,
805 sizeof(LttvExecutionState));
806 g_array_set_size(process->execution_stack, 1);
807 es = process->state = &g_array_index(process->execution_stack,
808 LttvExecutionState, 0);
809 es->t = LTTV_STATE_USER_MODE;
810 es->n = LTTV_STATE_SUBMODE_NONE;
811 es->entry = tfs->parent.timestamp;
812 g_assert(tfs->parent.timestamp.tv_sec != 0);
813 es->change = tfs->parent.timestamp;
814 es->s = LTTV_STATE_WAIT_FORK;
815
816 return process;
817}
818
819LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
820 guint pid)
821{
822 LttvProcessState key;
823 LttvProcessState *process;
824
825 LttvTraceState* ts = (LttvTraceState*)tfs->parent.t_context;
826
827 key.pid = pid;
828 key.last_cpu = tfs->cpu_name;
829 process = g_hash_table_lookup(ts->processes, &key);
830 return process;
831}
832
833LttvProcessState *
834lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
835{
836 LttvProcessState *process = lttv_state_find_process(tfs, pid);
837
838 if(process == NULL) process = lttv_state_create_process(tfs, NULL, pid);
839 return process;
840}
841
842/* FIXME : this function should be called when we receive an event telling that
843 * release_task has been called in the kernel. In happens generally when
844 * the parent waits for its child terminaison, but may also happen in special
845 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
846 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
847 * of a killed thread ground, but isn't the leader.
848 */
849static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
850{
851 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
852 LttvProcessState key;
853
854 key.pid = process->pid;
855 key.last_cpu = process->last_cpu;
856 g_hash_table_remove(ts->processes, &key);
857 g_array_free(process->execution_stack, TRUE);
858 g_free(process);
859}
860
861
862static void free_process_state(gpointer key, gpointer value,gpointer user_data)
863{
864 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
865 g_free(value);
866}
867
868
869static void lttv_state_free_process_table(GHashTable *processes)
870{
871 g_hash_table_foreach(processes, free_process_state, NULL);
872 g_hash_table_destroy(processes);
873}
874
875
876static gboolean syscall_entry(void *hook_data, void *call_data)
877{
878 LttField *f = ((LttvTraceHook *)hook_data)->f1;
879
880 LttvTracefileState *s = (LttvTracefileState *)call_data;
881
882 LttvExecutionSubmode submode;
883
884 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
885 ltt_event_get_unsigned(s->parent.e, f)];
886 push_state(s, LTTV_STATE_SYSCALL, submode);
887 return FALSE;
888}
889
890
891static gboolean syscall_exit(void *hook_data, void *call_data)
892{
893 LttvTracefileState *s = (LttvTracefileState *)call_data;
894
895 pop_state(s, LTTV_STATE_SYSCALL);
896 return FALSE;
897}
898
899
900static gboolean trap_entry(void *hook_data, void *call_data)
901{
902 LttField *f = ((LttvTraceHook *)hook_data)->f1;
903
904 LttvTracefileState *s = (LttvTracefileState *)call_data;
905
906 LttvExecutionSubmode submode;
907
908 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
909 ltt_event_get_unsigned(s->parent.e, f)];
910 push_state(s, LTTV_STATE_TRAP, submode);
911 return FALSE;
912}
913
914
915static gboolean trap_exit(void *hook_data, void *call_data)
916{
917 LttvTracefileState *s = (LttvTracefileState *)call_data;
918
919 pop_state(s, LTTV_STATE_TRAP);
920 return FALSE;
921}
922
923
924static gboolean irq_entry(void *hook_data, void *call_data)
925{
926 LttField *f = ((LttvTraceHook *)hook_data)->f1;
927
928 LttvTracefileState *s = (LttvTracefileState *)call_data;
929
930 LttvExecutionSubmode submode;
931
932 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
933 ltt_event_get_unsigned(s->parent.e, f)];
934
935 /* Do something with the info about being in user or system mode when int? */
936 push_state(s, LTTV_STATE_IRQ, submode);
937 return FALSE;
938}
939
940
941static gboolean irq_exit(void *hook_data, void *call_data)
942{
943 LttvTracefileState *s = (LttvTracefileState *)call_data;
944
945 pop_state(s, LTTV_STATE_IRQ);
946 return FALSE;
947}
948
949
950static gboolean schedchange(void *hook_data, void *call_data)
951{
952 LttvTraceHook *h = (LttvTraceHook *)hook_data;
953
954 LttvTracefileState *s = (LttvTracefileState *)call_data;
955
956 guint pid_in, pid_out, state_out;
957
958 pid_in = ltt_event_get_unsigned(s->parent.e, h->f1);
959 pid_out = ltt_event_get_unsigned(s->parent.e, h->f2);
960 state_out = ltt_event_get_unsigned(s->parent.e, h->f3);
961
962 if(s->process != NULL) {
963
964 /* We could not know but it was not the idle process executing.
965 This should only happen at the beginning, before the first schedule
966 event, and when the initial information (current process for each CPU)
967 is missing. It is not obvious how we could, after the fact, compensate
968 the wrongly attributed statistics. */
969
970 if(s->process->pid != pid_out) {
971 g_assert(s->process->pid == 0);
972 }
973
974 if(s->process->state->s == LTTV_STATE_EXIT) {
975 s->process->state->s = LTTV_STATE_ZOMBIE;
976 } else {
977 if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
978 else s->process->state->s = LTTV_STATE_WAIT;
979 } /* FIXME : we do not remove process here, because the kernel
980 * still has them : they may be zombies. We need to know
981 * exactly when release_task is executed on the PID to
982 * know when the zombie is destroyed.
983 */
984 //else
985 // exit_process(s, s->process);
986
987 s->process->state->change = s->parent.timestamp;
988 }
989 s->process = lttv_state_find_process_or_create(s, pid_in);
990 s->process->state->s = LTTV_STATE_RUN;
991 s->process->last_cpu = s->cpu_name;
992 s->process->state->change = s->parent.timestamp;
993 return FALSE;
994}
995
996
997static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
998{
999 LttField *f;
1000 guint child_pid;
1001 LttvProcessState *zombie_process;
1002
1003 /* Child PID */
1004 f = trace_hook->f2;
1005 child_pid = ltt_event_get_unsigned(s->parent.e, f);
1006
1007 zombie_process = lttv_state_find_process(s, child_pid);
1008
1009 if(zombie_process != NULL) {
1010 /* Reutilisation of PID. Only now we are sure that the old PID
1011 * has been released. FIXME : sould know when release_task happens instead.
1012 */
1013 exit_process(s, zombie_process);
1014 }
1015 g_assert(s->process->pid != child_pid);
1016 lttv_state_create_process(s, s->process, child_pid);
1017
1018 return FALSE;
1019}
1020
1021
1022static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
1023{
1024 if(s->process != NULL) {
1025 s->process->state->s = LTTV_STATE_EXIT;
1026 }
1027 return FALSE;
1028}
1029
1030gboolean process(void *hook_data, void *call_data)
1031{
1032 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1033 LttField *f = trace_hook->f1;
1034
1035 LttvTracefileState *s = (LttvTracefileState *)call_data;
1036
1037 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1038
1039 /* CHECK : do not hardcode the sub_id values here ? */
1040 if(sub_id == 2) {
1041 return process_fork(trace_hook, s);
1042 } else if(sub_id == 3) {
1043 return process_exit(trace_hook, s);
1044 }
1045 return 0;
1046}
1047
1048gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1049{
1050 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1051
1052 lttv_state_add_event_hooks(tss);
1053
1054 return 0;
1055}
1056
1057void lttv_state_add_event_hooks(LttvTracesetState *self)
1058{
1059 LttvTraceset *traceset = self->parent.ts;
1060
1061 guint i, j, k, nb_trace, nb_tracefile;
1062
1063 LttvTraceState *ts;
1064
1065 LttvTracefileState *tfs;
1066
1067 GArray *hooks;
1068
1069 LttvTraceHook hook;
1070
1071 LttvAttributeValue val;
1072
1073 nb_trace = lttv_traceset_number(traceset);
1074 for(i = 0 ; i < nb_trace ; i++) {
1075 ts = (LttvTraceState *)self->parent.traces[i];
1076
1077 /* Find the eventtype id for the following events and register the
1078 associated by id hooks. */
1079
1080 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1081 g_array_set_size(hooks, 8);
1082
1083 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1084 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
1085
1086 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1087 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
1088
1089 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1090 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
1091
1092 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1093 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
1094
1095 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1096 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
1097
1098 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1099 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
1100
1101 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1102 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
1103
1104 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1105 "event_data1", "event_data2", process,
1106 &g_array_index(hooks, LttvTraceHook, 7));
1107
1108#if 0
1109 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1110 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
1111
1112 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1113 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
1114#endif //0
1115 /* Add these hooks to each event_by_id hooks list */
1116
1117 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1118 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1119
1120 for(j = 0 ; j < nb_tracefile ; j++) {
1121 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1122
1123 for(k = 0 ; k < hooks->len ; k++) {
1124 hook = g_array_index(hooks, LttvTraceHook, k);
1125 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1126 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
1127 }
1128 }
1129 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1130 *(val.v_pointer) = hooks;
1131 }
1132}
1133
1134gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1135{
1136 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1137
1138 lttv_state_remove_event_hooks(tss);
1139
1140 return 0;
1141}
1142
1143void lttv_state_remove_event_hooks(LttvTracesetState *self)
1144{
1145 LttvTraceset *traceset = self->parent.ts;
1146
1147 guint i, j, k, nb_trace, nb_tracefile;
1148
1149 LttvTraceState *ts;
1150
1151 LttvTracefileState *tfs;
1152
1153 GArray *hooks;
1154
1155 LttvTraceHook hook;
1156
1157 LttvAttributeValue val;
1158
1159 nb_trace = lttv_traceset_number(traceset);
1160 for(i = 0 ; i < nb_trace ; i++) {
1161 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1162 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1163 hooks = *(val.v_pointer);
1164
1165 /* Remove these hooks from each event_by_id hooks list */
1166
1167 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1168 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1169
1170 for(j = 0 ; j < nb_tracefile ; j++) {
1171 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1172
1173 for(k = 0 ; k < hooks->len ; k++) {
1174 hook = g_array_index(hooks, LttvTraceHook, k);
1175 lttv_hooks_remove_data(
1176 lttv_hooks_by_id_find(tfs->parent.event_by_id,
1177 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1178 }
1179 }
1180 g_array_free(hooks, TRUE);
1181 }
1182}
1183
1184
1185static gboolean block_start(void *hook_data, void *call_data)
1186{
1187 LttvTracefileState *self = (LttvTracefileState *)call_data;
1188
1189 LttvTracefileState *tfcs;
1190
1191 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1192
1193 LttEventPosition *ep;
1194
1195 guint i, nb_block, nb_event, nb_tracefile;
1196
1197 LttTracefile *tf;
1198
1199 LttvAttribute *saved_states_tree, *saved_state_tree;
1200
1201 LttvAttributeValue value;
1202
1203 ep = ltt_event_position_new();
1204 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1205 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1206
1207 /* Count the number of events added since the last block end in any
1208 tracefile. */
1209
1210 for(i = 0 ; i < nb_tracefile ; i++) {
1211 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1212 ltt_event_position(tfcs->parent.e, ep);
1213 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1214 tcs->nb_event += nb_event - tfcs->saved_position;
1215 tfcs->saved_position = nb_event;
1216 }
1217 g_free(ep);
1218
1219 if(tcs->nb_event >= tcs->save_interval) {
1220 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1221 LTTV_STATE_SAVED_STATES);
1222 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1223 value = lttv_attribute_add(saved_states_tree,
1224 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1225 *(value.v_gobject) = (GObject *)saved_state_tree;
1226 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1227 *(value.v_time) = self->parent.timestamp;
1228 lttv_state_save(tcs, saved_state_tree);
1229 tcs->nb_event = 0;
1230 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1231 self->parent.timestamp.tv_nsec);
1232 }
1233 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1234 return FALSE;
1235}
1236
1237
1238static gboolean block_end(void *hook_data, void *call_data)
1239{
1240 LttvTracefileState *self = (LttvTracefileState *)call_data;
1241
1242 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1243
1244 LttTracefile *tf;
1245
1246 LttEventPosition *ep;
1247
1248 guint nb_block, nb_event;
1249
1250 ep = ltt_event_position_new();
1251 ltt_event_position(self->parent.e, ep);
1252 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1253 tcs->nb_event += nb_event - self->saved_position + 1;
1254 self->saved_position = 0;
1255 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1256 g_free(ep);
1257
1258 return FALSE;
1259}
1260
1261
1262void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1263{
1264 LttvTraceset *traceset = self->parent.ts;
1265
1266 guint i, j, nb_trace, nb_tracefile;
1267
1268 LttvTraceState *ts;
1269
1270 LttvTracefileState *tfs;
1271
1272 LttvTraceHook hook_start, hook_end;
1273
1274 nb_trace = lttv_traceset_number(traceset);
1275 for(i = 0 ; i < nb_trace ; i++) {
1276 ts = (LttvTraceState *)self->parent.traces[i];
1277 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1278 NULL, NULL, block_start, &hook_start);
1279 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1280 NULL, NULL, block_end, &hook_end);
1281
1282 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1283 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1284
1285 for(j = 0 ; j < nb_tracefile ; j++) {
1286 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1287 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1288 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1289 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1290 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1291 }
1292 }
1293}
1294
1295gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1296{
1297 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1298
1299 lttv_state_save_add_event_hooks(tss);
1300
1301 return 0;
1302}
1303
1304
1305void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1306{
1307 LttvTraceset *traceset = self->parent.ts;
1308
1309 guint i, j, nb_trace, nb_tracefile;
1310
1311 LttvTraceState *ts;
1312
1313 LttvTracefileState *tfs;
1314
1315 LttvTraceHook hook_start, hook_end;
1316
1317 nb_trace = lttv_traceset_number(traceset);
1318 for(i = 0 ; i < nb_trace ; i++) {
1319 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1320 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1321 NULL, NULL, block_start, &hook_start);
1322
1323 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1324 NULL, NULL, block_end, &hook_end);
1325
1326 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1327 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1328
1329 for(j = 0 ; j < nb_tracefile ; j++) {
1330 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1331 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1332 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1333 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1334 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1335 }
1336 }
1337}
1338
1339gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1340{
1341 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1342
1343 lttv_state_save_remove_event_hooks(tss);
1344
1345 return 0;
1346}
1347
1348void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1349{
1350 LttvTraceset *traceset = self->parent.ts;
1351
1352 guint i, nb_trace;
1353
1354 int min_pos, mid_pos, max_pos;
1355
1356 LttvTraceState *tcs;
1357
1358 LttvAttributeValue value;
1359
1360 LttvAttributeType type;
1361
1362 LttvAttributeName name;
1363
1364 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1365
1366 nb_trace = lttv_traceset_number(traceset);
1367 for(i = 0 ; i < nb_trace ; i++) {
1368 tcs = (LttvTraceState *)self->parent.traces[i];
1369
1370 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1371 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1372 LTTV_STATE_SAVED_STATES);
1373 min_pos = -1;
1374
1375 if(saved_states_tree) {
1376 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1377 mid_pos = max_pos / 2;
1378 while(min_pos < max_pos) {
1379 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1380 g_assert(type == LTTV_GOBJECT);
1381 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1382 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1383 &value);
1384 g_assert(type == LTTV_TIME);
1385 if(ltt_time_compare(*(value.v_time), t) < 0) {
1386 min_pos = mid_pos;
1387 closest_tree = saved_state_tree;
1388 }
1389 else max_pos = mid_pos - 1;
1390
1391 mid_pos = (min_pos + max_pos + 1) / 2;
1392 }
1393 }
1394
1395 /* restore the closest earlier saved state */
1396 if(min_pos != -1) {
1397 lttv_state_restore(tcs, closest_tree);
1398 }
1399
1400 /* There is no saved state, yet we want to have it. Restart at T0 */
1401 else {
1402 restore_init_state(tcs);
1403 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1404 }
1405 }
1406 /* We want to seek quickly without restoring/updating the state */
1407 else {
1408 restore_init_state(tcs);
1409 lttv_process_trace_seek_time(&(tcs->parent), t);
1410 }
1411 }
1412}
1413
1414
1415static void
1416traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1417{
1418}
1419
1420
1421static void
1422traceset_state_finalize (LttvTracesetState *self)
1423{
1424 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1425 finalize(G_OBJECT(self));
1426}
1427
1428
1429static void
1430traceset_state_class_init (LttvTracesetContextClass *klass)
1431{
1432 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1433
1434 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1435 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1436 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1437 klass->new_traceset_context = new_traceset_context;
1438 klass->new_trace_context = new_trace_context;
1439 klass->new_tracefile_context = new_tracefile_context;
1440}
1441
1442
1443GType
1444lttv_traceset_state_get_type(void)
1445{
1446 static GType type = 0;
1447 if (type == 0) {
1448 static const GTypeInfo info = {
1449 sizeof (LttvTracesetStateClass),
1450 NULL, /* base_init */
1451 NULL, /* base_finalize */
1452 (GClassInitFunc) traceset_state_class_init, /* class_init */
1453 NULL, /* class_finalize */
1454 NULL, /* class_data */
1455 sizeof (LttvTracesetState),
1456 0, /* n_preallocs */
1457 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1458 NULL /* value handling */
1459 };
1460
1461 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1462 &info, 0);
1463 }
1464 return type;
1465}
1466
1467
1468static void
1469trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1470{
1471}
1472
1473
1474static void
1475trace_state_finalize (LttvTraceState *self)
1476{
1477 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1478 finalize(G_OBJECT(self));
1479}
1480
1481
1482static void
1483trace_state_class_init (LttvTraceStateClass *klass)
1484{
1485 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1486
1487 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1488 klass->state_save = state_save;
1489 klass->state_restore = state_restore;
1490 klass->state_saved_free = state_saved_free;
1491}
1492
1493
1494GType
1495lttv_trace_state_get_type(void)
1496{
1497 static GType type = 0;
1498 if (type == 0) {
1499 static const GTypeInfo info = {
1500 sizeof (LttvTraceStateClass),
1501 NULL, /* base_init */
1502 NULL, /* base_finalize */
1503 (GClassInitFunc) trace_state_class_init, /* class_init */
1504 NULL, /* class_finalize */
1505 NULL, /* class_data */
1506 sizeof (LttvTraceState),
1507 0, /* n_preallocs */
1508 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1509 NULL /* value handling */
1510 };
1511
1512 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1513 "LttvTraceStateType", &info, 0);
1514 }
1515 return type;
1516}
1517
1518
1519static void
1520tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1521{
1522}
1523
1524
1525static void
1526tracefile_state_finalize (LttvTracefileState *self)
1527{
1528 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1529 finalize(G_OBJECT(self));
1530}
1531
1532
1533static void
1534tracefile_state_class_init (LttvTracefileStateClass *klass)
1535{
1536 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1537
1538 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1539}
1540
1541
1542GType
1543lttv_tracefile_state_get_type(void)
1544{
1545 static GType type = 0;
1546 if (type == 0) {
1547 static const GTypeInfo info = {
1548 sizeof (LttvTracefileStateClass),
1549 NULL, /* base_init */
1550 NULL, /* base_finalize */
1551 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1552 NULL, /* class_finalize */
1553 NULL, /* class_data */
1554 sizeof (LttvTracefileState),
1555 0, /* n_preallocs */
1556 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1557 NULL /* value handling */
1558 };
1559
1560 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1561 "LttvTracefileStateType", &info, 0);
1562 }
1563 return type;
1564}
1565
1566
1567static void module_init()
1568{
1569 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1570 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1571 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1572 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1573 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1574 LTTV_STATE_TRAP = g_quark_from_string("trap");
1575 LTTV_STATE_IRQ = g_quark_from_string("irq");
1576 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1577 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1578 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1579 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1580 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
1581 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1582 LTTV_STATE_RUN = g_quark_from_string("running");
1583 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1584 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1585 LTTV_STATE_PROCESS = g_quark_from_string("process");
1586 LTTV_STATE_EVENT = g_quark_from_string("event");
1587 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1588 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1589 LTTV_STATE_TIME = g_quark_from_string("time");
1590 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1591 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1592 LTTV_STATE_TRACE_STATE_USE_COUNT =
1593 g_quark_from_string("trace_state_use_count");
1594}
1595
1596static void module_destroy()
1597{
1598}
1599
1600
1601LTTV_MODULE("state", "State computation", \
1602 "Update the system state, possibly saving it at intervals", \
1603 module_init, module_destroy)
1604
1605
1606
This page took 0.028159 seconds and 4 git commands to generate.