Add reference counts to state and stats saved attributes. This way, the
[lttv.git] / ltt / branches / poly / lttv / main / state.c
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
29 LttvExecutionMode
30 LTTV_STATE_MODE_UNKNOWN,
31 LTTV_STATE_USER_MODE,
32 LTTV_STATE_SYSCALL,
33 LTTV_STATE_TRAP,
34 LTTV_STATE_IRQ;
35
36 LttvExecutionSubmode
37 LTTV_STATE_SUBMODE_UNKNOWN,
38 LTTV_STATE_SUBMODE_NONE;
39
40 LttvProcessStatus
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
48 static 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
61 static void create_max_time(LttvTraceState *tcs);
62
63 static void get_max_time(LttvTraceState *tcs);
64
65 static void free_max_time(LttvTraceState *tcs);
66
67 static void create_name_tables(LttvTraceState *tcs);
68
69 static void get_name_tables(LttvTraceState *tcs);
70
71 static void free_name_tables(LttvTraceState *tcs);
72
73 static void free_saved_state(LttvTraceState *tcs);
74
75 static void lttv_state_free_process_table(GHashTable *processes);
76
77
78 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
79 {
80 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
81 }
82
83
84 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
85 {
86 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
87 }
88
89
90 void 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
97 guint process_hash(gconstpointer key)
98 {
99 return ((LttvProcessState *)key)->pid;
100 }
101
102
103 gboolean 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
117 static void
118 restore_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
143 static LttTime time_zero = {0,0};
144
145 static void
146 init(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
190 static void
191 fini(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
222 static LttvTracesetContext *
223 new_traceset_context(LttvTracesetContext *self)
224 {
225 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
226 }
227
228
229 static LttvTraceContext *
230 new_trace_context(LttvTracesetContext *self)
231 {
232 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
233 }
234
235
236 static LttvTracefileContext *
237 new_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
245 static 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
275 void 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
313 static 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
337 static 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
352 static 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
405 static 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 ltt_tracefile_seek_position(tfcs->parent.tf, ep);
452 tfcs->parent.e = ltt_tracefile_read(tfcs->parent.tf);
453 tfcs->parent.timestamp = ltt_event_time(tfcs->parent.e);
454 }
455 }
456 }
457
458
459 static 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 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 lttv_attribute_recursive_free(tracefiles_tree);
501 }
502
503
504 static 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 lttv_attribute_recursive_free(saved_states);
528 }
529
530
531 static void
532 create_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
544 static void
545 get_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
556 static void
557 free_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
568 typedef struct _LttvNameTables {
569 GQuark *eventtype_names;
570 GQuark *syscall_names;
571 GQuark *trap_names;
572 GQuark *irq_names;
573 } LttvNameTables;
574
575
576 static void
577 create_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
671 static void
672 get_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
689 static void
690 free_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
709 static 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
728 static 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 (%d.%09d): 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 (%d.%09d): 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
761 LttvProcessState *
762 lttv_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 tcs = ((LttvTraceState *)tc = tfs->parent.t_context);
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
818 LttvProcessState *
819 lttv_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
831 LttvProcessState *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
839 LttvProcessState *
840 lttv_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
849 static 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
862 static 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
869 static 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
876 static 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
891 static 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
900 static 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
915 static 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
924 static 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
941 static 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
950 static 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
989 static gboolean process_fork(void *hook_data, void *call_data)
990 {
991 LttField *f = ((LttvTraceHook *)hook_data)->f1;
992
993 LttvTracefileState *s = (LttvTracefileState *)call_data;
994
995 guint child_pid;
996
997 child_pid = ltt_event_get_unsigned(s->parent.e, f);
998 lttv_state_create_process(s, s->process, child_pid);
999 return FALSE;
1000 }
1001
1002
1003 static gboolean process_exit(void *hook_data, void *call_data)
1004 {
1005 LttvTracefileState *s = (LttvTracefileState *)call_data;
1006
1007 if(s->process != NULL) {
1008 s->process->state->s = LTTV_STATE_EXIT;
1009 }
1010 return FALSE;
1011 }
1012
1013
1014 void lttv_state_add_event_hooks(LttvTracesetState *self)
1015 {
1016 LttvTraceset *traceset = self->parent.ts;
1017
1018 guint i, j, k, nb_trace, nb_tracefile;
1019
1020 LttvTraceState *ts;
1021
1022 LttvTracefileState *tfs;
1023
1024 GArray *hooks;
1025
1026 LttvTraceHook hook;
1027
1028 LttvAttributeValue val;
1029
1030 nb_trace = lttv_traceset_number(traceset);
1031 for(i = 0 ; i < nb_trace ; i++) {
1032 ts = (LttvTraceState *)self->parent.traces[i];
1033
1034 /* Find the eventtype id for the following events and register the
1035 associated by id hooks. */
1036
1037 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1038 g_array_set_size(hooks, 9);
1039
1040 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1041 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
1042
1043 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1044 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
1045
1046 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1047 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
1048
1049 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1050 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
1051
1052 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1053 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
1054
1055 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1056 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
1057
1058 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1059 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
1060
1061 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1062 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
1063
1064 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1065 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
1066
1067 /* Add these hooks to each before_event_by_id hooks list */
1068
1069 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1070 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1071
1072 for(j = 0 ; j < nb_tracefile ; j++) {
1073 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1074
1075 for(k = 0 ; k < hooks->len ; k++) {
1076 hook = g_array_index(hooks, LttvTraceHook, k);
1077 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1078 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1079 }
1080 }
1081 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1082 *(val.v_pointer) = hooks;
1083 }
1084 }
1085
1086
1087 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1088 {
1089 LttvTraceset *traceset = self->parent.ts;
1090
1091 guint i, j, k, nb_trace, nb_tracefile;
1092
1093 LttvTraceState *ts;
1094
1095 LttvTracefileState *tfs;
1096
1097 GArray *hooks;
1098
1099 LttvTraceHook hook;
1100
1101 LttvAttributeValue val;
1102
1103 nb_trace = lttv_traceset_number(traceset);
1104 for(i = 0 ; i < nb_trace ; i++) {
1105 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1106 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1107 hooks = *(val.v_pointer);
1108
1109 /* Add these hooks to each before_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_remove_data(
1120 lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1121 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1122 }
1123 }
1124 g_array_free(hooks, TRUE);
1125 }
1126 }
1127
1128
1129 static gboolean block_start(void *hook_data, void *call_data)
1130 {
1131 LttvTracefileState *self = (LttvTracefileState *)call_data;
1132
1133 LttvTracefileState *tfcs;
1134
1135 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1136
1137 LttEventPosition *ep;
1138
1139 guint i, nb_block, nb_event, nb_tracefile;
1140
1141 LttTracefile *tf;
1142
1143 LttvAttribute *saved_states_tree, *saved_state_tree;
1144
1145 LttvAttributeValue value;
1146
1147 ep = ltt_event_position_new();
1148 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1149 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1150
1151 /* Count the number of events added since the last block end in any
1152 tracefile. */
1153
1154 for(i = 0 ; i < nb_tracefile ; i++) {
1155 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1156 ltt_event_position(tfcs->parent.e, ep);
1157 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1158 tcs->nb_event += nb_event - tfcs->saved_position;
1159 tfcs->saved_position = nb_event;
1160 }
1161 g_free(ep);
1162
1163 if(tcs->nb_event >= tcs->save_interval) {
1164 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1165 LTTV_STATE_SAVED_STATES);
1166 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1167 value = lttv_attribute_add(saved_states_tree,
1168 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1169 *(value.v_gobject) = (GObject *)saved_state_tree;
1170 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1171 *(value.v_time) = self->parent.timestamp;
1172 lttv_state_save(tcs, saved_state_tree);
1173 tcs->nb_event = 0;
1174 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1175 self->parent.timestamp.tv_nsec);
1176 }
1177 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1178 return FALSE;
1179 }
1180
1181
1182 static gboolean block_end(void *hook_data, void *call_data)
1183 {
1184 LttvTracefileState *self = (LttvTracefileState *)call_data;
1185
1186 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1187
1188 LttTracefile *tf;
1189
1190 LttEventPosition *ep;
1191
1192 guint nb_block, nb_event;
1193
1194 ep = ltt_event_position_new();
1195 ltt_event_position(self->parent.e, ep);
1196 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1197 tcs->nb_event += nb_event - self->saved_position + 1;
1198 self->saved_position = 0;
1199 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1200 g_free(ep);
1201 }
1202
1203
1204 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1205 {
1206 LttvTraceset *traceset = self->parent.ts;
1207
1208 guint i, j, k, nb_trace, nb_tracefile;
1209
1210 LttvTraceState *ts;
1211
1212 LttvTracefileState *tfs;
1213
1214 LttvTraceHook hook_start, hook_end;
1215
1216 nb_trace = lttv_traceset_number(traceset);
1217 for(i = 0 ; i < nb_trace ; i++) {
1218 ts = (LttvTraceState *)self->parent.traces[i];
1219 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1220 NULL, NULL, block_start, &hook_start);
1221 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1222 NULL, NULL, block_end, &hook_end);
1223
1224 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1225 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1226
1227 for(j = 0 ; j < nb_tracefile ; j++) {
1228 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1229 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1230 hook_start.id), hook_start.h, NULL);
1231 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1232 hook_end.id), hook_end.h, NULL);
1233 }
1234 }
1235 }
1236
1237
1238 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1239 {
1240 LttvTraceset *traceset = self->parent.ts;
1241
1242 guint i, j, k, nb_trace, nb_tracefile;
1243
1244 LttvTraceState *ts;
1245
1246 LttvTracefileState *tfs;
1247
1248 LttvTraceHook hook_start, hook_end;
1249
1250 nb_trace = lttv_traceset_number(traceset);
1251 for(i = 0 ; i < nb_trace ; i++) {
1252 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1253 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1254 NULL, NULL, block_start, &hook_start);
1255
1256 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1257 NULL, NULL, block_end, &hook_end);
1258
1259 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1260 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1261
1262 for(j = 0 ; j < nb_tracefile ; j++) {
1263 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1264 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1265 tfs->parent.after_event_by_id, hook_start.id), hook_start.h, NULL);
1266 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1267 tfs->parent.after_event_by_id, hook_end.id), hook_end.h, NULL);
1268 }
1269 }
1270 }
1271
1272
1273 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1274 {
1275 LttvTraceset *traceset = self->parent.ts;
1276
1277 guint i, j, nb_trace, nb_saved_state;
1278
1279 int min_pos, mid_pos, max_pos;
1280
1281 LttvTraceState *tcs;
1282
1283 LttvAttributeValue value;
1284
1285 LttvAttributeType type;
1286
1287 LttvAttributeName name;
1288
1289 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1290
1291 nb_trace = lttv_traceset_number(traceset);
1292 for(i = 0 ; i < nb_trace ; i++) {
1293 tcs = (LttvTraceState *)self->parent.traces[i];
1294
1295 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1296 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1297 LTTV_STATE_SAVED_STATES);
1298 min_pos = -1;
1299
1300 if(saved_states_tree) {
1301 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1302 mid_pos = max_pos / 2;
1303 while(min_pos < max_pos) {
1304 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1305 g_assert(type == LTTV_GOBJECT);
1306 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1307 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1308 &value);
1309 g_assert(type == LTTV_TIME);
1310 if(ltt_time_compare(*(value.v_time), t) < 0) {
1311 min_pos = mid_pos;
1312 closest_tree = saved_state_tree;
1313 }
1314 else max_pos = mid_pos - 1;
1315
1316 mid_pos = (min_pos + max_pos + 1) / 2;
1317 }
1318 }
1319
1320 /* restore the closest earlier saved state */
1321 if(min_pos != -1) {
1322 lttv_state_restore(tcs, closest_tree);
1323 }
1324
1325 /* There is no saved state, yet we want to have it. Restart at T0 */
1326 else {
1327 restore_init_state(tcs);
1328 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1329 }
1330 }
1331 /* We want to seek quickly without restoring/updating the state */
1332 else {
1333 restore_init_state(tcs);
1334 lttv_process_trace_seek_time(&(tcs->parent), t);
1335 }
1336 }
1337 }
1338
1339
1340 static void
1341 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1342 {
1343 }
1344
1345
1346 static void
1347 traceset_state_finalize (LttvTracesetState *self)
1348 {
1349 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1350 finalize(G_OBJECT(self));
1351 }
1352
1353
1354 static void
1355 traceset_state_class_init (LttvTracesetContextClass *klass)
1356 {
1357 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1358
1359 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1360 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1361 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1362 klass->new_traceset_context = new_traceset_context;
1363 klass->new_trace_context = new_trace_context;
1364 klass->new_tracefile_context = new_tracefile_context;
1365 }
1366
1367
1368 GType
1369 lttv_traceset_state_get_type(void)
1370 {
1371 static GType type = 0;
1372 if (type == 0) {
1373 static const GTypeInfo info = {
1374 sizeof (LttvTracesetStateClass),
1375 NULL, /* base_init */
1376 NULL, /* base_finalize */
1377 (GClassInitFunc) traceset_state_class_init, /* class_init */
1378 NULL, /* class_finalize */
1379 NULL, /* class_data */
1380 sizeof (LttvTracesetState),
1381 0, /* n_preallocs */
1382 (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
1383 };
1384
1385 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1386 &info, 0);
1387 }
1388 return type;
1389 }
1390
1391
1392 static void
1393 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1394 {
1395 }
1396
1397
1398 static void
1399 trace_state_finalize (LttvTraceState *self)
1400 {
1401 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1402 finalize(G_OBJECT(self));
1403 }
1404
1405
1406 static void
1407 trace_state_class_init (LttvTraceStateClass *klass)
1408 {
1409 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1410
1411 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1412 klass->state_save = state_save;
1413 klass->state_restore = state_restore;
1414 klass->state_saved_free = state_saved_free;
1415 }
1416
1417
1418 GType
1419 lttv_trace_state_get_type(void)
1420 {
1421 static GType type = 0;
1422 if (type == 0) {
1423 static const GTypeInfo info = {
1424 sizeof (LttvTraceStateClass),
1425 NULL, /* base_init */
1426 NULL, /* base_finalize */
1427 (GClassInitFunc) trace_state_class_init, /* class_init */
1428 NULL, /* class_finalize */
1429 NULL, /* class_data */
1430 sizeof (LttvTraceState),
1431 0, /* n_preallocs */
1432 (GInstanceInitFunc) trace_state_instance_init /* instance_init */
1433 };
1434
1435 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1436 "LttvTraceStateType", &info, 0);
1437 }
1438 return type;
1439 }
1440
1441
1442 static void
1443 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1444 {
1445 }
1446
1447
1448 static void
1449 tracefile_state_finalize (LttvTracefileState *self)
1450 {
1451 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1452 finalize(G_OBJECT(self));
1453 }
1454
1455
1456 static void
1457 tracefile_state_class_init (LttvTracefileStateClass *klass)
1458 {
1459 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1460
1461 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1462 }
1463
1464
1465 GType
1466 lttv_tracefile_state_get_type(void)
1467 {
1468 static GType type = 0;
1469 if (type == 0) {
1470 static const GTypeInfo info = {
1471 sizeof (LttvTracefileStateClass),
1472 NULL, /* base_init */
1473 NULL, /* base_finalize */
1474 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1475 NULL, /* class_finalize */
1476 NULL, /* class_data */
1477 sizeof (LttvTracefileState),
1478 0, /* n_preallocs */
1479 (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
1480 };
1481
1482 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1483 "LttvTracefileStateType", &info, 0);
1484 }
1485 return type;
1486 }
1487
1488
1489 static void module_init()
1490 {
1491 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1492 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1493 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1494 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1495 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1496 LTTV_STATE_TRAP = g_quark_from_string("trap");
1497 LTTV_STATE_IRQ = g_quark_from_string("irq");
1498 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1499 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1500 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1501 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1502 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1503 LTTV_STATE_RUN = g_quark_from_string("running");
1504 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1505 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1506 LTTV_STATE_PROCESS = g_quark_from_string("process");
1507 LTTV_STATE_EVENT = g_quark_from_string("event");
1508 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1509 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1510 LTTV_STATE_TIME = g_quark_from_string("time");
1511 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1512 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1513 LTTV_STATE_TRACE_STATE_USE_COUNT =
1514 g_quark_from_string("trace_state_use_count");
1515 }
1516
1517 static void module_destroy()
1518 {
1519 }
1520
1521
1522 LTTV_MODULE("state", "State computation", \
1523 "Update the system state, possibly saving it at intervals", \
1524 module_init, module_destroy)
1525
1526
1527
This page took 0.060546 seconds and 4 git commands to generate.