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