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