put back hook adder the way they were, new state hook adder and remover hook
[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 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1049 {
1050 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1051
1052 lttv_state_add_event_hooks(tss);
1053
1054 return 0;
1055 }
1056
1057 void lttv_state_add_event_hooks(LttvTracesetState *self)
1058 {
1059 LttvTraceset *traceset = self->parent.ts;
1060
1061 guint i, j, k, nb_trace, nb_tracefile;
1062
1063 LttvTraceState *ts;
1064
1065 LttvTracefileState *tfs;
1066
1067 GArray *hooks;
1068
1069 LttvTraceHook hook;
1070
1071 LttvAttributeValue val;
1072
1073 nb_trace = lttv_traceset_number(traceset);
1074 for(i = 0 ; i < nb_trace ; i++) {
1075 ts = (LttvTraceState *)self->parent.traces[i];
1076
1077 /* Find the eventtype id for the following events and register the
1078 associated by id hooks. */
1079
1080 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1081 g_array_set_size(hooks, 8);
1082
1083 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1084 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
1085
1086 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1087 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
1088
1089 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1090 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
1091
1092 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1093 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
1094
1095 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1096 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
1097
1098 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1099 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
1100
1101 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1102 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
1103
1104 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1105 "event_data1", "event_data2", process,
1106 &g_array_index(hooks, LttvTraceHook, 7));
1107
1108 #if 0
1109 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1110 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
1111
1112 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1113 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
1114 #endif //0
1115 /* Add these hooks to each event_by_id hooks list */
1116
1117 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1118 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1119
1120 for(j = 0 ; j < nb_tracefile ; j++) {
1121 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1122
1123 for(k = 0 ; k < hooks->len ; k++) {
1124 hook = g_array_index(hooks, LttvTraceHook, k);
1125 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1126 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
1127 }
1128 }
1129 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1130 *(val.v_pointer) = hooks;
1131 }
1132 }
1133
1134 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1135 {
1136 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1137
1138 lttv_state_remove_event_hooks(tss);
1139
1140 return 0;
1141 }
1142
1143 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1144 {
1145 LttvTraceset *traceset = self->parent.ts;
1146
1147 guint i, j, k, nb_trace, nb_tracefile;
1148
1149 LttvTraceState *ts;
1150
1151 LttvTracefileState *tfs;
1152
1153 GArray *hooks;
1154
1155 LttvTraceHook hook;
1156
1157 LttvAttributeValue val;
1158
1159 nb_trace = lttv_traceset_number(traceset);
1160 for(i = 0 ; i < nb_trace ; i++) {
1161 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1162 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1163 hooks = *(val.v_pointer);
1164
1165 /* Remove these hooks from each event_by_id hooks list */
1166
1167 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1168 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1169
1170 for(j = 0 ; j < nb_tracefile ; j++) {
1171 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1172
1173 for(k = 0 ; k < hooks->len ; k++) {
1174 hook = g_array_index(hooks, LttvTraceHook, k);
1175 lttv_hooks_remove_data(
1176 lttv_hooks_by_id_find(tfs->parent.event_by_id,
1177 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
1178 }
1179 }
1180 g_array_free(hooks, TRUE);
1181 }
1182 }
1183
1184
1185 static gboolean block_start(void *hook_data, void *call_data)
1186 {
1187 LttvTracefileState *self = (LttvTracefileState *)call_data;
1188
1189 LttvTracefileState *tfcs;
1190
1191 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1192
1193 LttEventPosition *ep;
1194
1195 guint i, nb_block, nb_event, nb_tracefile;
1196
1197 LttTracefile *tf;
1198
1199 LttvAttribute *saved_states_tree, *saved_state_tree;
1200
1201 LttvAttributeValue value;
1202
1203 ep = ltt_event_position_new();
1204 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1205 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1206
1207 /* Count the number of events added since the last block end in any
1208 tracefile. */
1209
1210 for(i = 0 ; i < nb_tracefile ; i++) {
1211 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1212 ltt_event_position(tfcs->parent.e, ep);
1213 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1214 tcs->nb_event += nb_event - tfcs->saved_position;
1215 tfcs->saved_position = nb_event;
1216 }
1217 g_free(ep);
1218
1219 if(tcs->nb_event >= tcs->save_interval) {
1220 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1221 LTTV_STATE_SAVED_STATES);
1222 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1223 value = lttv_attribute_add(saved_states_tree,
1224 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1225 *(value.v_gobject) = (GObject *)saved_state_tree;
1226 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1227 *(value.v_time) = self->parent.timestamp;
1228 lttv_state_save(tcs, saved_state_tree);
1229 tcs->nb_event = 0;
1230 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1231 self->parent.timestamp.tv_nsec);
1232 }
1233 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1234 return FALSE;
1235 }
1236
1237
1238 static gboolean block_end(void *hook_data, void *call_data)
1239 {
1240 LttvTracefileState *self = (LttvTracefileState *)call_data;
1241
1242 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1243
1244 LttTracefile *tf;
1245
1246 LttEventPosition *ep;
1247
1248 guint nb_block, nb_event;
1249
1250 ep = ltt_event_position_new();
1251 ltt_event_position(self->parent.e, ep);
1252 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1253 tcs->nb_event += nb_event - self->saved_position + 1;
1254 self->saved_position = 0;
1255 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1256 g_free(ep);
1257 }
1258
1259
1260 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1261 {
1262 LttvTraceset *traceset = self->parent.ts;
1263
1264 guint i, j, k, nb_trace, nb_tracefile;
1265
1266 LttvTraceState *ts;
1267
1268 LttvTracefileState *tfs;
1269
1270 LttvTraceHook hook_start, hook_end;
1271
1272 nb_trace = lttv_traceset_number(traceset);
1273 for(i = 0 ; i < nb_trace ; i++) {
1274 ts = (LttvTraceState *)self->parent.traces[i];
1275 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1276 NULL, NULL, block_start, &hook_start);
1277 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1278 NULL, NULL, block_end, &hook_end);
1279
1280 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1281 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1282
1283 for(j = 0 ; j < nb_tracefile ; j++) {
1284 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1285 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1286 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1287 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1288 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1289 }
1290 }
1291 }
1292
1293 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1294 {
1295 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1296
1297 lttv_state_save_add_event_hooks(tss);
1298
1299 return 0;
1300 }
1301
1302
1303 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1304 {
1305 LttvTraceset *traceset = self->parent.ts;
1306
1307 guint i, j, k, nb_trace, nb_tracefile;
1308
1309 LttvTraceState *ts;
1310
1311 LttvTracefileState *tfs;
1312
1313 LttvTraceHook hook_start, hook_end;
1314
1315 nb_trace = lttv_traceset_number(traceset);
1316 for(i = 0 ; i < nb_trace ; i++) {
1317 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1318 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1319 NULL, NULL, block_start, &hook_start);
1320
1321 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1322 NULL, NULL, block_end, &hook_end);
1323
1324 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1325 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1326
1327 for(j = 0 ; j < nb_tracefile ; j++) {
1328 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
1329 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1330 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1331 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1332 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1333 }
1334 }
1335 }
1336
1337 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1338 {
1339 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1340
1341 lttv_state_save_remove_event_hooks(tss);
1342
1343 return 0;
1344 }
1345
1346 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1347 {
1348 LttvTraceset *traceset = self->parent.ts;
1349
1350 guint i, j, nb_trace, nb_saved_state;
1351
1352 int min_pos, mid_pos, max_pos;
1353
1354 LttvTraceState *tcs;
1355
1356 LttvAttributeValue value;
1357
1358 LttvAttributeType type;
1359
1360 LttvAttributeName name;
1361
1362 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1363
1364 nb_trace = lttv_traceset_number(traceset);
1365 for(i = 0 ; i < nb_trace ; i++) {
1366 tcs = (LttvTraceState *)self->parent.traces[i];
1367
1368 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1369 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1370 LTTV_STATE_SAVED_STATES);
1371 min_pos = -1;
1372
1373 if(saved_states_tree) {
1374 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1375 mid_pos = max_pos / 2;
1376 while(min_pos < max_pos) {
1377 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1378 g_assert(type == LTTV_GOBJECT);
1379 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1380 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1381 &value);
1382 g_assert(type == LTTV_TIME);
1383 if(ltt_time_compare(*(value.v_time), t) < 0) {
1384 min_pos = mid_pos;
1385 closest_tree = saved_state_tree;
1386 }
1387 else max_pos = mid_pos - 1;
1388
1389 mid_pos = (min_pos + max_pos + 1) / 2;
1390 }
1391 }
1392
1393 /* restore the closest earlier saved state */
1394 if(min_pos != -1) {
1395 lttv_state_restore(tcs, closest_tree);
1396 }
1397
1398 /* There is no saved state, yet we want to have it. Restart at T0 */
1399 else {
1400 restore_init_state(tcs);
1401 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1402 }
1403 }
1404 /* We want to seek quickly without restoring/updating the state */
1405 else {
1406 restore_init_state(tcs);
1407 lttv_process_trace_seek_time(&(tcs->parent), t);
1408 }
1409 }
1410 }
1411
1412
1413 static void
1414 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1415 {
1416 }
1417
1418
1419 static void
1420 traceset_state_finalize (LttvTracesetState *self)
1421 {
1422 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1423 finalize(G_OBJECT(self));
1424 }
1425
1426
1427 static void
1428 traceset_state_class_init (LttvTracesetContextClass *klass)
1429 {
1430 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1431
1432 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1433 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1434 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1435 klass->new_traceset_context = new_traceset_context;
1436 klass->new_trace_context = new_trace_context;
1437 klass->new_tracefile_context = new_tracefile_context;
1438 }
1439
1440
1441 GType
1442 lttv_traceset_state_get_type(void)
1443 {
1444 static GType type = 0;
1445 if (type == 0) {
1446 static const GTypeInfo info = {
1447 sizeof (LttvTracesetStateClass),
1448 NULL, /* base_init */
1449 NULL, /* base_finalize */
1450 (GClassInitFunc) traceset_state_class_init, /* class_init */
1451 NULL, /* class_finalize */
1452 NULL, /* class_data */
1453 sizeof (LttvTracesetState),
1454 0, /* n_preallocs */
1455 (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
1456 };
1457
1458 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1459 &info, 0);
1460 }
1461 return type;
1462 }
1463
1464
1465 static void
1466 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1467 {
1468 }
1469
1470
1471 static void
1472 trace_state_finalize (LttvTraceState *self)
1473 {
1474 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1475 finalize(G_OBJECT(self));
1476 }
1477
1478
1479 static void
1480 trace_state_class_init (LttvTraceStateClass *klass)
1481 {
1482 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1483
1484 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1485 klass->state_save = state_save;
1486 klass->state_restore = state_restore;
1487 klass->state_saved_free = state_saved_free;
1488 }
1489
1490
1491 GType
1492 lttv_trace_state_get_type(void)
1493 {
1494 static GType type = 0;
1495 if (type == 0) {
1496 static const GTypeInfo info = {
1497 sizeof (LttvTraceStateClass),
1498 NULL, /* base_init */
1499 NULL, /* base_finalize */
1500 (GClassInitFunc) trace_state_class_init, /* class_init */
1501 NULL, /* class_finalize */
1502 NULL, /* class_data */
1503 sizeof (LttvTraceState),
1504 0, /* n_preallocs */
1505 (GInstanceInitFunc) trace_state_instance_init /* instance_init */
1506 };
1507
1508 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1509 "LttvTraceStateType", &info, 0);
1510 }
1511 return type;
1512 }
1513
1514
1515 static void
1516 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1517 {
1518 }
1519
1520
1521 static void
1522 tracefile_state_finalize (LttvTracefileState *self)
1523 {
1524 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1525 finalize(G_OBJECT(self));
1526 }
1527
1528
1529 static void
1530 tracefile_state_class_init (LttvTracefileStateClass *klass)
1531 {
1532 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1533
1534 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1535 }
1536
1537
1538 GType
1539 lttv_tracefile_state_get_type(void)
1540 {
1541 static GType type = 0;
1542 if (type == 0) {
1543 static const GTypeInfo info = {
1544 sizeof (LttvTracefileStateClass),
1545 NULL, /* base_init */
1546 NULL, /* base_finalize */
1547 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1548 NULL, /* class_finalize */
1549 NULL, /* class_data */
1550 sizeof (LttvTracefileState),
1551 0, /* n_preallocs */
1552 (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
1553 };
1554
1555 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1556 "LttvTracefileStateType", &info, 0);
1557 }
1558 return type;
1559 }
1560
1561
1562 static void module_init()
1563 {
1564 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
1565 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
1566 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1567 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1568 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1569 LTTV_STATE_TRAP = g_quark_from_string("trap");
1570 LTTV_STATE_IRQ = g_quark_from_string("irq");
1571 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1572 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
1573 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1574 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1575 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1576 LTTV_STATE_RUN = g_quark_from_string("running");
1577 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1578 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1579 LTTV_STATE_PROCESS = g_quark_from_string("process");
1580 LTTV_STATE_EVENT = g_quark_from_string("event");
1581 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
1582 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
1583 LTTV_STATE_TIME = g_quark_from_string("time");
1584 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
1585 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1586 LTTV_STATE_TRACE_STATE_USE_COUNT =
1587 g_quark_from_string("trace_state_use_count");
1588 }
1589
1590 static void module_destroy()
1591 {
1592 }
1593
1594
1595 LTTV_MODULE("state", "State computation", \
1596 "Update the system state, possibly saving it at intervals", \
1597 module_init, module_destroy)
1598
1599
1600
This page took 0.083182 seconds and 4 git commands to generate.