update compat
[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
34/* Facilities Quarks */
35
36GQuark
37 LTT_FACILITY_KERNEL,
38 LTT_FACILITY_KERNEL_ARCH,
39 LTT_FACILITY_PROCESS,
40 LTT_FACILITY_FS;
41
42/* Events Quarks */
43
44GQuark
45 LTT_EVENT_SYSCALL_ENTRY,
46 LTT_EVENT_SYSCALL_EXIT,
47 LTT_EVENT_TRAP_ENTRY,
48 LTT_EVENT_TRAP_EXIT,
49 LTT_EVENT_IRQ_ENTRY,
50 LTT_EVENT_IRQ_EXIT,
51 LTT_EVENT_SOFT_IRQ_ENTRY,
52 LTT_EVENT_SOFT_IRQ_EXIT,
53 LTT_EVENT_SCHEDCHANGE,
54 LTT_EVENT_FORK,
55 LTT_EVENT_EXIT,
56 LTT_EVENT_FREE,
57 LTT_EVENT_EXEC;
58
59/* Fields Quarks */
60
61GQuark
62 LTT_FIELD_SYSCALL_ID,
63 LTT_FIELD_TRAP_ID,
64 LTT_FIELD_IRQ_ID,
65 LTT_FIELD_SOFT_IRQ_ID,
66 LTT_FIELD_OUT,
67 LTT_FIELD_IN,
68 LTT_FIELD_OUT_STATE,
69 LTT_FIELD_PARENT_PID,
70 LTT_FIELD_CHILD_PID,
71 LTT_FIELD_PID,
72 LTT_FIELD_FILENAME;
73
74LttvExecutionMode
75 LTTV_STATE_MODE_UNKNOWN,
76 LTTV_STATE_USER_MODE,
77 LTTV_STATE_SYSCALL,
78 LTTV_STATE_TRAP,
79 LTTV_STATE_IRQ,
80 LTTV_STATE_SOFT_IRQ;
81
82LttvExecutionSubmode
83 LTTV_STATE_SUBMODE_UNKNOWN,
84 LTTV_STATE_SUBMODE_NONE;
85
86LttvProcessStatus
87 LTTV_STATE_UNNAMED,
88 LTTV_STATE_WAIT_FORK,
89 LTTV_STATE_WAIT_CPU,
90 LTTV_STATE_EXIT,
91 LTTV_STATE_ZOMBIE,
92 LTTV_STATE_WAIT,
93 LTTV_STATE_RUN,
94 LTTV_STATE_DEAD;
95
96static GQuark
97 LTTV_STATE_TRACEFILES,
98 LTTV_STATE_PROCESSES,
99 LTTV_STATE_PROCESS,
100 LTTV_STATE_RUNNING_PROCESS,
101 LTTV_STATE_EVENT,
102 LTTV_STATE_SAVED_STATES,
103 LTTV_STATE_SAVED_STATES_TIME,
104 LTTV_STATE_TIME,
105 LTTV_STATE_HOOKS,
106 LTTV_STATE_NAME_TABLES,
107 LTTV_STATE_TRACE_STATE_USE_COUNT;
108
109static void create_max_time(LttvTraceState *tcs);
110
111static void get_max_time(LttvTraceState *tcs);
112
113static void free_max_time(LttvTraceState *tcs);
114
115static void create_name_tables(LttvTraceState *tcs);
116
117static void get_name_tables(LttvTraceState *tcs);
118
119static void free_name_tables(LttvTraceState *tcs);
120
121static void free_saved_state(LttvTraceState *tcs);
122
123static void lttv_state_free_process_table(GHashTable *processes);
124
125
126void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
127{
128 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
129}
130
131
132void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
133{
134 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
135}
136
137
138void lttv_state_state_saved_free(LttvTraceState *self,
139 LttvAttribute *container)
140{
141 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
142}
143
144
145guint process_hash(gconstpointer key)
146{
147 guint pid = ((const LttvProcessState *)key)->pid;
148 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
149}
150
151
152/* If the hash table hash function is well distributed,
153 * the process_equal should compare different pid */
154gboolean process_equal(gconstpointer a, gconstpointer b)
155{
156 const LttvProcessState *process_a, *process_b;
157 gboolean ret = TRUE;
158
159 process_a = (const LttvProcessState *)a;
160 process_b = (const LttvProcessState *)b;
161
162 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
163 else if(likely(process_a->pid == 0 &&
164 process_a->cpu != process_b->cpu)) ret = FALSE;
165
166 return ret;
167}
168
169
170static void
171restore_init_state(LttvTraceState *self)
172{
173 guint i, nb_cpus;
174
175 LttvTracefileState *tfcs;
176
177 /* Free the process tables */
178 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
179 self->processes = g_hash_table_new(process_hash, process_equal);
180 self->nb_event = 0;
181
182 /* Seek time to beginning */
183 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
184 // closest. It's the tracecontext job to seek the trace to the beginning
185 // anyway : the init state might be used at the middle of the trace as well...
186 //g_tree_destroy(self->parent.ts_context->pqueue);
187 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
188
189
190 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
191
192 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
193
194 /* Put the per cpu running_process to beginning state : process 0. */
195 for(i=0; i< nb_cpus; i++) {
196 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0,
197 &ltt_time_zero);
198 self->running_process[i]->state->s = LTTV_STATE_RUN;
199 self->running_process[i]->cpu = i;
200 }
201
202#if 0
203 nb_tracefile = self->parent.tracefiles->len;
204
205 for(i = 0 ; i < nb_tracefile ; i++) {
206 tfcs =
207 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
208 LttvTracefileContext*, i));
209 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
210// tfcs->saved_position = 0;
211 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
212 tfcs->process->state->s = LTTV_STATE_RUN;
213 tfcs->process->last_cpu = tfcs->cpu_name;
214 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
215 }
216#endif //0
217}
218
219//static LttTime time_zero = {0,0};
220
221static void
222init(LttvTracesetState *self, LttvTraceset *ts)
223{
224 guint i, j, nb_trace, nb_tracefile;
225
226 LttvTraceContext *tc;
227
228 LttvTraceState *tcs;
229
230 LttvTracefileState *tfcs;
231
232 LttvAttributeValue v;
233
234 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
235 init((LttvTracesetContext *)self, ts);
236
237 nb_trace = lttv_traceset_number(ts);
238 for(i = 0 ; i < nb_trace ; i++) {
239 tc = self->parent.traces[i];
240 tcs = LTTV_TRACE_STATE(tc);
241 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
242 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
243 LTTV_UINT, &v);
244 (*v.v_uint)++;
245
246 if(*(v.v_uint) == 1) {
247 create_name_tables(tcs);
248 create_max_time(tcs);
249 }
250 get_name_tables(tcs);
251 get_max_time(tcs);
252
253 nb_tracefile = tc->tracefiles->len;
254#if 0
255 for(j = 0 ; j < nb_tracefile ; j++) {
256 tfcs =
257 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
258 LttvTracefileContext*, j));
259 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
260 }
261#endif //0
262 tcs->processes = NULL;
263 tcs->running_process = g_new(LttvProcessState*,
264 ltt_trace_get_num_cpu(tc->t));
265 restore_init_state(tcs);
266 }
267}
268
269
270static void
271fini(LttvTracesetState *self)
272{
273 guint i, nb_trace;
274
275 LttvTraceState *tcs;
276
277 LttvTracefileState *tfcs;
278
279 LttvAttributeValue v;
280
281 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
282 for(i = 0 ; i < nb_trace ; i++) {
283 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
284 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
285 LTTV_UINT, &v);
286
287 g_assert(*(v.v_uint) != 0);
288 (*v.v_uint)--;
289
290 if(*(v.v_uint) == 0) {
291 free_name_tables(tcs);
292 free_max_time(tcs);
293 free_saved_state(tcs);
294 }
295 g_free(tcs->running_process);
296 tcs->running_process = NULL;
297 lttv_state_free_process_table(tcs->processes);
298 tcs->processes = NULL;
299 }
300 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
301 fini((LttvTracesetContext *)self);
302}
303
304
305static LttvTracesetContext *
306new_traceset_context(LttvTracesetContext *self)
307{
308 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
309}
310
311
312static LttvTraceContext *
313new_trace_context(LttvTracesetContext *self)
314{
315 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
316}
317
318
319static LttvTracefileContext *
320new_tracefile_context(LttvTracesetContext *self)
321{
322 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
323}
324
325
326/* Write the process state of the trace */
327
328static void write_process_state(gpointer key, gpointer value,
329 gpointer user_data)
330{
331 LttvProcessState *process;
332
333 LttvExecutionState *es;
334
335 FILE *fp = (FILE *)user_data;
336
337 guint i;
338
339 process = (LttvProcessState *)value;
340 fprintf(fp,
341" <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
342 process, process->pid, process->ppid, process->creation_time.tv_sec,
343 process->creation_time.tv_nsec, g_quark_to_string(process->name),
344 process->cpu);
345
346 for(i = 0 ; i < process->execution_stack->len; i++) {
347 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
348 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
349 g_quark_to_string(es->t), g_quark_to_string(es->n),
350 es->entry.tv_sec, es->entry.tv_nsec);
351 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
352 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
353 }
354 fprintf(fp, " </PROCESS>\n");
355}
356
357
358void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
359{
360 guint i, nb_tracefile, nb_block, offset;
361 guint64 tsc;
362
363 LttvTracefileState *tfcs;
364
365 LttTracefile *tf;
366
367 LttEventPosition *ep;
368
369 guint nb_cpus;
370
371 ep = ltt_event_position_new();
372
373 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
374
375 g_hash_table_foreach(self->processes, write_process_state, fp);
376
377 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
378 for(i=0;i<nb_cpus;i++) {
379 fprintf(fp,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
380 i, self->running_process[i]->pid);
381 }
382
383 nb_tracefile = self->parent.tracefiles->len;
384
385 for(i = 0 ; i < nb_tracefile ; i++) {
386 tfcs =
387 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
388 LttvTracefileContext*, i));
389 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
390 tfcs->parent.timestamp.tv_sec,
391 tfcs->parent.timestamp.tv_nsec);
392 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
393 if(e == NULL) fprintf(fp,"/>\n");
394 else {
395 ltt_event_position(e, ep);
396 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
397 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
398 tsc);
399 }
400 }
401 g_free(ep);
402 fprintf(fp,"</PROCESS_STATE>");
403}
404
405
406/* Copy each process from an existing hash table to a new one */
407
408static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
409{
410 LttvProcessState *process, *new_process;
411
412 GHashTable *new_processes = (GHashTable *)user_data;
413
414 guint i;
415
416 process = (LttvProcessState *)value;
417 new_process = g_new(LttvProcessState, 1);
418 *new_process = *process;
419 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
420 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
421 new_process->execution_stack =
422 g_array_set_size(new_process->execution_stack,
423 process->execution_stack->len);
424 for(i = 0 ; i < process->execution_stack->len; i++) {
425 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
426 g_array_index(process->execution_stack, LttvExecutionState, i);
427 }
428 new_process->state = &g_array_index(new_process->execution_stack,
429 LttvExecutionState, new_process->execution_stack->len - 1);
430 g_hash_table_insert(new_processes, new_process, new_process);
431}
432
433
434static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
435{
436 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
437
438 g_hash_table_foreach(processes, copy_process_state, new_processes);
439 return new_processes;
440}
441
442
443/* The saved state for each trace contains a member "processes", which
444 stores a copy of the process table, and a member "tracefiles" with
445 one entry per tracefile. Each tracefile has a "process" member pointing
446 to the current process and a "position" member storing the tracefile
447 position (needed to seek to the current "next" event. */
448
449static void state_save(LttvTraceState *self, LttvAttribute *container)
450{
451 guint i, nb_tracefile, nb_cpus;
452
453 LttvTracefileState *tfcs;
454
455 LttvAttribute *tracefiles_tree, *tracefile_tree;
456
457 guint *running_process;
458
459 LttvAttributeType type;
460
461 LttvAttributeValue value;
462
463 LttvAttributeName name;
464
465 LttEventPosition *ep;
466
467 tracefiles_tree = lttv_attribute_find_subdir(container,
468 LTTV_STATE_TRACEFILES);
469
470 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
471 LTTV_POINTER);
472 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
473
474 /* Add the currently running processes array */
475 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
476 running_process = g_new(guint, nb_cpus);
477 for(i=0;i<nb_cpus;i++) {
478 running_process[i] = self->running_process[i]->pid;
479 }
480 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
481 LTTV_POINTER);
482 *(value.v_pointer) = running_process;
483
484 g_info("State save");
485
486 nb_tracefile = self->parent.tracefiles->len;
487
488 for(i = 0 ; i < nb_tracefile ; i++) {
489 tfcs =
490 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
491 LttvTracefileContext*, i));
492 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
493 value = lttv_attribute_add(tracefiles_tree, i,
494 LTTV_GOBJECT);
495 *(value.v_gobject) = (GObject *)tracefile_tree;
496#if 0
497 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
498 LTTV_UINT);
499 *(value.v_uint) = tfcs->process->pid;
500#endif //0
501 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
502 LTTV_POINTER);
503 /* Only save the position if the tfs has not infinite time. */
504 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
505 // && current_tfcs != tfcs) {
506 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
507 *(value.v_pointer) = NULL;
508 } else {
509 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
510 ep = ltt_event_position_new();
511 ltt_event_position(e, ep);
512 *(value.v_pointer) = ep;
513
514 guint nb_block, offset;
515 guint64 tsc;
516 LttTracefile *tf;
517 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
518 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
519 tsc,
520 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
521 }
522 }
523}
524
525
526static void state_restore(LttvTraceState *self, LttvAttribute *container)
527{
528 guint i, nb_tracefile, pid, nb_cpus;
529
530 LttvTracefileState *tfcs;
531
532 LttvAttribute *tracefiles_tree, *tracefile_tree;
533
534 guint *running_process;
535
536 LttvAttributeType type;
537
538 LttvAttributeValue value;
539
540 LttvAttributeName name;
541
542 LttEventPosition *ep;
543
544 LttvTracesetContext *tsc = self->parent.ts_context;
545
546 tracefiles_tree = lttv_attribute_find_subdir(container,
547 LTTV_STATE_TRACEFILES);
548
549 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
550 &value);
551 g_assert(type == LTTV_POINTER);
552 lttv_state_free_process_table(self->processes);
553 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
554
555 /* Add the currently running processes array */
556 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
557 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
558 &value);
559 g_assert(type == LTTV_POINTER);
560 running_process = *(value.v_pointer);
561 for(i=0;i<nb_cpus;i++) {
562 pid = running_process[i];
563 self->running_process[i] = lttv_state_find_process(self, i, pid);
564 g_assert(self->running_process[i] != NULL);
565 }
566
567
568 nb_tracefile = self->parent.tracefiles->len;
569
570 //g_tree_destroy(tsc->pqueue);
571 //tsc->pqueue = g_tree_new(compare_tracefile);
572
573 for(i = 0 ; i < nb_tracefile ; i++) {
574 tfcs =
575 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
576 LttvTracefileContext*, i));
577 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
578 g_assert(type == LTTV_GOBJECT);
579 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
580#if 0
581 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
582 &value);
583 g_assert(type == LTTV_UINT);
584 pid = *(value.v_uint);
585 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
586#endif //0
587 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
588 &value);
589 g_assert(type == LTTV_POINTER);
590 //g_assert(*(value.v_pointer) != NULL);
591 ep = *(value.v_pointer);
592 g_assert(tfcs->parent.t_context != NULL);
593
594 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
595 g_tree_remove(tsc->pqueue, tfc);
596
597 if(ep != NULL) {
598 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
599 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
600 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
601 g_tree_insert(tsc->pqueue, tfc, tfc);
602 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
603 } else {
604 tfc->timestamp = ltt_time_infinite;
605 }
606 }
607}
608
609
610static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
611{
612 guint i, nb_tracefile, nb_cpus;
613
614 LttvTracefileState *tfcs;
615
616 LttvAttribute *tracefiles_tree, *tracefile_tree;
617
618 guint *running_process;
619
620 LttvAttributeType type;
621
622 LttvAttributeValue value;
623
624 LttvAttributeName name;
625
626 LttEventPosition *ep;
627
628 tracefiles_tree = lttv_attribute_find_subdir(container,
629 LTTV_STATE_TRACEFILES);
630 g_object_ref(G_OBJECT(tracefiles_tree));
631 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
632
633 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
634 &value);
635 g_assert(type == LTTV_POINTER);
636 lttv_state_free_process_table(*(value.v_pointer));
637 *(value.v_pointer) = NULL;
638 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
639
640 /* Free running processes array */
641 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
642 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
643 &value);
644 g_assert(type == LTTV_POINTER);
645 running_process = *(value.v_pointer);
646 g_free(running_process);
647
648 nb_tracefile = self->parent.tracefiles->len;
649
650 for(i = 0 ; i < nb_tracefile ; i++) {
651 tfcs =
652 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
653 LttvTracefileContext*, i));
654 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
655 g_assert(type == LTTV_GOBJECT);
656 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
657
658 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
659 &value);
660 g_assert(type == LTTV_POINTER);
661 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
662 }
663 g_object_unref(G_OBJECT(tracefiles_tree));
664}
665
666
667static void free_saved_state(LttvTraceState *self)
668{
669 guint i, nb;
670
671 LttvAttributeType type;
672
673 LttvAttributeValue value;
674
675 LttvAttributeName name;
676
677 LttvAttribute *saved_states;
678
679 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
680 LTTV_STATE_SAVED_STATES);
681
682 nb = lttv_attribute_get_number(saved_states);
683 for(i = 0 ; i < nb ; i++) {
684 type = lttv_attribute_get(saved_states, i, &name, &value);
685 g_assert(type == LTTV_GOBJECT);
686 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
687 }
688
689 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
690}
691
692
693static void
694create_max_time(LttvTraceState *tcs)
695{
696 LttvAttributeValue v;
697
698 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
699 LTTV_POINTER, &v);
700 g_assert(*(v.v_pointer) == NULL);
701 *(v.v_pointer) = g_new(LttTime,1);
702 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
703}
704
705
706static void
707get_max_time(LttvTraceState *tcs)
708{
709 LttvAttributeValue v;
710
711 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
712 LTTV_POINTER, &v);
713 g_assert(*(v.v_pointer) != NULL);
714 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
715}
716
717
718static void
719free_max_time(LttvTraceState *tcs)
720{
721 LttvAttributeValue v;
722
723 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
724 LTTV_POINTER, &v);
725 g_free(*(v.v_pointer));
726 *(v.v_pointer) = NULL;
727}
728
729
730typedef struct _LttvNameTables {
731 // FIXME GQuark *eventtype_names;
732 GQuark *syscall_names;
733 GQuark *trap_names;
734 GQuark *irq_names;
735 GQuark *soft_irq_names;
736} LttvNameTables;
737
738
739static void
740create_name_tables(LttvTraceState *tcs)
741{
742 int i, nb;
743
744 GQuark f_name, e_name;
745
746 LttvTraceHook h;
747
748 LttvTraceHookByFacility *thf;
749
750 LttEventType *et;
751
752 LttType *t;
753
754 GString *fe_name = g_string_new("");
755
756 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
757
758 LttvAttributeValue v;
759
760 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
761 LTTV_POINTER, &v);
762 g_assert(*(v.v_pointer) == NULL);
763 *(v.v_pointer) = name_tables;
764#if 0 // Use iteration over the facilities_by_name and then list all event
765 // types of each facility
766 nb = ltt_trace_eventtype_number(tcs->parent.t);
767 name_tables->eventtype_names = g_new(GQuark, nb);
768 for(i = 0 ; i < nb ; i++) {
769 et = ltt_trace_eventtype_get(tcs->parent.t, i);
770 e_name = ltt_eventtype_name(et);
771 f_name = ltt_facility_name(ltt_eventtype_facility(et));
772 g_string_printf(fe_name, "%s.%s", f_name, e_name);
773 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
774 }
775#endif //0
776 if(lttv_trace_find_hook(tcs->parent.t,
777 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
778 LTT_FIELD_SYSCALL_ID, 0, 0,
779 NULL, NULL, &h))
780 return;
781
782 thf = lttv_trace_hook_get_first(&h);
783
784 t = ltt_field_type(thf->f1);
785 nb = ltt_type_element_number(t);
786
787 lttv_trace_hook_destroy(&h);
788
789 name_tables->syscall_names = g_new(GQuark, nb);
790
791 for(i = 0 ; i < nb ; i++) {
792 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
793 }
794
795 //name_tables->syscall_names = g_new(GQuark, 256);
796 //for(i = 0 ; i < 256 ; i++) {
797 // g_string_printf(fe_name, "syscall %d", i);
798 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
799 //}
800
801 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
802 LTT_EVENT_TRAP_ENTRY,
803 LTT_FIELD_TRAP_ID, 0, 0,
804 NULL, NULL, &h))
805 return;
806
807 thf = lttv_trace_hook_get_first(&h);
808
809 t = ltt_field_type(thf->f1);
810 //nb = ltt_type_element_number(t);
811
812 lttv_trace_hook_destroy(&h);
813
814 /*
815 name_tables->trap_names = g_new(GQuark, nb);
816 for(i = 0 ; i < nb ; i++) {
817 name_tables->trap_names[i] = g_quark_from_string(
818 ltt_enum_string_get(t, i));
819 }
820 */
821
822 name_tables->trap_names = g_new(GQuark, 256);
823 for(i = 0 ; i < 256 ; i++) {
824 g_string_printf(fe_name, "trap %d", i);
825 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
826 }
827
828 if(lttv_trace_find_hook(tcs->parent.t,
829 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
830 LTT_FIELD_IRQ_ID, 0, 0,
831 NULL, NULL, &h))
832 return;
833
834 thf = lttv_trace_hook_get_first(&h);
835
836 t = ltt_field_type(thf->f1);
837 //nb = ltt_type_element_number(t);
838
839 lttv_trace_hook_destroy(&h);
840
841 /*
842 name_tables->irq_names = g_new(GQuark, nb);
843 for(i = 0 ; i < nb ; i++) {
844 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
845 }
846 */
847
848 name_tables->irq_names = g_new(GQuark, 256);
849 for(i = 0 ; i < 256 ; i++) {
850 g_string_printf(fe_name, "irq %d", i);
851 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
852 }
853
854 /*
855 name_tables->soft_irq_names = g_new(GQuark, nb);
856 for(i = 0 ; i < nb ; i++) {
857 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
858 }
859 */
860
861 name_tables->soft_irq_names = g_new(GQuark, 256);
862 for(i = 0 ; i < 256 ; i++) {
863 g_string_printf(fe_name, "softirq %d", i);
864 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
865 }
866
867
868 g_string_free(fe_name, TRUE);
869}
870
871
872static void
873get_name_tables(LttvTraceState *tcs)
874{
875 LttvNameTables *name_tables;
876
877 LttvAttributeValue v;
878
879 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
880 LTTV_POINTER, &v);
881 g_assert(*(v.v_pointer) != NULL);
882 name_tables = (LttvNameTables *)*(v.v_pointer);
883 //tcs->eventtype_names = name_tables->eventtype_names;
884 tcs->syscall_names = name_tables->syscall_names;
885 tcs->trap_names = name_tables->trap_names;
886 tcs->irq_names = name_tables->irq_names;
887 tcs->soft_irq_names = name_tables->soft_irq_names;
888}
889
890
891static void
892free_name_tables(LttvTraceState *tcs)
893{
894 LttvNameTables *name_tables;
895
896 LttvAttributeValue v;
897
898 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
899 LTTV_POINTER, &v);
900 name_tables = (LttvNameTables *)*(v.v_pointer);
901 *(v.v_pointer) = NULL;
902
903 // g_free(name_tables->eventtype_names);
904 g_free(name_tables->syscall_names);
905 g_free(name_tables->trap_names);
906 g_free(name_tables->irq_names);
907 g_free(name_tables->soft_irq_names);
908 g_free(name_tables);
909}
910
911#ifdef HASH_TABLE_DEBUG
912
913static void test_process(gpointer key, gpointer value, gpointer user_data)
914{
915 LttvProcessState *process = (LttvProcessState *)value;
916
917 /* Test for process corruption */
918 guint stack_len = process->execution_stack->len;
919}
920
921static void hash_table_check(GHashTable *table)
922{
923 g_hash_table_foreach(table, test_process, NULL);
924}
925
926
927#endif
928
929
930static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
931 guint state_id)
932{
933 LttvExecutionState *es;
934
935 guint cpu = ltt_tracefile_num(tfs->parent.tf);
936 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
937
938#ifdef HASH_TABLE_DEBUG
939 hash_table_check(ts->processes);
940#endif
941 LttvProcessState *process = ts->running_process[cpu];
942
943 guint depth = process->execution_stack->len;
944
945 process->execution_stack =
946 g_array_set_size(process->execution_stack, depth + 1);
947 /* Keep in sync */
948 process->state =
949 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
950
951 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
952 es->t = t;
953 es->n = state_id;
954 es->entry = es->change = tfs->parent.timestamp;
955 es->s = process->state->s;
956 process->state = es;
957}
958
959
960static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
961{
962 guint cpu = ltt_tracefile_num(tfs->parent.tf);
963 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
964 LttvProcessState *process = ts->running_process[cpu];
965
966 guint depth = process->execution_stack->len;
967
968 if(process->state->t != t){
969 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
970 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
971 g_info("process state has %s when pop_int is %s\n",
972 g_quark_to_string(process->state->t),
973 g_quark_to_string(t));
974 g_info("{ %u, %u, %s, %s }\n",
975 process->pid,
976 process->ppid,
977 g_quark_to_string(process->name),
978 g_quark_to_string(process->state->s));
979 return;
980 }
981
982 if(depth == 1){
983 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
984 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
985 return;
986 }
987
988 process->execution_stack =
989 g_array_set_size(process->execution_stack, depth - 1);
990 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
991 depth - 2);
992 process->state->change = tfs->parent.timestamp;
993}
994
995
996LttvProcessState *
997lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
998 guint cpu, guint pid, const LttTime *timestamp)
999{
1000 LttvProcessState *process = g_new(LttvProcessState, 1);
1001
1002 LttvExecutionState *es;
1003
1004 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1005
1006 char buffer[128];
1007
1008 process->pid = pid;
1009 process->cpu = cpu;
1010 //process->last_cpu = tfs->cpu_name;
1011 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1012 g_info("Process %u, core %p", process->pid, process);
1013 g_hash_table_insert(tcs->processes, process, process);
1014
1015 if(parent) {
1016 process->ppid = parent->pid;
1017 process->name = parent->name;
1018 process->creation_time = *timestamp;
1019 }
1020
1021 /* No parent. This process exists but we are missing all information about
1022 its creation. The birth time is set to zero but we remember the time of
1023 insertion */
1024
1025 else {
1026 process->ppid = 0;
1027 process->name = LTTV_STATE_UNNAMED;
1028 process->creation_time = ltt_time_zero;
1029 }
1030
1031 process->insertion_time = *timestamp;
1032 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1033 process->creation_time.tv_nsec);
1034 process->pid_time = g_quark_from_string(buffer);
1035 process->cpu = cpu;
1036 //process->last_cpu = tfs->cpu_name;
1037 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1038 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1039 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1040 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1041 es = process->state = &g_array_index(process->execution_stack,
1042 LttvExecutionState, 0);
1043 es->t = LTTV_STATE_USER_MODE;
1044 es->n = LTTV_STATE_SUBMODE_NONE;
1045 es->entry = *timestamp;
1046 //g_assert(timestamp->tv_sec != 0);
1047 es->change = *timestamp;
1048 es->s = LTTV_STATE_RUN;
1049
1050 es = process->state = &g_array_index(process->execution_stack,
1051 LttvExecutionState, 1);
1052 es->t = LTTV_STATE_SYSCALL;
1053 es->n = LTTV_STATE_SUBMODE_NONE;
1054 es->entry = *timestamp;
1055 //g_assert(timestamp->tv_sec != 0);
1056 es->change = *timestamp;
1057 es->s = LTTV_STATE_WAIT_FORK;
1058
1059 return process;
1060}
1061
1062LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1063 guint pid)
1064{
1065 LttvProcessState key;
1066 LttvProcessState *process;
1067
1068 key.pid = pid;
1069 key.cpu = cpu;
1070 process = g_hash_table_lookup(ts->processes, &key);
1071 return process;
1072}
1073
1074LttvProcessState *
1075lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1076 LttTime *timestamp)
1077{
1078 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1079
1080 /* Put ltt_time_zero creation time for unexisting processes */
1081 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1082 NULL, cpu, pid, timestamp);
1083 return process;
1084}
1085
1086/* FIXME : this function should be called when we receive an event telling that
1087 * release_task has been called in the kernel. In happens generally when
1088 * the parent waits for its child terminaison, but may also happen in special
1089 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1090 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1091 * of a killed thread ground, but isn't the leader.
1092 */
1093static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1094{
1095 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1096 LttvProcessState key;
1097
1098 key.pid = process->pid;
1099 key.cpu = process->cpu;
1100 g_hash_table_remove(ts->processes, &key);
1101 g_array_free(process->execution_stack, TRUE);
1102 g_free(process);
1103}
1104
1105
1106static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1107{
1108 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1109 g_free(value);
1110}
1111
1112
1113static void lttv_state_free_process_table(GHashTable *processes)
1114{
1115 g_hash_table_foreach(processes, free_process_state, NULL);
1116 g_hash_table_destroy(processes);
1117}
1118
1119
1120static gboolean syscall_entry(void *hook_data, void *call_data)
1121{
1122 LttvTracefileState *s = (LttvTracefileState *)call_data;
1123 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1124 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1125 LttField *f = thf->f1;
1126
1127 LttvExecutionSubmode submode;
1128
1129 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1130 ltt_event_get_unsigned(e, f)];
1131 push_state(s, LTTV_STATE_SYSCALL, submode);
1132 return FALSE;
1133}
1134
1135
1136static gboolean syscall_exit(void *hook_data, void *call_data)
1137{
1138 LttvTracefileState *s = (LttvTracefileState *)call_data;
1139
1140 pop_state(s, LTTV_STATE_SYSCALL);
1141 return FALSE;
1142}
1143
1144
1145static gboolean trap_entry(void *hook_data, void *call_data)
1146{
1147 LttvTracefileState *s = (LttvTracefileState *)call_data;
1148 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1149 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1150 LttField *f = thf->f1;
1151
1152 LttvExecutionSubmode submode;
1153
1154 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1155 ltt_event_get_unsigned(e, f)];
1156 push_state(s, LTTV_STATE_TRAP, submode);
1157 return FALSE;
1158}
1159
1160
1161static gboolean trap_exit(void *hook_data, void *call_data)
1162{
1163 LttvTracefileState *s = (LttvTracefileState *)call_data;
1164
1165 pop_state(s, LTTV_STATE_TRAP);
1166 return FALSE;
1167}
1168
1169
1170static gboolean irq_entry(void *hook_data, void *call_data)
1171{
1172 LttvTracefileState *s = (LttvTracefileState *)call_data;
1173 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1174 guint8 fac_id = ltt_event_facility_id(e);
1175 guint8 ev_id = ltt_event_eventtype_id(e);
1176 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1177 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1178 g_assert(thf->f1 != NULL);
1179 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1180 LttField *f = thf->f1;
1181
1182 LttvExecutionSubmode submode;
1183
1184 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1185 ltt_event_get_unsigned(e, f)];
1186
1187 /* Do something with the info about being in user or system mode when int? */
1188 push_state(s, LTTV_STATE_IRQ, submode);
1189 return FALSE;
1190}
1191
1192
1193static gboolean irq_exit(void *hook_data, void *call_data)
1194{
1195 LttvTracefileState *s = (LttvTracefileState *)call_data;
1196
1197 pop_state(s, LTTV_STATE_IRQ);
1198 return FALSE;
1199}
1200
1201static gboolean soft_irq_entry(void *hook_data, void *call_data)
1202{
1203 LttvTracefileState *s = (LttvTracefileState *)call_data;
1204 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1205 guint8 fac_id = ltt_event_facility_id(e);
1206 guint8 ev_id = ltt_event_eventtype_id(e);
1207 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1208 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1209 g_assert(thf->f1 != NULL);
1210 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1211 LttField *f = thf->f1;
1212
1213 LttvExecutionSubmode submode;
1214
1215 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1216 ltt_event_get_unsigned(e, f)];
1217
1218 /* Do something with the info about being in user or system mode when int? */
1219 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1220 return FALSE;
1221}
1222
1223
1224static gboolean soft_irq_exit(void *hook_data, void *call_data)
1225{
1226 LttvTracefileState *s = (LttvTracefileState *)call_data;
1227
1228 pop_state(s, LTTV_STATE_SOFT_IRQ);
1229 return FALSE;
1230}
1231
1232
1233static gboolean schedchange(void *hook_data, void *call_data)
1234{
1235 LttvTracefileState *s = (LttvTracefileState *)call_data;
1236 guint cpu = ltt_tracefile_num(s->parent.tf);
1237 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1238 LttvProcessState *process = ts->running_process[cpu];
1239
1240 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1241 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1242 guint pid_in, pid_out;
1243 gint state_out;
1244
1245 pid_out = ltt_event_get_unsigned(e, thf->f1);
1246 pid_in = ltt_event_get_unsigned(e, thf->f2);
1247 state_out = ltt_event_get_int(e, thf->f3);
1248
1249 if(likely(process != NULL)) {
1250
1251 /* We could not know but it was not the idle process executing.
1252 This should only happen at the beginning, before the first schedule
1253 event, and when the initial information (current process for each CPU)
1254 is missing. It is not obvious how we could, after the fact, compensate
1255 the wrongly attributed statistics. */
1256
1257 //This test only makes sense once the state is known and if there is no
1258 //missing events.
1259 //if(unlikely(process->pid != pid_out)) {
1260 // g_assert(process->pid == 0);
1261 //}
1262
1263 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1264 process->state->s = LTTV_STATE_ZOMBIE;
1265 process->state->change = s->parent.timestamp;
1266 } else {
1267 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1268 else process->state->s = LTTV_STATE_WAIT;
1269 process->state->change = s->parent.timestamp;
1270 }
1271
1272 if(state_out == 32)
1273 exit_process(s, process); /* EXIT_DEAD */
1274 /* see sched.h for states */
1275 }
1276 process = ts->running_process[cpu] =
1277 lttv_state_find_process_or_create(
1278 (LttvTraceState*)s->parent.t_context,
1279 cpu, pid_in,
1280 &s->parent.timestamp);
1281 process->state->s = LTTV_STATE_RUN;
1282 process->cpu = cpu;
1283 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1284 process->state->change = s->parent.timestamp;
1285 return FALSE;
1286}
1287
1288static gboolean process_fork(void *hook_data, void *call_data)
1289{
1290 LttvTracefileState *s = (LttvTracefileState *)call_data;
1291 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1292 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1293 LttField *f;
1294 guint parent_pid;
1295 guint child_pid;
1296 LttvProcessState *zombie_process;
1297 guint cpu = ltt_tracefile_num(s->parent.tf);
1298 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1299 LttvProcessState *process = ts->running_process[cpu];
1300 LttvProcessState *child_process;
1301
1302 /* Parent PID */
1303 f = thf->f1;
1304 parent_pid = ltt_event_get_unsigned(e, f);
1305
1306 /* Child PID */
1307 f = thf->f2;
1308 child_pid = ltt_event_get_unsigned(e, f);
1309
1310 /* Mathieu : it seems like the process might have been scheduled in before the
1311 * fork, and, in a rare case, might be the current process. This might happen
1312 * in a SMP case where we don't have enough precision on the clocks.
1313 *
1314 * Test reenabled after precision fixes on time. (Mathieu) */
1315#if 0
1316 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1317
1318 if(unlikely(zombie_process != NULL)) {
1319 /* Reutilisation of PID. Only now we are sure that the old PID
1320 * has been released. FIXME : should know when release_task happens instead.
1321 */
1322 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1323 guint i;
1324 for(i=0; i< num_cpus; i++) {
1325 g_assert(zombie_process != ts->running_process[i]);
1326 }
1327
1328 exit_process(s, zombie_process);
1329 }
1330#endif //0
1331 g_assert(process->pid != child_pid);
1332 // FIXME : Add this test in the "known state" section
1333 // g_assert(process->pid == parent_pid);
1334 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1335 if(child_process == NULL) {
1336 lttv_state_create_process(ts, process, cpu,
1337 child_pid, &s->parent.timestamp);
1338 } else {
1339 /* The process has already been created : due to time imprecision between
1340 * multiple CPUs : it has been scheduled in before creation. Note that we
1341 * shouldn't have this kind of imprecision.
1342 *
1343 * Simply put a correct parent.
1344 */
1345 g_assert(0); /* This is a problematic case : the process has been created
1346 before the fork event */
1347 child_process->ppid = process->pid;
1348 }
1349
1350 return FALSE;
1351}
1352
1353
1354static gboolean process_exit(void *hook_data, void *call_data)
1355{
1356 LttvTracefileState *s = (LttvTracefileState *)call_data;
1357 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1358 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1359 LttField *f;
1360 guint pid;
1361 guint cpu = ltt_tracefile_num(s->parent.tf);
1362 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1363 LttvProcessState *process = ts->running_process[cpu];
1364
1365 pid = ltt_event_get_unsigned(e, thf->f1);
1366
1367 // FIXME : Add this test in the "known state" section
1368 // g_assert(process->pid == pid);
1369
1370 if(likely(process != NULL)) {
1371 process->state->s = LTTV_STATE_EXIT;
1372 }
1373 return FALSE;
1374}
1375
1376static gboolean process_free(void *hook_data, void *call_data)
1377{
1378 LttvTracefileState *s = (LttvTracefileState *)call_data;
1379 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1380 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1381 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1382 guint release_pid;
1383 LttvProcessState *process;
1384
1385 /* PID of the process to release */
1386 release_pid = ltt_event_get_unsigned(e, thf->f1);
1387
1388 g_assert(release_pid != 0);
1389
1390 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1391
1392 if(likely(process != NULL)) {
1393 /* release_task is happening at kernel level : we can now safely release
1394 * the data structure of the process */
1395 //This test is fun, though, as it may happen that
1396 //at time t : CPU 0 : process_free
1397 //at time t+150ns : CPU 1 : schedule out
1398 //Clearly due to time imprecision, we disable it. (Mathieu)
1399 //If this weird case happen, we have no choice but to put the
1400 //Currently running process on the cpu to 0.
1401 //I re-enable it following time precision fixes. (Mathieu)
1402 //Well, in the case where an process is freed by a process on another CPU
1403 //and still scheduled, it happens that this is the schedchange that will
1404 //drop the last reference count. Do not free it here!
1405 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1406 guint i;
1407 for(i=0; i< num_cpus; i++) {
1408 //g_assert(process != ts->running_process[i]);
1409 if(process == ts->running_process[i]) {
1410 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1411 break;
1412 }
1413 }
1414 if(i == num_cpus) /* process is not scheduled */
1415 exit_process(s, process);
1416 }
1417
1418 return FALSE;
1419}
1420
1421
1422static gboolean process_exec(void *hook_data, void *call_data)
1423{
1424 LttvTracefileState *s = (LttvTracefileState *)call_data;
1425 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1426 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1427 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1428 //gchar *name;
1429 guint cpu = ltt_tracefile_num(s->parent.tf);
1430 LttvProcessState *process = ts->running_process[cpu];
1431
1432 /* PID of the process to release */
1433 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1434 //name = ltt_event_get_string(e, thf->f1);
1435 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1436 gchar *name_begin =
1437 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1438 gchar *null_term_name = g_new(gchar, name_len+1);
1439 memcpy(null_term_name, name_begin, name_len);
1440 null_term_name[name_len] = '\0';
1441
1442 process->name = g_quark_from_string(null_term_name);
1443 g_free(null_term_name);
1444 return FALSE;
1445}
1446
1447
1448
1449
1450gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1451{
1452 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1453
1454 lttv_state_add_event_hooks(tss);
1455
1456 return 0;
1457}
1458
1459void lttv_state_add_event_hooks(LttvTracesetState *self)
1460{
1461 LttvTraceset *traceset = self->parent.ts;
1462
1463 guint i, j, k, l, nb_trace, nb_tracefile;
1464
1465 LttvTraceState *ts;
1466
1467 LttvTracefileState *tfs;
1468
1469 GArray *hooks;
1470
1471 LttvTraceHookByFacility *thf;
1472
1473 LttvTraceHook *hook;
1474
1475 LttvAttributeValue val;
1476
1477 gint ret;
1478
1479 nb_trace = lttv_traceset_number(traceset);
1480 for(i = 0 ; i < nb_trace ; i++) {
1481 ts = (LttvTraceState *)self->parent.traces[i];
1482
1483 /* Find the eventtype id for the following events and register the
1484 associated by id hooks. */
1485
1486 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 13);
1487 hooks = g_array_set_size(hooks, 13);
1488
1489 ret = lttv_trace_find_hook(ts->parent.t,
1490 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1491 LTT_FIELD_SYSCALL_ID, 0, 0,
1492 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1493 g_assert(!ret);
1494
1495 ret = lttv_trace_find_hook(ts->parent.t,
1496 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1497 0, 0, 0,
1498 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1499 g_assert(!ret);
1500
1501 ret = lttv_trace_find_hook(ts->parent.t,
1502 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1503 LTT_FIELD_TRAP_ID, 0, 0,
1504 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1505 g_assert(!ret);
1506
1507 ret = lttv_trace_find_hook(ts->parent.t,
1508 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1509 0, 0, 0,
1510 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1511 g_assert(!ret);
1512
1513 ret = lttv_trace_find_hook(ts->parent.t,
1514 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1515 LTT_FIELD_IRQ_ID, 0, 0,
1516 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1517 g_assert(!ret);
1518
1519 ret = lttv_trace_find_hook(ts->parent.t,
1520 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1521 0, 0, 0,
1522 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1523 g_assert(!ret);
1524
1525 ret = lttv_trace_find_hook(ts->parent.t,
1526 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1527 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1528 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1529 g_assert(!ret);
1530
1531 ret = lttv_trace_find_hook(ts->parent.t,
1532 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1533 0, 0, 0,
1534 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1535 g_assert(!ret);
1536
1537 ret = lttv_trace_find_hook(ts->parent.t,
1538 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1539 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1540 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1541 g_assert(!ret);
1542
1543 ret = lttv_trace_find_hook(ts->parent.t,
1544 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1545 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1546 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1547 g_assert(!ret);
1548
1549 ret = lttv_trace_find_hook(ts->parent.t,
1550 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1551 LTT_FIELD_PID, 0, 0,
1552 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1553 g_assert(!ret);
1554
1555 ret = lttv_trace_find_hook(ts->parent.t,
1556 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1557 LTT_FIELD_PID, 0, 0,
1558 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 11));
1559 g_assert(!ret);
1560
1561 ret = lttv_trace_find_hook(ts->parent.t,
1562 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1563 LTT_FIELD_FILENAME, 0, 0,
1564 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 12));
1565 g_assert(!ret);
1566
1567
1568
1569 /* Add these hooks to each event_by_id hooks list */
1570
1571 nb_tracefile = ts->parent.tracefiles->len;
1572
1573 for(j = 0 ; j < nb_tracefile ; j++) {
1574 tfs =
1575 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1576 LttvTracefileContext*, j));
1577
1578 for(k = 0 ; k < hooks->len ; k++) {
1579 hook = &g_array_index(hooks, LttvTraceHook, k);
1580 for(l=0;l<hook->fac_list->len;l++) {
1581 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1582 lttv_hooks_add(
1583 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1584 thf->h,
1585 thf,
1586 LTTV_PRIO_STATE);
1587 }
1588 }
1589 }
1590 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1591 *(val.v_pointer) = hooks;
1592 }
1593}
1594
1595gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1596{
1597 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1598
1599 lttv_state_remove_event_hooks(tss);
1600
1601 return 0;
1602}
1603
1604void lttv_state_remove_event_hooks(LttvTracesetState *self)
1605{
1606 LttvTraceset *traceset = self->parent.ts;
1607
1608 guint i, j, k, l, nb_trace, nb_tracefile;
1609
1610 LttvTraceState *ts;
1611
1612 LttvTracefileState *tfs;
1613
1614 GArray *hooks;
1615
1616 LttvTraceHook *hook;
1617
1618 LttvTraceHookByFacility *thf;
1619
1620 LttvAttributeValue val;
1621
1622 nb_trace = lttv_traceset_number(traceset);
1623 for(i = 0 ; i < nb_trace ; i++) {
1624 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1625 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1626 hooks = *(val.v_pointer);
1627
1628 /* Remove these hooks from each event_by_id hooks list */
1629
1630 nb_tracefile = ts->parent.tracefiles->len;
1631
1632 for(j = 0 ; j < nb_tracefile ; j++) {
1633 tfs =
1634 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1635 LttvTracefileContext*, j));
1636
1637 for(k = 0 ; k < hooks->len ; k++) {
1638 hook = &g_array_index(hooks, LttvTraceHook, k);
1639 for(l=0;l<hook->fac_list->len;l++) {
1640 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1641
1642 lttv_hooks_remove_data(
1643 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1644 thf->h,
1645 thf);
1646 }
1647 }
1648 }
1649 for(k = 0 ; k < hooks->len ; k++)
1650 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1651 g_array_free(hooks, TRUE);
1652 }
1653}
1654
1655static gboolean state_save_event_hook(void *hook_data, void *call_data)
1656{
1657 guint *event_count = (guint*)hook_data;
1658
1659 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1660 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1661 return FALSE;
1662 else
1663 *event_count = 0;
1664
1665 LttvTracefileState *self = (LttvTracefileState *)call_data;
1666
1667 LttvTracefileState *tfcs;
1668
1669 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1670
1671 LttEventPosition *ep;
1672
1673 guint i;
1674
1675 LttTracefile *tf;
1676
1677 LttvAttribute *saved_states_tree, *saved_state_tree;
1678
1679 LttvAttributeValue value;
1680
1681 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1682 LTTV_STATE_SAVED_STATES);
1683 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1684 value = lttv_attribute_add(saved_states_tree,
1685 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1686 *(value.v_gobject) = (GObject *)saved_state_tree;
1687 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1688 *(value.v_time) = self->parent.timestamp;
1689 lttv_state_save(tcs, saved_state_tree);
1690 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1691 self->parent.timestamp.tv_nsec);
1692
1693 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1694
1695 return FALSE;
1696}
1697
1698static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1699{
1700 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1701
1702 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1703
1704 return FALSE;
1705}
1706
1707#if 0
1708static gboolean block_start(void *hook_data, void *call_data)
1709{
1710 LttvTracefileState *self = (LttvTracefileState *)call_data;
1711
1712 LttvTracefileState *tfcs;
1713
1714 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1715
1716 LttEventPosition *ep;
1717
1718 guint i, nb_block, nb_event, nb_tracefile;
1719
1720 LttTracefile *tf;
1721
1722 LttvAttribute *saved_states_tree, *saved_state_tree;
1723
1724 LttvAttributeValue value;
1725
1726 ep = ltt_event_position_new();
1727
1728 nb_tracefile = tcs->parent.tracefiles->len;
1729
1730 /* Count the number of events added since the last block end in any
1731 tracefile. */
1732
1733 for(i = 0 ; i < nb_tracefile ; i++) {
1734 tfcs =
1735 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1736 LttvTracefileContext, i));
1737 ltt_event_position(tfcs->parent.e, ep);
1738 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1739 tcs->nb_event += nb_event - tfcs->saved_position;
1740 tfcs->saved_position = nb_event;
1741 }
1742 g_free(ep);
1743
1744 if(tcs->nb_event >= tcs->save_interval) {
1745 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1746 LTTV_STATE_SAVED_STATES);
1747 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1748 value = lttv_attribute_add(saved_states_tree,
1749 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1750 *(value.v_gobject) = (GObject *)saved_state_tree;
1751 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1752 *(value.v_time) = self->parent.timestamp;
1753 lttv_state_save(tcs, saved_state_tree);
1754 tcs->nb_event = 0;
1755 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1756 self->parent.timestamp.tv_nsec);
1757 }
1758 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1759 return FALSE;
1760}
1761#endif //0
1762
1763#if 0
1764static gboolean block_end(void *hook_data, void *call_data)
1765{
1766 LttvTracefileState *self = (LttvTracefileState *)call_data;
1767
1768 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1769
1770 LttTracefile *tf;
1771
1772 LttEventPosition *ep;
1773
1774 guint nb_block, nb_event;
1775
1776 ep = ltt_event_position_new();
1777 ltt_event_position(self->parent.e, ep);
1778 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1779 tcs->nb_event += nb_event - self->saved_position + 1;
1780 self->saved_position = 0;
1781 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1782 g_free(ep);
1783
1784 return FALSE;
1785}
1786#endif //0
1787#if 0
1788void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1789{
1790 LttvTraceset *traceset = self->parent.ts;
1791
1792 guint i, j, nb_trace, nb_tracefile;
1793
1794 LttvTraceState *ts;
1795
1796 LttvTracefileState *tfs;
1797
1798 LttvTraceHook hook_start, hook_end;
1799
1800 nb_trace = lttv_traceset_number(traceset);
1801 for(i = 0 ; i < nb_trace ; i++) {
1802 ts = (LttvTraceState *)self->parent.traces[i];
1803
1804 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1805 NULL, NULL, block_start, &hook_start);
1806 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1807 NULL, NULL, block_end, &hook_end);
1808
1809 nb_tracefile = ts->parent.tracefiles->len;
1810
1811 for(j = 0 ; j < nb_tracefile ; j++) {
1812 tfs =
1813 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1814 LttvTracefileContext, j));
1815 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1816 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1817 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1818 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1819 }
1820 }
1821}
1822#endif //0
1823
1824void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1825{
1826 LttvTraceset *traceset = self->parent.ts;
1827
1828 guint i, j, nb_trace, nb_tracefile;
1829
1830 LttvTraceState *ts;
1831
1832 LttvTracefileState *tfs;
1833
1834
1835 nb_trace = lttv_traceset_number(traceset);
1836 for(i = 0 ; i < nb_trace ; i++) {
1837
1838 ts = (LttvTraceState *)self->parent.traces[i];
1839 nb_tracefile = ts->parent.tracefiles->len;
1840
1841 guint *event_count = g_new(guint, 1);
1842 *event_count = 0;
1843
1844 for(j = 0 ; j < nb_tracefile ; j++) {
1845 tfs =
1846 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1847 LttvTracefileContext*, j));
1848 lttv_hooks_add(tfs->parent.event,
1849 state_save_event_hook,
1850 event_count,
1851 LTTV_PRIO_STATE);
1852
1853 }
1854 }
1855
1856 lttv_process_traceset_begin(&self->parent,
1857 NULL, NULL, NULL, NULL, NULL);
1858
1859}
1860
1861gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1862{
1863 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1864
1865 lttv_state_save_add_event_hooks(tss);
1866
1867 return 0;
1868}
1869
1870
1871#if 0
1872void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1873{
1874 LttvTraceset *traceset = self->parent.ts;
1875
1876 guint i, j, nb_trace, nb_tracefile;
1877
1878 LttvTraceState *ts;
1879
1880 LttvTracefileState *tfs;
1881
1882 LttvTraceHook hook_start, hook_end;
1883
1884 nb_trace = lttv_traceset_number(traceset);
1885 for(i = 0 ; i < nb_trace ; i++) {
1886 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1887
1888 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1889 NULL, NULL, block_start, &hook_start);
1890
1891 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1892 NULL, NULL, block_end, &hook_end);
1893
1894 nb_tracefile = ts->parent.tracefiles->len;
1895
1896 for(j = 0 ; j < nb_tracefile ; j++) {
1897 tfs =
1898 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1899 LttvTracefileContext, j));
1900 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1901 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1902 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1903 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1904 }
1905 }
1906}
1907#endif //0
1908
1909void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1910{
1911 LttvTraceset *traceset = self->parent.ts;
1912
1913 guint i, j, nb_trace, nb_tracefile;
1914
1915 LttvTraceState *ts;
1916
1917 LttvTracefileState *tfs;
1918
1919 LttvHooks *after_trace = lttv_hooks_new();
1920
1921 lttv_hooks_add(after_trace,
1922 state_save_after_trace_hook,
1923 NULL,
1924 LTTV_PRIO_STATE);
1925
1926
1927 lttv_process_traceset_end(&self->parent,
1928 NULL, after_trace, NULL, NULL, NULL);
1929
1930 lttv_hooks_destroy(after_trace);
1931
1932 nb_trace = lttv_traceset_number(traceset);
1933 for(i = 0 ; i < nb_trace ; i++) {
1934
1935 ts = (LttvTraceState *)self->parent.traces[i];
1936 nb_tracefile = ts->parent.tracefiles->len;
1937
1938 guint *event_count = NULL;
1939
1940 for(j = 0 ; j < nb_tracefile ; j++) {
1941 tfs =
1942 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1943 LttvTracefileContext*, j));
1944 event_count = lttv_hooks_remove(tfs->parent.event,
1945 state_save_event_hook);
1946 }
1947 if(event_count) g_free(event_count);
1948 }
1949}
1950
1951gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1952{
1953 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1954
1955 lttv_state_save_remove_event_hooks(tss);
1956
1957 return 0;
1958}
1959
1960void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1961{
1962 LttvTraceset *traceset = self->parent.ts;
1963
1964 guint i, nb_trace;
1965
1966 int min_pos, mid_pos, max_pos;
1967
1968 guint call_rest = 0;
1969
1970 LttvTraceState *tcs;
1971
1972 LttvAttributeValue value;
1973
1974 LttvAttributeType type;
1975
1976 LttvAttributeName name;
1977
1978 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1979
1980 //g_tree_destroy(self->parent.pqueue);
1981 //self->parent.pqueue = g_tree_new(compare_tracefile);
1982
1983 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1984
1985 nb_trace = lttv_traceset_number(traceset);
1986 for(i = 0 ; i < nb_trace ; i++) {
1987 tcs = (LttvTraceState *)self->parent.traces[i];
1988
1989 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1990 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1991 LTTV_STATE_SAVED_STATES);
1992 min_pos = -1;
1993
1994 if(saved_states_tree) {
1995 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1996 mid_pos = max_pos / 2;
1997 while(min_pos < max_pos) {
1998 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1999 g_assert(type == LTTV_GOBJECT);
2000 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2001 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2002 &value);
2003 g_assert(type == LTTV_TIME);
2004 if(ltt_time_compare(*(value.v_time), t) < 0) {
2005 min_pos = mid_pos;
2006 closest_tree = saved_state_tree;
2007 }
2008 else max_pos = mid_pos - 1;
2009
2010 mid_pos = (min_pos + max_pos + 1) / 2;
2011 }
2012 }
2013
2014 /* restore the closest earlier saved state */
2015 if(min_pos != -1) {
2016 lttv_state_restore(tcs, closest_tree);
2017 call_rest = 1;
2018 }
2019
2020 /* There is no saved state, yet we want to have it. Restart at T0 */
2021 else {
2022 restore_init_state(tcs);
2023 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2024 }
2025 }
2026 /* We want to seek quickly without restoring/updating the state */
2027 else {
2028 restore_init_state(tcs);
2029 lttv_process_trace_seek_time(&(tcs->parent), t);
2030 }
2031 }
2032 if(!call_rest) g_info("NOT Calling restore");
2033}
2034
2035
2036static void
2037traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2038{
2039}
2040
2041
2042static void
2043traceset_state_finalize (LttvTracesetState *self)
2044{
2045 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2046 finalize(G_OBJECT(self));
2047}
2048
2049
2050static void
2051traceset_state_class_init (LttvTracesetContextClass *klass)
2052{
2053 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2054
2055 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2056 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2057 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2058 klass->new_traceset_context = new_traceset_context;
2059 klass->new_trace_context = new_trace_context;
2060 klass->new_tracefile_context = new_tracefile_context;
2061}
2062
2063
2064GType
2065lttv_traceset_state_get_type(void)
2066{
2067 static GType type = 0;
2068 if (type == 0) {
2069 static const GTypeInfo info = {
2070 sizeof (LttvTracesetStateClass),
2071 NULL, /* base_init */
2072 NULL, /* base_finalize */
2073 (GClassInitFunc) traceset_state_class_init, /* class_init */
2074 NULL, /* class_finalize */
2075 NULL, /* class_data */
2076 sizeof (LttvTracesetState),
2077 0, /* n_preallocs */
2078 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2079 NULL /* value handling */
2080 };
2081
2082 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2083 &info, 0);
2084 }
2085 return type;
2086}
2087
2088
2089static void
2090trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2091{
2092}
2093
2094
2095static void
2096trace_state_finalize (LttvTraceState *self)
2097{
2098 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2099 finalize(G_OBJECT(self));
2100}
2101
2102
2103static void
2104trace_state_class_init (LttvTraceStateClass *klass)
2105{
2106 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2107
2108 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2109 klass->state_save = state_save;
2110 klass->state_restore = state_restore;
2111 klass->state_saved_free = state_saved_free;
2112}
2113
2114
2115GType
2116lttv_trace_state_get_type(void)
2117{
2118 static GType type = 0;
2119 if (type == 0) {
2120 static const GTypeInfo info = {
2121 sizeof (LttvTraceStateClass),
2122 NULL, /* base_init */
2123 NULL, /* base_finalize */
2124 (GClassInitFunc) trace_state_class_init, /* class_init */
2125 NULL, /* class_finalize */
2126 NULL, /* class_data */
2127 sizeof (LttvTraceState),
2128 0, /* n_preallocs */
2129 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2130 NULL /* value handling */
2131 };
2132
2133 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2134 "LttvTraceStateType", &info, 0);
2135 }
2136 return type;
2137}
2138
2139
2140static void
2141tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2142{
2143}
2144
2145
2146static void
2147tracefile_state_finalize (LttvTracefileState *self)
2148{
2149 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2150 finalize(G_OBJECT(self));
2151}
2152
2153
2154static void
2155tracefile_state_class_init (LttvTracefileStateClass *klass)
2156{
2157 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2158
2159 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2160}
2161
2162
2163GType
2164lttv_tracefile_state_get_type(void)
2165{
2166 static GType type = 0;
2167 if (type == 0) {
2168 static const GTypeInfo info = {
2169 sizeof (LttvTracefileStateClass),
2170 NULL, /* base_init */
2171 NULL, /* base_finalize */
2172 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2173 NULL, /* class_finalize */
2174 NULL, /* class_data */
2175 sizeof (LttvTracefileState),
2176 0, /* n_preallocs */
2177 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2178 NULL /* value handling */
2179 };
2180
2181 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2182 "LttvTracefileStateType", &info, 0);
2183 }
2184 return type;
2185}
2186
2187
2188static void module_init()
2189{
2190 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2191 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
2192 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2193 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2194 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2195 LTTV_STATE_TRAP = g_quark_from_string("trap");
2196 LTTV_STATE_IRQ = g_quark_from_string("irq");
2197 LTTV_STATE_SOFT_IRQ = g_quark_from_string("softirq");
2198 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2199 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
2200 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
2201 LTTV_STATE_EXIT = g_quark_from_string("exiting");
2202 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
2203 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2204 LTTV_STATE_RUN = g_quark_from_string("running");
2205 LTTV_STATE_DEAD = g_quark_from_string("dead");
2206 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2207 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2208 LTTV_STATE_PROCESS = g_quark_from_string("process");
2209 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2210 LTTV_STATE_EVENT = g_quark_from_string("event");
2211 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2212 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2213 LTTV_STATE_TIME = g_quark_from_string("time");
2214 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2215 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2216 LTTV_STATE_TRACE_STATE_USE_COUNT =
2217 g_quark_from_string("trace_state_use_count");
2218
2219
2220 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2221 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2222 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2223 LTT_FACILITY_FS = g_quark_from_string("fs");
2224
2225
2226 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2227 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2228 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2229 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2230 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2231 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2232 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2233 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2234 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2235 LTT_EVENT_FORK = g_quark_from_string("fork");
2236 LTT_EVENT_EXIT = g_quark_from_string("exit");
2237 LTT_EVENT_FREE = g_quark_from_string("free");
2238 LTT_EVENT_EXEC = g_quark_from_string("exec");
2239
2240
2241 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2242 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2243 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2244 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2245 LTT_FIELD_OUT = g_quark_from_string("out");
2246 LTT_FIELD_IN = g_quark_from_string("in");
2247 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2248 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2249 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2250 LTT_FIELD_PID = g_quark_from_string("pid");
2251 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2252
2253}
2254
2255static void module_destroy()
2256{
2257}
2258
2259
2260LTTV_MODULE("state", "State computation", \
2261 "Update the system state, possibly saving it at intervals", \
2262 module_init, module_destroy)
2263
2264
2265
This page took 0.029094 seconds and 4 git commands to generate.