fix state computation so it put max time computed in seek to end of trace time value...
[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
590 if(ep != NULL) {
591 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
592 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
593 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
594 g_tree_insert(tsc->pqueue, tfc, tfc);
595 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
596 } else {
597 tfc->timestamp = ltt_time_infinite;
598 }
599 }
600 }
601
602
603 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
604 {
605 guint i, nb_tracefile, nb_cpus;
606
607 LttvTracefileState *tfcs;
608
609 LttvAttribute *tracefiles_tree, *tracefile_tree;
610
611 guint *running_process;
612
613 LttvAttributeType type;
614
615 LttvAttributeValue value;
616
617 LttvAttributeName name;
618
619 LttEventPosition *ep;
620
621 tracefiles_tree = lttv_attribute_find_subdir(container,
622 LTTV_STATE_TRACEFILES);
623 g_object_ref(G_OBJECT(tracefiles_tree));
624 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
625
626 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
627 &value);
628 g_assert(type == LTTV_POINTER);
629 lttv_state_free_process_table(*(value.v_pointer));
630 *(value.v_pointer) = NULL;
631 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
632
633 /* Free running processes array */
634 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
635 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
636 &value);
637 g_assert(type == LTTV_POINTER);
638 running_process = *(value.v_pointer);
639 g_free(running_process);
640
641 nb_tracefile = self->parent.tracefiles->len;
642
643 for(i = 0 ; i < nb_tracefile ; i++) {
644 tfcs =
645 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
646 LttvTracefileContext*, i));
647 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
648 g_assert(type == LTTV_GOBJECT);
649 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
650
651 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
652 &value);
653 g_assert(type == LTTV_POINTER);
654 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
655 }
656 g_object_unref(G_OBJECT(tracefiles_tree));
657 }
658
659
660 static void free_saved_state(LttvTraceState *self)
661 {
662 guint i, nb;
663
664 LttvAttributeType type;
665
666 LttvAttributeValue value;
667
668 LttvAttributeName name;
669
670 LttvAttribute *saved_states;
671
672 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
673 LTTV_STATE_SAVED_STATES);
674
675 nb = lttv_attribute_get_number(saved_states);
676 for(i = 0 ; i < nb ; i++) {
677 type = lttv_attribute_get(saved_states, i, &name, &value);
678 g_assert(type == LTTV_GOBJECT);
679 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
680 }
681
682 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
683 }
684
685
686 static void
687 create_max_time(LttvTraceState *tcs)
688 {
689 LttvAttributeValue v;
690
691 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
692 LTTV_POINTER, &v);
693 g_assert(*(v.v_pointer) == NULL);
694 *(v.v_pointer) = g_new(LttTime,1);
695 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
696 }
697
698
699 static void
700 get_max_time(LttvTraceState *tcs)
701 {
702 LttvAttributeValue v;
703
704 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
705 LTTV_POINTER, &v);
706 g_assert(*(v.v_pointer) != NULL);
707 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
708 }
709
710
711 static void
712 free_max_time(LttvTraceState *tcs)
713 {
714 LttvAttributeValue v;
715
716 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
717 LTTV_POINTER, &v);
718 g_free(*(v.v_pointer));
719 *(v.v_pointer) = NULL;
720 }
721
722
723 typedef struct _LttvNameTables {
724 // FIXME GQuark *eventtype_names;
725 GQuark *syscall_names;
726 GQuark *trap_names;
727 GQuark *irq_names;
728 } LttvNameTables;
729
730
731 static void
732 create_name_tables(LttvTraceState *tcs)
733 {
734 int i, nb;
735
736 GQuark f_name, e_name;
737
738 LttvTraceHook h;
739
740 LttvTraceHookByFacility *thf;
741
742 LttEventType *et;
743
744 LttType *t;
745
746 GString *fe_name = g_string_new("");
747
748 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
749
750 LttvAttributeValue v;
751
752 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
753 LTTV_POINTER, &v);
754 g_assert(*(v.v_pointer) == NULL);
755 *(v.v_pointer) = name_tables;
756 #if 0 // Use iteration over the facilities_by_name and then list all event
757 // types of each facility
758 nb = ltt_trace_eventtype_number(tcs->parent.t);
759 name_tables->eventtype_names = g_new(GQuark, nb);
760 for(i = 0 ; i < nb ; i++) {
761 et = ltt_trace_eventtype_get(tcs->parent.t, i);
762 e_name = ltt_eventtype_name(et);
763 f_name = ltt_facility_name(ltt_eventtype_facility(et));
764 g_string_printf(fe_name, "%s.%s", f_name, e_name);
765 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
766 }
767 #endif //0
768 if(lttv_trace_find_hook(tcs->parent.t,
769 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
770 LTT_FIELD_SYSCALL_ID, 0, 0,
771 NULL, NULL, &h))
772 return;
773
774 thf = lttv_trace_hook_get_first(&h);
775
776 t = ltt_field_type(thf->f1);
777 nb = ltt_type_element_number(t);
778
779 lttv_trace_hook_destroy(&h);
780
781 /* CHECK syscalls should be an enum but currently are not!
782 name_tables->syscall_names = g_new(GQuark, nb);
783
784 for(i = 0 ; i < nb ; i++) {
785 name_tables->syscall_names[i] = g_quark_from_string(
786 ltt_enum_string_get(t, i));
787 }
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, 1);
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_WAIT_FORK;
1028
1029 return process;
1030 }
1031
1032 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1033 guint pid)
1034 {
1035 LttvProcessState key;
1036 LttvProcessState *process;
1037
1038 key.pid = pid;
1039 key.cpu = cpu;
1040 process = g_hash_table_lookup(ts->processes, &key);
1041 return process;
1042 }
1043
1044 LttvProcessState *
1045 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1046 LttTime *timestamp)
1047 {
1048 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1049
1050 /* Put ltt_time_zero creation time for unexisting processes */
1051 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1052 NULL, cpu, pid, timestamp);
1053 return process;
1054 }
1055
1056 /* FIXME : this function should be called when we receive an event telling that
1057 * release_task has been called in the kernel. In happens generally when
1058 * the parent waits for its child terminaison, but may also happen in special
1059 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1060 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1061 * of a killed thread ground, but isn't the leader.
1062 */
1063 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1064 {
1065 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1066 LttvProcessState key;
1067
1068 key.pid = process->pid;
1069 key.cpu = process->cpu;
1070 g_hash_table_remove(ts->processes, &key);
1071 g_array_free(process->execution_stack, TRUE);
1072 g_free(process);
1073 }
1074
1075
1076 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1077 {
1078 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1079 g_free(value);
1080 }
1081
1082
1083 static void lttv_state_free_process_table(GHashTable *processes)
1084 {
1085 g_hash_table_foreach(processes, free_process_state, NULL);
1086 g_hash_table_destroy(processes);
1087 }
1088
1089
1090 static gboolean syscall_entry(void *hook_data, void *call_data)
1091 {
1092 LttvTracefileState *s = (LttvTracefileState *)call_data;
1093 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1094 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1095 LttField *f = thf->f1;
1096
1097 LttvExecutionSubmode submode;
1098
1099 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1100 ltt_event_get_unsigned(e, f)];
1101 push_state(s, LTTV_STATE_SYSCALL, submode);
1102 return FALSE;
1103 }
1104
1105
1106 static gboolean syscall_exit(void *hook_data, void *call_data)
1107 {
1108 LttvTracefileState *s = (LttvTracefileState *)call_data;
1109
1110 pop_state(s, LTTV_STATE_SYSCALL);
1111 return FALSE;
1112 }
1113
1114
1115 static gboolean trap_entry(void *hook_data, void *call_data)
1116 {
1117 LttvTracefileState *s = (LttvTracefileState *)call_data;
1118 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1119 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1120 LttField *f = thf->f1;
1121
1122 LttvExecutionSubmode submode;
1123
1124 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1125 ltt_event_get_unsigned(e, f)];
1126 push_state(s, LTTV_STATE_TRAP, submode);
1127 return FALSE;
1128 }
1129
1130
1131 static gboolean trap_exit(void *hook_data, void *call_data)
1132 {
1133 LttvTracefileState *s = (LttvTracefileState *)call_data;
1134
1135 pop_state(s, LTTV_STATE_TRAP);
1136 return FALSE;
1137 }
1138
1139
1140 static gboolean irq_entry(void *hook_data, void *call_data)
1141 {
1142 LttvTracefileState *s = (LttvTracefileState *)call_data;
1143 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1144 guint8 fac_id = ltt_event_facility_id(e);
1145 guint8 ev_id = ltt_event_eventtype_id(e);
1146 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1147 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1148 g_assert(thf->f1 != NULL);
1149 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1150 LttField *f = thf->f1;
1151
1152 LttvExecutionSubmode submode;
1153
1154 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1155 ltt_event_get_unsigned(e, f)];
1156
1157 /* Do something with the info about being in user or system mode when int? */
1158 push_state(s, LTTV_STATE_IRQ, submode);
1159 return FALSE;
1160 }
1161
1162
1163 static gboolean irq_exit(void *hook_data, void *call_data)
1164 {
1165 LttvTracefileState *s = (LttvTracefileState *)call_data;
1166
1167 pop_state(s, LTTV_STATE_IRQ);
1168 return FALSE;
1169 }
1170
1171
1172 static gboolean schedchange(void *hook_data, void *call_data)
1173 {
1174 LttvTracefileState *s = (LttvTracefileState *)call_data;
1175 guint cpu = ltt_tracefile_num(s->parent.tf);
1176 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1177 LttvProcessState *process = ts->running_process[cpu];
1178
1179 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1180 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1181 guint pid_in, pid_out;
1182 gint state_out;
1183
1184 pid_out = ltt_event_get_unsigned(e, thf->f1);
1185 pid_in = ltt_event_get_unsigned(e, thf->f2);
1186 state_out = ltt_event_get_int(e, thf->f3);
1187
1188 if(likely(process != NULL)) {
1189
1190 /* We could not know but it was not the idle process executing.
1191 This should only happen at the beginning, before the first schedule
1192 event, and when the initial information (current process for each CPU)
1193 is missing. It is not obvious how we could, after the fact, compensate
1194 the wrongly attributed statistics. */
1195
1196 //This test only makes sense once the state is known and if there is no
1197 //missing events.
1198 //if(unlikely(process->pid != pid_out)) {
1199 // g_assert(process->pid == 0);
1200 //}
1201
1202 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1203 process->state->s = LTTV_STATE_ZOMBIE;
1204 } else {
1205 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1206 else process->state->s = LTTV_STATE_WAIT;
1207 } /* FIXME : we do not remove process here, because the kernel
1208 * still has them : they may be zombies. We need to know
1209 * exactly when release_task is executed on the PID to
1210 * know when the zombie is destroyed.
1211 */
1212 //else
1213 // exit_process(s, process);
1214
1215 process->state->change = s->parent.timestamp;
1216 }
1217 process = ts->running_process[cpu] =
1218 lttv_state_find_process_or_create(
1219 (LttvTraceState*)s->parent.t_context,
1220 cpu, pid_in,
1221 &s->parent.timestamp);
1222 process->state->s = LTTV_STATE_RUN;
1223 process->cpu = cpu;
1224 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1225 process->state->change = s->parent.timestamp;
1226 return FALSE;
1227 }
1228
1229 static gboolean process_fork(void *hook_data, void *call_data)
1230 {
1231 LttvTracefileState *s = (LttvTracefileState *)call_data;
1232 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1233 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1234 LttField *f;
1235 guint parent_pid;
1236 guint child_pid;
1237 LttvProcessState *zombie_process;
1238 guint cpu = ltt_tracefile_num(s->parent.tf);
1239 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1240 LttvProcessState *process = ts->running_process[cpu];
1241 LttvProcessState *child_process;
1242
1243 /* Parent PID */
1244 f = thf->f1;
1245 parent_pid = ltt_event_get_unsigned(e, f);
1246
1247 /* Child PID */
1248 f = thf->f2;
1249 child_pid = ltt_event_get_unsigned(e, f);
1250
1251 /* Mathieu : it seems like the process might have been scheduled in before the
1252 * fork, and, in a rare case, might be the current process. This might happen
1253 * in a SMP case where we don't have enough precision on the clocks */
1254 #if 0
1255 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1256
1257 if(unlikely(zombie_process != NULL)) {
1258 /* Reutilisation of PID. Only now we are sure that the old PID
1259 * has been released. FIXME : should know when release_task happens instead.
1260 */
1261 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1262 guint i;
1263 for(i=0; i< num_cpus; i++) {
1264 g_assert(process != ts->running_process[i]);
1265 }
1266
1267 exit_process(s, zombie_process);
1268 }
1269 #endif //0
1270 g_assert(process->pid != child_pid);
1271 // FIXME : Add this test in the "known state" section
1272 // g_assert(process->pid == parent_pid);
1273 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1274 if(child_process == NULL) {
1275 lttv_state_create_process(ts, process, cpu,
1276 child_pid, &s->parent.timestamp);
1277 } else {
1278 /* The process has already been created : due to time imprecision between
1279 * multiple CPUs : it has been scheduled in before creation.
1280 *
1281 * Simply put a correct parent.
1282 */
1283 child_process->ppid = process->pid;
1284 }
1285
1286 return FALSE;
1287 }
1288
1289
1290 static gboolean process_exit(void *hook_data, void *call_data)
1291 {
1292 LttvTracefileState *s = (LttvTracefileState *)call_data;
1293 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1294 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1295 LttField *f;
1296 guint pid;
1297 guint cpu = ltt_tracefile_num(s->parent.tf);
1298 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1299 LttvProcessState *process = ts->running_process[cpu];
1300
1301 pid = ltt_event_get_unsigned(e, thf->f1);
1302
1303 // FIXME : Add this test in the "known state" section
1304 // g_assert(process->pid == pid);
1305
1306 if(likely(process != NULL)) {
1307 process->state->s = LTTV_STATE_EXIT;
1308 }
1309 return FALSE;
1310 }
1311
1312 static gboolean process_free(void *hook_data, void *call_data)
1313 {
1314 LttvTracefileState *s = (LttvTracefileState *)call_data;
1315 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1316 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1317 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1318 guint release_pid;
1319 LttvProcessState *process;
1320
1321 /* PID of the process to release */
1322 release_pid = ltt_event_get_unsigned(e, thf->f1);
1323
1324 g_assert(release_pid != 0);
1325
1326 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1327
1328 if(likely(process != NULL)) {
1329 /* release_task is happening at kernel level : we can now safely release
1330 * the data structure of the process */
1331 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1332 guint i;
1333 for(i=0; i< num_cpus; i++) {
1334 g_assert(process != ts->running_process[i]);
1335 }
1336 exit_process(s, process);
1337 }
1338
1339 return FALSE;
1340 }
1341
1342
1343 static gboolean process_exec(void *hook_data, void *call_data)
1344 {
1345 LttvTracefileState *s = (LttvTracefileState *)call_data;
1346 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1347 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1348 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1349 gchar *name;
1350 guint cpu = ltt_tracefile_num(s->parent.tf);
1351 LttvProcessState *process = ts->running_process[cpu];
1352
1353 /* PID of the process to release */
1354 name = ltt_event_get_string(e, thf->f1);
1355
1356 process->name = g_quark_from_string(name);
1357
1358 return FALSE;
1359 }
1360
1361
1362
1363
1364 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1365 {
1366 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1367
1368 lttv_state_add_event_hooks(tss);
1369
1370 return 0;
1371 }
1372
1373 void lttv_state_add_event_hooks(LttvTracesetState *self)
1374 {
1375 LttvTraceset *traceset = self->parent.ts;
1376
1377 guint i, j, k, l, nb_trace, nb_tracefile;
1378
1379 LttvTraceState *ts;
1380
1381 LttvTracefileState *tfs;
1382
1383 GArray *hooks;
1384
1385 LttvTraceHookByFacility *thf;
1386
1387 LttvTraceHook *hook;
1388
1389 LttvAttributeValue val;
1390
1391 gint ret;
1392
1393 nb_trace = lttv_traceset_number(traceset);
1394 for(i = 0 ; i < nb_trace ; i++) {
1395 ts = (LttvTraceState *)self->parent.traces[i];
1396
1397 /* Find the eventtype id for the following events and register the
1398 associated by id hooks. */
1399
1400 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1401 hooks = g_array_set_size(hooks, 11);
1402
1403 ret = lttv_trace_find_hook(ts->parent.t,
1404 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1405 LTT_FIELD_SYSCALL_ID, 0, 0,
1406 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1407 g_assert(!ret);
1408
1409 ret = lttv_trace_find_hook(ts->parent.t,
1410 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1411 0, 0, 0,
1412 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1413 g_assert(!ret);
1414
1415 ret = lttv_trace_find_hook(ts->parent.t,
1416 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1417 LTT_FIELD_TRAP_ID, 0, 0,
1418 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1419 g_assert(!ret);
1420
1421 ret = lttv_trace_find_hook(ts->parent.t,
1422 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1423 0, 0, 0,
1424 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1425 g_assert(!ret);
1426
1427 ret = lttv_trace_find_hook(ts->parent.t,
1428 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1429 LTT_FIELD_IRQ_ID, 0, 0,
1430 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1431 g_assert(!ret);
1432
1433 ret = lttv_trace_find_hook(ts->parent.t,
1434 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1435 0, 0, 0,
1436 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1437 g_assert(!ret);
1438
1439 ret = lttv_trace_find_hook(ts->parent.t,
1440 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1441 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1442 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1443 g_assert(!ret);
1444
1445 ret = lttv_trace_find_hook(ts->parent.t,
1446 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1447 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1448 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1449 g_assert(!ret);
1450
1451 ret = lttv_trace_find_hook(ts->parent.t,
1452 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1453 LTT_FIELD_PID, 0, 0,
1454 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1455 g_assert(!ret);
1456
1457 ret = lttv_trace_find_hook(ts->parent.t,
1458 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1459 LTT_FIELD_PID, 0, 0,
1460 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1461 g_assert(!ret);
1462
1463 ret = lttv_trace_find_hook(ts->parent.t,
1464 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1465 LTT_FIELD_FILENAME, 0, 0,
1466 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1467 g_assert(!ret);
1468
1469
1470
1471 /* Add these hooks to each event_by_id hooks list */
1472
1473 nb_tracefile = ts->parent.tracefiles->len;
1474
1475 for(j = 0 ; j < nb_tracefile ; j++) {
1476 tfs =
1477 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1478 LttvTracefileContext*, j));
1479
1480 for(k = 0 ; k < hooks->len ; k++) {
1481 hook = &g_array_index(hooks, LttvTraceHook, k);
1482 for(l=0;l<hook->fac_list->len;l++) {
1483 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1484 lttv_hooks_add(
1485 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1486 thf->h,
1487 thf,
1488 LTTV_PRIO_STATE);
1489 }
1490 }
1491 }
1492 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1493 *(val.v_pointer) = hooks;
1494 }
1495 }
1496
1497 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1498 {
1499 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1500
1501 lttv_state_remove_event_hooks(tss);
1502
1503 return 0;
1504 }
1505
1506 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1507 {
1508 LttvTraceset *traceset = self->parent.ts;
1509
1510 guint i, j, k, l, nb_trace, nb_tracefile;
1511
1512 LttvTraceState *ts;
1513
1514 LttvTracefileState *tfs;
1515
1516 GArray *hooks;
1517
1518 LttvTraceHook *hook;
1519
1520 LttvTraceHookByFacility *thf;
1521
1522 LttvAttributeValue val;
1523
1524 nb_trace = lttv_traceset_number(traceset);
1525 for(i = 0 ; i < nb_trace ; i++) {
1526 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1527 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1528 hooks = *(val.v_pointer);
1529
1530 /* Remove these hooks from each event_by_id hooks list */
1531
1532 nb_tracefile = ts->parent.tracefiles->len;
1533
1534 for(j = 0 ; j < nb_tracefile ; j++) {
1535 tfs =
1536 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1537 LttvTracefileContext*, j));
1538
1539 for(k = 0 ; k < hooks->len ; k++) {
1540 hook = &g_array_index(hooks, LttvTraceHook, k);
1541 for(l=0;l<hook->fac_list->len;l++) {
1542 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1543
1544 lttv_hooks_remove_data(
1545 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1546 thf->h,
1547 thf);
1548 }
1549 }
1550 }
1551 for(k = 0 ; k < hooks->len ; k++)
1552 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1553 g_array_free(hooks, TRUE);
1554 }
1555 }
1556
1557 static gboolean state_save_event_hook(void *hook_data, void *call_data)
1558 {
1559 guint *event_count = (guint*)hook_data;
1560
1561 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1562 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1563 return FALSE;
1564 else
1565 *event_count = 0;
1566
1567 LttvTracefileState *self = (LttvTracefileState *)call_data;
1568
1569 LttvTracefileState *tfcs;
1570
1571 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1572
1573 LttEventPosition *ep;
1574
1575 guint i;
1576
1577 LttTracefile *tf;
1578
1579 LttvAttribute *saved_states_tree, *saved_state_tree;
1580
1581 LttvAttributeValue value;
1582
1583 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1584 LTTV_STATE_SAVED_STATES);
1585 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1586 value = lttv_attribute_add(saved_states_tree,
1587 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1588 *(value.v_gobject) = (GObject *)saved_state_tree;
1589 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1590 *(value.v_time) = self->parent.timestamp;
1591 lttv_state_save(tcs, saved_state_tree);
1592 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1593 self->parent.timestamp.tv_nsec);
1594
1595 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1596
1597 return FALSE;
1598 }
1599
1600 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1601 {
1602 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1603
1604 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1605
1606 return FALSE;
1607 }
1608
1609 #if 0
1610 static gboolean block_start(void *hook_data, void *call_data)
1611 {
1612 LttvTracefileState *self = (LttvTracefileState *)call_data;
1613
1614 LttvTracefileState *tfcs;
1615
1616 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1617
1618 LttEventPosition *ep;
1619
1620 guint i, nb_block, nb_event, nb_tracefile;
1621
1622 LttTracefile *tf;
1623
1624 LttvAttribute *saved_states_tree, *saved_state_tree;
1625
1626 LttvAttributeValue value;
1627
1628 ep = ltt_event_position_new();
1629
1630 nb_tracefile = tcs->parent.tracefiles->len;
1631
1632 /* Count the number of events added since the last block end in any
1633 tracefile. */
1634
1635 for(i = 0 ; i < nb_tracefile ; i++) {
1636 tfcs =
1637 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1638 LttvTracefileContext, i));
1639 ltt_event_position(tfcs->parent.e, ep);
1640 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1641 tcs->nb_event += nb_event - tfcs->saved_position;
1642 tfcs->saved_position = nb_event;
1643 }
1644 g_free(ep);
1645
1646 if(tcs->nb_event >= tcs->save_interval) {
1647 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1648 LTTV_STATE_SAVED_STATES);
1649 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1650 value = lttv_attribute_add(saved_states_tree,
1651 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1652 *(value.v_gobject) = (GObject *)saved_state_tree;
1653 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1654 *(value.v_time) = self->parent.timestamp;
1655 lttv_state_save(tcs, saved_state_tree);
1656 tcs->nb_event = 0;
1657 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1658 self->parent.timestamp.tv_nsec);
1659 }
1660 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1661 return FALSE;
1662 }
1663 #endif //0
1664
1665 #if 0
1666 static gboolean block_end(void *hook_data, void *call_data)
1667 {
1668 LttvTracefileState *self = (LttvTracefileState *)call_data;
1669
1670 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1671
1672 LttTracefile *tf;
1673
1674 LttEventPosition *ep;
1675
1676 guint nb_block, nb_event;
1677
1678 ep = ltt_event_position_new();
1679 ltt_event_position(self->parent.e, ep);
1680 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1681 tcs->nb_event += nb_event - self->saved_position + 1;
1682 self->saved_position = 0;
1683 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1684 g_free(ep);
1685
1686 return FALSE;
1687 }
1688 #endif //0
1689 #if 0
1690 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1691 {
1692 LttvTraceset *traceset = self->parent.ts;
1693
1694 guint i, j, nb_trace, nb_tracefile;
1695
1696 LttvTraceState *ts;
1697
1698 LttvTracefileState *tfs;
1699
1700 LttvTraceHook hook_start, hook_end;
1701
1702 nb_trace = lttv_traceset_number(traceset);
1703 for(i = 0 ; i < nb_trace ; i++) {
1704 ts = (LttvTraceState *)self->parent.traces[i];
1705
1706 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1707 NULL, NULL, block_start, &hook_start);
1708 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1709 NULL, NULL, block_end, &hook_end);
1710
1711 nb_tracefile = ts->parent.tracefiles->len;
1712
1713 for(j = 0 ; j < nb_tracefile ; j++) {
1714 tfs =
1715 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1716 LttvTracefileContext, j));
1717 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1718 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1719 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1720 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1721 }
1722 }
1723 }
1724 #endif //0
1725
1726 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1727 {
1728 LttvTraceset *traceset = self->parent.ts;
1729
1730 guint i, j, nb_trace, nb_tracefile;
1731
1732 LttvTraceState *ts;
1733
1734 LttvTracefileState *tfs;
1735
1736
1737 nb_trace = lttv_traceset_number(traceset);
1738 for(i = 0 ; i < nb_trace ; i++) {
1739
1740 ts = (LttvTraceState *)self->parent.traces[i];
1741 nb_tracefile = ts->parent.tracefiles->len;
1742
1743 guint *event_count = g_new(guint, 1);
1744 *event_count = 0;
1745
1746 for(j = 0 ; j < nb_tracefile ; j++) {
1747 tfs =
1748 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1749 LttvTracefileContext*, j));
1750 lttv_hooks_add(tfs->parent.event,
1751 state_save_event_hook,
1752 event_count,
1753 LTTV_PRIO_STATE);
1754
1755 }
1756 }
1757
1758 lttv_process_traceset_begin(&self->parent,
1759 NULL, NULL, NULL, NULL, NULL);
1760
1761 }
1762
1763 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1764 {
1765 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1766
1767 lttv_state_save_add_event_hooks(tss);
1768
1769 return 0;
1770 }
1771
1772
1773 #if 0
1774 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1775 {
1776 LttvTraceset *traceset = self->parent.ts;
1777
1778 guint i, j, nb_trace, nb_tracefile;
1779
1780 LttvTraceState *ts;
1781
1782 LttvTracefileState *tfs;
1783
1784 LttvTraceHook hook_start, hook_end;
1785
1786 nb_trace = lttv_traceset_number(traceset);
1787 for(i = 0 ; i < nb_trace ; i++) {
1788 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1789
1790 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1791 NULL, NULL, block_start, &hook_start);
1792
1793 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1794 NULL, NULL, block_end, &hook_end);
1795
1796 nb_tracefile = ts->parent.tracefiles->len;
1797
1798 for(j = 0 ; j < nb_tracefile ; j++) {
1799 tfs =
1800 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1801 LttvTracefileContext, j));
1802 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1803 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
1804 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1805 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
1806 }
1807 }
1808 }
1809 #endif //0
1810
1811 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1812 {
1813 LttvTraceset *traceset = self->parent.ts;
1814
1815 guint i, j, nb_trace, nb_tracefile;
1816
1817 LttvTraceState *ts;
1818
1819 LttvTracefileState *tfs;
1820
1821 LttvHooks *after_trace = lttv_hooks_new();
1822
1823 lttv_hooks_add(after_trace,
1824 state_save_after_trace_hook,
1825 NULL,
1826 LTTV_PRIO_STATE);
1827
1828
1829 lttv_process_traceset_end(&self->parent,
1830 NULL, after_trace, NULL, NULL, NULL);
1831
1832 lttv_hooks_destroy(after_trace);
1833
1834 nb_trace = lttv_traceset_number(traceset);
1835 for(i = 0 ; i < nb_trace ; i++) {
1836
1837 ts = (LttvTraceState *)self->parent.traces[i];
1838 nb_tracefile = ts->parent.tracefiles->len;
1839
1840 guint *event_count;
1841
1842 for(j = 0 ; j < nb_tracefile ; j++) {
1843 tfs =
1844 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1845 LttvTracefileContext*, j));
1846 event_count = lttv_hooks_remove(tfs->parent.event,
1847 state_save_event_hook);
1848 }
1849 g_free(event_count);
1850 }
1851 }
1852
1853 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1854 {
1855 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1856
1857 lttv_state_save_remove_event_hooks(tss);
1858
1859 return 0;
1860 }
1861
1862 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
1863 {
1864 LttvTraceset *traceset = self->parent.ts;
1865
1866 guint i, nb_trace;
1867
1868 int min_pos, mid_pos, max_pos;
1869
1870 guint call_rest = 0;
1871
1872 LttvTraceState *tcs;
1873
1874 LttvAttributeValue value;
1875
1876 LttvAttributeType type;
1877
1878 LttvAttributeName name;
1879
1880 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1881
1882 g_tree_destroy(self->parent.pqueue);
1883 self->parent.pqueue = g_tree_new(compare_tracefile);
1884
1885 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1886
1887 nb_trace = lttv_traceset_number(traceset);
1888 for(i = 0 ; i < nb_trace ; i++) {
1889 tcs = (LttvTraceState *)self->parent.traces[i];
1890
1891 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1892 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1893 LTTV_STATE_SAVED_STATES);
1894 min_pos = -1;
1895
1896 if(saved_states_tree) {
1897 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1898 mid_pos = max_pos / 2;
1899 while(min_pos < max_pos) {
1900 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1901 g_assert(type == LTTV_GOBJECT);
1902 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1903 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1904 &value);
1905 g_assert(type == LTTV_TIME);
1906 if(ltt_time_compare(*(value.v_time), t) < 0) {
1907 min_pos = mid_pos;
1908 closest_tree = saved_state_tree;
1909 }
1910 else max_pos = mid_pos - 1;
1911
1912 mid_pos = (min_pos + max_pos + 1) / 2;
1913 }
1914 }
1915
1916 /* restore the closest earlier saved state */
1917 if(min_pos != -1) {
1918 lttv_state_restore(tcs, closest_tree);
1919 call_rest = 1;
1920 }
1921
1922 /* There is no saved state, yet we want to have it. Restart at T0 */
1923 else {
1924 restore_init_state(tcs);
1925 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
1926 }
1927 }
1928 /* We want to seek quickly without restoring/updating the state */
1929 else {
1930 restore_init_state(tcs);
1931 lttv_process_trace_seek_time(&(tcs->parent), t);
1932 }
1933 }
1934 if(!call_rest) g_info("NOT Calling restore");
1935 }
1936
1937
1938 static void
1939 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1940 {
1941 }
1942
1943
1944 static void
1945 traceset_state_finalize (LttvTracesetState *self)
1946 {
1947 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1948 finalize(G_OBJECT(self));
1949 }
1950
1951
1952 static void
1953 traceset_state_class_init (LttvTracesetContextClass *klass)
1954 {
1955 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1956
1957 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1958 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1959 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1960 klass->new_traceset_context = new_traceset_context;
1961 klass->new_trace_context = new_trace_context;
1962 klass->new_tracefile_context = new_tracefile_context;
1963 }
1964
1965
1966 GType
1967 lttv_traceset_state_get_type(void)
1968 {
1969 static GType type = 0;
1970 if (type == 0) {
1971 static const GTypeInfo info = {
1972 sizeof (LttvTracesetStateClass),
1973 NULL, /* base_init */
1974 NULL, /* base_finalize */
1975 (GClassInitFunc) traceset_state_class_init, /* class_init */
1976 NULL, /* class_finalize */
1977 NULL, /* class_data */
1978 sizeof (LttvTracesetState),
1979 0, /* n_preallocs */
1980 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1981 NULL /* value handling */
1982 };
1983
1984 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1985 &info, 0);
1986 }
1987 return type;
1988 }
1989
1990
1991 static void
1992 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1993 {
1994 }
1995
1996
1997 static void
1998 trace_state_finalize (LttvTraceState *self)
1999 {
2000 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2001 finalize(G_OBJECT(self));
2002 }
2003
2004
2005 static void
2006 trace_state_class_init (LttvTraceStateClass *klass)
2007 {
2008 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2009
2010 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2011 klass->state_save = state_save;
2012 klass->state_restore = state_restore;
2013 klass->state_saved_free = state_saved_free;
2014 }
2015
2016
2017 GType
2018 lttv_trace_state_get_type(void)
2019 {
2020 static GType type = 0;
2021 if (type == 0) {
2022 static const GTypeInfo info = {
2023 sizeof (LttvTraceStateClass),
2024 NULL, /* base_init */
2025 NULL, /* base_finalize */
2026 (GClassInitFunc) trace_state_class_init, /* class_init */
2027 NULL, /* class_finalize */
2028 NULL, /* class_data */
2029 sizeof (LttvTraceState),
2030 0, /* n_preallocs */
2031 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2032 NULL /* value handling */
2033 };
2034
2035 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2036 "LttvTraceStateType", &info, 0);
2037 }
2038 return type;
2039 }
2040
2041
2042 static void
2043 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2044 {
2045 }
2046
2047
2048 static void
2049 tracefile_state_finalize (LttvTracefileState *self)
2050 {
2051 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2052 finalize(G_OBJECT(self));
2053 }
2054
2055
2056 static void
2057 tracefile_state_class_init (LttvTracefileStateClass *klass)
2058 {
2059 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2060
2061 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2062 }
2063
2064
2065 GType
2066 lttv_tracefile_state_get_type(void)
2067 {
2068 static GType type = 0;
2069 if (type == 0) {
2070 static const GTypeInfo info = {
2071 sizeof (LttvTracefileStateClass),
2072 NULL, /* base_init */
2073 NULL, /* base_finalize */
2074 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2075 NULL, /* class_finalize */
2076 NULL, /* class_data */
2077 sizeof (LttvTracefileState),
2078 0, /* n_preallocs */
2079 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2080 NULL /* value handling */
2081 };
2082
2083 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2084 "LttvTracefileStateType", &info, 0);
2085 }
2086 return type;
2087 }
2088
2089
2090 static void module_init()
2091 {
2092 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2093 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
2094 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2095 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2096 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2097 LTTV_STATE_TRAP = g_quark_from_string("trap");
2098 LTTV_STATE_IRQ = g_quark_from_string("irq");
2099 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2100 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
2101 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
2102 LTTV_STATE_EXIT = g_quark_from_string("exiting");
2103 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
2104 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2105 LTTV_STATE_RUN = g_quark_from_string("running");
2106 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2107 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2108 LTTV_STATE_PROCESS = g_quark_from_string("process");
2109 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2110 LTTV_STATE_EVENT = g_quark_from_string("event");
2111 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2112 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2113 LTTV_STATE_TIME = g_quark_from_string("time");
2114 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2115 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2116 LTTV_STATE_TRACE_STATE_USE_COUNT =
2117 g_quark_from_string("trace_state_use_count");
2118
2119
2120 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2121 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2122 LTT_FACILITY_FS = g_quark_from_string("fs");
2123
2124
2125 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2126 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2127 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2128 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2129 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2130 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2131 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2132 LTT_EVENT_FORK = g_quark_from_string("fork");
2133 LTT_EVENT_EXIT = g_quark_from_string("exit");
2134 LTT_EVENT_FREE = g_quark_from_string("free");
2135 LTT_EVENT_EXEC = g_quark_from_string("exec");
2136
2137
2138 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2139 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2140 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2141 LTT_FIELD_OUT = g_quark_from_string("out");
2142 LTT_FIELD_IN = g_quark_from_string("in");
2143 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2144 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2145 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2146 LTT_FIELD_PID = g_quark_from_string("pid");
2147 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2148
2149 }
2150
2151 static void module_destroy()
2152 {
2153 }
2154
2155
2156 LTTV_MODULE("state", "State computation", \
2157 "Update the system state, possibly saving it at intervals", \
2158 module_init, module_destroy)
2159
2160
2161
This page took 0.072868 seconds and 4 git commands to generate.