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