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