aa235f2d27ee350580ec30ac8613198b9d900b72
[lttv.git] / ltt / branches / poly / lttv / lttv / 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 lttv_process_tracefile_seek_position(tfcs->parent, ep);
452 }
453 }
454 }
455
456
457 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
458 {
459 guint i, nb_tracefile;
460
461 LttvTracefileState *tfcs;
462
463 LttvAttribute *tracefiles_tree, *tracefile_tree;
464
465 LttvAttributeType type;
466
467 LttvAttributeValue value;
468
469 LttvAttributeName name;
470
471 LttEventPosition *ep;
472
473 tracefiles_tree = lttv_attribute_find_subdir(container,
474 LTTV_STATE_TRACEFILES);
475 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
476
477 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
478 &value);
479 g_assert(type == LTTV_POINTER);
480 lttv_state_free_process_table(*(value.v_pointer));
481 *(value.v_pointer) = NULL;
482 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
483
484 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
485 ltt_trace_per_cpu_tracefile_number(self->parent.t);
486
487 for(i = 0 ; i < nb_tracefile ; i++) {
488 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
489 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
490 g_assert(type == LTTV_GOBJECT);
491 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
492
493 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
494 &value);
495 g_assert(type == LTTV_POINTER);
496 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
497 }
498 lttv_attribute_recursive_free(tracefiles_tree);
499 }
500
501
502 static void free_saved_state(LttvTraceState *self)
503 {
504 guint i, nb;
505
506 LttvAttributeType type;
507
508 LttvAttributeValue value;
509
510 LttvAttributeName name;
511
512 LttvAttribute *saved_states;
513
514 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
515 LTTV_STATE_SAVED_STATES);
516
517 nb = lttv_attribute_get_number(saved_states);
518 for(i = 0 ; i < nb ; i++) {
519 type = lttv_attribute_get(saved_states, i, &name, &value);
520 g_assert(type == LTTV_GOBJECT);
521 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
522 }
523
524 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
525 lttv_attribute_recursive_free(saved_states);
526 }
527
528
529 static void
530 create_max_time(LttvTraceState *tcs)
531 {
532 LttvAttributeValue v;
533
534 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
535 LTTV_POINTER, &v);
536 g_assert(*(v.v_pointer) == NULL);
537 *(v.v_pointer) = g_new(LttTime,1);
538 *((LttTime *)*(v.v_pointer)) = time_zero;
539 }
540
541
542 static void
543 get_max_time(LttvTraceState *tcs)
544 {
545 LttvAttributeValue v;
546
547 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
548 LTTV_POINTER, &v);
549 g_assert(*(v.v_pointer) != NULL);
550 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
551 }
552
553
554 static void
555 free_max_time(LttvTraceState *tcs)
556 {
557 LttvAttributeValue v;
558
559 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
560 LTTV_POINTER, &v);
561 g_free(*(v.v_pointer));
562 *(v.v_pointer) = NULL;
563 }
564
565
566 typedef struct _LttvNameTables {
567 GQuark *eventtype_names;
568 GQuark *syscall_names;
569 GQuark *trap_names;
570 GQuark *irq_names;
571 } LttvNameTables;
572
573
574 static void
575 create_name_tables(LttvTraceState *tcs)
576 {
577 int i, nb;
578
579 char *f_name, *e_name;
580
581 LttvTraceHook h;
582
583 LttEventType *et;
584
585 LttType *t;
586
587 GString *fe_name = g_string_new("");
588
589 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
590
591 LttvAttributeValue v;
592
593 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
594 LTTV_POINTER, &v);
595 g_assert(*(v.v_pointer) == NULL);
596 *(v.v_pointer) = name_tables;
597
598 nb = ltt_trace_eventtype_number(tcs->parent.t);
599 name_tables->eventtype_names = g_new(GQuark, nb);
600 for(i = 0 ; i < nb ; i++) {
601 et = ltt_trace_eventtype_get(tcs->parent.t, i);
602 e_name = ltt_eventtype_name(et);
603 f_name = ltt_facility_name(ltt_eventtype_facility(et));
604 g_string_printf(fe_name, "%s.%s", f_name, e_name);
605 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
606 }
607
608 lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry",
609 "syscall_id", NULL, NULL, NULL, &h);
610 t = ltt_field_type(h.f1);
611 nb = ltt_type_element_number(t);
612
613 /* CHECK syscalls should be an emun but currently are not!
614 name_tables->syscall_names = g_new(GQuark, nb);
615
616 for(i = 0 ; i < nb ; i++) {
617 name_tables->syscall_names[i] = g_quark_from_string(
618 ltt_enum_string_get(t, i));
619 }
620 */
621
622 name_tables->syscall_names = g_new(GQuark, 256);
623 for(i = 0 ; i < 256 ; i++) {
624 g_string_printf(fe_name, "syscall %d", i);
625 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
626 }
627
628 lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry",
629 "trap_id", NULL, NULL, NULL, &h);
630 t = ltt_field_type(h.f1);
631 nb = ltt_type_element_number(t);
632
633 /*
634 name_tables->trap_names = g_new(GQuark, nb);
635 for(i = 0 ; i < nb ; i++) {
636 name_tables->trap_names[i] = g_quark_from_string(
637 ltt_enum_string_get(t, i));
638 }
639 */
640
641 name_tables->trap_names = g_new(GQuark, 256);
642 for(i = 0 ; i < 256 ; i++) {
643 g_string_printf(fe_name, "trap %d", i);
644 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
645 }
646
647 lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry",
648 "irq_id", NULL, NULL, NULL, &h);
649 t = ltt_field_type(h.f1);
650 nb = ltt_type_element_number(t);
651
652 /*
653 name_tables->irq_names = g_new(GQuark, nb);
654 for(i = 0 ; i < nb ; i++) {
655 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
656 }
657 */
658
659 name_tables->irq_names = g_new(GQuark, 256);
660 for(i = 0 ; i < 256 ; i++) {
661 g_string_printf(fe_name, "irq %d", i);
662 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
663 }
664
665 g_string_free(fe_name, TRUE);
666 }
667
668
669 static void
670 get_name_tables(LttvTraceState *tcs)
671 {
672 LttvNameTables *name_tables;
673
674 LttvAttributeValue v;
675
676 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
677 LTTV_POINTER, &v);
678 g_assert(*(v.v_pointer) != NULL);
679 name_tables = (LttvNameTables *)*(v.v_pointer);
680 tcs->eventtype_names = name_tables->eventtype_names;
681 tcs->syscall_names = name_tables->syscall_names;
682 tcs->trap_names = name_tables->trap_names;
683 tcs->irq_names = name_tables->irq_names;
684 }
685
686
687 static void
688 free_name_tables(LttvTraceState *tcs)
689 {
690 LttvNameTables *name_tables;
691
692 LttvAttributeValue v;
693
694 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
695 LTTV_POINTER, &v);
696 name_tables = (LttvNameTables *)*(v.v_pointer);
697 *(v.v_pointer) = NULL;
698
699 g_free(name_tables->eventtype_names);
700 g_free(name_tables->syscall_names);
701 g_free(name_tables->trap_names);
702 g_free(name_tables->irq_names);
703 g_free(name_tables);
704 }
705
706
707 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
708 guint state_id)
709 {
710 LttvExecutionState *es;
711
712 LttvProcessState *process = tfs->process;
713
714 guint depth = process->execution_stack->len;
715
716 g_array_set_size(process->execution_stack, depth + 1);
717 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
718 es->t = t;
719 es->n = state_id;
720 es->entry = es->change = tfs->parent.timestamp;
721 es->s = process->state->s;
722 process->state = es;
723 }
724
725
726 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
727 {
728 LttvProcessState *process = tfs->process;
729
730 guint depth = process->execution_stack->len;
731
732 if(process->state->t != t){
733 g_info("Different execution mode type (%d.%09d): ignore it\n",
734 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
735 g_info("process state has %s when pop_int is %s\n",
736 g_quark_to_string(process->state->t),
737 g_quark_to_string(t));
738 g_info("{ %u, %u, %s, %s }\n",
739 process->pid,
740 process->ppid,
741 g_quark_to_string(process->name),
742 g_quark_to_string(process->state->s));
743 return;
744 }
745
746 if(depth == 1){
747 g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
748 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
749 return;
750 }
751
752 g_array_set_size(process->execution_stack, depth - 1);
753 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
754 depth - 2);
755 process->state->change = tfs->parent.timestamp;
756 }
757
758
759 LttvProcessState *
760 lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
761 guint pid)
762 {
763 LttvProcessState *process = g_new(LttvProcessState, 1);
764
765 LttvExecutionState *es;
766
767 LttvTraceContext *tc;
768
769 LttvTraceState *tcs;
770
771 char buffer[128];
772
773 tc = tfs->parent.t_context;
774 tcs = (LttvTraceState *)tc;
775
776 process->pid = pid;
777 process->last_cpu = tfs->cpu_name;
778 g_warning("Process %u, core %p", process->pid, process);
779 g_hash_table_insert(tcs->processes, process, process);
780
781 if(parent) {
782 process->ppid = parent->pid;
783 process->name = parent->name;
784 process->creation_time = tfs->parent.timestamp;
785 }
786
787 /* No parent. This process exists but we are missing all information about
788 its creation. The birth time is set to zero but we remember the time of
789 insertion */
790
791 else {
792 process->ppid = 0;
793 process->name = LTTV_STATE_UNNAMED;
794 process->creation_time = ltt_time_zero;
795 }
796
797 process->insertion_time = tfs->parent.timestamp;
798 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
799 process->creation_time.tv_nsec);
800 process->pid_time = g_quark_from_string(buffer);
801 process->last_cpu = tfs->cpu_name;
802 process->execution_stack = g_array_new(FALSE, FALSE,
803 sizeof(LttvExecutionState));
804 g_array_set_size(process->execution_stack, 1);
805 es = process->state = &g_array_index(process->execution_stack,
806 LttvExecutionState, 0);
807 es->t = LTTV_STATE_USER_MODE;
808 es->n = LTTV_STATE_SUBMODE_NONE;
809 es->entry = tfs->parent.timestamp;
810 es->change = tfs->parent.timestamp;
811 es->s = LTTV_STATE_WAIT_FORK;
812
813 return process;
814 }
815
816
817 LttvProcessState *
818 lttv_state_find_process_from_trace(LttvTraceState *ts, GQuark cpu, guint pid)
819 {
820 LttvProcessState key;
821 LttvProcessState *process;
822
823 key.pid = pid;
824 key.last_cpu = cpu;
825 process = g_hash_table_lookup(ts->processes, &key);
826 return process;
827 }
828
829
830 LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
831 guint pid)
832 {
833 LttvTraceState *ts =(LttvTraceState *)tfs->parent.t_context;
834 return lttv_state_find_process_from_trace(ts, tfs->cpu_name, pid);
835 }
836
837
838 LttvProcessState *
839 lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
840 {
841 LttvProcessState *process = lttv_state_find_process(tfs, pid);
842
843 if(process == NULL) process = lttv_state_create_process(tfs, NULL, pid);
844 return process;
845 }
846
847
848 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
849 {
850 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
851 LttvProcessState key;
852
853 key.pid = process->pid;
854 key.last_cpu = process->last_cpu;
855 g_hash_table_remove(ts->processes, &key);
856 g_array_free(process->execution_stack, TRUE);
857 g_free(process);
858 }
859
860
861 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
862 {
863 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
864 g_free(value);
865 }
866
867
868 static void lttv_state_free_process_table(GHashTable *processes)
869 {
870 g_hash_table_foreach(processes, free_process_state, NULL);
871 g_hash_table_destroy(processes);
872 }
873
874
875 static gboolean syscall_entry(void *hook_data, void *call_data)
876 {
877 LttField *f = ((LttvTraceHook *)hook_data)->f1;
878
879 LttvTracefileState *s = (LttvTracefileState *)call_data;
880
881 LttvExecutionSubmode submode;
882
883 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
884 ltt_event_get_unsigned(s->parent.e, f)];
885 push_state(s, LTTV_STATE_SYSCALL, submode);
886 return FALSE;
887 }
888
889
890 static gboolean syscall_exit(void *hook_data, void *call_data)
891 {
892 LttvTracefileState *s = (LttvTracefileState *)call_data;
893
894 pop_state(s, LTTV_STATE_SYSCALL);
895 return FALSE;
896 }
897
898
899 static gboolean trap_entry(void *hook_data, void *call_data)
900 {
901 LttField *f = ((LttvTraceHook *)hook_data)->f1;
902
903 LttvTracefileState *s = (LttvTracefileState *)call_data;
904
905 LttvExecutionSubmode submode;
906
907 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
908 ltt_event_get_unsigned(s->parent.e, f)];
909 push_state(s, LTTV_STATE_TRAP, submode);
910 return FALSE;
911 }
912
913
914 static gboolean trap_exit(void *hook_data, void *call_data)
915 {
916 LttvTracefileState *s = (LttvTracefileState *)call_data;
917
918 pop_state(s, LTTV_STATE_TRAP);
919 return FALSE;
920 }
921
922
923 static gboolean irq_entry(void *hook_data, void *call_data)
924 {
925 LttField *f = ((LttvTraceHook *)hook_data)->f1;
926
927 LttvTracefileState *s = (LttvTracefileState *)call_data;
928
929 LttvExecutionSubmode submode;
930
931 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
932 ltt_event_get_unsigned(s->parent.e, f)];
933
934 /* Do something with the info about being in user or system mode when int? */
935 push_state(s, LTTV_STATE_IRQ, submode);
936 return FALSE;
937 }
938
939
940 static gboolean irq_exit(void *hook_data, void *call_data)
941 {
942 LttvTracefileState *s = (LttvTracefileState *)call_data;
943
944 pop_state(s, LTTV_STATE_IRQ);
945 return FALSE;
946 }
947
948
949 static gboolean schedchange(void *hook_data, void *call_data)
950 {
951 LttvTraceHook *h = (LttvTraceHook *)hook_data;
952
953 LttvTracefileState *s = (LttvTracefileState *)call_data;
954
955 guint pid_in, pid_out, state_out;
956
957 pid_in = ltt_event_get_unsigned(s->parent.e, h->f1);
958 pid_out = ltt_event_get_unsigned(s->parent.e, h->f2);
959 state_out = ltt_event_get_unsigned(s->parent.e, h->f3);
960
961 if(s->process != NULL) {
962
963 /* We could not know but it was not the idle process executing.
964 This should only happen at the beginning, before the first schedule
965 event, and when the initial information (current process for each CPU)
966 is missing. It is not obvious how we could, after the fact, compensate
967 the wrongly attributed statistics. */
968
969 if(s->process->pid != pid_out) {
970 g_assert(s->process->pid == 0);
971 }
972
973 if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
974 else if(s->process->state->s == LTTV_STATE_EXIT)
975 exit_process(s, s->process);
976 else s->process->state->s = LTTV_STATE_WAIT;
977
978 s->process->state->change = s->parent.timestamp;
979 }
980 s->process = lttv_state_find_process_or_create(s, pid_in);
981 s->process->state->s = LTTV_STATE_RUN;
982 s->process->last_cpu = s->cpu_name;
983 s->process->state->change = s->parent.timestamp;
984 return FALSE;
985 }
986
987
988 static gboolean process_fork(void *hook_data, void *call_data)
989 {
990 LttField *f = ((LttvTraceHook *)hook_data)->f1;
991
992 LttvTracefileState *s = (LttvTracefileState *)call_data;
993
994 guint child_pid;
995
996 child_pid = ltt_event_get_unsigned(s->parent.e, f);
997 lttv_state_create_process(s, s->process, child_pid);
998 return FALSE;
999 }
1000
1001
1002 static gboolean process_exit(void *hook_data, void *call_data)
1003 {
1004 LttvTracefileState *s = (LttvTracefileState *)call_data;
1005
1006 if(s->process != NULL) {
1007 s->process->state->s = LTTV_STATE_EXIT;
1008 }
1009 return FALSE;
1010 }
1011
1012
1013 void lttv_state_add_event_hooks(LttvTracesetState *self)
1014 {
1015 LttvTraceset *traceset = self->parent.ts;
1016
1017 guint i, j, k, nb_trace, nb_tracefile;
1018
1019 LttvTraceState *ts;
1020
1021 LttvTracefileState *tfs;
1022
1023 GArray *hooks;
1024
1025 LttvTraceHook hook;
1026
1027 LttvAttributeValue val;
1028
1029 nb_trace = lttv_traceset_number(traceset);
1030 for(i = 0 ; i < nb_trace ; i++) {
1031 ts = (LttvTraceState *)self->parent.traces[i];
1032
1033 /* Find the eventtype id for the following events and register the
1034 associated by id hooks. */
1035
1036 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1037 g_array_set_size(hooks, 9);
1038
1039 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1040 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
1041
1042 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1043 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
1044
1045 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1046 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
1047
1048 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1049 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
1050
1051 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1052 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
1053
1054 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1055 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
1056
1057 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1058 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
1059
1060 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1061 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
1062
1063 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1064 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
1065
1066 /* Add these hooks to each event_by_id hooks list */
1067
1068 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1069 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1070
1071 for(j = 0 ; j < nb_tracefile ; j++) {
1072 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1073
1074 for(k = 0 ; k < hooks->len ; k++) {
1075 hook = g_array_index(hooks, LttvTraceHook, k);
1076 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1077 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
1078 }
1079 }
1080 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1081 *(val.v_pointer) = hooks;
1082 }
1083 }
1084
1085
1086 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1087 {
1088 LttvTraceset *traceset = self->parent.ts;
1089
1090 guint i, j, k, nb_trace, nb_tracefile;
1091
1092 LttvTraceState *ts;
1093
1094 LttvTracefileState *tfs;
1095
1096 GArray *hooks;
1097
1098 LttvTraceHook hook;
1099
1100 LttvAttributeValue val;
1101
1102 nb_trace = lttv_traceset_number(traceset);
1103 for(i = 0 ; i < nb_trace ; i++) {
1104 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1105 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1106 hooks = *(val.v_pointer);
1107
1108 /* Remove these hooks from each event_by_id hooks list */
1109
1110 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1111 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1112
1113 for(j = 0 ; j < nb_tracefile ; j++) {
1114 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1115
1116 for(k = 0 ; k < hooks->len ; k++) {
1117 hook = g_array_index(hooks, LttvTraceHook, k);
1118 lttv_hooks_remove_data(
1119 lttv_hooks_by_id_find(tfs->parent.event_by_id,
1120 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1121 }
1122 }
1123 g_array_free(hooks, TRUE);
1124 }
1125 }
1126
1127
1128 static gboolean block_start(void *hook_data, void *call_data)
1129 {
1130 LttvTracefileState *self = (LttvTracefileState *)call_data;
1131
1132 LttvTracefileState *tfcs;
1133
1134 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1135
1136 LttEventPosition *ep;
1137
1138 guint i, nb_block, nb_event, nb_tracefile;
1139
1140 LttTracefile *tf;
1141
1142 LttvAttribute *saved_states_tree, *saved_state_tree;
1143
1144 LttvAttributeValue value;
1145
1146 ep = ltt_event_position_new();
1147 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1148 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1149
1150 /* Count the number of events added since the last block end in any
1151 tracefile. */
1152
1153 for(i = 0 ; i < nb_tracefile ; i++) {
1154 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1155 ltt_event_position(tfcs->parent.e, ep);
1156 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1157 tcs->nb_event += nb_event - tfcs->saved_position;
1158 tfcs->saved_position = nb_event;
1159 }
1160 g_free(ep);
1161
1162 if(tcs->nb_event >= tcs->save_interval) {
1163 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1164 LTTV_STATE_SAVED_STATES);
1165 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1166 value = lttv_attribute_add(saved_states_tree,
1167 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1168 *(value.v_gobject) = (GObject *)saved_state_tree;
1169 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1170 *(value.v_time) = self->parent.timestamp;
1171 lttv_state_save(tcs, saved_state_tree);
1172 tcs->nb_event = 0;
1173 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1174 self->parent.timestamp.tv_nsec);
1175 }
1176 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1177 return FALSE;
1178 }
1179
1180
1181 static gboolean block_end(void *hook_data, void *call_data)
1182 {
1183 LttvTracefileState *self = (LttvTracefileState *)call_data;
1184
1185 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1186
1187 LttTracefile *tf;
1188
1189 LttEventPosition *ep;
1190
1191 guint nb_block, nb_event;
1192
1193 ep = ltt_event_position_new();
1194 ltt_event_position(self->parent.e, ep);
1195 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1196 tcs->nb_event += nb_event - self->saved_position + 1;
1197 self->saved_position = 0;
1198 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1199 g_free(ep);
1200 }
1201
1202
1203 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1204 {
1205 LttvTraceset *traceset = self->parent.ts;
1206
1207 guint i, j, k, nb_trace, nb_tracefile;
1208
1209 LttvTraceState *ts;
1210
1211 LttvTracefileState *tfs;
1212
1213 LttvTraceHook hook_start, hook_end;
1214
1215 nb_trace = lttv_traceset_number(traceset);
1216 for(i = 0 ; i < nb_trace ; i++) {
1217 ts = (LttvTraceState *)self->parent.traces[i];
1218 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1219 NULL, NULL, block_start, &hook_start);
1220 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1221 NULL, NULL, block_end, &hook_end);
1222
1223 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1224 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1225
1226 for(j = 0 ; j < nb_tracefile ; j++) {
1227 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1228 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1229 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1230 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1231 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1232 }
1233 }
1234 }
1235
1236
1237 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1238 {
1239 LttvTraceset *traceset = self->parent.ts;
1240
1241 guint i, j, k, nb_trace, nb_tracefile;
1242
1243 LttvTraceState *ts;
1244
1245 LttvTracefileState *tfs;
1246
1247 LttvTraceHook hook_start, hook_end;
1248
1249 nb_trace = lttv_traceset_number(traceset);
1250 for(i = 0 ; i < nb_trace ; i++) {
1251 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1252 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1253 NULL, NULL, block_start, &hook_start);
1254
1255 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1256 NULL, NULL, block_end, &hook_end);
1257
1258 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1259 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1260
1261 for(j = 0 ; j < nb_tracefile ; j++) {
1262 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1263 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1264 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1265 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1266 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1267 }
1268 }
1269 }
1270
1271
1272 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1273 {
1274 LttvTraceset *traceset = self->parent.ts;
1275
1276 guint i, j, nb_trace, nb_saved_state;
1277
1278 int min_pos, mid_pos, max_pos;
1279
1280 LttvTraceState *tcs;
1281
1282 LttvAttributeValue value;
1283
1284 LttvAttributeType type;
1285
1286 LttvAttributeName name;
1287
1288 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1289
1290 nb_trace = lttv_traceset_number(traceset);
1291 for(i = 0 ; i < nb_trace ; i++) {
1292 tcs = (LttvTraceState *)self->parent.traces[i];
1293
1294 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1295 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1296 LTTV_STATE_SAVED_STATES);
1297 min_pos = -1;
1298
1299 if(saved_states_tree) {
1300 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1301 mid_pos = max_pos / 2;
1302 while(min_pos < max_pos) {
1303 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1304 g_assert(type == LTTV_GOBJECT);
1305 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1306 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1307 &value);
1308 g_assert(type == LTTV_TIME);
1309 if(ltt_time_compare(*(value.v_time), t) < 0) {
1310 min_pos = mid_pos;
1311 closest_tree = saved_state_tree;
1312 }
1313 else max_pos = mid_pos - 1;
1314
1315 mid_pos = (min_pos + max_pos + 1) / 2;
1316 }
1317 }
1318
1319 /* restore the closest earlier saved state */
1320 if(min_pos != -1) {
1321 lttv_state_restore(tcs, closest_tree);
1322 }
1323
1324 /* There is no saved state, yet we want to have it. Restart at T0 */
1325 else {
1326 restore_init_state(tcs);
1327 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1328 }
1329 }
1330 /* We want to seek quickly without restoring/updating the state */
1331 else {
1332 restore_init_state(tcs);
1333 lttv_process_trace_seek_time(&(tcs->parent), t);
1334 }
1335 }
1336 }
1337
1338
1339 static void
1340 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1341 {
1342 }
1343
1344
1345 static void
1346 traceset_state_finalize (LttvTracesetState *self)
1347 {
1348 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1349 finalize(G_OBJECT(self));
1350 }
1351
1352
1353 static void
1354 traceset_state_class_init (LttvTracesetContextClass *klass)
1355 {
1356 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1357
1358 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1359 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1360 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1361 klass->new_traceset_context = new_traceset_context;
1362 klass->new_trace_context = new_trace_context;
1363 klass->new_tracefile_context = new_tracefile_context;
1364 }
1365
1366
1367 GType
1368 lttv_traceset_state_get_type(void)
1369 {
1370 static GType type = 0;
1371 if (type == 0) {
1372 static const GTypeInfo info = {
1373 sizeof (LttvTracesetStateClass),
1374 NULL, /* base_init */
1375 NULL, /* base_finalize */
1376 (GClassInitFunc) traceset_state_class_init, /* class_init */
1377 NULL, /* class_finalize */
1378 NULL, /* class_data */
1379 sizeof (LttvTracesetState),
1380 0, /* n_preallocs */
1381 (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
1382 };
1383
1384 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1385 &info, 0);
1386 }
1387 return type;
1388 }
1389
1390
1391 static void
1392 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1393 {
1394 }
1395
1396
1397 static void
1398 trace_state_finalize (LttvTraceState *self)
1399 {
1400 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1401 finalize(G_OBJECT(self));
1402 }
1403
1404
1405 static void
1406 trace_state_class_init (LttvTraceStateClass *klass)
1407 {
1408 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1409
1410 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1411 klass->state_save = state_save;
1412 klass->state_restore = state_restore;
1413 klass->state_saved_free = state_saved_free;
1414 }
1415
1416
1417 GType
1418 lttv_trace_state_get_type(void)
1419 {
1420 static GType type = 0;
1421 if (type == 0) {
1422 static const GTypeInfo info = {
1423 sizeof (LttvTraceStateClass),
1424 NULL, /* base_init */
1425 NULL, /* base_finalize */
1426 (GClassInitFunc) trace_state_class_init, /* class_init */
1427 NULL, /* class_finalize */
1428 NULL, /* class_data */
1429 sizeof (LttvTraceState),
1430 0, /* n_preallocs */
1431 (GInstanceInitFunc) trace_state_instance_init /* instance_init */
1432 };
1433
1434 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1435 "LttvTraceStateType", &info, 0);
1436 }
1437 return type;
1438 }
1439
1440
1441 static void
1442 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1443 {
1444 }
1445
1446
1447 static void
1448 tracefile_state_finalize (LttvTracefileState *self)
1449 {
1450 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1451 finalize(G_OBJECT(self));
1452 }
1453
1454
1455 static void
1456 tracefile_state_class_init (LttvTracefileStateClass *klass)
1457 {
1458 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1459
1460 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1461 }
1462
1463
1464 GType
1465 lttv_tracefile_state_get_type(void)
1466 {
1467 static GType type = 0;
1468 if (type == 0) {
1469 static const GTypeInfo info = {
1470 sizeof (LttvTracefileStateClass),
1471 NULL, /* base_init */
1472 NULL, /* base_finalize */
1473 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1474 NULL, /* class_finalize */
1475 NULL, /* class_data */
1476 sizeof (LttvTracefileState),
1477 0, /* n_preallocs */
1478 (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
1479 };
1480
1481 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1482 "LttvTracefileStateType", &info, 0);
1483 }
1484 return type;
1485 }
1486
1487
1488 static void module_init()
1489 {
1490 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1491 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1492 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1493 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1494 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1495 LTTV_STATE_TRAP = g_quark_from_string("trap");
1496 LTTV_STATE_IRQ = g_quark_from_string("irq");
1497 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1498 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1499 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1500 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1501 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1502 LTTV_STATE_RUN = g_quark_from_string("running");
1503 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1504 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1505 LTTV_STATE_PROCESS = g_quark_from_string("process");
1506 LTTV_STATE_EVENT = g_quark_from_string("event");
1507 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1508 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1509 LTTV_STATE_TIME = g_quark_from_string("time");
1510 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1511 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1512 LTTV_STATE_TRACE_STATE_USE_COUNT =
1513 g_quark_from_string("trace_state_use_count");
1514 }
1515
1516 static void module_destroy()
1517 {
1518 }
1519
1520
1521 LTTV_MODULE("state", "State computation", \
1522 "Update the system state, possibly saving it at intervals", \
1523 module_init, module_destroy)
1524
1525
1526
This page took 0.067188 seconds and 3 git commands to generate.