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