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