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