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