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