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