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