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