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