format update
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
... / ...
CommitLineData
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
37GQuark
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
46GQuark
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
64GQuark
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
81LttvExecutionMode
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
89LttvExecutionSubmode
90 LTTV_STATE_SUBMODE_UNKNOWN,
91 LTTV_STATE_SUBMODE_NONE;
92
93LttvProcessStatus
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
103static 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
116static void create_max_time(LttvTraceState *tcs);
117
118static void get_max_time(LttvTraceState *tcs);
119
120static void free_max_time(LttvTraceState *tcs);
121
122static void create_name_tables(LttvTraceState *tcs);
123
124static void get_name_tables(LttvTraceState *tcs);
125
126static void free_name_tables(LttvTraceState *tcs);
127
128static void free_saved_state(LttvTraceState *tcs);
129
130static void lttv_state_free_process_table(GHashTable *processes);
131
132
133void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
134{
135 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
136}
137
138
139void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
140{
141 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
142}
143
144
145void 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
152guint 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 */
161gboolean 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
177static void
178restore_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
228static void
229init(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
277static void
278fini(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
312static LttvTracesetContext *
313new_traceset_context(LttvTracesetContext *self)
314{
315 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
316}
317
318
319static LttvTraceContext *
320new_trace_context(LttvTracesetContext *self)
321{
322 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
323}
324
325
326static LttvTracefileContext *
327new_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
335static 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
365void 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
415static 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
441static 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
456static 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
533static 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
617static 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
674static 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
700static void
701create_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
713static void
714get_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
725static void
726free_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
737typedef 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
746static void
747create_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
879static void
880get_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
898static void
899free_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
920static 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
928static void hash_table_check(GHashTable *table)
929{
930 g_hash_table_foreach(table, test_process, NULL);
931}
932
933
934#endif
935
936
937static 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
967static 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
1003LttvProcessState *
1004lttv_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
1068LttvProcessState *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
1080LttvProcessState *
1081lttv_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 */
1099static 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
1112static 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
1119static 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
1126static 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
1142static 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
1151static 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
1167static 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
1176static 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
1199static 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
1207static 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
1230static 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
1239static 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
1294static 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 child_process = 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 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1353 child_process->name = process->name;
1354
1355 return FALSE;
1356}
1357
1358
1359static gboolean process_exit(void *hook_data, void *call_data)
1360{
1361 LttvTracefileState *s = (LttvTracefileState *)call_data;
1362 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1363 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1364 LttField *f;
1365 guint pid;
1366 guint cpu = ltt_tracefile_num(s->parent.tf);
1367 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1368 LttvProcessState *process = ts->running_process[cpu];
1369
1370 pid = ltt_event_get_unsigned(e, thf->f1);
1371
1372 // FIXME : Add this test in the "known state" section
1373 // g_assert(process->pid == pid);
1374
1375 if(likely(process != NULL)) {
1376 process->state->s = LTTV_STATE_EXIT;
1377 }
1378 return FALSE;
1379}
1380
1381static gboolean process_free(void *hook_data, void *call_data)
1382{
1383 LttvTracefileState *s = (LttvTracefileState *)call_data;
1384 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1385 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1386 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1387 guint release_pid;
1388 LttvProcessState *process;
1389
1390 /* PID of the process to release */
1391 release_pid = ltt_event_get_unsigned(e, thf->f1);
1392
1393 g_assert(release_pid != 0);
1394
1395 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1396
1397 if(likely(process != NULL)) {
1398 /* release_task is happening at kernel level : we can now safely release
1399 * the data structure of the process */
1400 //This test is fun, though, as it may happen that
1401 //at time t : CPU 0 : process_free
1402 //at time t+150ns : CPU 1 : schedule out
1403 //Clearly due to time imprecision, we disable it. (Mathieu)
1404 //If this weird case happen, we have no choice but to put the
1405 //Currently running process on the cpu to 0.
1406 //I re-enable it following time precision fixes. (Mathieu)
1407 //Well, in the case where an process is freed by a process on another CPU
1408 //and still scheduled, it happens that this is the schedchange that will
1409 //drop the last reference count. Do not free it here!
1410 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1411 guint i;
1412 for(i=0; i< num_cpus; i++) {
1413 //g_assert(process != ts->running_process[i]);
1414 if(process == ts->running_process[i]) {
1415 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1416 break;
1417 }
1418 }
1419 if(i == num_cpus) /* process is not scheduled */
1420 exit_process(s, process);
1421 }
1422
1423 return FALSE;
1424}
1425
1426
1427static gboolean process_exec(void *hook_data, void *call_data)
1428{
1429 LttvTracefileState *s = (LttvTracefileState *)call_data;
1430 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1431 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1432 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1433 //gchar *name;
1434 guint cpu = ltt_tracefile_num(s->parent.tf);
1435 LttvProcessState *process = ts->running_process[cpu];
1436
1437 /* PID of the process to release */
1438 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1439 //name = ltt_event_get_string(e, thf->f1);
1440 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1441 gchar *name_begin =
1442 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1443 gchar *null_term_name = g_new(gchar, name_len+1);
1444 memcpy(null_term_name, name_begin, name_len);
1445 null_term_name[name_len] = '\0';
1446
1447 process->name = g_quark_from_string(null_term_name);
1448 g_free(null_term_name);
1449 return FALSE;
1450}
1451
1452static gboolean enum_process_state(void *hook_data, void *call_data)
1453{
1454 LttvTracefileState *s = (LttvTracefileState *)call_data;
1455 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1456 //It's slow : optimise later by doing this before reading trace.
1457 LttEventType *et = ltt_event_eventtype(e);
1458 //
1459 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1460 guint parent_pid;
1461 guint pid;
1462 gchar * command;
1463 guint cpu = ltt_tracefile_num(s->parent.tf);
1464 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1465 LttvProcessState *process = ts->running_process[cpu];
1466 LttvProcessState *parent_process;
1467 LttField *f4, *f5, *f6;
1468 GQuark mode, submode, status;
1469
1470 /* PID */
1471 pid = ltt_event_get_unsigned(e, thf->f1);
1472
1473 /* Parent PID */
1474 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1475
1476 /* Command name */
1477 command = ltt_event_get_string(e, thf->f3);
1478
1479 /* mode */
1480 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1481 mode = ltt_enum_string_get(ltt_field_type(f4),
1482 ltt_event_get_unsigned(e, f4));
1483
1484 /* submode */
1485 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1486 submode = ltt_enum_string_get(ltt_field_type(f5),
1487 ltt_event_get_unsigned(e, f5));
1488
1489 /* status */
1490 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1491 status = ltt_enum_string_get(ltt_field_type(f6),
1492 ltt_event_get_unsigned(e, f6));
1493
1494 /* The process might exist if a process was forked while performing the sate dump. */
1495 process = lttv_state_find_process(ts, ANY_CPU, pid);
1496 if(process == NULL) {
1497 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1498 process = lttv_state_create_process(ts, parent_process, cpu,
1499 pid, g_quark_from_string(command),
1500 &s->parent.timestamp);
1501
1502 /* Keep the stack bottom : a running user mode */
1503#if 0
1504 /* Disabled because of inconsistencies in the current statedump states. */
1505 if(mode == LTTV_STATE_USER_MODE) {
1506 /* Only keep the bottom */
1507 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1508 } else {
1509 /* On top of it : */
1510 LttvExecutionState *es;
1511 es = process->state = &g_array_index(process->execution_stack,
1512 LttvExecutionState, 1);
1513 es->t = mode;
1514 es->s = status;
1515 es->n = submode;
1516 }
1517#endif //0
1518
1519 /* UNKNOWN STATE */
1520 {
1521 LttvExecutionState *es;
1522 es = process->state = &g_array_index(process->execution_stack,
1523 LttvExecutionState, 1);
1524 es->t = LTTV_STATE_MODE_UNKNOWN;
1525 es->s = LTTV_STATE_UNNAMED;
1526 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1527 }
1528 } else {
1529 /* The process has already been created :
1530 * Probably was forked while dumping the process state or
1531 * was simply scheduled in prior to get the state dump event.
1532 */
1533 process->ppid = parent_pid;
1534 process->name = g_quark_from_string(command);
1535 /* Don't mess around with the stack, it will eventually become
1536 * ok after the end of state dump. */
1537 }
1538
1539 return FALSE;
1540}
1541
1542gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1543{
1544 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1545
1546 lttv_state_add_event_hooks(tss);
1547
1548 return 0;
1549}
1550
1551void lttv_state_add_event_hooks(LttvTracesetState *self)
1552{
1553 LttvTraceset *traceset = self->parent.ts;
1554
1555 guint i, j, k, l, nb_trace, nb_tracefile;
1556
1557 LttvTraceState *ts;
1558
1559 LttvTracefileState *tfs;
1560
1561 GArray *hooks;
1562
1563 LttvTraceHookByFacility *thf;
1564
1565 LttvTraceHook *hook;
1566
1567 LttvAttributeValue val;
1568
1569 gint ret;
1570
1571 nb_trace = lttv_traceset_number(traceset);
1572 for(i = 0 ; i < nb_trace ; i++) {
1573 ts = (LttvTraceState *)self->parent.traces[i];
1574
1575 /* Find the eventtype id for the following events and register the
1576 associated by id hooks. */
1577
1578 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 14);
1579 hooks = g_array_set_size(hooks, 14);
1580
1581 ret = lttv_trace_find_hook(ts->parent.t,
1582 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1583 LTT_FIELD_SYSCALL_ID, 0, 0,
1584 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
1585 g_assert(!ret);
1586
1587 ret = lttv_trace_find_hook(ts->parent.t,
1588 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1589 0, 0, 0,
1590 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
1591 g_assert(!ret);
1592
1593 ret = lttv_trace_find_hook(ts->parent.t,
1594 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1595 LTT_FIELD_TRAP_ID, 0, 0,
1596 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
1597 g_assert(!ret);
1598
1599 ret = lttv_trace_find_hook(ts->parent.t,
1600 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1601 0, 0, 0,
1602 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
1603 g_assert(!ret);
1604
1605 ret = lttv_trace_find_hook(ts->parent.t,
1606 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1607 LTT_FIELD_IRQ_ID, 0, 0,
1608 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
1609 g_assert(!ret);
1610
1611 ret = lttv_trace_find_hook(ts->parent.t,
1612 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1613 0, 0, 0,
1614 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
1615 g_assert(!ret);
1616
1617 ret = lttv_trace_find_hook(ts->parent.t,
1618 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1619 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1620 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1621 g_assert(!ret);
1622
1623 ret = lttv_trace_find_hook(ts->parent.t,
1624 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1625 0, 0, 0,
1626 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1627 g_assert(!ret);
1628
1629 ret = lttv_trace_find_hook(ts->parent.t,
1630 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1631 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1632 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
1633 g_assert(!ret);
1634
1635 ret = lttv_trace_find_hook(ts->parent.t,
1636 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1637 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1638 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
1639 g_assert(!ret);
1640
1641 ret = lttv_trace_find_hook(ts->parent.t,
1642 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1643 LTT_FIELD_PID, 0, 0,
1644 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1645 g_assert(!ret);
1646
1647 ret = lttv_trace_find_hook(ts->parent.t,
1648 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1649 LTT_FIELD_PID, 0, 0,
1650 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 11));
1651 g_assert(!ret);
1652
1653 ret = lttv_trace_find_hook(ts->parent.t,
1654 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1655 LTT_FIELD_FILENAME, 0, 0,
1656 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 12));
1657 g_assert(!ret);
1658
1659 /* statedump-related hooks */
1660 ret = lttv_trace_find_hook(ts->parent.t,
1661 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1662 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1663 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, 13));
1664 g_assert(!ret);
1665
1666
1667 /* Add these hooks to each event_by_id hooks list */
1668
1669 nb_tracefile = ts->parent.tracefiles->len;
1670
1671 for(j = 0 ; j < nb_tracefile ; j++) {
1672 tfs =
1673 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1674 LttvTracefileContext*, j));
1675
1676 for(k = 0 ; k < hooks->len ; k++) {
1677 hook = &g_array_index(hooks, LttvTraceHook, k);
1678 for(l=0;l<hook->fac_list->len;l++) {
1679 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1680 lttv_hooks_add(
1681 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1682 thf->h,
1683 thf,
1684 LTTV_PRIO_STATE);
1685 }
1686 }
1687 }
1688 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1689 *(val.v_pointer) = hooks;
1690 }
1691}
1692
1693gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1694{
1695 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1696
1697 lttv_state_remove_event_hooks(tss);
1698
1699 return 0;
1700}
1701
1702void lttv_state_remove_event_hooks(LttvTracesetState *self)
1703{
1704 LttvTraceset *traceset = self->parent.ts;
1705
1706 guint i, j, k, l, nb_trace, nb_tracefile;
1707
1708 LttvTraceState *ts;
1709
1710 LttvTracefileState *tfs;
1711
1712 GArray *hooks;
1713
1714 LttvTraceHook *hook;
1715
1716 LttvTraceHookByFacility *thf;
1717
1718 LttvAttributeValue val;
1719
1720 nb_trace = lttv_traceset_number(traceset);
1721 for(i = 0 ; i < nb_trace ; i++) {
1722 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1723 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1724 hooks = *(val.v_pointer);
1725
1726 /* Remove these hooks from each event_by_id hooks list */
1727
1728 nb_tracefile = ts->parent.tracefiles->len;
1729
1730 for(j = 0 ; j < nb_tracefile ; j++) {
1731 tfs =
1732 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1733 LttvTracefileContext*, j));
1734
1735 for(k = 0 ; k < hooks->len ; k++) {
1736 hook = &g_array_index(hooks, LttvTraceHook, k);
1737 for(l=0;l<hook->fac_list->len;l++) {
1738 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1739
1740 lttv_hooks_remove_data(
1741 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1742 thf->h,
1743 thf);
1744 }
1745 }
1746 }
1747 for(k = 0 ; k < hooks->len ; k++)
1748 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
1749 g_array_free(hooks, TRUE);
1750 }
1751}
1752
1753static gboolean state_save_event_hook(void *hook_data, void *call_data)
1754{
1755 guint *event_count = (guint*)hook_data;
1756
1757 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1758 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1759 return FALSE;
1760 else
1761 *event_count = 0;
1762
1763 LttvTracefileState *self = (LttvTracefileState *)call_data;
1764
1765 LttvTracefileState *tfcs;
1766
1767 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1768
1769 LttEventPosition *ep;
1770
1771 guint i;
1772
1773 LttTracefile *tf;
1774
1775 LttvAttribute *saved_states_tree, *saved_state_tree;
1776
1777 LttvAttributeValue value;
1778
1779 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1780 LTTV_STATE_SAVED_STATES);
1781 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1782 value = lttv_attribute_add(saved_states_tree,
1783 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1784 *(value.v_gobject) = (GObject *)saved_state_tree;
1785 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1786 *(value.v_time) = self->parent.timestamp;
1787 lttv_state_save(tcs, saved_state_tree);
1788 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1789 self->parent.timestamp.tv_nsec);
1790
1791 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1792
1793 return FALSE;
1794}
1795
1796static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1797{
1798 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1799
1800 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1801
1802 return FALSE;
1803}
1804
1805#if 0
1806static gboolean block_start(void *hook_data, void *call_data)
1807{
1808 LttvTracefileState *self = (LttvTracefileState *)call_data;
1809
1810 LttvTracefileState *tfcs;
1811
1812 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1813
1814 LttEventPosition *ep;
1815
1816 guint i, nb_block, nb_event, nb_tracefile;
1817
1818 LttTracefile *tf;
1819
1820 LttvAttribute *saved_states_tree, *saved_state_tree;
1821
1822 LttvAttributeValue value;
1823
1824 ep = ltt_event_position_new();
1825
1826 nb_tracefile = tcs->parent.tracefiles->len;
1827
1828 /* Count the number of events added since the last block end in any
1829 tracefile. */
1830
1831 for(i = 0 ; i < nb_tracefile ; i++) {
1832 tfcs =
1833 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1834 LttvTracefileContext, i));
1835 ltt_event_position(tfcs->parent.e, ep);
1836 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1837 tcs->nb_event += nb_event - tfcs->saved_position;
1838 tfcs->saved_position = nb_event;
1839 }
1840 g_free(ep);
1841
1842 if(tcs->nb_event >= tcs->save_interval) {
1843 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1844 LTTV_STATE_SAVED_STATES);
1845 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1846 value = lttv_attribute_add(saved_states_tree,
1847 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1848 *(value.v_gobject) = (GObject *)saved_state_tree;
1849 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1850 *(value.v_time) = self->parent.timestamp;
1851 lttv_state_save(tcs, saved_state_tree);
1852 tcs->nb_event = 0;
1853 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1854 self->parent.timestamp.tv_nsec);
1855 }
1856 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1857 return FALSE;
1858}
1859#endif //0
1860
1861#if 0
1862static gboolean block_end(void *hook_data, void *call_data)
1863{
1864 LttvTracefileState *self = (LttvTracefileState *)call_data;
1865
1866 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1867
1868 LttTracefile *tf;
1869
1870 LttEventPosition *ep;
1871
1872 guint nb_block, nb_event;
1873
1874 ep = ltt_event_position_new();
1875 ltt_event_position(self->parent.e, ep);
1876 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1877 tcs->nb_event += nb_event - self->saved_position + 1;
1878 self->saved_position = 0;
1879 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1880 g_free(ep);
1881
1882 return FALSE;
1883}
1884#endif //0
1885#if 0
1886void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1887{
1888 LttvTraceset *traceset = self->parent.ts;
1889
1890 guint i, j, nb_trace, nb_tracefile;
1891
1892 LttvTraceState *ts;
1893
1894 LttvTracefileState *tfs;
1895
1896 LttvTraceHook hook_start, hook_end;
1897
1898 nb_trace = lttv_traceset_number(traceset);
1899 for(i = 0 ; i < nb_trace ; i++) {
1900 ts = (LttvTraceState *)self->parent.traces[i];
1901
1902 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1903 NULL, NULL, block_start, &hook_start);
1904 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1905 NULL, NULL, block_end, &hook_end);
1906
1907 nb_tracefile = ts->parent.tracefiles->len;
1908
1909 for(j = 0 ; j < nb_tracefile ; j++) {
1910 tfs =
1911 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1912 LttvTracefileContext, j));
1913 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1914 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1915 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1916 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1917 }
1918 }
1919}
1920#endif //0
1921
1922void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1923{
1924 LttvTraceset *traceset = self->parent.ts;
1925
1926 guint i, j, nb_trace, nb_tracefile;
1927
1928 LttvTraceState *ts;
1929
1930 LttvTracefileState *tfs;
1931
1932
1933 nb_trace = lttv_traceset_number(traceset);
1934 for(i = 0 ; i < nb_trace ; i++) {
1935
1936 ts = (LttvTraceState *)self->parent.traces[i];
1937 nb_tracefile = ts->parent.tracefiles->len;
1938
1939 guint *event_count = g_new(guint, 1);
1940 *event_count = 0;
1941
1942 for(j = 0 ; j < nb_tracefile ; j++) {
1943 tfs =
1944 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1945 LttvTracefileContext*, j));
1946 lttv_hooks_add(tfs->parent.event,
1947 state_save_event_hook,
1948 event_count,
1949 LTTV_PRIO_STATE);
1950
1951 }
1952 }
1953
1954 lttv_process_traceset_begin(&self->parent,
1955 NULL, NULL, NULL, NULL, NULL);
1956
1957}
1958
1959gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1960{
1961 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1962
1963 lttv_state_save_add_event_hooks(tss);
1964
1965 return 0;
1966}
1967
1968
1969#if 0
1970void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1971{
1972 LttvTraceset *traceset = self->parent.ts;
1973
1974 guint i, j, nb_trace, nb_tracefile;
1975
1976 LttvTraceState *ts;
1977
1978 LttvTracefileState *tfs;
1979
1980 LttvTraceHook hook_start, hook_end;
1981
1982 nb_trace = lttv_traceset_number(traceset);
1983 for(i = 0 ; i < nb_trace ; i++) {
1984 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1985
1986 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1987 NULL, NULL, block_start, &hook_start);
1988
1989 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
1990 NULL, NULL, block_end, &hook_end);
1991
1992 nb_tracefile = ts->parent.tracefiles->len;
1993
1994 for(j = 0 ; j < nb_tracefile ; j++) {
1995 tfs =
1996 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1997 LttvTracefileContext, j));
1998 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1999 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2000 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2001 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2002 }
2003 }
2004}
2005#endif //0
2006
2007void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2008{
2009 LttvTraceset *traceset = self->parent.ts;
2010
2011 guint i, j, nb_trace, nb_tracefile;
2012
2013 LttvTraceState *ts;
2014
2015 LttvTracefileState *tfs;
2016
2017 LttvHooks *after_trace = lttv_hooks_new();
2018
2019 lttv_hooks_add(after_trace,
2020 state_save_after_trace_hook,
2021 NULL,
2022 LTTV_PRIO_STATE);
2023
2024
2025 lttv_process_traceset_end(&self->parent,
2026 NULL, after_trace, NULL, NULL, NULL);
2027
2028 lttv_hooks_destroy(after_trace);
2029
2030 nb_trace = lttv_traceset_number(traceset);
2031 for(i = 0 ; i < nb_trace ; i++) {
2032
2033 ts = (LttvTraceState *)self->parent.traces[i];
2034 nb_tracefile = ts->parent.tracefiles->len;
2035
2036 guint *event_count = NULL;
2037
2038 for(j = 0 ; j < nb_tracefile ; j++) {
2039 tfs =
2040 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2041 LttvTracefileContext*, j));
2042 event_count = lttv_hooks_remove(tfs->parent.event,
2043 state_save_event_hook);
2044 }
2045 if(event_count) g_free(event_count);
2046 }
2047}
2048
2049gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2050{
2051 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2052
2053 lttv_state_save_remove_event_hooks(tss);
2054
2055 return 0;
2056}
2057
2058void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2059{
2060 LttvTraceset *traceset = self->parent.ts;
2061
2062 guint i, nb_trace;
2063
2064 int min_pos, mid_pos, max_pos;
2065
2066 guint call_rest = 0;
2067
2068 LttvTraceState *tcs;
2069
2070 LttvAttributeValue value;
2071
2072 LttvAttributeType type;
2073
2074 LttvAttributeName name;
2075
2076 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2077
2078 //g_tree_destroy(self->parent.pqueue);
2079 //self->parent.pqueue = g_tree_new(compare_tracefile);
2080
2081 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2082
2083 nb_trace = lttv_traceset_number(traceset);
2084 for(i = 0 ; i < nb_trace ; i++) {
2085 tcs = (LttvTraceState *)self->parent.traces[i];
2086
2087 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2088 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2089 LTTV_STATE_SAVED_STATES);
2090 min_pos = -1;
2091
2092 if(saved_states_tree) {
2093 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2094 mid_pos = max_pos / 2;
2095 while(min_pos < max_pos) {
2096 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
2097 g_assert(type == LTTV_GOBJECT);
2098 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2099 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2100 &value);
2101 g_assert(type == LTTV_TIME);
2102 if(ltt_time_compare(*(value.v_time), t) < 0) {
2103 min_pos = mid_pos;
2104 closest_tree = saved_state_tree;
2105 }
2106 else max_pos = mid_pos - 1;
2107
2108 mid_pos = (min_pos + max_pos + 1) / 2;
2109 }
2110 }
2111
2112 /* restore the closest earlier saved state */
2113 if(min_pos != -1) {
2114 lttv_state_restore(tcs, closest_tree);
2115 call_rest = 1;
2116 }
2117
2118 /* There is no saved state, yet we want to have it. Restart at T0 */
2119 else {
2120 restore_init_state(tcs);
2121 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2122 }
2123 }
2124 /* We want to seek quickly without restoring/updating the state */
2125 else {
2126 restore_init_state(tcs);
2127 lttv_process_trace_seek_time(&(tcs->parent), t);
2128 }
2129 }
2130 if(!call_rest) g_info("NOT Calling restore");
2131}
2132
2133
2134static void
2135traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2136{
2137}
2138
2139
2140static void
2141traceset_state_finalize (LttvTracesetState *self)
2142{
2143 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2144 finalize(G_OBJECT(self));
2145}
2146
2147
2148static void
2149traceset_state_class_init (LttvTracesetContextClass *klass)
2150{
2151 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2152
2153 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2154 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2155 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2156 klass->new_traceset_context = new_traceset_context;
2157 klass->new_trace_context = new_trace_context;
2158 klass->new_tracefile_context = new_tracefile_context;
2159}
2160
2161
2162GType
2163lttv_traceset_state_get_type(void)
2164{
2165 static GType type = 0;
2166 if (type == 0) {
2167 static const GTypeInfo info = {
2168 sizeof (LttvTracesetStateClass),
2169 NULL, /* base_init */
2170 NULL, /* base_finalize */
2171 (GClassInitFunc) traceset_state_class_init, /* class_init */
2172 NULL, /* class_finalize */
2173 NULL, /* class_data */
2174 sizeof (LttvTracesetState),
2175 0, /* n_preallocs */
2176 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2177 NULL /* value handling */
2178 };
2179
2180 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2181 &info, 0);
2182 }
2183 return type;
2184}
2185
2186
2187static void
2188trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2189{
2190}
2191
2192
2193static void
2194trace_state_finalize (LttvTraceState *self)
2195{
2196 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2197 finalize(G_OBJECT(self));
2198}
2199
2200
2201static void
2202trace_state_class_init (LttvTraceStateClass *klass)
2203{
2204 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2205
2206 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2207 klass->state_save = state_save;
2208 klass->state_restore = state_restore;
2209 klass->state_saved_free = state_saved_free;
2210}
2211
2212
2213GType
2214lttv_trace_state_get_type(void)
2215{
2216 static GType type = 0;
2217 if (type == 0) {
2218 static const GTypeInfo info = {
2219 sizeof (LttvTraceStateClass),
2220 NULL, /* base_init */
2221 NULL, /* base_finalize */
2222 (GClassInitFunc) trace_state_class_init, /* class_init */
2223 NULL, /* class_finalize */
2224 NULL, /* class_data */
2225 sizeof (LttvTraceState),
2226 0, /* n_preallocs */
2227 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2228 NULL /* value handling */
2229 };
2230
2231 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2232 "LttvTraceStateType", &info, 0);
2233 }
2234 return type;
2235}
2236
2237
2238static void
2239tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2240{
2241}
2242
2243
2244static void
2245tracefile_state_finalize (LttvTracefileState *self)
2246{
2247 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2248 finalize(G_OBJECT(self));
2249}
2250
2251
2252static void
2253tracefile_state_class_init (LttvTracefileStateClass *klass)
2254{
2255 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2256
2257 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2258}
2259
2260
2261GType
2262lttv_tracefile_state_get_type(void)
2263{
2264 static GType type = 0;
2265 if (type == 0) {
2266 static const GTypeInfo info = {
2267 sizeof (LttvTracefileStateClass),
2268 NULL, /* base_init */
2269 NULL, /* base_finalize */
2270 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2271 NULL, /* class_finalize */
2272 NULL, /* class_data */
2273 sizeof (LttvTracefileState),
2274 0, /* n_preallocs */
2275 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2276 NULL /* value handling */
2277 };
2278
2279 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2280 "LttvTracefileStateType", &info, 0);
2281 }
2282 return type;
2283}
2284
2285
2286static void module_init()
2287{
2288 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2289 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2290 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2291 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2292 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2293 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2294 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2295 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2296 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2297 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2298 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2299 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2300 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2301 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2302 LTTV_STATE_RUN = g_quark_from_string("RUN");
2303 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2304 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2305 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2306 LTTV_STATE_PROCESS = g_quark_from_string("process");
2307 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2308 LTTV_STATE_EVENT = g_quark_from_string("event");
2309 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2310 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2311 LTTV_STATE_TIME = g_quark_from_string("time");
2312 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2313 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2314 LTTV_STATE_TRACE_STATE_USE_COUNT =
2315 g_quark_from_string("trace_state_use_count");
2316
2317
2318 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2319 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2320 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2321 LTT_FACILITY_FS = g_quark_from_string("fs");
2322 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2323
2324
2325 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2326 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2327 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2328 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2329 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2330 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2331 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2332 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2333 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2334 LTT_EVENT_FORK = g_quark_from_string("fork");
2335 LTT_EVENT_EXIT = g_quark_from_string("exit");
2336 LTT_EVENT_FREE = g_quark_from_string("free");
2337 LTT_EVENT_EXEC = g_quark_from_string("exec");
2338 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2339
2340
2341 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2342 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2343 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2344 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2345 LTT_FIELD_OUT = g_quark_from_string("out");
2346 LTT_FIELD_IN = g_quark_from_string("in");
2347 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2348 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2349 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2350 LTT_FIELD_PID = g_quark_from_string("pid");
2351 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2352 LTT_FIELD_NAME = g_quark_from_string("name");
2353 LTT_FIELD_MODE = g_quark_from_string("mode");
2354 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2355 LTT_FIELD_STATUS = g_quark_from_string("status");
2356
2357}
2358
2359static void module_destroy()
2360{
2361}
2362
2363
2364LTTV_MODULE("state", "State computation", \
2365 "Update the system state, possibly saving it at intervals", \
2366 module_init, module_destroy)
2367
2368
2369
This page took 0.051582 seconds and 4 git commands to generate.