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