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