uninitialized variables checked, plus O2 optimisations checked : strict aliasing...
[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 ((const LttvProcessState *)key)->pid;
100 }
101
102
103 gboolean process_equal(gconstpointer a, gconstpointer b)
104 {
105 const LttvProcessState *process_a, *process_b;
106
107 process_a = (const LttvProcessState *)a;
108 process_b = (const 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 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
125 self->processes = g_hash_table_new(process_hash, process_equal);
126 self->nb_event = 0;
127
128 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
129 ltt_trace_per_cpu_tracefile_number(self->parent.t);
130
131 for(i = 0 ; i < nb_tracefile ; i++) {
132 tfcs = LTTV_TRACEFILE_STATE(self->parent.tracefiles[i]);
133 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
134 tfcs->saved_position = 0;
135 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
136 tfcs->process->state->s = LTTV_STATE_RUN;
137 tfcs->process->last_cpu = tfcs->cpu_name;
138 }
139 }
140
141 static LttTime time_zero = {0,0};
142
143 static void
144 init(LttvTracesetState *self, LttvTraceset *ts)
145 {
146 guint i, j, nb_trace, nb_tracefile;
147
148 LttvTraceContext *tc;
149
150 LttvTraceState *tcs;
151
152 LttvTracefileState *tfcs;
153
154 LttvAttributeValue v;
155
156 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
157 init((LttvTracesetContext *)self, ts);
158
159 nb_trace = lttv_traceset_number(ts);
160 for(i = 0 ; i < nb_trace ; i++) {
161 tc = self->parent.traces[i];
162 tcs = (LttvTraceState *)tc;
163 tcs->save_interval = 50000;
164 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
165 LTTV_UINT, &v);
166 (*v.v_uint)++;
167
168 if(*(v.v_uint) == 1) {
169 create_name_tables(tcs);
170 create_max_time(tcs);
171 }
172 get_name_tables(tcs);
173 get_max_time(tcs);
174
175 nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
176 ltt_trace_per_cpu_tracefile_number(tc->t);
177
178 for(j = 0 ; j < nb_tracefile ; j++) {
179 tfcs = LTTV_TRACEFILE_STATE(tc->tracefiles[j]);
180 tfcs->cpu_name= g_quark_from_string(ltt_tracefile_name(tfcs->parent.tf));
181 }
182 tcs->processes = NULL;
183 restore_init_state(tcs);
184 }
185 }
186
187
188 static void
189 fini(LttvTracesetState *self)
190 {
191 guint i, nb_trace;
192
193 LttvTraceState *tcs;
194
195 LttvTracefileState *tfcs;
196
197 LttvAttributeValue v;
198
199 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
200 for(i = 0 ; i < nb_trace ; i++) {
201 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
202 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
203 LTTV_UINT, &v);
204
205 g_assert(*(v.v_uint) != 0);
206 (*v.v_uint)--;
207
208 if(*(v.v_uint) == 0) {
209 free_name_tables(tcs);
210 free_max_time(tcs);
211 free_saved_state(tcs);
212 }
213 lttv_state_free_process_table(tcs->processes);
214 tcs->processes = NULL;
215 }
216 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
217 fini((LttvTracesetContext *)self);
218 }
219
220
221 static LttvTracesetContext *
222 new_traceset_context(LttvTracesetContext *self)
223 {
224 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
225 }
226
227
228 static LttvTraceContext *
229 new_trace_context(LttvTracesetContext *self)
230 {
231 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
232 }
233
234
235 static LttvTracefileContext *
236 new_tracefile_context(LttvTracesetContext *self)
237 {
238 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
239 }
240
241
242 /* Write the process state of the trace */
243
244 static void write_process_state(gpointer key, gpointer value,
245 gpointer user_data)
246 {
247 LttvProcessState *process;
248
249 LttvExecutionState *es;
250
251 FILE *fp = (FILE *)user_data;
252
253 guint i;
254
255 process = (LttvProcessState *)value;
256 fprintf(fp,
257 " <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
258 process, process->pid, process->ppid, process->creation_time.tv_sec,
259 process->creation_time.tv_nsec, g_quark_to_string(process->name),
260 g_quark_to_string(process->last_cpu));
261
262 for(i = 0 ; i < process->execution_stack->len; i++) {
263 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
264 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
265 g_quark_to_string(es->t), g_quark_to_string(es->n),
266 es->entry.tv_sec, es->entry.tv_nsec);
267 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
268 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
269 }
270 fprintf(fp, " </PROCESS>\n");
271 }
272
273
274 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
275 {
276 guint i, nb_tracefile, nb_block, nb_event;
277
278 LttvTracefileState *tfcs;
279
280 LttTracefile *tf;
281
282 LttEventPosition *ep;
283
284 ep = ltt_event_position_new();
285
286 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
287
288 g_hash_table_foreach(self->processes, write_process_state, fp);
289
290 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
291 ltt_trace_per_cpu_tracefile_number(self->parent.t);
292
293 for(i = 0 ; i < nb_tracefile ; i++) {
294 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
295 fprintf(fp, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
296 tfcs->process->pid, tfcs->parent.timestamp.tv_sec,
297 tfcs->parent.timestamp.tv_nsec);
298 if(tfcs->parent.e == NULL) fprintf(fp,"/>\n");
299 else {
300 ltt_event_position(tfcs->parent.e, ep);
301 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
302 fprintf(fp, " BLOCK=%u EVENT=%u/>\n", nb_block, nb_event);
303 }
304 }
305 g_free(ep);
306 fprintf(fp,"</PROCESS_STATE>");
307 }
308
309
310 /* Copy each process from an existing hash table to a new one */
311
312 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
313 {
314 LttvProcessState *process, *new_process;
315
316 GHashTable *new_processes = (GHashTable *)user_data;
317
318 guint i;
319
320 process = (LttvProcessState *)value;
321 new_process = g_new(LttvProcessState, 1);
322 *new_process = *process;
323 new_process->execution_stack = g_array_new(FALSE, FALSE,
324 sizeof(LttvExecutionState));
325 g_array_set_size(new_process->execution_stack,process->execution_stack->len);
326 for(i = 0 ; i < process->execution_stack->len; i++) {
327 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
328 g_array_index(process->execution_stack, LttvExecutionState, i);
329 }
330 new_process->state = &g_array_index(new_process->execution_stack,
331 LttvExecutionState, new_process->execution_stack->len - 1);
332 g_hash_table_insert(new_processes, new_process, new_process);
333 }
334
335
336 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
337 {
338 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
339
340 g_hash_table_foreach(processes, copy_process_state, new_processes);
341 return new_processes;
342 }
343
344
345 /* The saved state for each trace contains a member "processes", which
346 stores a copy of the process table, and a member "tracefiles" with
347 one entry per tracefile. Each tracefile has a "process" member pointing
348 to the current process and a "position" member storing the tracefile
349 position (needed to seek to the current "next" event. */
350
351 static void state_save(LttvTraceState *self, LttvAttribute *container)
352 {
353 guint i, nb_tracefile;
354
355 LttvTracefileState *tfcs;
356
357 LttvAttribute *tracefiles_tree, *tracefile_tree;
358
359 LttvAttributeType type;
360
361 LttvAttributeValue value;
362
363 LttvAttributeName name;
364
365 LttEventPosition *ep;
366
367 tracefiles_tree = lttv_attribute_find_subdir(container,
368 LTTV_STATE_TRACEFILES);
369
370 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
371 LTTV_POINTER);
372 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
373
374 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
375 ltt_trace_per_cpu_tracefile_number(self->parent.t);
376
377 for(i = 0 ; i < nb_tracefile ; i++) {
378 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
379 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
380 value = lttv_attribute_add(tracefiles_tree, i,
381 LTTV_GOBJECT);
382 *(value.v_gobject) = (GObject *)tracefile_tree;
383 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
384 LTTV_UINT);
385 *(value.v_uint) = tfcs->process->pid;
386 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
387 LTTV_POINTER);
388 if(tfcs->parent.e == NULL) *(value.v_pointer) = NULL;
389 else {
390 ep = ltt_event_position_new();
391 ltt_event_position(tfcs->parent.e, ep);
392 *(value.v_pointer) = ep;
393
394 guint nb_block, nb_event;
395 LttTracefile *tf;
396 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
397 g_debug("Block %u event %u time %lu.%lu", nb_block, nb_event,
398 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
399 }
400 }
401 }
402
403
404 static void state_restore(LttvTraceState *self, LttvAttribute *container)
405 {
406 guint i, nb_tracefile, pid;
407
408 LttvTracefileState *tfcs;
409
410 LttvAttribute *tracefiles_tree, *tracefile_tree;
411
412 LttvAttributeType type;
413
414 LttvAttributeValue value;
415
416 LttvAttributeName name;
417
418 LttEventPosition *ep;
419
420 tracefiles_tree = lttv_attribute_find_subdir(container,
421 LTTV_STATE_TRACEFILES);
422
423 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
424 &value);
425 g_assert(type == LTTV_POINTER);
426 lttv_state_free_process_table(self->processes);
427 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
428
429 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
430 ltt_trace_per_cpu_tracefile_number(self->parent.t);
431
432 for(i = 0 ; i < nb_tracefile ; i++) {
433 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
434 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
435 g_assert(type == LTTV_GOBJECT);
436 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
437
438 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
439 &value);
440 g_assert(type == LTTV_UINT);
441 pid = *(value.v_uint);
442 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
443
444 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
445 &value);
446 g_assert(type == LTTV_POINTER);
447 if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL;
448 else {
449 ep = *(value.v_pointer);
450 g_assert(tfcs->parent.t_context != NULL);
451 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), 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 g_object_ref(G_OBJECT(tracefiles_tree));
476 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
477
478 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
479 &value);
480 g_assert(type == LTTV_POINTER);
481 lttv_state_free_process_table(*(value.v_pointer));
482 *(value.v_pointer) = NULL;
483 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
484
485 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
486 ltt_trace_per_cpu_tracefile_number(self->parent.t);
487
488 for(i = 0 ; i < nb_tracefile ; i++) {
489 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
490 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
491 g_assert(type == LTTV_GOBJECT);
492 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
493
494 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
495 &value);
496 g_assert(type == LTTV_POINTER);
497 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
498 }
499 g_object_unref(G_OBJECT(tracefiles_tree));
500 }
501
502
503 static void free_saved_state(LttvTraceState *self)
504 {
505 guint i, nb;
506
507 LttvAttributeType type;
508
509 LttvAttributeValue value;
510
511 LttvAttributeName name;
512
513 LttvAttribute *saved_states;
514
515 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
516 LTTV_STATE_SAVED_STATES);
517
518 nb = lttv_attribute_get_number(saved_states);
519 for(i = 0 ; i < nb ; i++) {
520 type = lttv_attribute_get(saved_states, i, &name, &value);
521 g_assert(type == LTTV_GOBJECT);
522 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
523 }
524
525 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_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 (%lu.%09lu): 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 (%lu.%09lu): 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 g_assert(tfs->parent.timestamp.tv_sec != 0);
811 es->change = tfs->parent.timestamp;
812 es->s = LTTV_STATE_WAIT_FORK;
813
814 return process;
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(LttvTraceHook *trace_hook, LttvTracefileState *s)
989 {
990 LttField *f;
991 guint child_pid;
992
993 /* Child PID */
994 f = trace_hook->f2;
995 child_pid = ltt_event_get_unsigned(s->parent.e, f);
996
997 lttv_state_create_process(s, s->process, child_pid);
998
999 return FALSE;
1000 #if 0
1001 LttField *f = ((LttvTraceHook *)hook_data)->f1;
1002
1003 LttvTracefileState *s = (LttvTracefileState *)call_data;
1004
1005 guint child_pid;
1006
1007 child_pid = ltt_event_get_unsigned(s->parent.e, f);
1008 lttv_state_create_process(s, s->process, child_pid);
1009 return FALSE;
1010 #endif //0
1011 }
1012
1013
1014 static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
1015 {
1016 if(s->process != NULL) {
1017 s->process->state->s = LTTV_STATE_EXIT;
1018 }
1019 return FALSE;
1020
1021 #if 0
1022 LttvTracefileState *s = (LttvTracefileState *)call_data;
1023
1024 if(s->process != NULL) {
1025 s->process->state->s = LTTV_STATE_EXIT;
1026 }
1027 return FALSE;
1028 #endif //0
1029 }
1030
1031 gboolean process(void *hook_data, void *call_data)
1032 {
1033 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1034 LttField *f = trace_hook->f1;
1035
1036 LttvTracefileState *s = (LttvTracefileState *)call_data;
1037
1038 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1039
1040 /* CHECK : do not hardcode the sub_id values here ? */
1041 if(sub_id == 2) {
1042 return process_fork(trace_hook, s);
1043 } else if(sub_id == 3) {
1044 return process_exit(trace_hook, s);
1045 }
1046 return 0;
1047 }
1048
1049 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1050 {
1051 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1052
1053 lttv_state_add_event_hooks(tss);
1054
1055 return 0;
1056 }
1057
1058 void lttv_state_add_event_hooks(LttvTracesetState *self)
1059 {
1060 LttvTraceset *traceset = self->parent.ts;
1061
1062 guint i, j, k, nb_trace, nb_tracefile;
1063
1064 LttvTraceState *ts;
1065
1066 LttvTracefileState *tfs;
1067
1068 GArray *hooks;
1069
1070 LttvTraceHook hook;
1071
1072 LttvAttributeValue val;
1073
1074 nb_trace = lttv_traceset_number(traceset);
1075 for(i = 0 ; i < nb_trace ; i++) {
1076 ts = (LttvTraceState *)self->parent.traces[i];
1077
1078 /* Find the eventtype id for the following events and register the
1079 associated by id hooks. */
1080
1081 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1082 g_array_set_size(hooks, 8);
1083
1084 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1085 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
1086
1087 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1088 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
1089
1090 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1091 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
1092
1093 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1094 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
1095
1096 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1097 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
1098
1099 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1100 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
1101
1102 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1103 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
1104
1105 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1106 "event_data1", "event_data2", process,
1107 &g_array_index(hooks, LttvTraceHook, 7));
1108
1109 #if 0
1110 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1111 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
1112
1113 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1114 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
1115 #endif //0
1116 /* Add these hooks to each event_by_id hooks list */
1117
1118 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1119 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1120
1121 for(j = 0 ; j < nb_tracefile ; j++) {
1122 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1123
1124 for(k = 0 ; k < hooks->len ; k++) {
1125 hook = g_array_index(hooks, LttvTraceHook, k);
1126 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1127 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
1128 }
1129 }
1130 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1131 *(val.v_pointer) = hooks;
1132 }
1133 }
1134
1135 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1136 {
1137 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1138
1139 lttv_state_remove_event_hooks(tss);
1140
1141 return 0;
1142 }
1143
1144 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1145 {
1146 LttvTraceset *traceset = self->parent.ts;
1147
1148 guint i, j, k, nb_trace, nb_tracefile;
1149
1150 LttvTraceState *ts;
1151
1152 LttvTracefileState *tfs;
1153
1154 GArray *hooks;
1155
1156 LttvTraceHook hook;
1157
1158 LttvAttributeValue val;
1159
1160 nb_trace = lttv_traceset_number(traceset);
1161 for(i = 0 ; i < nb_trace ; i++) {
1162 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1163 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1164 hooks = *(val.v_pointer);
1165
1166 /* Remove these hooks from each event_by_id hooks list */
1167
1168 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1169 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1170
1171 for(j = 0 ; j < nb_tracefile ; j++) {
1172 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1173
1174 for(k = 0 ; k < hooks->len ; k++) {
1175 hook = g_array_index(hooks, LttvTraceHook, k);
1176 lttv_hooks_remove_data(
1177 lttv_hooks_by_id_find(tfs->parent.event_by_id,
1178 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1179 }
1180 }
1181 g_array_free(hooks, TRUE);
1182 }
1183 }
1184
1185
1186 static gboolean block_start(void *hook_data, void *call_data)
1187 {
1188 LttvTracefileState *self = (LttvTracefileState *)call_data;
1189
1190 LttvTracefileState *tfcs;
1191
1192 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1193
1194 LttEventPosition *ep;
1195
1196 guint i, nb_block, nb_event, nb_tracefile;
1197
1198 LttTracefile *tf;
1199
1200 LttvAttribute *saved_states_tree, *saved_state_tree;
1201
1202 LttvAttributeValue value;
1203
1204 ep = ltt_event_position_new();
1205 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1206 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1207
1208 /* Count the number of events added since the last block end in any
1209 tracefile. */
1210
1211 for(i = 0 ; i < nb_tracefile ; i++) {
1212 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1213 ltt_event_position(tfcs->parent.e, ep);
1214 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1215 tcs->nb_event += nb_event - tfcs->saved_position;
1216 tfcs->saved_position = nb_event;
1217 }
1218 g_free(ep);
1219
1220 if(tcs->nb_event >= tcs->save_interval) {
1221 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1222 LTTV_STATE_SAVED_STATES);
1223 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1224 value = lttv_attribute_add(saved_states_tree,
1225 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1226 *(value.v_gobject) = (GObject *)saved_state_tree;
1227 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1228 *(value.v_time) = self->parent.timestamp;
1229 lttv_state_save(tcs, saved_state_tree);
1230 tcs->nb_event = 0;
1231 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1232 self->parent.timestamp.tv_nsec);
1233 }
1234 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1235 return FALSE;
1236 }
1237
1238
1239 static gboolean block_end(void *hook_data, void *call_data)
1240 {
1241 LttvTracefileState *self = (LttvTracefileState *)call_data;
1242
1243 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1244
1245 LttTracefile *tf;
1246
1247 LttEventPosition *ep;
1248
1249 guint nb_block, nb_event;
1250
1251 ep = ltt_event_position_new();
1252 ltt_event_position(self->parent.e, ep);
1253 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1254 tcs->nb_event += nb_event - self->saved_position + 1;
1255 self->saved_position = 0;
1256 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1257 g_free(ep);
1258
1259 return FALSE;
1260 }
1261
1262
1263 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1264 {
1265 LttvTraceset *traceset = self->parent.ts;
1266
1267 guint i, j, nb_trace, nb_tracefile;
1268
1269 LttvTraceState *ts;
1270
1271 LttvTracefileState *tfs;
1272
1273 LttvTraceHook hook_start, hook_end;
1274
1275 nb_trace = lttv_traceset_number(traceset);
1276 for(i = 0 ; i < nb_trace ; i++) {
1277 ts = (LttvTraceState *)self->parent.traces[i];
1278 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1279 NULL, NULL, block_start, &hook_start);
1280 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1281 NULL, NULL, block_end, &hook_end);
1282
1283 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1284 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1285
1286 for(j = 0 ; j < nb_tracefile ; j++) {
1287 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1288 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1289 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1290 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1291 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1292 }
1293 }
1294 }
1295
1296 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1297 {
1298 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1299
1300 lttv_state_save_add_event_hooks(tss);
1301
1302 return 0;
1303 }
1304
1305
1306 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1307 {
1308 LttvTraceset *traceset = self->parent.ts;
1309
1310 guint i, j, nb_trace, nb_tracefile;
1311
1312 LttvTraceState *ts;
1313
1314 LttvTracefileState *tfs;
1315
1316 LttvTraceHook hook_start, hook_end;
1317
1318 nb_trace = lttv_traceset_number(traceset);
1319 for(i = 0 ; i < nb_trace ; i++) {
1320 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1321 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1322 NULL, NULL, block_start, &hook_start);
1323
1324 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1325 NULL, NULL, block_end, &hook_end);
1326
1327 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1328 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1329
1330 for(j = 0 ; j < nb_tracefile ; j++) {
1331 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1332 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1333 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1334 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1335 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1336 }
1337 }
1338 }
1339
1340 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1341 {
1342 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1343
1344 lttv_state_save_remove_event_hooks(tss);
1345
1346 return 0;
1347 }
1348
1349 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1350 {
1351 LttvTraceset *traceset = self->parent.ts;
1352
1353 guint i, nb_trace;
1354
1355 int min_pos, mid_pos, max_pos;
1356
1357 LttvTraceState *tcs;
1358
1359 LttvAttributeValue value;
1360
1361 LttvAttributeType type;
1362
1363 LttvAttributeName name;
1364
1365 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1366
1367 nb_trace = lttv_traceset_number(traceset);
1368 for(i = 0 ; i < nb_trace ; i++) {
1369 tcs = (LttvTraceState *)self->parent.traces[i];
1370
1371 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1372 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1373 LTTV_STATE_SAVED_STATES);
1374 min_pos = -1;
1375
1376 if(saved_states_tree) {
1377 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1378 mid_pos = max_pos / 2;
1379 while(min_pos < max_pos) {
1380 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1381 g_assert(type == LTTV_GOBJECT);
1382 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1383 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1384 &value);
1385 g_assert(type == LTTV_TIME);
1386 if(ltt_time_compare(*(value.v_time), t) < 0) {
1387 min_pos = mid_pos;
1388 closest_tree = saved_state_tree;
1389 }
1390 else max_pos = mid_pos - 1;
1391
1392 mid_pos = (min_pos + max_pos + 1) / 2;
1393 }
1394 }
1395
1396 /* restore the closest earlier saved state */
1397 if(min_pos != -1) {
1398 lttv_state_restore(tcs, closest_tree);
1399 }
1400
1401 /* There is no saved state, yet we want to have it. Restart at T0 */
1402 else {
1403 restore_init_state(tcs);
1404 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1405 }
1406 }
1407 /* We want to seek quickly without restoring/updating the state */
1408 else {
1409 restore_init_state(tcs);
1410 lttv_process_trace_seek_time(&(tcs->parent), t);
1411 }
1412 }
1413 }
1414
1415
1416 static void
1417 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1418 {
1419 }
1420
1421
1422 static void
1423 traceset_state_finalize (LttvTracesetState *self)
1424 {
1425 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1426 finalize(G_OBJECT(self));
1427 }
1428
1429
1430 static void
1431 traceset_state_class_init (LttvTracesetContextClass *klass)
1432 {
1433 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1434
1435 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1436 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1437 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1438 klass->new_traceset_context = new_traceset_context;
1439 klass->new_trace_context = new_trace_context;
1440 klass->new_tracefile_context = new_tracefile_context;
1441 }
1442
1443
1444 GType
1445 lttv_traceset_state_get_type(void)
1446 {
1447 static GType type = 0;
1448 if (type == 0) {
1449 static const GTypeInfo info = {
1450 sizeof (LttvTracesetStateClass),
1451 NULL, /* base_init */
1452 NULL, /* base_finalize */
1453 (GClassInitFunc) traceset_state_class_init, /* class_init */
1454 NULL, /* class_finalize */
1455 NULL, /* class_data */
1456 sizeof (LttvTracesetState),
1457 0, /* n_preallocs */
1458 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1459 NULL /* value handling */
1460 };
1461
1462 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1463 &info, 0);
1464 }
1465 return type;
1466 }
1467
1468
1469 static void
1470 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1471 {
1472 }
1473
1474
1475 static void
1476 trace_state_finalize (LttvTraceState *self)
1477 {
1478 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1479 finalize(G_OBJECT(self));
1480 }
1481
1482
1483 static void
1484 trace_state_class_init (LttvTraceStateClass *klass)
1485 {
1486 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1487
1488 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1489 klass->state_save = state_save;
1490 klass->state_restore = state_restore;
1491 klass->state_saved_free = state_saved_free;
1492 }
1493
1494
1495 GType
1496 lttv_trace_state_get_type(void)
1497 {
1498 static GType type = 0;
1499 if (type == 0) {
1500 static const GTypeInfo info = {
1501 sizeof (LttvTraceStateClass),
1502 NULL, /* base_init */
1503 NULL, /* base_finalize */
1504 (GClassInitFunc) trace_state_class_init, /* class_init */
1505 NULL, /* class_finalize */
1506 NULL, /* class_data */
1507 sizeof (LttvTraceState),
1508 0, /* n_preallocs */
1509 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1510 NULL /* value handling */
1511 };
1512
1513 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1514 "LttvTraceStateType", &info, 0);
1515 }
1516 return type;
1517 }
1518
1519
1520 static void
1521 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1522 {
1523 }
1524
1525
1526 static void
1527 tracefile_state_finalize (LttvTracefileState *self)
1528 {
1529 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1530 finalize(G_OBJECT(self));
1531 }
1532
1533
1534 static void
1535 tracefile_state_class_init (LttvTracefileStateClass *klass)
1536 {
1537 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1538
1539 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1540 }
1541
1542
1543 GType
1544 lttv_tracefile_state_get_type(void)
1545 {
1546 static GType type = 0;
1547 if (type == 0) {
1548 static const GTypeInfo info = {
1549 sizeof (LttvTracefileStateClass),
1550 NULL, /* base_init */
1551 NULL, /* base_finalize */
1552 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1553 NULL, /* class_finalize */
1554 NULL, /* class_data */
1555 sizeof (LttvTracefileState),
1556 0, /* n_preallocs */
1557 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1558 NULL /* value handling */
1559 };
1560
1561 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1562 "LttvTracefileStateType", &info, 0);
1563 }
1564 return type;
1565 }
1566
1567
1568 static void module_init()
1569 {
1570 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1571 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1572 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1573 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1574 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1575 LTTV_STATE_TRAP = g_quark_from_string("trap");
1576 LTTV_STATE_IRQ = g_quark_from_string("irq");
1577 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1578 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1579 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1580 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1581 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1582 LTTV_STATE_RUN = g_quark_from_string("running");
1583 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1584 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1585 LTTV_STATE_PROCESS = g_quark_from_string("process");
1586 LTTV_STATE_EVENT = g_quark_from_string("event");
1587 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1588 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1589 LTTV_STATE_TIME = g_quark_from_string("time");
1590 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1591 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1592 LTTV_STATE_TRACE_STATE_USE_COUNT =
1593 g_quark_from_string("trace_state_use_count");
1594 }
1595
1596 static void module_destroy()
1597 {
1598 }
1599
1600
1601 LTTV_MODULE("state", "State computation", \
1602 "Update the system state, possibly saving it at intervals", \
1603 module_init, module_destroy)
1604
1605
1606
This page took 0.087938 seconds and 4 git commands to generate.