fix problem with time drift and process free : it may happen that a process is still...
[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 //This test is fun, though, as it may happen that
1342 //at time t : CPU 0 : process_free
1343 //at time t+150ns : CPU 1 : schedule out
1344 //Clearly due to time imprecision, we disable it. (Mathieu)
1345 //If this weird case happen, we have no choice but to put the
1346 //Currently running process on the cpu to 0.
1347 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1348 guint i;
1349 for(i=0; i< num_cpus; i++) {
1350 //g_assert(process != ts->running_process[i]);
1351 if(process == ts->running_process[i]) {
1352 ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1353 }
1354 }
1355 exit_process(s, process);
1356 }
1357
1358 return FALSE;
1359 }
1360
1361
1362 static gboolean process_exec(void *hook_data, void *call_data)
1363 {
1364 LttvTracefileState *s = (LttvTracefileState *)call_data;
1365 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1366 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1367 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1368 gchar *name;
1369 guint cpu = ltt_tracefile_num(s->parent.tf);
1370 LttvProcessState *process = ts->running_process[cpu];
1371
1372 /* PID of the process to release */
1373 name = ltt_event_get_string(e, thf->f1);
1374
1375 process->name = g_quark_from_string(name);
1376
1377 return FALSE;
1378 }
1379
1380
1381
1382
1383 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1384 {
1385 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1386
1387 lttv_state_add_event_hooks(tss);
1388
1389 return 0;
1390 }
1391
1392 void lttv_state_add_event_hooks(LttvTracesetState *self)
1393 {
1394 LttvTraceset *traceset = self->parent.ts;
1395
1396 guint i, j, k, l, nb_trace, nb_tracefile;
1397
1398 LttvTraceState *ts;
1399
1400 LttvTracefileState *tfs;
1401
1402 GArray *hooks;
1403
1404 LttvTraceHookByFacility *thf;
1405
1406 LttvTraceHook *hook;
1407
1408 LttvAttributeValue val;
1409
1410 gint ret;
1411
1412 nb_trace = lttv_traceset_number(traceset);
1413 for(i = 0 ; i < nb_trace ; i++) {
1414 ts = (LttvTraceState *)self->parent.traces[i];
1415
1416 /* Find the eventtype id for the following events and register the
1417 associated by id hooks. */
1418
1419 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1420 hooks = g_array_set_size(hooks, 11);
1421
1422 ret = lttv_trace_find_hook(ts->parent.t,
1423 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1424 LTT_FIELD_SYSCALL_ID, 0, 0,
1425 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1426 g_assert(!ret);
1427
1428 ret = lttv_trace_find_hook(ts->parent.t,
1429 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1430 0, 0, 0,
1431 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1432 g_assert(!ret);
1433
1434 ret = lttv_trace_find_hook(ts->parent.t,
1435 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1436 LTT_FIELD_TRAP_ID, 0, 0,
1437 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1438 g_assert(!ret);
1439
1440 ret = lttv_trace_find_hook(ts->parent.t,
1441 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1442 0, 0, 0,
1443 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1444 g_assert(!ret);
1445
1446 ret = lttv_trace_find_hook(ts->parent.t,
1447 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1448 LTT_FIELD_IRQ_ID, 0, 0,
1449 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1450 g_assert(!ret);
1451
1452 ret = lttv_trace_find_hook(ts->parent.t,
1453 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1454 0, 0, 0,
1455 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1456 g_assert(!ret);
1457
1458 ret = lttv_trace_find_hook(ts->parent.t,
1459 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1460 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1461 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1462 g_assert(!ret);
1463
1464 ret = lttv_trace_find_hook(ts->parent.t,
1465 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1466 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1467 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1468 g_assert(!ret);
1469
1470 ret = lttv_trace_find_hook(ts->parent.t,
1471 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1472 LTT_FIELD_PID, 0, 0,
1473 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1474 g_assert(!ret);
1475
1476 ret = lttv_trace_find_hook(ts->parent.t,
1477 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1478 LTT_FIELD_PID, 0, 0,
1479 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1480 g_assert(!ret);
1481
1482 ret = lttv_trace_find_hook(ts->parent.t,
1483 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1484 LTT_FIELD_FILENAME, 0, 0,
1485 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1486 g_assert(!ret);
1487
1488
1489
1490 /* Add these hooks to each event_by_id hooks list */
1491
1492 nb_tracefile = ts->parent.tracefiles->len;
1493
1494 for(j = 0 ; j < nb_tracefile ; j++) {
1495 tfs =
1496 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1497 LttvTracefileContext*, j));
1498
1499 for(k = 0 ; k < hooks->len ; k++) {
1500 hook = &g_array_index(hooks, LttvTraceHook, k);
1501 for(l=0;l<hook->fac_list->len;l++) {
1502 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1503 lttv_hooks_add(
1504 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1505 thf->h,
1506 thf,
1507 LTTV_PRIO_STATE);
1508 }
1509 }
1510 }
1511 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1512 *(val.v_pointer) = hooks;
1513 }
1514 }
1515
1516 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1517 {
1518 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1519
1520 lttv_state_remove_event_hooks(tss);
1521
1522 return 0;
1523 }
1524
1525 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1526 {
1527 LttvTraceset *traceset = self->parent.ts;
1528
1529 guint i, j, k, l, nb_trace, nb_tracefile;
1530
1531 LttvTraceState *ts;
1532
1533 LttvTracefileState *tfs;
1534
1535 GArray *hooks;
1536
1537 LttvTraceHook *hook;
1538
1539 LttvTraceHookByFacility *thf;
1540
1541 LttvAttributeValue val;
1542
1543 nb_trace = lttv_traceset_number(traceset);
1544 for(i = 0 ; i < nb_trace ; i++) {
1545 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1546 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1547 hooks = *(val.v_pointer);
1548
1549 /* Remove these hooks from each event_by_id hooks list */
1550
1551 nb_tracefile = ts->parent.tracefiles->len;
1552
1553 for(j = 0 ; j < nb_tracefile ; j++) {
1554 tfs =
1555 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1556 LttvTracefileContext*, j));
1557
1558 for(k = 0 ; k < hooks->len ; k++) {
1559 hook = &g_array_index(hooks, LttvTraceHook, k);
1560 for(l=0;l<hook->fac_list->len;l++) {
1561 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1562
1563 lttv_hooks_remove_data(
1564 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1565 thf->h,
1566 thf);
1567 }
1568 }
1569 }
1570 for(k = 0 ; k < hooks->len ; k++)
1571 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1572 g_array_free(hooks, TRUE);
1573 }
1574 }
1575
1576 static gboolean state_save_event_hook(void *hook_data, void *call_data)
1577 {
1578 guint *event_count = (guint*)hook_data;
1579
1580 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1581 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1582 return FALSE;
1583 else
1584 *event_count = 0;
1585
1586 LttvTracefileState *self = (LttvTracefileState *)call_data;
1587
1588 LttvTracefileState *tfcs;
1589
1590 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1591
1592 LttEventPosition *ep;
1593
1594 guint i;
1595
1596 LttTracefile *tf;
1597
1598 LttvAttribute *saved_states_tree, *saved_state_tree;
1599
1600 LttvAttributeValue value;
1601
1602 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1603 LTTV_STATE_SAVED_STATES);
1604 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1605 value = lttv_attribute_add(saved_states_tree,
1606 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1607 *(value.v_gobject) = (GObject *)saved_state_tree;
1608 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1609 *(value.v_time) = self->parent.timestamp;
1610 lttv_state_save(tcs, saved_state_tree);
1611 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1612 self->parent.timestamp.tv_nsec);
1613
1614 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1615
1616 return FALSE;
1617 }
1618
1619 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1620 {
1621 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1622
1623 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1624
1625 return FALSE;
1626 }
1627
1628 #if 0
1629 static gboolean block_start(void *hook_data, void *call_data)
1630 {
1631 LttvTracefileState *self = (LttvTracefileState *)call_data;
1632
1633 LttvTracefileState *tfcs;
1634
1635 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1636
1637 LttEventPosition *ep;
1638
1639 guint i, nb_block, nb_event, nb_tracefile;
1640
1641 LttTracefile *tf;
1642
1643 LttvAttribute *saved_states_tree, *saved_state_tree;
1644
1645 LttvAttributeValue value;
1646
1647 ep = ltt_event_position_new();
1648
1649 nb_tracefile = tcs->parent.tracefiles->len;
1650
1651 /* Count the number of events added since the last block end in any
1652 tracefile. */
1653
1654 for(i = 0 ; i < nb_tracefile ; i++) {
1655 tfcs =
1656 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1657 LttvTracefileContext, i));
1658 ltt_event_position(tfcs->parent.e, ep);
1659 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1660 tcs->nb_event += nb_event - tfcs->saved_position;
1661 tfcs->saved_position = nb_event;
1662 }
1663 g_free(ep);
1664
1665 if(tcs->nb_event >= tcs->save_interval) {
1666 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1667 LTTV_STATE_SAVED_STATES);
1668 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1669 value = lttv_attribute_add(saved_states_tree,
1670 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1671 *(value.v_gobject) = (GObject *)saved_state_tree;
1672 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1673 *(value.v_time) = self->parent.timestamp;
1674 lttv_state_save(tcs, saved_state_tree);
1675 tcs->nb_event = 0;
1676 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1677 self->parent.timestamp.tv_nsec);
1678 }
1679 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1680 return FALSE;
1681 }
1682 #endif //0
1683
1684 #if 0
1685 static gboolean block_end(void *hook_data, void *call_data)
1686 {
1687 LttvTracefileState *self = (LttvTracefileState *)call_data;
1688
1689 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1690
1691 LttTracefile *tf;
1692
1693 LttEventPosition *ep;
1694
1695 guint nb_block, nb_event;
1696
1697 ep = ltt_event_position_new();
1698 ltt_event_position(self->parent.e, ep);
1699 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1700 tcs->nb_event += nb_event - self->saved_position + 1;
1701 self->saved_position = 0;
1702 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1703 g_free(ep);
1704
1705 return FALSE;
1706 }
1707 #endif //0
1708 #if 0
1709 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1710 {
1711 LttvTraceset *traceset = self->parent.ts;
1712
1713 guint i, j, nb_trace, nb_tracefile;
1714
1715 LttvTraceState *ts;
1716
1717 LttvTracefileState *tfs;
1718
1719 LttvTraceHook hook_start, hook_end;
1720
1721 nb_trace = lttv_traceset_number(traceset);
1722 for(i = 0 ; i < nb_trace ; i++) {
1723 ts = (LttvTraceState *)self->parent.traces[i];
1724
1725 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1726 NULL, NULL, block_start, &hook_start);
1727 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1728 NULL, NULL, block_end, &hook_end);
1729
1730 nb_tracefile = ts->parent.tracefiles->len;
1731
1732 for(j = 0 ; j < nb_tracefile ; j++) {
1733 tfs =
1734 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1735 LttvTracefileContext, j));
1736 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1737 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1738 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1739 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1740 }
1741 }
1742 }
1743 #endif //0
1744
1745 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1746 {
1747 LttvTraceset *traceset = self->parent.ts;
1748
1749 guint i, j, nb_trace, nb_tracefile;
1750
1751 LttvTraceState *ts;
1752
1753 LttvTracefileState *tfs;
1754
1755
1756 nb_trace = lttv_traceset_number(traceset);
1757 for(i = 0 ; i < nb_trace ; i++) {
1758
1759 ts = (LttvTraceState *)self->parent.traces[i];
1760 nb_tracefile = ts->parent.tracefiles->len;
1761
1762 guint *event_count = g_new(guint, 1);
1763 *event_count = 0;
1764
1765 for(j = 0 ; j < nb_tracefile ; j++) {
1766 tfs =
1767 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1768 LttvTracefileContext*, j));
1769 lttv_hooks_add(tfs->parent.event,
1770 state_save_event_hook,
1771 event_count,
1772 LTTV_PRIO_STATE);
1773
1774 }
1775 }
1776
1777 lttv_process_traceset_begin(&self->parent,
1778 NULL, NULL, NULL, NULL, NULL);
1779
1780 }
1781
1782 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1783 {
1784 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1785
1786 lttv_state_save_add_event_hooks(tss);
1787
1788 return 0;
1789 }
1790
1791
1792 #if 0
1793 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1794 {
1795 LttvTraceset *traceset = self->parent.ts;
1796
1797 guint i, j, nb_trace, nb_tracefile;
1798
1799 LttvTraceState *ts;
1800
1801 LttvTracefileState *tfs;
1802
1803 LttvTraceHook hook_start, hook_end;
1804
1805 nb_trace = lttv_traceset_number(traceset);
1806 for(i = 0 ; i < nb_trace ; i++) {
1807 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1808
1809 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1810 NULL, NULL, block_start, &hook_start);
1811
1812 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1813 NULL, NULL, block_end, &hook_end);
1814
1815 nb_tracefile = ts->parent.tracefiles->len;
1816
1817 for(j = 0 ; j < nb_tracefile ; j++) {
1818 tfs =
1819 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1820 LttvTracefileContext, j));
1821 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1822 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1823 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1824 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1825 }
1826 }
1827 }
1828 #endif //0
1829
1830 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1831 {
1832 LttvTraceset *traceset = self->parent.ts;
1833
1834 guint i, j, nb_trace, nb_tracefile;
1835
1836 LttvTraceState *ts;
1837
1838 LttvTracefileState *tfs;
1839
1840 LttvHooks *after_trace = lttv_hooks_new();
1841
1842 lttv_hooks_add(after_trace,
1843 state_save_after_trace_hook,
1844 NULL,
1845 LTTV_PRIO_STATE);
1846
1847
1848 lttv_process_traceset_end(&self->parent,
1849 NULL, after_trace, NULL, NULL, NULL);
1850
1851 lttv_hooks_destroy(after_trace);
1852
1853 nb_trace = lttv_traceset_number(traceset);
1854 for(i = 0 ; i < nb_trace ; i++) {
1855
1856 ts = (LttvTraceState *)self->parent.traces[i];
1857 nb_tracefile = ts->parent.tracefiles->len;
1858
1859 guint *event_count;
1860
1861 for(j = 0 ; j < nb_tracefile ; j++) {
1862 tfs =
1863 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1864 LttvTracefileContext*, j));
1865 event_count = lttv_hooks_remove(tfs->parent.event,
1866 state_save_event_hook);
1867 }
1868 g_free(event_count);
1869 }
1870 }
1871
1872 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1873 {
1874 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1875
1876 lttv_state_save_remove_event_hooks(tss);
1877
1878 return 0;
1879 }
1880
1881 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1882 {
1883 LttvTraceset *traceset = self->parent.ts;
1884
1885 guint i, nb_trace;
1886
1887 int min_pos, mid_pos, max_pos;
1888
1889 guint call_rest = 0;
1890
1891 LttvTraceState *tcs;
1892
1893 LttvAttributeValue value;
1894
1895 LttvAttributeType type;
1896
1897 LttvAttributeName name;
1898
1899 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1900
1901 //g_tree_destroy(self->parent.pqueue);
1902 //self->parent.pqueue = g_tree_new(compare_tracefile);
1903
1904 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1905
1906 nb_trace = lttv_traceset_number(traceset);
1907 for(i = 0 ; i < nb_trace ; i++) {
1908 tcs = (LttvTraceState *)self->parent.traces[i];
1909
1910 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1911 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1912 LTTV_STATE_SAVED_STATES);
1913 min_pos = -1;
1914
1915 if(saved_states_tree) {
1916 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1917 mid_pos = max_pos / 2;
1918 while(min_pos < max_pos) {
1919 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1920 g_assert(type == LTTV_GOBJECT);
1921 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1922 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1923 &value);
1924 g_assert(type == LTTV_TIME);
1925 if(ltt_time_compare(*(value.v_time), t) < 0) {
1926 min_pos = mid_pos;
1927 closest_tree = saved_state_tree;
1928 }
1929 else max_pos = mid_pos - 1;
1930
1931 mid_pos = (min_pos + max_pos + 1) / 2;
1932 }
1933 }
1934
1935 /* restore the closest earlier saved state */
1936 if(min_pos != -1) {
1937 lttv_state_restore(tcs, closest_tree);
1938 call_rest = 1;
1939 }
1940
1941 /* There is no saved state, yet we want to have it. Restart at T0 */
1942 else {
1943 restore_init_state(tcs);
1944 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1945 }
1946 }
1947 /* We want to seek quickly without restoring/updating the state */
1948 else {
1949 restore_init_state(tcs);
1950 lttv_process_trace_seek_time(&(tcs->parent), t);
1951 }
1952 }
1953 if(!call_rest) g_info("NOT Calling restore");
1954 }
1955
1956
1957 static void
1958 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1959 {
1960 }
1961
1962
1963 static void
1964 traceset_state_finalize (LttvTracesetState *self)
1965 {
1966 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1967 finalize(G_OBJECT(self));
1968 }
1969
1970
1971 static void
1972 traceset_state_class_init (LttvTracesetContextClass *klass)
1973 {
1974 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1975
1976 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1977 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1978 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1979 klass->new_traceset_context = new_traceset_context;
1980 klass->new_trace_context = new_trace_context;
1981 klass->new_tracefile_context = new_tracefile_context;
1982 }
1983
1984
1985 GType
1986 lttv_traceset_state_get_type(void)
1987 {
1988 static GType type = 0;
1989 if (type == 0) {
1990 static const GTypeInfo info = {
1991 sizeof (LttvTracesetStateClass),
1992 NULL, /* base_init */
1993 NULL, /* base_finalize */
1994 (GClassInitFunc) traceset_state_class_init, /* class_init */
1995 NULL, /* class_finalize */
1996 NULL, /* class_data */
1997 sizeof (LttvTracesetState),
1998 0, /* n_preallocs */
1999 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2000 NULL /* value handling */
2001 };
2002
2003 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2004 &info, 0);
2005 }
2006 return type;
2007 }
2008
2009
2010 static void
2011 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2012 {
2013 }
2014
2015
2016 static void
2017 trace_state_finalize (LttvTraceState *self)
2018 {
2019 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2020 finalize(G_OBJECT(self));
2021 }
2022
2023
2024 static void
2025 trace_state_class_init (LttvTraceStateClass *klass)
2026 {
2027 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2028
2029 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2030 klass->state_save = state_save;
2031 klass->state_restore = state_restore;
2032 klass->state_saved_free = state_saved_free;
2033 }
2034
2035
2036 GType
2037 lttv_trace_state_get_type(void)
2038 {
2039 static GType type = 0;
2040 if (type == 0) {
2041 static const GTypeInfo info = {
2042 sizeof (LttvTraceStateClass),
2043 NULL, /* base_init */
2044 NULL, /* base_finalize */
2045 (GClassInitFunc) trace_state_class_init, /* class_init */
2046 NULL, /* class_finalize */
2047 NULL, /* class_data */
2048 sizeof (LttvTraceState),
2049 0, /* n_preallocs */
2050 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2051 NULL /* value handling */
2052 };
2053
2054 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2055 "LttvTraceStateType", &info, 0);
2056 }
2057 return type;
2058 }
2059
2060
2061 static void
2062 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2063 {
2064 }
2065
2066
2067 static void
2068 tracefile_state_finalize (LttvTracefileState *self)
2069 {
2070 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2071 finalize(G_OBJECT(self));
2072 }
2073
2074
2075 static void
2076 tracefile_state_class_init (LttvTracefileStateClass *klass)
2077 {
2078 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2079
2080 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2081 }
2082
2083
2084 GType
2085 lttv_tracefile_state_get_type(void)
2086 {
2087 static GType type = 0;
2088 if (type == 0) {
2089 static const GTypeInfo info = {
2090 sizeof (LttvTracefileStateClass),
2091 NULL, /* base_init */
2092 NULL, /* base_finalize */
2093 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2094 NULL, /* class_finalize */
2095 NULL, /* class_data */
2096 sizeof (LttvTracefileState),
2097 0, /* n_preallocs */
2098 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2099 NULL /* value handling */
2100 };
2101
2102 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2103 "LttvTracefileStateType", &info, 0);
2104 }
2105 return type;
2106 }
2107
2108
2109 static void module_init()
2110 {
2111 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2112 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
2113 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2114 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2115 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2116 LTTV_STATE_TRAP = g_quark_from_string("trap");
2117 LTTV_STATE_IRQ = g_quark_from_string("irq");
2118 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2119 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
2120 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
2121 LTTV_STATE_EXIT = g_quark_from_string("exiting");
2122 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
2123 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2124 LTTV_STATE_RUN = g_quark_from_string("running");
2125 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2126 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2127 LTTV_STATE_PROCESS = g_quark_from_string("process");
2128 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2129 LTTV_STATE_EVENT = g_quark_from_string("event");
2130 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2131 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2132 LTTV_STATE_TIME = g_quark_from_string("time");
2133 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2134 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2135 LTTV_STATE_TRACE_STATE_USE_COUNT =
2136 g_quark_from_string("trace_state_use_count");
2137
2138
2139 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2140 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2141 LTT_FACILITY_FS = g_quark_from_string("fs");
2142
2143
2144 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2145 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2146 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2147 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2148 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2149 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2150 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2151 LTT_EVENT_FORK = g_quark_from_string("fork");
2152 LTT_EVENT_EXIT = g_quark_from_string("exit");
2153 LTT_EVENT_FREE = g_quark_from_string("free");
2154 LTT_EVENT_EXEC = g_quark_from_string("exec");
2155
2156
2157 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2158 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2159 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2160 LTT_FIELD_OUT = g_quark_from_string("out");
2161 LTT_FIELD_IN = g_quark_from_string("in");
2162 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2163 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2164 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2165 LTT_FIELD_PID = g_quark_from_string("pid");
2166 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2167
2168 }
2169
2170 static void module_destroy()
2171 {
2172 }
2173
2174
2175 LTTV_MODULE("state", "State computation", \
2176 "Update the system state, possibly saving it at intervals", \
2177 module_init, module_destroy)
2178
2179
2180
This page took 0.10808 seconds and 4 git commands to generate.