fix request state computation upon traceset change for detailed event list
[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_KERNEL_ARCH,
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_KERNEL_ARCH, 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 name_tables->syscall_names = g_new(GQuark, nb);
785
786 for(i = 0 ; i < nb ; i++) {
787 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
788 }
789
790 //name_tables->syscall_names = g_new(GQuark, 256);
791 //for(i = 0 ; i < 256 ; i++) {
792 // g_string_printf(fe_name, "syscall %d", i);
793 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
794 //}
795
796 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
797 LTT_EVENT_TRAP_ENTRY,
798 LTT_FIELD_TRAP_ID, 0, 0,
799 NULL, NULL, &h))
800 return;
801
802 thf = lttv_trace_hook_get_first(&h);
803
804 t = ltt_field_type(thf->f1);
805 //nb = ltt_type_element_number(t);
806
807 lttv_trace_hook_destroy(&h);
808
809 /*
810 name_tables->trap_names = g_new(GQuark, nb);
811 for(i = 0 ; i < nb ; i++) {
812 name_tables->trap_names[i] = g_quark_from_string(
813 ltt_enum_string_get(t, i));
814 }
815 */
816
817 name_tables->trap_names = g_new(GQuark, 256);
818 for(i = 0 ; i < 256 ; i++) {
819 g_string_printf(fe_name, "trap %d", i);
820 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
821 }
822
823 if(lttv_trace_find_hook(tcs->parent.t,
824 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
825 LTT_FIELD_IRQ_ID, 0, 0,
826 NULL, NULL, &h))
827 return;
828
829 thf = lttv_trace_hook_get_first(&h);
830
831 t = ltt_field_type(thf->f1);
832 //nb = ltt_type_element_number(t);
833
834 lttv_trace_hook_destroy(&h);
835
836 /*
837 name_tables->irq_names = g_new(GQuark, nb);
838 for(i = 0 ; i < nb ; i++) {
839 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
840 }
841 */
842
843 name_tables->irq_names = g_new(GQuark, 256);
844 for(i = 0 ; i < 256 ; i++) {
845 g_string_printf(fe_name, "irq %d", i);
846 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
847 }
848
849 g_string_free(fe_name, TRUE);
850 }
851
852
853 static void
854 get_name_tables(LttvTraceState *tcs)
855 {
856 LttvNameTables *name_tables;
857
858 LttvAttributeValue v;
859
860 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
861 LTTV_POINTER, &v);
862 g_assert(*(v.v_pointer) != NULL);
863 name_tables = (LttvNameTables *)*(v.v_pointer);
864 //tcs->eventtype_names = name_tables->eventtype_names;
865 tcs->syscall_names = name_tables->syscall_names;
866 tcs->trap_names = name_tables->trap_names;
867 tcs->irq_names = name_tables->irq_names;
868 }
869
870
871 static void
872 free_name_tables(LttvTraceState *tcs)
873 {
874 LttvNameTables *name_tables;
875
876 LttvAttributeValue v;
877
878 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
879 LTTV_POINTER, &v);
880 name_tables = (LttvNameTables *)*(v.v_pointer);
881 *(v.v_pointer) = NULL;
882
883 // g_free(name_tables->eventtype_names);
884 g_free(name_tables->syscall_names);
885 g_free(name_tables->trap_names);
886 g_free(name_tables->irq_names);
887 g_free(name_tables);
888 }
889
890 #ifdef HASH_TABLE_DEBUG
891
892 static void test_process(gpointer key, gpointer value, gpointer user_data)
893 {
894 LttvProcessState *process = (LttvProcessState *)value;
895
896 /* Test for process corruption */
897 guint stack_len = process->execution_stack->len;
898 }
899
900 static void hash_table_check(GHashTable *table)
901 {
902 g_hash_table_foreach(table, test_process, NULL);
903 }
904
905
906 #endif
907
908
909 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
910 guint state_id)
911 {
912 LttvExecutionState *es;
913
914 guint cpu = ltt_tracefile_num(tfs->parent.tf);
915 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
916
917 #ifdef HASH_TABLE_DEBUG
918 hash_table_check(ts->processes);
919 #endif
920 LttvProcessState *process = ts->running_process[cpu];
921
922 guint depth = process->execution_stack->len;
923
924 process->execution_stack =
925 g_array_set_size(process->execution_stack, depth + 1);
926 /* Keep in sync */
927 process->state =
928 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
929
930 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
931 es->t = t;
932 es->n = state_id;
933 es->entry = es->change = tfs->parent.timestamp;
934 es->s = process->state->s;
935 process->state = es;
936 }
937
938
939 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
940 {
941 guint cpu = ltt_tracefile_num(tfs->parent.tf);
942 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
943 LttvProcessState *process = ts->running_process[cpu];
944
945 guint depth = process->execution_stack->len;
946
947 if(process->state->t != t){
948 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
949 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
950 g_info("process state has %s when pop_int is %s\n",
951 g_quark_to_string(process->state->t),
952 g_quark_to_string(t));
953 g_info("{ %u, %u, %s, %s }\n",
954 process->pid,
955 process->ppid,
956 g_quark_to_string(process->name),
957 g_quark_to_string(process->state->s));
958 return;
959 }
960
961 if(depth == 1){
962 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
963 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
964 return;
965 }
966
967 process->execution_stack =
968 g_array_set_size(process->execution_stack, depth - 1);
969 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
970 depth - 2);
971 process->state->change = tfs->parent.timestamp;
972 }
973
974
975 LttvProcessState *
976 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
977 guint cpu, guint pid, const LttTime *timestamp)
978 {
979 LttvProcessState *process = g_new(LttvProcessState, 1);
980
981 LttvExecutionState *es;
982
983 LttvTraceContext *tc = (LttvTraceContext*)tcs;
984
985 char buffer[128];
986
987 process->pid = pid;
988 process->cpu = cpu;
989 //process->last_cpu = tfs->cpu_name;
990 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
991 g_info("Process %u, core %p", process->pid, process);
992 g_hash_table_insert(tcs->processes, process, process);
993
994 if(parent) {
995 process->ppid = parent->pid;
996 process->name = parent->name;
997 process->creation_time = *timestamp;
998 }
999
1000 /* No parent. This process exists but we are missing all information about
1001 its creation. The birth time is set to zero but we remember the time of
1002 insertion */
1003
1004 else {
1005 process->ppid = 0;
1006 process->name = LTTV_STATE_UNNAMED;
1007 process->creation_time = ltt_time_zero;
1008 }
1009
1010 process->insertion_time = *timestamp;
1011 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1012 process->creation_time.tv_nsec);
1013 process->pid_time = g_quark_from_string(buffer);
1014 process->cpu = cpu;
1015 //process->last_cpu = tfs->cpu_name;
1016 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1017 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1018 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1019 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1020 es = process->state = &g_array_index(process->execution_stack,
1021 LttvExecutionState, 0);
1022 es->t = LTTV_STATE_USER_MODE;
1023 es->n = LTTV_STATE_SUBMODE_NONE;
1024 es->entry = *timestamp;
1025 //g_assert(timestamp->tv_sec != 0);
1026 es->change = *timestamp;
1027 es->s = LTTV_STATE_RUN;
1028
1029 es = process->state = &g_array_index(process->execution_stack,
1030 LttvExecutionState, 1);
1031 es->t = LTTV_STATE_SYSCALL;
1032 es->n = LTTV_STATE_SUBMODE_NONE;
1033 es->entry = *timestamp;
1034 //g_assert(timestamp->tv_sec != 0);
1035 es->change = *timestamp;
1036 es->s = LTTV_STATE_WAIT_FORK;
1037
1038 return process;
1039 }
1040
1041 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1042 guint pid)
1043 {
1044 LttvProcessState key;
1045 LttvProcessState *process;
1046
1047 key.pid = pid;
1048 key.cpu = cpu;
1049 process = g_hash_table_lookup(ts->processes, &key);
1050 return process;
1051 }
1052
1053 LttvProcessState *
1054 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1055 LttTime *timestamp)
1056 {
1057 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1058
1059 /* Put ltt_time_zero creation time for unexisting processes */
1060 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1061 NULL, cpu, pid, timestamp);
1062 return process;
1063 }
1064
1065 /* FIXME : this function should be called when we receive an event telling that
1066 * release_task has been called in the kernel. In happens generally when
1067 * the parent waits for its child terminaison, but may also happen in special
1068 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1069 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1070 * of a killed thread ground, but isn't the leader.
1071 */
1072 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1073 {
1074 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1075 LttvProcessState key;
1076
1077 key.pid = process->pid;
1078 key.cpu = process->cpu;
1079 g_hash_table_remove(ts->processes, &key);
1080 g_array_free(process->execution_stack, TRUE);
1081 g_free(process);
1082 }
1083
1084
1085 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1086 {
1087 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1088 g_free(value);
1089 }
1090
1091
1092 static void lttv_state_free_process_table(GHashTable *processes)
1093 {
1094 g_hash_table_foreach(processes, free_process_state, NULL);
1095 g_hash_table_destroy(processes);
1096 }
1097
1098
1099 static gboolean syscall_entry(void *hook_data, void *call_data)
1100 {
1101 LttvTracefileState *s = (LttvTracefileState *)call_data;
1102 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1103 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1104 LttField *f = thf->f1;
1105
1106 LttvExecutionSubmode submode;
1107
1108 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1109 ltt_event_get_unsigned(e, f)];
1110 push_state(s, LTTV_STATE_SYSCALL, submode);
1111 return FALSE;
1112 }
1113
1114
1115 static gboolean syscall_exit(void *hook_data, void *call_data)
1116 {
1117 LttvTracefileState *s = (LttvTracefileState *)call_data;
1118
1119 pop_state(s, LTTV_STATE_SYSCALL);
1120 return FALSE;
1121 }
1122
1123
1124 static gboolean trap_entry(void *hook_data, void *call_data)
1125 {
1126 LttvTracefileState *s = (LttvTracefileState *)call_data;
1127 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1128 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1129 LttField *f = thf->f1;
1130
1131 LttvExecutionSubmode submode;
1132
1133 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1134 ltt_event_get_unsigned(e, f)];
1135 push_state(s, LTTV_STATE_TRAP, submode);
1136 return FALSE;
1137 }
1138
1139
1140 static gboolean trap_exit(void *hook_data, void *call_data)
1141 {
1142 LttvTracefileState *s = (LttvTracefileState *)call_data;
1143
1144 pop_state(s, LTTV_STATE_TRAP);
1145 return FALSE;
1146 }
1147
1148
1149 static gboolean irq_entry(void *hook_data, void *call_data)
1150 {
1151 LttvTracefileState *s = (LttvTracefileState *)call_data;
1152 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1153 guint8 fac_id = ltt_event_facility_id(e);
1154 guint8 ev_id = ltt_event_eventtype_id(e);
1155 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1156 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1157 g_assert(thf->f1 != NULL);
1158 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1159 LttField *f = thf->f1;
1160
1161 LttvExecutionSubmode submode;
1162
1163 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1164 ltt_event_get_unsigned(e, f)];
1165
1166 /* Do something with the info about being in user or system mode when int? */
1167 push_state(s, LTTV_STATE_IRQ, submode);
1168 return FALSE;
1169 }
1170
1171
1172 static gboolean irq_exit(void *hook_data, void *call_data)
1173 {
1174 LttvTracefileState *s = (LttvTracefileState *)call_data;
1175
1176 pop_state(s, LTTV_STATE_IRQ);
1177 return FALSE;
1178 }
1179
1180
1181 static gboolean schedchange(void *hook_data, void *call_data)
1182 {
1183 LttvTracefileState *s = (LttvTracefileState *)call_data;
1184 guint cpu = ltt_tracefile_num(s->parent.tf);
1185 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1186 LttvProcessState *process = ts->running_process[cpu];
1187
1188 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1189 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1190 guint pid_in, pid_out;
1191 gint state_out;
1192
1193 pid_out = ltt_event_get_unsigned(e, thf->f1);
1194 pid_in = ltt_event_get_unsigned(e, thf->f2);
1195 state_out = ltt_event_get_int(e, thf->f3);
1196
1197 if(likely(process != NULL)) {
1198
1199 /* We could not know but it was not the idle process executing.
1200 This should only happen at the beginning, before the first schedule
1201 event, and when the initial information (current process for each CPU)
1202 is missing. It is not obvious how we could, after the fact, compensate
1203 the wrongly attributed statistics. */
1204
1205 //This test only makes sense once the state is known and if there is no
1206 //missing events.
1207 //if(unlikely(process->pid != pid_out)) {
1208 // g_assert(process->pid == 0);
1209 //}
1210
1211 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1212 process->state->s = LTTV_STATE_ZOMBIE;
1213 process->state->change = s->parent.timestamp;
1214 } else {
1215 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1216 else process->state->s = LTTV_STATE_WAIT;
1217 process->state->change = s->parent.timestamp;
1218 }
1219
1220 if(state_out == 32)
1221 exit_process(s, process); /* EXIT_DEAD */
1222 /* see sched.h for states */
1223 }
1224 process = ts->running_process[cpu] =
1225 lttv_state_find_process_or_create(
1226 (LttvTraceState*)s->parent.t_context,
1227 cpu, pid_in,
1228 &s->parent.timestamp);
1229 process->state->s = LTTV_STATE_RUN;
1230 process->cpu = cpu;
1231 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1232 process->state->change = s->parent.timestamp;
1233 return FALSE;
1234 }
1235
1236 static gboolean process_fork(void *hook_data, void *call_data)
1237 {
1238 LttvTracefileState *s = (LttvTracefileState *)call_data;
1239 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1240 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1241 LttField *f;
1242 guint parent_pid;
1243 guint child_pid;
1244 LttvProcessState *zombie_process;
1245 guint cpu = ltt_tracefile_num(s->parent.tf);
1246 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1247 LttvProcessState *process = ts->running_process[cpu];
1248 LttvProcessState *child_process;
1249
1250 /* Parent PID */
1251 f = thf->f1;
1252 parent_pid = ltt_event_get_unsigned(e, f);
1253
1254 /* Child PID */
1255 f = thf->f2;
1256 child_pid = ltt_event_get_unsigned(e, f);
1257
1258 /* Mathieu : it seems like the process might have been scheduled in before the
1259 * fork, and, in a rare case, might be the current process. This might happen
1260 * in a SMP case where we don't have enough precision on the clocks.
1261 *
1262 * Test reenabled after precision fixes on time. (Mathieu) */
1263 #if 0
1264 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1265
1266 if(unlikely(zombie_process != NULL)) {
1267 /* Reutilisation of PID. Only now we are sure that the old PID
1268 * has been released. FIXME : should know when release_task happens instead.
1269 */
1270 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1271 guint i;
1272 for(i=0; i< num_cpus; i++) {
1273 g_assert(zombie_process != ts->running_process[i]);
1274 }
1275
1276 exit_process(s, zombie_process);
1277 }
1278 #endif //0
1279 g_assert(process->pid != child_pid);
1280 // FIXME : Add this test in the "known state" section
1281 // g_assert(process->pid == parent_pid);
1282 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1283 if(child_process == NULL) {
1284 lttv_state_create_process(ts, process, cpu,
1285 child_pid, &s->parent.timestamp);
1286 } else {
1287 /* The process has already been created : due to time imprecision between
1288 * multiple CPUs : it has been scheduled in before creation. Note that we
1289 * shouldn't have this kind of imprecision.
1290 *
1291 * Simply put a correct parent.
1292 */
1293 g_assert(0); /* This is a problematic case : the process has been created
1294 before the fork event */
1295 child_process->ppid = process->pid;
1296 }
1297
1298 return FALSE;
1299 }
1300
1301
1302 static gboolean process_exit(void *hook_data, void *call_data)
1303 {
1304 LttvTracefileState *s = (LttvTracefileState *)call_data;
1305 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1306 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1307 LttField *f;
1308 guint pid;
1309 guint cpu = ltt_tracefile_num(s->parent.tf);
1310 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1311 LttvProcessState *process = ts->running_process[cpu];
1312
1313 pid = ltt_event_get_unsigned(e, thf->f1);
1314
1315 // FIXME : Add this test in the "known state" section
1316 // g_assert(process->pid == pid);
1317
1318 if(likely(process != NULL)) {
1319 process->state->s = LTTV_STATE_EXIT;
1320 }
1321 return FALSE;
1322 }
1323
1324 static gboolean process_free(void *hook_data, void *call_data)
1325 {
1326 LttvTracefileState *s = (LttvTracefileState *)call_data;
1327 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1328 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1329 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1330 guint release_pid;
1331 LttvProcessState *process;
1332
1333 /* PID of the process to release */
1334 release_pid = ltt_event_get_unsigned(e, thf->f1);
1335
1336 g_assert(release_pid != 0);
1337
1338 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1339
1340 if(likely(process != NULL)) {
1341 /* release_task is happening at kernel level : we can now safely release
1342 * the data structure of the process */
1343 //This test is fun, though, as it may happen that
1344 //at time t : CPU 0 : process_free
1345 //at time t+150ns : CPU 1 : schedule out
1346 //Clearly due to time imprecision, we disable it. (Mathieu)
1347 //If this weird case happen, we have no choice but to put the
1348 //Currently running process on the cpu to 0.
1349 //I re-enable it following time precision fixes. (Mathieu)
1350 //Well, in the case where an process is freed by a process on another CPU
1351 //and still scheduled, it happens that this is the schedchange that will
1352 //drop the last reference count. Do not free it here!
1353 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1354 guint i;
1355 for(i=0; i< num_cpus; i++) {
1356 //g_assert(process != ts->running_process[i]);
1357 if(process == ts->running_process[i]) {
1358 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1359 break;
1360 }
1361 }
1362 if(i == num_cpus) /* process is not scheduled */
1363 exit_process(s, process);
1364 }
1365
1366 return FALSE;
1367 }
1368
1369
1370 static gboolean process_exec(void *hook_data, void *call_data)
1371 {
1372 LttvTracefileState *s = (LttvTracefileState *)call_data;
1373 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1374 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1375 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1376 //gchar *name;
1377 guint cpu = ltt_tracefile_num(s->parent.tf);
1378 LttvProcessState *process = ts->running_process[cpu];
1379
1380 /* PID of the process to release */
1381 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1382 //name = ltt_event_get_string(e, thf->f1);
1383 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1384 gchar *name_begin =
1385 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1386 gchar *null_term_name = g_new(gchar, name_len+1);
1387 memcpy(null_term_name, name_begin, name_len);
1388 null_term_name[name_len] = '\0';
1389
1390 process->name = g_quark_from_string(null_term_name);
1391 g_free(null_term_name);
1392 return FALSE;
1393 }
1394
1395
1396
1397
1398 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1399 {
1400 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1401
1402 lttv_state_add_event_hooks(tss);
1403
1404 return 0;
1405 }
1406
1407 void lttv_state_add_event_hooks(LttvTracesetState *self)
1408 {
1409 LttvTraceset *traceset = self->parent.ts;
1410
1411 guint i, j, k, l, nb_trace, nb_tracefile;
1412
1413 LttvTraceState *ts;
1414
1415 LttvTracefileState *tfs;
1416
1417 GArray *hooks;
1418
1419 LttvTraceHookByFacility *thf;
1420
1421 LttvTraceHook *hook;
1422
1423 LttvAttributeValue val;
1424
1425 gint ret;
1426
1427 nb_trace = lttv_traceset_number(traceset);
1428 for(i = 0 ; i < nb_trace ; i++) {
1429 ts = (LttvTraceState *)self->parent.traces[i];
1430
1431 /* Find the eventtype id for the following events and register the
1432 associated by id hooks. */
1433
1434 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1435 hooks = g_array_set_size(hooks, 11);
1436
1437 ret = lttv_trace_find_hook(ts->parent.t,
1438 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1439 LTT_FIELD_SYSCALL_ID, 0, 0,
1440 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1441 g_assert(!ret);
1442
1443 ret = lttv_trace_find_hook(ts->parent.t,
1444 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1445 0, 0, 0,
1446 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1447 g_assert(!ret);
1448
1449 ret = lttv_trace_find_hook(ts->parent.t,
1450 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1451 LTT_FIELD_TRAP_ID, 0, 0,
1452 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1453 g_assert(!ret);
1454
1455 ret = lttv_trace_find_hook(ts->parent.t,
1456 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1457 0, 0, 0,
1458 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1459 g_assert(!ret);
1460
1461 ret = lttv_trace_find_hook(ts->parent.t,
1462 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1463 LTT_FIELD_IRQ_ID, 0, 0,
1464 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1465 g_assert(!ret);
1466
1467 ret = lttv_trace_find_hook(ts->parent.t,
1468 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1469 0, 0, 0,
1470 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1471 g_assert(!ret);
1472
1473 ret = lttv_trace_find_hook(ts->parent.t,
1474 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1475 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1476 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1477 g_assert(!ret);
1478
1479 ret = lttv_trace_find_hook(ts->parent.t,
1480 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1481 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1482 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1483 g_assert(!ret);
1484
1485 ret = lttv_trace_find_hook(ts->parent.t,
1486 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1487 LTT_FIELD_PID, 0, 0,
1488 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1489 g_assert(!ret);
1490
1491 ret = lttv_trace_find_hook(ts->parent.t,
1492 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1493 LTT_FIELD_PID, 0, 0,
1494 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1495 g_assert(!ret);
1496
1497 ret = lttv_trace_find_hook(ts->parent.t,
1498 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1499 LTT_FIELD_FILENAME, 0, 0,
1500 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1501 g_assert(!ret);
1502
1503
1504
1505 /* Add these hooks to each event_by_id hooks list */
1506
1507 nb_tracefile = ts->parent.tracefiles->len;
1508
1509 for(j = 0 ; j < nb_tracefile ; j++) {
1510 tfs =
1511 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1512 LttvTracefileContext*, j));
1513
1514 for(k = 0 ; k < hooks->len ; k++) {
1515 hook = &g_array_index(hooks, LttvTraceHook, k);
1516 for(l=0;l<hook->fac_list->len;l++) {
1517 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1518 lttv_hooks_add(
1519 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1520 thf->h,
1521 thf,
1522 LTTV_PRIO_STATE);
1523 }
1524 }
1525 }
1526 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1527 *(val.v_pointer) = hooks;
1528 }
1529 }
1530
1531 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1532 {
1533 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1534
1535 lttv_state_remove_event_hooks(tss);
1536
1537 return 0;
1538 }
1539
1540 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1541 {
1542 LttvTraceset *traceset = self->parent.ts;
1543
1544 guint i, j, k, l, nb_trace, nb_tracefile;
1545
1546 LttvTraceState *ts;
1547
1548 LttvTracefileState *tfs;
1549
1550 GArray *hooks;
1551
1552 LttvTraceHook *hook;
1553
1554 LttvTraceHookByFacility *thf;
1555
1556 LttvAttributeValue val;
1557
1558 nb_trace = lttv_traceset_number(traceset);
1559 for(i = 0 ; i < nb_trace ; i++) {
1560 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1561 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1562 hooks = *(val.v_pointer);
1563
1564 /* Remove these hooks from each event_by_id hooks list */
1565
1566 nb_tracefile = ts->parent.tracefiles->len;
1567
1568 for(j = 0 ; j < nb_tracefile ; j++) {
1569 tfs =
1570 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1571 LttvTracefileContext*, j));
1572
1573 for(k = 0 ; k < hooks->len ; k++) {
1574 hook = &g_array_index(hooks, LttvTraceHook, k);
1575 for(l=0;l<hook->fac_list->len;l++) {
1576 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1577
1578 lttv_hooks_remove_data(
1579 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1580 thf->h,
1581 thf);
1582 }
1583 }
1584 }
1585 for(k = 0 ; k < hooks->len ; k++)
1586 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1587 g_array_free(hooks, TRUE);
1588 }
1589 }
1590
1591 static gboolean state_save_event_hook(void *hook_data, void *call_data)
1592 {
1593 guint *event_count = (guint*)hook_data;
1594
1595 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1596 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1597 return FALSE;
1598 else
1599 *event_count = 0;
1600
1601 LttvTracefileState *self = (LttvTracefileState *)call_data;
1602
1603 LttvTracefileState *tfcs;
1604
1605 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1606
1607 LttEventPosition *ep;
1608
1609 guint i;
1610
1611 LttTracefile *tf;
1612
1613 LttvAttribute *saved_states_tree, *saved_state_tree;
1614
1615 LttvAttributeValue value;
1616
1617 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1618 LTTV_STATE_SAVED_STATES);
1619 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1620 value = lttv_attribute_add(saved_states_tree,
1621 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1622 *(value.v_gobject) = (GObject *)saved_state_tree;
1623 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1624 *(value.v_time) = self->parent.timestamp;
1625 lttv_state_save(tcs, saved_state_tree);
1626 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1627 self->parent.timestamp.tv_nsec);
1628
1629 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1630
1631 return FALSE;
1632 }
1633
1634 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1635 {
1636 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1637
1638 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1639
1640 return FALSE;
1641 }
1642
1643 #if 0
1644 static gboolean block_start(void *hook_data, void *call_data)
1645 {
1646 LttvTracefileState *self = (LttvTracefileState *)call_data;
1647
1648 LttvTracefileState *tfcs;
1649
1650 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1651
1652 LttEventPosition *ep;
1653
1654 guint i, nb_block, nb_event, nb_tracefile;
1655
1656 LttTracefile *tf;
1657
1658 LttvAttribute *saved_states_tree, *saved_state_tree;
1659
1660 LttvAttributeValue value;
1661
1662 ep = ltt_event_position_new();
1663
1664 nb_tracefile = tcs->parent.tracefiles->len;
1665
1666 /* Count the number of events added since the last block end in any
1667 tracefile. */
1668
1669 for(i = 0 ; i < nb_tracefile ; i++) {
1670 tfcs =
1671 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1672 LttvTracefileContext, i));
1673 ltt_event_position(tfcs->parent.e, ep);
1674 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1675 tcs->nb_event += nb_event - tfcs->saved_position;
1676 tfcs->saved_position = nb_event;
1677 }
1678 g_free(ep);
1679
1680 if(tcs->nb_event >= tcs->save_interval) {
1681 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1682 LTTV_STATE_SAVED_STATES);
1683 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1684 value = lttv_attribute_add(saved_states_tree,
1685 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1686 *(value.v_gobject) = (GObject *)saved_state_tree;
1687 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1688 *(value.v_time) = self->parent.timestamp;
1689 lttv_state_save(tcs, saved_state_tree);
1690 tcs->nb_event = 0;
1691 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1692 self->parent.timestamp.tv_nsec);
1693 }
1694 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1695 return FALSE;
1696 }
1697 #endif //0
1698
1699 #if 0
1700 static gboolean block_end(void *hook_data, void *call_data)
1701 {
1702 LttvTracefileState *self = (LttvTracefileState *)call_data;
1703
1704 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1705
1706 LttTracefile *tf;
1707
1708 LttEventPosition *ep;
1709
1710 guint nb_block, nb_event;
1711
1712 ep = ltt_event_position_new();
1713 ltt_event_position(self->parent.e, ep);
1714 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1715 tcs->nb_event += nb_event - self->saved_position + 1;
1716 self->saved_position = 0;
1717 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1718 g_free(ep);
1719
1720 return FALSE;
1721 }
1722 #endif //0
1723 #if 0
1724 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1725 {
1726 LttvTraceset *traceset = self->parent.ts;
1727
1728 guint i, j, nb_trace, nb_tracefile;
1729
1730 LttvTraceState *ts;
1731
1732 LttvTracefileState *tfs;
1733
1734 LttvTraceHook hook_start, hook_end;
1735
1736 nb_trace = lttv_traceset_number(traceset);
1737 for(i = 0 ; i < nb_trace ; i++) {
1738 ts = (LttvTraceState *)self->parent.traces[i];
1739
1740 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1741 NULL, NULL, block_start, &hook_start);
1742 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1743 NULL, NULL, block_end, &hook_end);
1744
1745 nb_tracefile = ts->parent.tracefiles->len;
1746
1747 for(j = 0 ; j < nb_tracefile ; j++) {
1748 tfs =
1749 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1750 LttvTracefileContext, j));
1751 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1752 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1753 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1754 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1755 }
1756 }
1757 }
1758 #endif //0
1759
1760 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1761 {
1762 LttvTraceset *traceset = self->parent.ts;
1763
1764 guint i, j, nb_trace, nb_tracefile;
1765
1766 LttvTraceState *ts;
1767
1768 LttvTracefileState *tfs;
1769
1770
1771 nb_trace = lttv_traceset_number(traceset);
1772 for(i = 0 ; i < nb_trace ; i++) {
1773
1774 ts = (LttvTraceState *)self->parent.traces[i];
1775 nb_tracefile = ts->parent.tracefiles->len;
1776
1777 guint *event_count = g_new(guint, 1);
1778 *event_count = 0;
1779
1780 for(j = 0 ; j < nb_tracefile ; j++) {
1781 tfs =
1782 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1783 LttvTracefileContext*, j));
1784 lttv_hooks_add(tfs->parent.event,
1785 state_save_event_hook,
1786 event_count,
1787 LTTV_PRIO_STATE);
1788
1789 }
1790 }
1791
1792 lttv_process_traceset_begin(&self->parent,
1793 NULL, NULL, NULL, NULL, NULL);
1794
1795 }
1796
1797 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1798 {
1799 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1800
1801 lttv_state_save_add_event_hooks(tss);
1802
1803 return 0;
1804 }
1805
1806
1807 #if 0
1808 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1809 {
1810 LttvTraceset *traceset = self->parent.ts;
1811
1812 guint i, j, nb_trace, nb_tracefile;
1813
1814 LttvTraceState *ts;
1815
1816 LttvTracefileState *tfs;
1817
1818 LttvTraceHook hook_start, hook_end;
1819
1820 nb_trace = lttv_traceset_number(traceset);
1821 for(i = 0 ; i < nb_trace ; i++) {
1822 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1823
1824 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1825 NULL, NULL, block_start, &hook_start);
1826
1827 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1828 NULL, NULL, block_end, &hook_end);
1829
1830 nb_tracefile = ts->parent.tracefiles->len;
1831
1832 for(j = 0 ; j < nb_tracefile ; j++) {
1833 tfs =
1834 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1835 LttvTracefileContext, j));
1836 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1837 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1838 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1839 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1840 }
1841 }
1842 }
1843 #endif //0
1844
1845 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1846 {
1847 LttvTraceset *traceset = self->parent.ts;
1848
1849 guint i, j, nb_trace, nb_tracefile;
1850
1851 LttvTraceState *ts;
1852
1853 LttvTracefileState *tfs;
1854
1855 LttvHooks *after_trace = lttv_hooks_new();
1856
1857 lttv_hooks_add(after_trace,
1858 state_save_after_trace_hook,
1859 NULL,
1860 LTTV_PRIO_STATE);
1861
1862
1863 lttv_process_traceset_end(&self->parent,
1864 NULL, after_trace, NULL, NULL, NULL);
1865
1866 lttv_hooks_destroy(after_trace);
1867
1868 nb_trace = lttv_traceset_number(traceset);
1869 for(i = 0 ; i < nb_trace ; i++) {
1870
1871 ts = (LttvTraceState *)self->parent.traces[i];
1872 nb_tracefile = ts->parent.tracefiles->len;
1873
1874 guint *event_count = NULL;
1875
1876 for(j = 0 ; j < nb_tracefile ; j++) {
1877 tfs =
1878 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1879 LttvTracefileContext*, j));
1880 event_count = lttv_hooks_remove(tfs->parent.event,
1881 state_save_event_hook);
1882 }
1883 if(event_count) g_free(event_count);
1884 }
1885 }
1886
1887 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1888 {
1889 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1890
1891 lttv_state_save_remove_event_hooks(tss);
1892
1893 return 0;
1894 }
1895
1896 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1897 {
1898 LttvTraceset *traceset = self->parent.ts;
1899
1900 guint i, nb_trace;
1901
1902 int min_pos, mid_pos, max_pos;
1903
1904 guint call_rest = 0;
1905
1906 LttvTraceState *tcs;
1907
1908 LttvAttributeValue value;
1909
1910 LttvAttributeType type;
1911
1912 LttvAttributeName name;
1913
1914 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1915
1916 //g_tree_destroy(self->parent.pqueue);
1917 //self->parent.pqueue = g_tree_new(compare_tracefile);
1918
1919 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1920
1921 nb_trace = lttv_traceset_number(traceset);
1922 for(i = 0 ; i < nb_trace ; i++) {
1923 tcs = (LttvTraceState *)self->parent.traces[i];
1924
1925 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1926 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1927 LTTV_STATE_SAVED_STATES);
1928 min_pos = -1;
1929
1930 if(saved_states_tree) {
1931 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1932 mid_pos = max_pos / 2;
1933 while(min_pos < max_pos) {
1934 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1935 g_assert(type == LTTV_GOBJECT);
1936 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1937 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1938 &value);
1939 g_assert(type == LTTV_TIME);
1940 if(ltt_time_compare(*(value.v_time), t) < 0) {
1941 min_pos = mid_pos;
1942 closest_tree = saved_state_tree;
1943 }
1944 else max_pos = mid_pos - 1;
1945
1946 mid_pos = (min_pos + max_pos + 1) / 2;
1947 }
1948 }
1949
1950 /* restore the closest earlier saved state */
1951 if(min_pos != -1) {
1952 lttv_state_restore(tcs, closest_tree);
1953 call_rest = 1;
1954 }
1955
1956 /* There is no saved state, yet we want to have it. Restart at T0 */
1957 else {
1958 restore_init_state(tcs);
1959 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1960 }
1961 }
1962 /* We want to seek quickly without restoring/updating the state */
1963 else {
1964 restore_init_state(tcs);
1965 lttv_process_trace_seek_time(&(tcs->parent), t);
1966 }
1967 }
1968 if(!call_rest) g_info("NOT Calling restore");
1969 }
1970
1971
1972 static void
1973 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1974 {
1975 }
1976
1977
1978 static void
1979 traceset_state_finalize (LttvTracesetState *self)
1980 {
1981 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1982 finalize(G_OBJECT(self));
1983 }
1984
1985
1986 static void
1987 traceset_state_class_init (LttvTracesetContextClass *klass)
1988 {
1989 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1990
1991 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1992 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1993 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1994 klass->new_traceset_context = new_traceset_context;
1995 klass->new_trace_context = new_trace_context;
1996 klass->new_tracefile_context = new_tracefile_context;
1997 }
1998
1999
2000 GType
2001 lttv_traceset_state_get_type(void)
2002 {
2003 static GType type = 0;
2004 if (type == 0) {
2005 static const GTypeInfo info = {
2006 sizeof (LttvTracesetStateClass),
2007 NULL, /* base_init */
2008 NULL, /* base_finalize */
2009 (GClassInitFunc) traceset_state_class_init, /* class_init */
2010 NULL, /* class_finalize */
2011 NULL, /* class_data */
2012 sizeof (LttvTracesetState),
2013 0, /* n_preallocs */
2014 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2015 NULL /* value handling */
2016 };
2017
2018 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2019 &info, 0);
2020 }
2021 return type;
2022 }
2023
2024
2025 static void
2026 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2027 {
2028 }
2029
2030
2031 static void
2032 trace_state_finalize (LttvTraceState *self)
2033 {
2034 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2035 finalize(G_OBJECT(self));
2036 }
2037
2038
2039 static void
2040 trace_state_class_init (LttvTraceStateClass *klass)
2041 {
2042 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2043
2044 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2045 klass->state_save = state_save;
2046 klass->state_restore = state_restore;
2047 klass->state_saved_free = state_saved_free;
2048 }
2049
2050
2051 GType
2052 lttv_trace_state_get_type(void)
2053 {
2054 static GType type = 0;
2055 if (type == 0) {
2056 static const GTypeInfo info = {
2057 sizeof (LttvTraceStateClass),
2058 NULL, /* base_init */
2059 NULL, /* base_finalize */
2060 (GClassInitFunc) trace_state_class_init, /* class_init */
2061 NULL, /* class_finalize */
2062 NULL, /* class_data */
2063 sizeof (LttvTraceState),
2064 0, /* n_preallocs */
2065 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2066 NULL /* value handling */
2067 };
2068
2069 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2070 "LttvTraceStateType", &info, 0);
2071 }
2072 return type;
2073 }
2074
2075
2076 static void
2077 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2078 {
2079 }
2080
2081
2082 static void
2083 tracefile_state_finalize (LttvTracefileState *self)
2084 {
2085 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2086 finalize(G_OBJECT(self));
2087 }
2088
2089
2090 static void
2091 tracefile_state_class_init (LttvTracefileStateClass *klass)
2092 {
2093 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2094
2095 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2096 }
2097
2098
2099 GType
2100 lttv_tracefile_state_get_type(void)
2101 {
2102 static GType type = 0;
2103 if (type == 0) {
2104 static const GTypeInfo info = {
2105 sizeof (LttvTracefileStateClass),
2106 NULL, /* base_init */
2107 NULL, /* base_finalize */
2108 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2109 NULL, /* class_finalize */
2110 NULL, /* class_data */
2111 sizeof (LttvTracefileState),
2112 0, /* n_preallocs */
2113 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2114 NULL /* value handling */
2115 };
2116
2117 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2118 "LttvTracefileStateType", &info, 0);
2119 }
2120 return type;
2121 }
2122
2123
2124 static void module_init()
2125 {
2126 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2127 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
2128 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2129 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2130 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2131 LTTV_STATE_TRAP = g_quark_from_string("trap");
2132 LTTV_STATE_IRQ = g_quark_from_string("irq");
2133 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2134 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
2135 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
2136 LTTV_STATE_EXIT = g_quark_from_string("exiting");
2137 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
2138 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2139 LTTV_STATE_RUN = g_quark_from_string("running");
2140 LTTV_STATE_DEAD = g_quark_from_string("dead");
2141 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2142 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2143 LTTV_STATE_PROCESS = g_quark_from_string("process");
2144 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2145 LTTV_STATE_EVENT = g_quark_from_string("event");
2146 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2147 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2148 LTTV_STATE_TIME = g_quark_from_string("time");
2149 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2150 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2151 LTTV_STATE_TRACE_STATE_USE_COUNT =
2152 g_quark_from_string("trace_state_use_count");
2153
2154
2155 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2156 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2157 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2158 LTT_FACILITY_FS = g_quark_from_string("fs");
2159
2160
2161 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2162 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2163 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2164 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2165 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2166 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2167 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2168 LTT_EVENT_FORK = g_quark_from_string("fork");
2169 LTT_EVENT_EXIT = g_quark_from_string("exit");
2170 LTT_EVENT_FREE = g_quark_from_string("free");
2171 LTT_EVENT_EXEC = g_quark_from_string("exec");
2172
2173
2174 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2175 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2176 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2177 LTT_FIELD_OUT = g_quark_from_string("out");
2178 LTT_FIELD_IN = g_quark_from_string("in");
2179 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2180 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2181 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2182 LTT_FIELD_PID = g_quark_from_string("pid");
2183 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2184
2185 }
2186
2187 static void module_destroy()
2188 {
2189 }
2190
2191
2192 LTTV_MODULE("state", "State computation", \
2193 "Update the system state, possibly saving it at intervals", \
2194 module_init, module_destroy)
2195
2196
2197
This page took 0.073356 seconds and 5 git commands to generate.