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