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