Fix first restoration point and set the right state when we pop from syscall
[lttv.git] / 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 #define _GNU_SOURCE
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <glib.h>
25 #include <lttv/lttv.h>
26 #include <lttv/module.h>
27 #include <lttv/state.h>
28 #include <lttv/compiler.h>
29 #include <lttv/traceset.h>
30 #include <lttv/trace.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <inttypes.h>
34 #include <babeltrace/babeltrace.h>
35
36 #define PREALLOCATED_EXECUTION_STACK 10
37
38 /* Channel Quarks */
39
40 GQuark
41 LTT_CHANNEL_FD_STATE,
42 LTT_CHANNEL_GLOBAL_STATE,
43 LTT_CHANNEL_IRQ_STATE,
44 LTT_CHANNEL_MODULE_STATE,
45 LTT_CHANNEL_NETIF_STATE,
46 LTT_CHANNEL_SOFTIRQ_STATE,
47 LTT_CHANNEL_SWAP_STATE,
48 LTT_CHANNEL_SYSCALL_STATE,
49 LTT_CHANNEL_TASK_STATE,
50 LTT_CHANNEL_VM_STATE,
51 LTT_CHANNEL_KPROBE_STATE,
52 LTT_CHANNEL_FS,
53 LTT_CHANNEL_KERNEL,
54 LTT_CHANNEL_MM,
55 LTT_CHANNEL_USERSPACE,
56 LTT_CHANNEL_BLOCK;
57
58 /* Events Quarks */
59
60 GQuark
61 LTT_EVENT_SYSCALL_ENTRY,
62 LTT_EVENT_SYSCALL_EXIT,
63 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
64 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
65 LTT_EVENT_PAGE_FAULT_ENTRY,
66 LTT_EVENT_PAGE_FAULT_EXIT,
67 //LTT_EVENT_TRAP_ENTRY,
68 //LTT_EVENT_TRAP_EXIT,
69 LTT_EVENT_IRQ_ENTRY,
70 LTT_EVENT_IRQ_EXIT,
71 LTT_EVENT_SOFT_IRQ_RAISE,
72 LTT_EVENT_SOFT_IRQ_ENTRY,
73 LTT_EVENT_SOFT_IRQ_EXIT,
74 LTT_EVENT_SCHED_SCHEDULE,
75 LTT_EVENT_SCHED_TRY_WAKEUP,
76 LTT_EVENT_PROCESS_FORK,
77 LTT_EVENT_KTHREAD_CREATE,
78 LTT_EVENT_PROCESS_EXIT,
79 LTT_EVENT_PROCESS_FREE,
80 LTT_EVENT_EXEC,
81 LTT_EVENT_PROCESS_STATE,
82 LTT_EVENT_STATEDUMP_END,
83 LTT_EVENT_FUNCTION_ENTRY,
84 LTT_EVENT_FUNCTION_EXIT,
85 LTT_EVENT_THREAD_BRAND,
86 LTT_EVENT_REQUEST_ISSUE,
87 LTT_EVENT_REQUEST_COMPLETE,
88 LTT_EVENT_LIST_INTERRUPT,
89 LTT_EVENT_SYS_CALL_TABLE,
90 LTT_EVENT_SOFTIRQ_VEC,
91 LTT_EVENT_KPROBE_TABLE,
92 LTT_EVENT_KPROBE,
93 LTT_EVENT_OPEN,
94 LTT_EVENT_READ,
95 LTT_EVENT_POLL_EVENT;
96
97 /* Fields Quarks */
98
99 GQuark
100 LTT_FIELD_SYSCALL_ID,
101 LTT_FIELD_TRAP_ID,
102 LTT_FIELD_IRQ_ID,
103 LTT_FIELD_SOFT_IRQ_ID,
104 LTT_FIELD_PREV_PID,
105 LTT_FIELD_NEXT_PID,
106 LTT_FIELD_PREV_STATE,
107 LTT_FIELD_PARENT_PID,
108 LTT_FIELD_CHILD_PID,
109 LTT_FIELD_PID,
110 LTT_FIELD_TGID,
111 LTT_FIELD_CHILD_TGID,
112 LTT_FIELD_FILENAME,
113 LTT_FIELD_NAME,
114 LTT_FIELD_TYPE,
115 LTT_FIELD_MODE,
116 LTT_FIELD_SUBMODE,
117 LTT_FIELD_STATUS,
118 LTT_FIELD_THIS_FN,
119 LTT_FIELD_CALL_SITE,
120 LTT_FIELD_MINOR,
121 LTT_FIELD_MAJOR,
122 LTT_FIELD_OPERATION,
123 LTT_FIELD_ACTION,
124 LTT_FIELD_ID,
125 LTT_FIELD_ADDRESS,
126 LTT_FIELD_SYMBOL,
127 LTT_FIELD_IP,
128 LTT_FIELD_FD,
129 LTT_FIELD_STATE,
130 LTT_FIELD_CPU_ID;
131
132 LttvExecutionMode
133 LTTV_STATE_MODE_UNKNOWN,
134 LTTV_STATE_USER_MODE,
135 LTTV_STATE_MAYBE_USER_MODE,
136 LTTV_STATE_SYSCALL,
137 LTTV_STATE_MAYBE_SYSCALL,
138 LTTV_STATE_TRAP,
139 LTTV_STATE_MAYBE_TRAP,
140 LTTV_STATE_IRQ,
141 LTTV_STATE_SOFT_IRQ;
142
143 LttvExecutionSubmode
144 LTTV_STATE_SUBMODE_UNKNOWN,
145 LTTV_STATE_SUBMODE_NONE;
146
147 LttvProcessStatus
148 LTTV_STATE_UNNAMED,
149 LTTV_STATE_WAIT_FORK,
150 LTTV_STATE_WAIT_CPU,
151 LTTV_STATE_EXIT,
152 LTTV_STATE_ZOMBIE,
153 LTTV_STATE_WAIT,
154 LTTV_STATE_RUN,
155 LTTV_STATE_DEAD;
156
157 GQuark
158 LTTV_STATE_UNBRANDED;
159
160 LttvProcessType
161 LTTV_STATE_USER_THREAD,
162 LTTV_STATE_KERNEL_THREAD;
163
164 LttvCPUMode
165 LTTV_CPU_UNKNOWN,
166 LTTV_CPU_IDLE,
167 LTTV_CPU_BUSY,
168 LTTV_CPU_IRQ,
169 LTTV_CPU_SOFT_IRQ,
170 LTTV_CPU_TRAP;
171
172 LttvIRQMode
173 LTTV_IRQ_UNKNOWN,
174 LTTV_IRQ_IDLE,
175 LTTV_IRQ_BUSY;
176
177 LttvBdevMode
178 LTTV_BDEV_UNKNOWN,
179 LTTV_BDEV_IDLE,
180 LTTV_BDEV_BUSY_READING,
181 LTTV_BDEV_BUSY_WRITING;
182
183 static GQuark
184 LTTV_STATE_TRACEFILES,
185 LTTV_STATE_PROCESSES,
186 LTTV_STATE_PROCESS,
187 LTTV_STATE_RUNNING_PROCESS,
188 LTTV_STATE_POSITION,
189 LTTV_STATE_SAVED_STATES,
190 LTTV_STATE_SAVED_STATES_TIME,
191 LTTV_STATE_TIME,
192 LTTV_STATE_HOOKS,
193 LTTV_STATE_NAME_TABLES,
194 LTTV_STATE_TRACE_STATE_USE_COUNT,
195 LTTV_STATE_RESOURCE_CPUS,
196 LTTV_STATE_RESOURCE_CPUS_COUNT,
197 LTTV_STATE_RESOURCE_IRQS,
198 LTTV_STATE_RESOURCE_SOFT_IRQS,
199 LTTV_STATE_RESOURCE_TRAPS,
200 LTTV_STATE_RESOURCE_BLKDEVS;
201
202 static void create_max_time(LttvTraceState *tcs);
203
204 static void get_max_time(LttvTraceState *tcs);
205
206 static void free_max_time(LttvTraceState *tcs);
207
208 static void create_name_tables(LttvTraceState *tcs);
209
210 static void get_name_tables(LttvTraceState *tcs);
211
212 static void free_name_tables(LttvTraceState *tcs);
213
214 static void free_saved_state(LttvTraceState *tcs);
215
216 static void lttv_state_free_process_table(GHashTable *processes);
217
218 static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
219 GPtrArray *quarktable);
220
221 /* Resource function prototypes */
222 static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint32 devcode);
223 static LttvBdevState *bdevstate_new(void);
224 static void bdevstate_free(LttvBdevState *);
225 static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data);
226 static LttvBdevState *bdevstate_copy(LttvBdevState *bds);
227 void lttv_state_add_event_hooks(LttvTraceset *traceset);
228
229 #if (__WORDSIZE == 32)
230 guint guint64_hash(gconstpointer key)
231 {
232 guint64 ukey = *(const guint64 *)key;
233
234 return (guint)ukey ^ (guint)(ukey >> 32);
235 }
236
237 gboolean guint64_equal(gconstpointer a, gconstpointer b)
238 {
239 guint64 ua = *(const guint64 *)a;
240 guint64 ub = *(const guint64 *)b;
241
242 return ua == ub;
243 }
244 #endif
245
246 guint process_hash(gconstpointer key)
247 {
248 guint pid = ((const LttvProcessState *)key)->pid;
249 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
250 }
251
252
253 /* If the hash table hash function is well distributed,
254 * the process_equal should compare different pid */
255 gboolean process_equal(gconstpointer a, gconstpointer b)
256 {
257 const LttvProcessState *process_a, *process_b;
258 gboolean ret = TRUE;
259
260 process_a = (const LttvProcessState *)a;
261 process_b = (const LttvProcessState *)b;
262
263 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
264 else if(likely(process_a->pid == 0 &&
265 process_a->cpu != process_b->cpu)) ret = FALSE;
266
267 return ret;
268 }
269
270 gboolean rettrue(gpointer key, gpointer value, gpointer user_data)
271 {
272 return TRUE;
273 }
274
275 static guint check_expand(nb, id)
276 {
277 if(likely(nb > id))
278 return nb;
279 else
280 return max(id + 1, nb * 2);
281 }
282
283 static void expand_name_table(LttvTraceState *ts, GQuark **table,
284 guint nb, guint new_nb)
285 {
286 /* Expand an incomplete table */
287 GQuark *old_table = *table;
288 *table = g_new(GQuark, new_nb);
289 memcpy(*table, old_table, nb * sizeof(GQuark));
290 g_free(old_table);
291 }
292
293 static void fill_name_table(LttvTraceState *ts, GQuark *table, guint nb,
294 guint new_nb, const char *def_string)
295 {
296 guint i;
297 GString *fe_name = g_string_new("");
298 for(i = nb; i < new_nb; i++) {
299 g_string_printf(fe_name, "%s %d", def_string, i);
300 table[i] = g_quark_from_string(fe_name->str);
301 }
302 g_string_free(fe_name, TRUE);
303 }
304
305 static void expand_kprobe_table(LttvTraceState *ts, guint64 ip, char *symbol)
306 {
307 LttvNameTables *nt = ts->name_tables;
308 #if (__WORDSIZE == 32)
309 guint64 *ip_ptr = g_new(guint64, 1);
310 g_hash_table_insert(nt->kprobe_hash, ip_ptr,
311 (gpointer)(glong)g_quark_from_string(symbol));
312 #else
313 g_hash_table_insert(nt->kprobe_hash, (gpointer)ip,
314 (gpointer)(glong)g_quark_from_string(symbol));
315 #endif
316 }
317
318 static void expand_trap_table(LttvTraceState *ts, int id)
319 {
320 LttvNameTables *nt = ts->name_tables;
321 LttvTrapState *old_table;
322 guint new_nb, i;
323
324 new_nb = check_expand(nt->nb_traps, id);
325 if(likely(new_nb == nt->nb_traps))
326 return;
327
328 expand_name_table(ts, &nt->trap_names, nt->nb_traps, new_nb);
329 fill_name_table(ts, nt->trap_names, nt->nb_traps, new_nb, "trap");
330
331 old_table = ts->trap_states;
332 ts->trap_states = g_new(LttvTrapState, new_nb);
333 memcpy(ts->trap_states, old_table, nt->nb_traps * sizeof(LttvTrapState));
334 g_free(old_table);
335 for(i = nt->nb_traps; i < new_nb; i++)
336 ts->trap_states[i].running = 0;
337
338 /* Update the table size */
339 nt->nb_traps = new_nb;
340 }
341
342 static void expand_irq_table(LttvTraceState *ts, int id)
343 {
344 LttvNameTables *nt = ts->name_tables;
345 LttvIRQState *old_table;
346 guint new_nb, i;
347
348 new_nb = check_expand(nt->nb_irqs, id);
349 if(likely(new_nb == nt->nb_irqs))
350 return;
351
352 expand_name_table(ts, &nt->irq_names, nt->nb_irqs, new_nb);
353 fill_name_table(ts, nt->irq_names, nt->nb_irqs, new_nb, "irq");
354
355 old_table = ts->irq_states;
356 ts->irq_states = g_new(LttvIRQState, new_nb);
357 memcpy(ts->irq_states, old_table, nt->nb_irqs * sizeof(LttvIRQState));
358 g_free(old_table);
359 for(i = nt->nb_irqs; i < new_nb; i++)
360 ts->irq_states[i].mode_stack =
361 g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
362
363 /* Update the table size */
364 nt->nb_irqs = new_nb;
365 }
366
367 static void expand_soft_irq_table(LttvTraceState *ts, int id)
368 {
369 LttvNameTables *nt = ts->name_tables;
370 LttvSoftIRQState *old_table;
371 guint new_nb, i;
372
373 new_nb = check_expand(nt->nb_soft_irqs, id);
374 if(likely(new_nb == nt->nb_soft_irqs))
375 return;
376
377 expand_name_table(ts, &nt->soft_irq_names, nt->nb_soft_irqs, new_nb);
378 fill_name_table(ts, nt->soft_irq_names, nt->nb_soft_irqs, new_nb, "softirq");
379
380 old_table = ts->soft_irq_states;
381 ts->soft_irq_states = g_new(LttvSoftIRQState, new_nb);
382 memcpy(ts->soft_irq_states, old_table,
383 nt->nb_soft_irqs * sizeof(LttvSoftIRQState));
384 g_free(old_table);
385 for(i = nt->nb_soft_irqs; i < new_nb; i++)
386 ts->soft_irq_states[i].running = 0;
387
388 /* Update the table size */
389 nt->nb_soft_irqs = new_nb;
390 }
391
392 static void restore_init_state(LttvTraceState *self)
393 {
394 guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
395
396 //LttvTracefileState *tfcs;
397
398 LttTime start_time;
399
400 /* Free the process tables */
401 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
402 self->processes = g_hash_table_new(process_hash, process_equal);
403 self->nb_event = 0;
404
405 /* Seek time to beginning */
406 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
407 // closest. It's the tracecontext job to seek the trace to the beginning
408 // anyway : the init state might be used at the middle of the trace as well...
409 //g_tree_destroy(self->parent.ts_context->pqueue);
410 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
411
412 start_time = ltt_time_from_uint64(
413 bt_trace_handle_get_timestamp_begin(self->trace->traceset->context,
414 self->trace->id,BT_CLOCK_REAL));
415
416
417 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
418
419 nb_cpus = lttv_trace_get_num_cpu(self->trace);
420 nb_irqs = self->name_tables->nb_irqs;
421 nb_soft_irqs = self->name_tables->nb_soft_irqs;
422 nb_traps = self->name_tables->nb_traps;
423
424 /* Put the per cpu running_process to beginning state : process 0. */
425 for(i=0; i< nb_cpus; i++) {
426 LttvExecutionState *es;
427 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
428 LTTV_STATE_UNNAMED, &start_time);
429 /* We are not sure is it's a kernel thread or normal thread, put the
430 * bottom stack state to unknown */
431 self->running_process[i]->execution_stack =
432 g_array_set_size(self->running_process[i]->execution_stack, 1);
433 es = self->running_process[i]->state =
434 &g_array_index(self->running_process[i]->execution_stack,
435 LttvExecutionState, 0);
436 es->t = LTTV_STATE_MODE_UNKNOWN;
437 es->s = LTTV_STATE_UNNAMED;
438
439 //self->running_process[i]->state->s = LTTV_STATE_RUN;
440 self->running_process[i]->cpu = i;
441
442 /* reset cpu states */
443 if(self->cpu_states[i].mode_stack->len > 0) {
444 g_array_remove_range(self->cpu_states[i].mode_stack, 0,
445 self->cpu_states[i].mode_stack->len);
446 if(self->cpu_states[i].irq_stack->len)
447 g_array_remove_range(self->cpu_states[i].irq_stack, 0,
448 self->cpu_states[i].irq_stack->len);
449 if(self->cpu_states[i].softirq_stack->len)
450 g_array_remove_range(self->cpu_states[i].softirq_stack, 0,
451 self->cpu_states[i].softirq_stack->len);
452 if(self->cpu_states[i].trap_stack->len)
453 g_array_remove_range(self->cpu_states[i].trap_stack, 0,
454 self->cpu_states[i].trap_stack->len);
455 }
456 }
457
458 /* reset irq states */
459 for(i=0; i<nb_irqs; i++) {
460 if(self->irq_states[i].mode_stack->len > 0)
461 g_array_remove_range(self->irq_states[i].mode_stack, 0,
462 self->irq_states[i].mode_stack->len);
463 }
464
465 /* reset softirq states */
466 for(i=0; i<nb_soft_irqs; i++) {
467 self->soft_irq_states[i].pending = 0;
468 self->soft_irq_states[i].running = 0;
469 }
470
471 /* reset trap states */
472 for(i=0; i<nb_traps; i++) {
473 self->trap_states[i].running = 0;
474 }
475
476 /* reset bdev states */
477 g_hash_table_foreach(self->bdev_states, bdevstate_free_cb, NULL);
478 //g_hash_table_steal_all(self->bdev_states);
479 g_hash_table_foreach_steal(self->bdev_states, rettrue, NULL);
480
481 #if 0
482 nb_tracefile = self->parent.tracefiles->len;
483
484 for(i = 0 ; i < nb_tracefile ; i++) {
485 tfcs =
486 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
487 LttvTracefileContext*, i));
488 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
489 // tfcs->saved_position = 0;
490 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
491 tfcs->process->state->s = LTTV_STATE_RUN;
492 tfcs->process->last_cpu = tfcs->cpu_name;
493 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
494 }
495 #endif //0
496 }
497
498 //static LttTime time_zero = {0,0};
499
500 #ifdef BABEL_CLEANUP
501
502 #define MAX_STRING_LEN 4096
503
504 static void state_load_saved_states(LttvTraceState *tcs)
505 {
506 FILE *fp;
507 GPtrArray *quarktable;
508 const char *trace_path;
509 char path[PATH_MAX];
510 guint count;
511 guint i;
512 tcs->has_precomputed_states = FALSE;
513 GQuark q;
514 gchar *string;
515 gint hdr;
516 gchar buf[MAX_STRING_LEN];
517 guint len;
518 size_t res;
519
520 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
521 strncpy(path, trace_path, PATH_MAX-1);
522 count = strnlen(trace_path, PATH_MAX-1);
523 // quarktable : open, test
524 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
525 fp = fopen(path, "r");
526 if(!fp) return;
527 quarktable = g_ptr_array_sized_new(4096);
528
529 /* Index 0 is null */
530 hdr = fgetc(fp);
531 if(hdr == EOF) return;
532 g_assert(hdr == HDR_QUARKS);
533 q = 1;
534 do {
535 hdr = fgetc(fp);
536 if(hdr == EOF) break;
537 g_assert(hdr == HDR_QUARK);
538 g_ptr_array_set_size(quarktable, q+1);
539 i=0;
540 while(1) {
541 res = fread(&buf[i], sizeof(gchar), 1, fp);
542 g_assert(res == 1);
543 if(buf[i] == '\0' || feof(fp)) break;
544 i++;
545 }
546 len = strnlen(buf, MAX_STRING_LEN-1);
547 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
548 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
549 q++;
550 } while(1);
551
552 fclose(fp);
553
554 // saved_states : open, test
555 strncpy(path, trace_path, PATH_MAX-1);
556 count = strnlen(trace_path, PATH_MAX-1);
557 strncat(path, "/precomputed/states", PATH_MAX-count-1);
558 fp = fopen(path, "r");
559 if(!fp) return;
560
561 hdr = fgetc(fp);
562 if(hdr != HDR_TRACE) goto end;
563
564 lttv_trace_states_read_raw(tcs, fp, quarktable);
565
566 tcs->has_precomputed_states = TRUE;
567
568 end:
569 fclose(fp);
570
571 /* Free the quarktable */
572 for(i=0; i<quarktable->len; i++) {
573 string = g_ptr_array_index (quarktable, i);
574 g_free(string);
575 }
576 g_ptr_array_free(quarktable, TRUE);
577 return;
578 }
579 #endif /* BABEL_CLEANUP */
580
581 void lttv_trace_state_init(LttvTraceState *trace_state, LttvTrace *trace)
582 {
583 guint j, nb_cpu;
584 guint64 nb_irq;
585 LttvAttributeValue v;
586
587 trace_state->trace = trace;
588
589 trace_state->save_interval = LTTV_STATE_SAVE_INTERVAL;
590 lttv_attribute_find(lttv_trace_attribute(trace), LTTV_STATE_TRACE_STATE_USE_COUNT,
591 LTTV_UINT, &v);
592 (*v.v_uint)++;
593
594 if (*(v.v_uint) == 1) {
595 create_name_tables(trace_state);
596 create_max_time(trace_state);
597 }
598 get_name_tables(trace_state);
599 get_max_time(trace_state);
600
601 nb_cpu = lttv_trace_get_num_cpu(trace);
602 nb_irq = trace_state->name_tables->nb_irqs;
603 trace_state->processes = NULL;
604 trace_state->running_process = g_new(LttvProcessState*, nb_cpu);
605
606 /* init cpu resource stuff */
607 trace_state->cpu_states = g_new(LttvCPUState, nb_cpu);
608 for (j = 0; j < nb_cpu; j++) {
609 trace_state->cpu_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
610 trace_state->cpu_states[j].irq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
611 trace_state->cpu_states[j].softirq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
612 trace_state->cpu_states[j].trap_stack = g_array_new(FALSE, FALSE, sizeof(gint));
613 g_assert(trace_state->cpu_states[j].mode_stack != NULL);
614 }
615
616 /* init irq resource stuff */
617 trace_state->irq_states = g_new(LttvIRQState, nb_irq);
618 for (j = 0; j < nb_irq; j++) {
619 trace_state->irq_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
620 g_assert(trace_state->irq_states[j].mode_stack != NULL);
621 }
622
623 /* init soft irq stuff */
624 /* the kernel has a statically fixed max of 32 softirqs */
625 trace_state->soft_irq_states = g_new(LttvSoftIRQState, trace_state->name_tables->nb_soft_irqs);
626
627 /* init trap stuff */
628 trace_state->trap_states = g_new(LttvTrapState, trace_state->name_tables->nb_traps);
629
630 /* init bdev resource stuff */
631 trace_state->bdev_states = g_hash_table_new(g_int_hash, g_int_equal);
632
633 restore_init_state(trace_state);
634
635 /* See if the trace has saved states */
636 //state_load_saved_states(trace_state);
637 }
638
639 void lttv_trace_state_fini(LttvTraceState *trace_state)
640 {
641 LttvTrace *trace = trace_state->trace;
642 LttvAttributeValue v;
643
644 lttv_attribute_find(lttv_trace_attribute(trace), LTTV_STATE_TRACE_STATE_USE_COUNT,
645 LTTV_UINT, &v);
646
647 g_assert(*(v.v_uint) != 0);
648 (*v.v_uint)--;
649
650 if (*(v.v_uint) == 0) {
651 free_name_tables(trace_state);
652 free_max_time(trace_state);
653 free_saved_state(trace_state);
654 }
655 g_free(trace_state->running_process);
656 trace_state->running_process = NULL;
657 lttv_state_free_process_table(trace_state->processes);
658 trace_state->processes = NULL;
659 }
660
661 #ifdef BABEL_CLEANUP
662
663 /* Write the process state of the trace */
664
665 static void write_process_state(gpointer key, gpointer value,
666 gpointer user_data)
667 {
668 LttvProcessState *process;
669
670 LttvExecutionState *es;
671
672 FILE *fp = (FILE *)user_data;
673
674 guint i;
675 guint64 address;
676
677 process = (LttvProcessState *)value;
678 fprintf(fp," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" FREE_EVENTS=\"%u\">\n",
679 process, process->pid, process->tgid, process->ppid,
680 g_quark_to_string(process->type),
681 process->creation_time.tv_sec,
682 process->creation_time.tv_nsec,
683 process->insertion_time.tv_sec,
684 process->insertion_time.tv_nsec,
685 g_quark_to_string(process->name),
686 g_quark_to_string(process->brand),
687 process->cpu, process->free_events);
688
689 for(i = 0 ; i < process->execution_stack->len; i++) {
690 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
691 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
692 g_quark_to_string(es->t), g_quark_to_string(es->n),
693 es->entry.tv_sec, es->entry.tv_nsec);
694 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
695 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
696 }
697
698 for(i = 0 ; i < process->user_stack->len; i++) {
699 address = g_array_index(process->user_stack, guint64, i);
700 fprintf(fp, " <USER_STACK ADDRESS=\"%" PRIu64 "\"/>\n", address);
701 }
702
703 fprintf(fp, " </PROCESS>\n");
704 }
705
706
707 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
708 {
709 guint i, nb_tracefile, nb_block, offset;
710 guint64 tsc;
711
712 LttvTracefileState *tfcs;
713
714 LttTracefile *tf;
715
716 LttEventPosition *ep;
717
718 guint nb_cpus;
719
720 ep = ltt_event_position_new();
721
722 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
723
724 g_hash_table_foreach(self->processes, write_process_state, fp);
725
726 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
727 for(i=0;i<nb_cpus;i++) {
728 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
729 i, self->running_process[i]->pid);
730 }
731
732 nb_tracefile = self->parent.tracefiles->len;
733
734 for(i = 0 ; i < nb_tracefile ; i++) {
735 tfcs =
736 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
737 LttvTracefileContext*, i));
738 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
739 tfcs->parent.timestamp.tv_sec,
740 tfcs->parent.timestamp.tv_nsec);
741 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
742 if(e == NULL) fprintf(fp,"/>\n");
743 else {
744 ltt_event_position(e, ep);
745 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
746 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%" PRIu64 "/>\n", nb_block, offset,
747 tsc);
748 }
749 }
750 g_free(ep);
751 fprintf(fp,"</PROCESS_STATE>\n");
752 }
753
754
755 static void write_process_state_raw(gpointer key, gpointer value,
756 gpointer user_data)
757 {
758 LttvProcessState *process;
759
760 LttvExecutionState *es;
761
762 FILE *fp = (FILE *)user_data;
763
764 guint i;
765 guint64 address;
766
767 process = (LttvProcessState *)value;
768 fputc(HDR_PROCESS, fp);
769 //fwrite(&header, sizeof(header), 1, fp);
770 //fprintf(fp, "%s", g_quark_to_string(process->type));
771 //fputc('\0', fp);
772 fwrite(&process->type, sizeof(process->type), 1, fp);
773 //fprintf(fp, "%s", g_quark_to_string(process->name));
774 //fputc('\0', fp);
775 fwrite(&process->name, sizeof(process->name), 1, fp);
776 //fprintf(fp, "%s", g_quark_to_string(process->brand));
777 //fputc('\0', fp);
778 fwrite(&process->brand, sizeof(process->brand), 1, fp);
779 fwrite(&process->pid, sizeof(process->pid), 1, fp);
780 fwrite(&process->free_events, sizeof(process->free_events), 1, fp);
781 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
782 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
783 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
784 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
785 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
786
787 #if 0
788 fprintf(fp," <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
789 process, process->pid, process->tgid, process->ppid,
790 g_quark_to_string(process->type),
791 process->creation_time.tv_sec,
792 process->creation_time.tv_nsec,
793 process->insertion_time.tv_sec,
794 process->insertion_time.tv_nsec,
795 g_quark_to_string(process->name),
796 g_quark_to_string(process->brand),
797 process->cpu);
798 #endif //0
799
800 for(i = 0 ; i < process->execution_stack->len; i++) {
801 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
802
803 fputc(HDR_ES, fp);
804 //fprintf(fp, "%s", g_quark_to_string(es->t));
805 //fputc('\0', fp);
806 fwrite(&es->t, sizeof(es->t), 1, fp);
807 //fprintf(fp, "%s", g_quark_to_string(es->n));
808 //fputc('\0', fp);
809 fwrite(&es->n, sizeof(es->n), 1, fp);
810 //fprintf(fp, "%s", g_quark_to_string(es->s));
811 //fputc('\0', fp);
812 fwrite(&es->s, sizeof(es->s), 1, fp);
813 fwrite(&es->entry, sizeof(es->entry), 1, fp);
814 fwrite(&es->change, sizeof(es->change), 1, fp);
815 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
816 #if 0
817 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
818 g_quark_to_string(es->t), g_quark_to_string(es->n),
819 es->entry.tv_sec, es->entry.tv_nsec);
820 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
821 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
822 #endif //0
823 }
824
825 for(i = 0 ; i < process->user_stack->len; i++) {
826 address = g_array_index(process->user_stack, guint64, i);
827 fputc(HDR_USER_STACK, fp);
828 fwrite(&address, sizeof(address), 1, fp);
829 #if 0
830 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n", address);
831 #endif //0
832 }
833 }
834
835
836 void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
837 {
838 guint i, nb_tracefile, nb_block, offset;
839 guint64 tsc;
840
841 LttvTracefileState *tfcs;
842
843 LttTracefile *tf;
844
845 LttEventPosition *ep;
846
847 guint nb_cpus;
848
849 ep = ltt_event_position_new();
850
851 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
852 fputc(HDR_PROCESS_STATE, fp);
853 fwrite(&t, sizeof(t), 1, fp);
854
855 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
856
857 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
858 for(i=0;i<nb_cpus;i++) {
859 fputc(HDR_CPU, fp);
860 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
861 fwrite(&self->running_process[i]->pid,
862 sizeof(self->running_process[i]->pid), 1, fp);
863 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
864 // i, self->running_process[i]->pid);
865 }
866
867 nb_tracefile = self->parent.tracefiles->len;
868
869 for(i = 0 ; i < nb_tracefile ; i++) {
870 tfcs =
871 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
872 LttvTracefileContext*, i));
873 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
874 // tfcs->parent.timestamp.tv_sec,
875 // tfcs->parent.timestamp.tv_nsec);
876 fputc(HDR_TRACEFILE, fp);
877 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
878 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
879 * position following : end of trace */
880 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
881 if(e != NULL) {
882 ltt_event_position(e, ep);
883 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
884 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
885 // tsc);
886 fwrite(&nb_block, sizeof(nb_block), 1, fp);
887 fwrite(&offset, sizeof(offset), 1, fp);
888 fwrite(&tsc, sizeof(tsc), 1, fp);
889 }
890 }
891 g_free(ep);
892 }
893
894
895 /* Read process state from a file */
896
897 /* Called because a HDR_PROCESS was found */
898 static void read_process_state_raw(LttvTraceState *self, FILE *fp,
899 GPtrArray *quarktable)
900 {
901 LttvExecutionState *es;
902 LttvProcessState *process, *parent_process;
903 LttvProcessState tmp;
904 GQuark tmpq;
905 size_t res;
906
907 guint64 *address;
908
909 res = fread(&tmp.type, sizeof(tmp.type), 1, fp);
910 res += fread(&tmp.name, sizeof(tmp.name), 1, fp);
911 res += fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
912 res += fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
913 res += fread(&tmp.free_events, sizeof(tmp.free_events), 1, fp);
914 res += fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
915 res += fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
916 res += fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
917 res += fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
918 res += fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
919 g_assert(res == 10);
920
921 if(tmp.pid == 0) {
922 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
923 } else {
924 /* We must link to the parent */
925 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
926 &ltt_time_zero);
927 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
928 if(process == NULL) {
929 process = lttv_state_create_process(self, parent_process, tmp.cpu,
930 tmp.pid, tmp.tgid,
931 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
932 &tmp.creation_time);
933 }
934 }
935 process->insertion_time = tmp.insertion_time;
936 process->creation_time = tmp.creation_time;
937 process->type = g_quark_from_string(
938 (gchar*)g_ptr_array_index(quarktable, tmp.type));
939 process->tgid = tmp.tgid;
940 process->ppid = tmp.ppid;
941 process->brand = g_quark_from_string(
942 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
943 process->name =
944 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
945 process->free_events = tmp.free_events;
946
947 do {
948 if(feof(fp) || ferror(fp)) goto end_loop;
949
950 gint hdr = fgetc(fp);
951 if(hdr == EOF) goto end_loop;
952
953 switch(hdr) {
954 case HDR_ES:
955 process->execution_stack =
956 g_array_set_size(process->execution_stack,
957 process->execution_stack->len + 1);
958 es = &g_array_index(process->execution_stack, LttvExecutionState,
959 process->execution_stack->len-1);
960 process->state = es;
961
962 res = fread(&es->t, sizeof(es->t), 1, fp);
963 g_assert(res == 1);
964 es->t = g_quark_from_string(
965 (gchar*)g_ptr_array_index(quarktable, es->t));
966 res = fread(&es->n, sizeof(es->n), 1, fp);
967 g_assert(res == 1);
968 es->n = g_quark_from_string(
969 (gchar*)g_ptr_array_index(quarktable, es->n));
970 res = fread(&es->s, sizeof(es->s), 1, fp);
971 g_assert(res == 1);
972 es->s = g_quark_from_string(
973 (gchar*)g_ptr_array_index(quarktable, es->s));
974 res = fread(&es->entry, sizeof(es->entry), 1, fp);
975 res += fread(&es->change, sizeof(es->change), 1, fp);
976 res += fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
977 g_assert(res == 3);
978 break;
979
980 case HDR_USER_STACK:
981 process->user_stack = g_array_set_size(process->user_stack,
982 process->user_stack->len + 1);
983 address = &g_array_index(process->user_stack, guint64,
984 process->user_stack->len-1);
985 res = fread(address, sizeof(address), 1, fp);
986 g_assert(res == 1);
987 process->current_function = *address;
988 break;
989
990 default:
991 ungetc(hdr, fp);
992 goto end_loop;
993 };
994 } while(1);
995 end_loop:
996 return;
997 }
998
999
1000 /* Called because a HDR_PROCESS_STATE was found */
1001 /* Append a saved state to the trace states */
1002 void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
1003 {
1004 guint i, nb_tracefile, nb_block, offset;
1005 guint64 tsc;
1006 LttvTracefileState *tfcs;
1007
1008 LttEventPosition *ep;
1009
1010 guint nb_cpus;
1011
1012 int hdr;
1013 size_t res;
1014
1015 LttTime t;
1016
1017 LttvAttribute *saved_states_tree, *saved_state_tree;
1018
1019 LttvAttributeValue value;
1020 GTree *pqueue = self->parent.ts_context->pqueue;
1021 ep = ltt_event_position_new();
1022
1023 restore_init_state(self);
1024
1025 res = fread(&t, sizeof(t), 1, fp);
1026 g_assert(res == 1);
1027
1028 do {
1029 if(feof(fp) || ferror(fp)) goto end_loop;
1030 hdr = fgetc(fp);
1031 if(hdr == EOF) goto end_loop;
1032
1033 switch(hdr) {
1034 case HDR_PROCESS:
1035 /* Call read_process_state_raw */
1036 read_process_state_raw(self, fp, quarktable);
1037 break;
1038 case HDR_TRACEFILE:
1039 case HDR_TRACESET:
1040 case HDR_TRACE:
1041 case HDR_QUARKS:
1042 case HDR_QUARK:
1043 case HDR_ES:
1044 case HDR_USER_STACK:
1045 case HDR_PROCESS_STATE:
1046 case HDR_CPU:
1047 ungetc(hdr, fp);
1048 goto end_loop;
1049 break;
1050 default:
1051 g_error("Error while parsing saved state file : unknown data header %d",
1052 hdr);
1053 };
1054 } while(1);
1055 end_loop:
1056
1057 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1058 for(i=0;i<nb_cpus;i++) {
1059 int cpu_num;
1060 hdr = fgetc(fp);
1061 g_assert(hdr == HDR_CPU);
1062 res = fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
1063 g_assert(res == 1);
1064 g_assert(i == cpu_num);
1065 res = fread(&self->running_process[i]->pid,
1066 sizeof(self->running_process[i]->pid), 1, fp);
1067 g_assert(res == 1);
1068 }
1069
1070 nb_tracefile = self->parent.tracefiles->len;
1071
1072 for(i = 0 ; i < nb_tracefile ; i++) {
1073 tfcs =
1074 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1075 LttvTracefileContext*, i));
1076 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
1077 // tfcs->parent.timestamp.tv_sec,
1078 // tfcs->parent.timestamp.tv_nsec);
1079 g_tree_remove(pqueue, &tfcs->parent);
1080 hdr = fgetc(fp);
1081 g_assert(hdr == HDR_TRACEFILE);
1082 res = fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
1083 g_assert(res == 1);
1084 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1085 * position following : end of trace */
1086 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
1087 res = fread(&nb_block, sizeof(nb_block), 1, fp);
1088 res += fread(&offset, sizeof(offset), 1, fp);
1089 res += fread(&tsc, sizeof(tsc), 1, fp);
1090 g_assert(res == 3);
1091 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
1092 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
1093 g_assert(ret == 0);
1094 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
1095 }
1096 }
1097 g_free(ep);
1098
1099 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
1100 LTTV_STATE_SAVED_STATES);
1101 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1102 value = lttv_attribute_add(saved_states_tree,
1103 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1104 *(value.v_gobject) = (GObject *)saved_state_tree;
1105 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1106 *(value.v_time) = t;
1107 lttv_state_save(self, saved_state_tree);
1108 g_debug("Saving state at time %lu.%lu", t.tv_sec,
1109 t.tv_nsec);
1110
1111 *(self->max_time_state_recomputed_in_seek) = t;
1112
1113 }
1114
1115 /* Called when a HDR_TRACE is found */
1116 void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
1117 GPtrArray *quarktable)
1118 {
1119 int hdr;
1120
1121 do {
1122 if(feof(fp) || ferror(fp)) goto end_loop;
1123 hdr = fgetc(fp);
1124 if(hdr == EOF) goto end_loop;
1125
1126 switch(hdr) {
1127 case HDR_PROCESS_STATE:
1128 /* Call read_process_state_raw */
1129 lttv_state_read_raw(tcs, fp, quarktable);
1130 break;
1131 case HDR_TRACEFILE:
1132 case HDR_TRACESET:
1133 case HDR_TRACE:
1134 case HDR_QUARKS:
1135 case HDR_QUARK:
1136 case HDR_ES:
1137 case HDR_USER_STACK:
1138 case HDR_PROCESS:
1139 case HDR_CPU:
1140 g_error("Error while parsing saved state file :"
1141 " unexpected data header %d",
1142 hdr);
1143 break;
1144 default:
1145 g_error("Error while parsing saved state file : unknown data header %d",
1146 hdr);
1147 };
1148 } while(1);
1149 end_loop:
1150 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1151 restore_init_state(tcs);
1152 lttv_process_trace_seek_time(&tcs->parent, ltt_time_zero);
1153 return;
1154 }
1155 #endif /* BABEL_CLEANUP */
1156
1157
1158 /* Copy each process from an existing hash table to a new one */
1159
1160 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
1161 {
1162 LttvProcessState *process, *new_process;
1163
1164 GHashTable *new_processes = (GHashTable *)user_data;
1165
1166 guint i;
1167
1168 process = (LttvProcessState *)value;
1169 new_process = g_new(LttvProcessState, 1);
1170 *new_process = *process;
1171 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1172 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1173 new_process->execution_stack =
1174 g_array_set_size(new_process->execution_stack,
1175 process->execution_stack->len);
1176 for(i = 0 ; i < process->execution_stack->len; i++) {
1177 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1178 g_array_index(process->execution_stack, LttvExecutionState, i);
1179 }
1180 new_process->state = &g_array_index(new_process->execution_stack,
1181 LttvExecutionState, new_process->execution_stack->len - 1);
1182 #ifdef BABEL_CLEANUP
1183 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1184 sizeof(guint64), 0);
1185 new_process->user_stack = g_array_set_size(new_process->user_stack,
1186 process->user_stack->len);
1187 for(i = 0 ; i < process->user_stack->len; i++) {
1188 g_array_index(new_process->user_stack, guint64, i) =
1189 g_array_index(process->user_stack, guint64, i);
1190 }
1191 new_process->current_function = process->current_function;
1192 #endif /* BABEL_CLEANUP */
1193
1194 /* fd hash table stuff */
1195 {
1196 GHashTableIter it;
1197 gpointer key;
1198 gpointer value;
1199
1200 /* copy every item in the hash table */
1201 new_process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
1202
1203 g_hash_table_iter_init(&it, process->fds);
1204 while (g_hash_table_iter_next (&it, (void *)&key, (void *)&value)) {
1205 g_hash_table_insert(new_process->fds, key, value);
1206 }
1207 }
1208
1209 /* When done creating the new process state, insert it in the
1210 * hash table */
1211 g_hash_table_insert(new_processes, new_process, new_process);
1212 }
1213
1214
1215 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
1216 {
1217 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
1218
1219 g_hash_table_foreach(processes, copy_process_state, new_processes);
1220 return new_processes;
1221 }
1222
1223 static LttvCPUState *lttv_state_copy_cpu_states(LttvCPUState *states, guint n)
1224 {
1225 guint i,j;
1226 LttvCPUState *retval;
1227
1228 retval = g_new(LttvCPUState, n);
1229
1230 for(i=0; i<n; i++) {
1231 retval[i].irq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1232 g_array_set_size(retval[i].irq_stack, states[i].irq_stack->len);
1233 for(j=0; j<states[i].irq_stack->len; j++) {
1234 g_array_index(retval[i].irq_stack, gint, j) =
1235 g_array_index(states[i].irq_stack, gint, j);
1236 }
1237
1238 retval[i].softirq_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1239 g_array_set_size(retval[i].softirq_stack, states[i].softirq_stack->len);
1240 for(j=0; j<states[i].softirq_stack->len; j++) {
1241 g_array_index(retval[i].softirq_stack, gint, j) =
1242 g_array_index(states[i].softirq_stack, gint, j);
1243 }
1244
1245 retval[i].trap_stack = g_array_new(FALSE, FALSE, sizeof(gint));
1246 g_array_set_size(retval[i].trap_stack, states[i].trap_stack->len);
1247 for(j=0; j<states[i].trap_stack->len; j++) {
1248 g_array_index(retval[i].trap_stack, gint, j) =
1249 g_array_index(states[i].trap_stack, gint, j);
1250 }
1251
1252 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
1253 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1254 for(j=0; j<states[i].mode_stack->len; j++) {
1255 g_array_index(retval[i].mode_stack, GQuark, j) =
1256 g_array_index(states[i].mode_stack, GQuark, j);
1257 }
1258 }
1259
1260 return retval;
1261 }
1262
1263 static void lttv_state_free_cpu_states(LttvCPUState *states, guint n)
1264 {
1265 guint i;
1266
1267 for(i=0; i<n; i++) {
1268 g_array_free(states[i].mode_stack, TRUE);
1269 g_array_free(states[i].irq_stack, TRUE);
1270 g_array_free(states[i].softirq_stack, TRUE);
1271 g_array_free(states[i].trap_stack, TRUE);
1272 }
1273
1274 g_free(states);
1275 }
1276
1277 static LttvIRQState *lttv_state_copy_irq_states(LttvIRQState *states, guint n)
1278 {
1279 guint i,j;
1280 LttvIRQState *retval;
1281
1282 retval = g_new(LttvIRQState, n);
1283
1284 for(i=0; i<n; i++) {
1285 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
1286 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1287 for(j=0; j<states[i].mode_stack->len; j++) {
1288 g_array_index(retval[i].mode_stack, GQuark, j) =
1289 g_array_index(states[i].mode_stack, GQuark, j);
1290 }
1291 }
1292
1293 return retval;
1294 }
1295
1296 static void lttv_state_free_irq_states(LttvIRQState *states, guint n)
1297 {
1298 guint i;
1299
1300 for(i=0; i<n; i++) {
1301 g_array_free(states[i].mode_stack, TRUE);
1302 }
1303
1304 g_free(states);
1305 }
1306
1307 static LttvSoftIRQState *
1308 lttv_state_copy_soft_irq_states(LttvSoftIRQState *states, guint n)
1309 {
1310 guint i;
1311 LttvSoftIRQState *retval;
1312
1313 retval = g_new(LttvSoftIRQState, n);
1314
1315 for(i=0; i<n; i++) {
1316 retval[i].pending = states[i].pending;
1317 retval[i].running = states[i].running;
1318 }
1319
1320 return retval;
1321 }
1322
1323 static void lttv_state_free_soft_irq_states(LttvSoftIRQState *states, guint n)
1324 {
1325 g_free(states);
1326 }
1327
1328 static LttvTrapState *
1329 lttv_state_copy_trap_states(LttvTrapState *states, guint n)
1330 {
1331 guint i;
1332 LttvTrapState *retval;
1333
1334 retval = g_new(LttvTrapState, n);
1335
1336 for(i=0; i<n; i++) {
1337 retval[i].running = states[i].running;
1338 }
1339
1340 return retval;
1341 }
1342
1343 static void lttv_state_free_trap_states(LttvTrapState *states, guint n)
1344 {
1345 g_free(states);
1346 }
1347
1348 /* bdevstate stuff */
1349
1350 static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint32 devcode)
1351 {
1352 gint devcode_gint = devcode;
1353 gpointer bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
1354 if(bdev == NULL) {
1355 LttvBdevState *bdevstate = g_new(LttvBdevState, 1);
1356 bdevstate->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1357
1358 gint * key = g_new(gint, 1);
1359 *key = devcode;
1360 g_hash_table_insert(ts->bdev_states, key, bdevstate);
1361
1362 bdev = bdevstate;
1363 }
1364
1365 return bdev;
1366 }
1367
1368 static LttvBdevState *bdevstate_new(void)
1369 {
1370 LttvBdevState *retval;
1371 retval = g_new(LttvBdevState, 1);
1372 retval->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
1373
1374 return retval;
1375 }
1376
1377 static void bdevstate_free(LttvBdevState *bds)
1378 {
1379 g_array_free(bds->mode_stack, TRUE);
1380 g_free(bds);
1381 }
1382
1383 static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data)
1384 {
1385 LttvBdevState *bds = (LttvBdevState *) value;
1386
1387 bdevstate_free(bds);
1388 }
1389
1390 static LttvBdevState *bdevstate_copy(LttvBdevState *bds)
1391 {
1392 LttvBdevState *retval;
1393
1394 retval = bdevstate_new();
1395 g_array_insert_vals(retval->mode_stack, 0, bds->mode_stack->data,
1396 bds->mode_stack->len);
1397
1398 return retval;
1399 }
1400
1401 static void insert_and_copy_bdev_state(gpointer k, gpointer v, gpointer u)
1402 {
1403 //GHashTable *ht = (GHashTable *)u;
1404 LttvBdevState *bds = (LttvBdevState *)v;
1405 LttvBdevState *newbds;
1406
1407 newbds = bdevstate_copy(bds);
1408
1409 g_hash_table_insert(u, k, newbds);
1410 }
1411
1412 static GHashTable *lttv_state_copy_blkdev_hashtable(GHashTable *ht)
1413 {
1414 GHashTable *retval;
1415
1416 retval = g_hash_table_new(g_int_hash, g_int_equal);
1417
1418 g_hash_table_foreach(ht, insert_and_copy_bdev_state, retval);
1419
1420 return retval;
1421 }
1422
1423 /* Free a hashtable and the LttvBdevState structures its values
1424 * point to. */
1425
1426 static void lttv_state_free_blkdev_hashtable(GHashTable *ht)
1427 {
1428 g_hash_table_foreach(ht, bdevstate_free_cb, NULL);
1429 g_hash_table_destroy(ht);
1430 }
1431
1432 /* The saved state for each trace contains a member "processes", which
1433 stores a copy of the process table, and a member "tracefiles" with
1434 one entry per tracefile. Each tracefile has a "process" member pointing
1435 to the current process and a "position" member storing the tracefile
1436 position (needed to seek to the current "next" event. */
1437
1438 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
1439 {
1440 guint i, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1441
1442 guint *running_process;
1443
1444 LttvAttributeValue value;
1445
1446 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1447 LTTV_POINTER);
1448 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1449
1450 /* Add the currently running processes array */
1451 nb_cpus = lttv_trace_get_num_cpu(self->trace);
1452 running_process = g_new(guint, nb_cpus);
1453 for(i=0;i<nb_cpus;i++) {
1454 running_process[i] = self->running_process[i]->pid;
1455 }
1456 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1457 LTTV_POINTER);
1458 *(value.v_pointer) = running_process;
1459
1460 g_info("State save");
1461
1462 /* Save the current position */
1463 value = lttv_attribute_add(container, LTTV_STATE_POSITION,
1464 LTTV_POINTER);
1465 *(value.v_pointer) = lttv_traceset_create_current_position(lttv_trace_get_traceset(self->trace));
1466
1467 #ifdef BABEL_CLEANUP
1468 nb_tracefile = self->parent.tracefiles->len;
1469 for(i = 0 ; i < nb_tracefile ; i++) {
1470 tfcs =
1471 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1472 LttvTracefileContext*, i));
1473 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1474 value = lttv_attribute_add(tracefiles_tree, i,
1475 LTTV_GOBJECT);
1476 *(value.v_gobject) = (GObject *)tracefile_tree;
1477 #if 0
1478 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1479 LTTV_UINT);
1480 *(value.v_uint) = tfcs->process->pid;
1481 #endif //0
1482 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1483 LTTV_POINTER);
1484 /* Only save the position if the tfs has not infinite time. */
1485 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1486 // && current_tfcs != tfcs) {
1487 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1488 *(value.v_pointer) = NULL;
1489 } else {
1490 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
1491 ep = ltt_event_position_new();
1492 ltt_event_position(e, ep);
1493 *(value.v_pointer) = ep;
1494
1495 guint nb_block, offset;
1496 guint64 tsc;
1497 LttTracefile *tf;
1498 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
1499 g_info("Block %u offset %u tsc %" PRIu64 " time %lu.%lu", nb_block,
1500 offset, tsc, tfcs->parent.timestamp.tv_sec,
1501 tfcs->parent.timestamp.tv_nsec);
1502 }
1503 }
1504 #endif /* BABEL_CLEANUP */
1505
1506 /* save the cpu state */
1507 {
1508 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS_COUNT,
1509 LTTV_UINT);
1510 *(value.v_uint) = nb_cpus;
1511
1512 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS,
1513 LTTV_POINTER);
1514 *(value.v_pointer) = lttv_state_copy_cpu_states(self->cpu_states, nb_cpus);
1515 }
1516
1517 /* save the irq state */
1518 nb_irqs = self->name_tables->nb_irqs;
1519 {
1520 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_IRQS,
1521 LTTV_POINTER);
1522 *(value.v_pointer) = lttv_state_copy_irq_states(self->irq_states, nb_irqs);
1523 }
1524
1525 /* save the soft irq state */
1526 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1527 {
1528 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_SOFT_IRQS,
1529 LTTV_POINTER);
1530 *(value.v_pointer) = lttv_state_copy_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1531 }
1532
1533 /* save the trap state */
1534 nb_traps = self->name_tables->nb_traps;
1535 {
1536 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_TRAPS,
1537 LTTV_POINTER);
1538 *(value.v_pointer) = lttv_state_copy_trap_states(self->trap_states, nb_traps);
1539 }
1540
1541 /* save the blkdev states */
1542 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_BLKDEVS,
1543 LTTV_POINTER);
1544 *(value.v_pointer) = lttv_state_copy_blkdev_hashtable(self->bdev_states);
1545 }
1546
1547 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
1548 {
1549 guint i, pid, nb_cpus, nb_irqs, nb_soft_irqs, nb_traps;
1550 guint *running_process;
1551 LttvAttributeType type;
1552 LttvAttributeValue value;
1553
1554 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1555 &value);
1556 g_assert(type == LTTV_POINTER);
1557 lttv_state_free_process_table(self->processes);
1558 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1559
1560 /* Add the currently running processes array */
1561 nb_cpus = lttv_trace_get_num_cpu(self->trace);
1562 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1563 &value);
1564 g_assert(type == LTTV_POINTER);
1565 running_process = *(value.v_pointer);
1566 for(i=0;i<nb_cpus;i++) {
1567 pid = running_process[i];
1568 self->running_process[i] = lttv_state_find_process(self, i, pid);
1569 g_assert(self->running_process[i] != NULL);
1570 }
1571
1572 //nb_tracefile = self->parent.tracefiles->len;
1573
1574 //g_tree_destroy(tsc->pqueue);
1575 //tsc->pqueue = g_tree_new(compare_tracefile);
1576
1577 /* restore cpu resource states */
1578 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1579 g_assert(type == LTTV_POINTER);
1580 lttv_state_free_cpu_states(self->cpu_states, nb_cpus);
1581 self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus);
1582
1583 /* restore irq resource states */
1584 nb_irqs = self->name_tables->nb_irqs;
1585 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1586 g_assert(type == LTTV_POINTER);
1587 lttv_state_free_irq_states(self->irq_states, nb_irqs);
1588 self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs);
1589
1590 /* restore soft irq resource states */
1591 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1592 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1593 g_assert(type == LTTV_POINTER);
1594 lttv_state_free_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1595 self->soft_irq_states = lttv_state_copy_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1596
1597 /* restore trap resource states */
1598 nb_traps = self->name_tables->nb_traps;
1599 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_TRAPS, &value);
1600 g_assert(type == LTTV_POINTER);
1601 lttv_state_free_trap_states(self->trap_states, nb_traps);
1602 self->trap_states = lttv_state_copy_trap_states(*(value.v_pointer), nb_traps);
1603
1604 /* restore the blkdev states */
1605 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1606 g_assert(type == LTTV_POINTER);
1607 lttv_state_free_blkdev_hashtable(self->bdev_states);
1608 self->bdev_states = lttv_state_copy_blkdev_hashtable(*(value.v_pointer));
1609
1610 #ifdef BABEL_CLEANUP
1611 for(i = 0 ; i < nb_tracefile ; i++) {
1612 tfcs =
1613 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1614 LttvTracefileContext*, i));
1615 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1616 g_assert(type == LTTV_GOBJECT);
1617 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1618 #if 0
1619 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1620 &value);
1621 g_assert(type == LTTV_UINT);
1622 pid = *(value.v_uint);
1623 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
1624 #endif //0
1625 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1626 &value);
1627 g_assert(type == LTTV_POINTER);
1628 //g_assert(*(value.v_pointer) != NULL);
1629 ep = *(value.v_pointer);
1630 g_assert(tfcs->parent.t_context != NULL);
1631
1632 tfcs->cpu_state = &self->cpu_states[tfcs->cpu];
1633
1634 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
1635 g_tree_remove(tsc->pqueue, tfc);
1636
1637 if(ep != NULL) {
1638 retval= ltt_tracefile_seek_position(tfc->tf, ep);
1639 g_assert_cmpint(retval, ==, 0);
1640 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
1641 g_assert_cmpint(ltt_time_compare(tfc->timestamp, ltt_time_infinite),
1642 !=, 0);
1643 g_tree_insert(tsc->pqueue, tfc, tfc);
1644 g_info("Restoring state for a tf at time %lu.%lu",
1645 tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1646 } else {
1647 tfc->timestamp = ltt_time_infinite;
1648 }
1649 }
1650 #endif /* BABEL_CLEANUP */
1651 }
1652
1653 /*
1654 * Note: the position must be explicitely set on the entire traceset to
1655 * match the trace states.
1656 */
1657 LttvTracesetPosition *lttv_trace_state_get_position(LttvAttribute *container)
1658 {
1659 LttvAttributeType type;
1660 LttvAttributeValue value;
1661
1662 type = lttv_attribute_get_by_name(container, LTTV_STATE_POSITION, &value);
1663 g_assert(type == LTTV_POINTER);
1664 return *(value.v_pointer);
1665 }
1666
1667 void lttv_state_saved_free(LttvTraceState *self, LttvAttribute *container)
1668 {
1669 guint nb_cpus, nb_irqs, nb_soft_irqs;
1670 guint *running_process;
1671 LttvAttributeType type;
1672 LttvAttributeValue value;
1673
1674 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1675 &value);
1676 g_assert(type == LTTV_POINTER);
1677 lttv_state_free_process_table(*(value.v_pointer));
1678 *(value.v_pointer) = NULL;
1679 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1680
1681 /* Free running processes array */
1682 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1683 &value);
1684 g_assert(type == LTTV_POINTER);
1685 running_process = *(value.v_pointer);
1686 g_free(running_process);
1687
1688 /* free cpu resources */
1689 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS_COUNT, &value);
1690 g_assert(type == LTTV_UINT);
1691 nb_cpus = *value.v_uint;
1692 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1693 g_assert(type == LTTV_POINTER);
1694 lttv_state_free_cpu_states(*(value.v_pointer), nb_cpus);
1695
1696 /* free irq resource states */
1697 nb_irqs = self->name_tables->nb_irqs;
1698 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1699 g_assert(type == LTTV_POINTER);
1700 lttv_state_free_irq_states(*(value.v_pointer), nb_irqs);
1701
1702 /* free softirq resource states */
1703 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1704 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1705 g_assert(type == LTTV_POINTER);
1706 lttv_state_free_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1707
1708 /* free the blkdev states */
1709 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1710 g_assert(type == LTTV_POINTER);
1711 lttv_state_free_blkdev_hashtable(*(value.v_pointer));
1712
1713 /* remove the position */
1714 type = lttv_attribute_get_by_name(container, LTTV_STATE_POSITION, &value);
1715 g_assert(type == LTTV_POINTER);
1716 lttv_traceset_destroy_position(*(value.v_pointer));
1717
1718 #ifdef BABEL_CLEANUP
1719 nb_tracefile = self->parent.tracefiles->len;
1720
1721 for(i = 0 ; i < nb_tracefile ; i++) {
1722
1723 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1724 g_assert(type == LTTV_GOBJECT);
1725 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1726
1727 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1728 &value);
1729 g_assert(type == LTTV_POINTER);
1730 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
1731 }
1732 g_object_unref(G_OBJECT(tracefiles_tree));
1733 #endif /* BABEL_CLEANUP */
1734 }
1735
1736
1737 static void free_saved_state(LttvTraceState *self)
1738 {
1739 guint i, nb;
1740 LttvAttributeType type;
1741 LttvAttributeValue value;
1742 LttvAttributeName name;
1743 gboolean is_named;
1744 LttvAttribute *saved_states;
1745
1746 saved_states = lttv_attribute_find_subdir(lttv_trace_attribute(self->trace),
1747 LTTV_STATE_SAVED_STATES);
1748
1749 nb = lttv_attribute_get_number(saved_states);
1750 for(i = 0 ; i < nb ; i++) {
1751 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
1752 g_assert(type == LTTV_GOBJECT);
1753 lttv_state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1754 }
1755
1756 lttv_attribute_remove_by_name(lttv_trace_attribute(self->trace),
1757 LTTV_STATE_SAVED_STATES);
1758 }
1759
1760
1761 static void create_max_time(LttvTraceState *trace_state)
1762 {
1763 LttvAttributeValue v;
1764
1765 lttv_attribute_find(lttv_trace_attribute(trace_state->trace),
1766 LTTV_STATE_SAVED_STATES_TIME,
1767 LTTV_POINTER, &v);
1768 g_assert(*(v.v_pointer) == NULL);
1769 *(v.v_pointer) = g_new(LttTime,1);
1770 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
1771 }
1772
1773
1774 static void get_max_time(LttvTraceState *trace_state)
1775 {
1776 LttvAttributeValue v;
1777
1778 lttv_attribute_find(lttv_trace_attribute(trace_state->trace),
1779 LTTV_STATE_SAVED_STATES_TIME,
1780 LTTV_POINTER, &v);
1781 g_assert(*(v.v_pointer) != NULL);
1782 trace_state->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1783 }
1784
1785
1786 static void free_max_time(LttvTraceState *trace_state)
1787 {
1788 LttvAttributeValue v;
1789
1790 lttv_attribute_find(lttv_trace_attribute(trace_state->trace),
1791 LTTV_STATE_SAVED_STATES_TIME,
1792 LTTV_POINTER, &v);
1793 g_free(*(v.v_pointer));
1794 *(v.v_pointer) = NULL;
1795 }
1796
1797 static void create_name_tables(LttvTraceState *tcs)
1798 {
1799 int i;
1800
1801 GString *fe_name = g_string_new("");
1802
1803 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1804
1805 LttvAttributeValue v;
1806
1807 // GArray *hooks;
1808
1809 lttv_attribute_find(lttv_trace_attribute(tcs->trace), LTTV_STATE_NAME_TABLES,
1810 LTTV_POINTER, &v);
1811 g_assert(*(v.v_pointer) == NULL);
1812 *(v.v_pointer) = name_tables;
1813
1814 #ifdef BABEL_CLEANUP
1815 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1);
1816
1817 if(!lttv_trace_find_hook(tcs->parent.t,
1818 LTT_CHANNEL_KERNEL,
1819 LTT_EVENT_SYSCALL_ENTRY,
1820 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
1821 NULL, NULL, &hooks)) {
1822
1823 // th = lttv_trace_hook_get_first(&th);
1824 //
1825 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1826 // nb = ltt_type_element_number(t);
1827 //
1828 // name_tables->syscall_names = g_new(GQuark, nb);
1829 // name_tables->nb_syscalls = nb;
1830 //
1831 // for(i = 0 ; i < nb ; i++) {
1832 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1833 // if(!name_tables->syscall_names[i]) {
1834 // GString *string = g_string_new("");
1835 // g_string_printf(string, "syscall %u", i);
1836 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1837 // g_string_free(string, TRUE);
1838 // }
1839 // }
1840 #endif /* BABEL_CLEANUP */
1841
1842 name_tables->nb_syscalls = PREALLOC_NB_SYSCALLS;
1843 name_tables->syscall_names = g_new(GQuark, name_tables->nb_syscalls);
1844 for(i = 0 ; i < name_tables->nb_syscalls; i++) {
1845 g_string_printf(fe_name, "syscall %d", i);
1846 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1847 }
1848 #ifdef BABEL_CLEANUP
1849 } else {
1850 name_tables->syscall_names = NULL;
1851 name_tables->nb_syscalls = 0;
1852 }
1853 lttv_trace_hook_remove_all(&hooks);
1854 #endif /* BABEL_CLEANUP */
1855
1856 #ifdef BABEL_CLEANUP
1857 if(!lttv_trace_find_hook(tcs->parent.t,
1858 LTT_CHANNEL_KERNEL,
1859 LTT_EVENT_TRAP_ENTRY,
1860 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
1861 NULL, NULL, &hooks) ||
1862 !lttv_trace_find_hook(tcs->parent.t,
1863 LTT_CHANNEL_KERNEL,
1864 LTT_EVENT_PAGE_FAULT_ENTRY,
1865 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
1866 NULL, NULL, &hooks)) {
1867
1868 // th = lttv_trace_hook_get_first(&th);
1869 //
1870 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1871 // //nb = ltt_type_element_number(t);
1872 //
1873 // name_tables->trap_names = g_new(GQuark, nb);
1874 // for(i = 0 ; i < nb ; i++) {
1875 // name_tables->trap_names[i] = g_quark_from_string(
1876 // ltt_enum_string_get(t, i));
1877 // }
1878
1879 #endif /* BABEL_CLEANUP */
1880 name_tables->nb_traps = PREALLOC_NB_TRAPS;
1881 name_tables->trap_names = g_new(GQuark, name_tables->nb_traps);
1882 for(i = 0 ; i < name_tables->nb_traps; i++) {
1883 g_string_printf(fe_name, "trap %d", i);
1884 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1885 }
1886 #ifdef BABEL_CLEANUP
1887 } else {
1888 name_tables->trap_names = NULL;
1889 name_tables->nb_traps = 0;
1890 }
1891 lttv_trace_hook_remove_all(&hooks);
1892 #endif /* BABEL_CLEANUP */
1893
1894 #ifdef BABEL_CLEANUP
1895 if(!lttv_trace_find_hook(tcs->parent.t,
1896 LTT_CHANNEL_KERNEL,
1897 LTT_EVENT_IRQ_ENTRY,
1898 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
1899 NULL, NULL, &hooks)) {
1900
1901 /*
1902 name_tables->irq_names = g_new(GQuark, nb);
1903 for(i = 0 ; i < nb ; i++) {
1904 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1905 }
1906 */
1907 /* FIXME: LttvIRQState *irq_states should become a g_array */
1908
1909 #endif /* BABEL_CLEANUP */
1910 name_tables->nb_irqs = PREALLOC_NB_IRQS;
1911 name_tables->irq_names = g_new(GQuark, name_tables->nb_irqs);
1912 for(i = 0 ; i < name_tables->nb_irqs; i++) {
1913 g_string_printf(fe_name, "irq %d", i);
1914 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1915 }
1916 #ifdef BABEL_CLEANUP
1917 } else {
1918 name_tables->nb_irqs = 0;
1919 name_tables->irq_names = NULL;
1920 }
1921 lttv_trace_hook_remove_all(&hooks);
1922 #endif /* BABEL_CLEANUP */
1923 /*
1924 name_tables->soft_irq_names = g_new(GQuark, nb);
1925 for(i = 0 ; i < nb ; i++) {
1926 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1927 }
1928 */
1929
1930 name_tables->nb_soft_irqs = PREALLOC_NB_SOFT_IRQS;
1931 name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_soft_irqs);
1932 for(i = 0 ; i < name_tables->nb_soft_irqs ; i++) {
1933 g_string_printf(fe_name, "softirq %d", i);
1934 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1935 }
1936 // g_array_free(hooks, TRUE);
1937
1938 g_string_free(fe_name, TRUE);
1939
1940 #if (__WORDSIZE == 32)
1941 name_tables->kprobe_hash = g_hash_table_new_full(guint64_hash, guint64_equal,
1942 g_free, NULL);
1943 #else
1944 name_tables->kprobe_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
1945 #endif
1946 }
1947
1948
1949 static void get_name_tables(LttvTraceState *tcs)
1950 {
1951 LttvAttributeValue v;
1952
1953 lttv_attribute_find(lttv_trace_attribute(tcs->trace), LTTV_STATE_NAME_TABLES,
1954 LTTV_POINTER, &v);
1955 g_assert(*(v.v_pointer) != NULL);
1956 tcs->name_tables = (LttvNameTables *)*(v.v_pointer);
1957 }
1958
1959
1960 static void free_name_tables(LttvTraceState *tcs)
1961 {
1962 LttvNameTables *name_tables;
1963
1964 LttvAttributeValue v;
1965
1966 lttv_attribute_find(lttv_trace_attribute(tcs->trace), LTTV_STATE_NAME_TABLES,
1967 LTTV_POINTER, &v);
1968 name_tables = (LttvNameTables *)*(v.v_pointer);
1969 *(v.v_pointer) = NULL;
1970
1971 // g_free(name_tables->eventtype_names);
1972 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1973 if(name_tables->trap_names) g_free(name_tables->trap_names);
1974 if(name_tables->irq_names) g_free(name_tables->irq_names);
1975 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1976 g_hash_table_destroy(name_tables->kprobe_hash);
1977 g_free(name_tables);
1978 }
1979
1980 #ifdef HASH_TABLE_DEBUG
1981
1982 static void test_process(gpointer key, gpointer value, gpointer user_data)
1983 {
1984 LttvProcessState *process = (LttvProcessState *)value;
1985
1986 /* Test for process corruption */
1987 guint stack_len = process->execution_stack->len;
1988 }
1989
1990 static void hash_table_check(GHashTable *table)
1991 {
1992 g_hash_table_foreach(table, test_process, NULL);
1993 }
1994
1995
1996 #endif
1997
1998 /* clears the stack and sets the state passed as argument */
1999 static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
2000 {
2001 g_array_set_size(cpust->mode_stack, 1);
2002 ((GQuark *)cpust->mode_stack->data)[0] = state;
2003 }
2004
2005 static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
2006 {
2007 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
2008 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
2009 }
2010
2011 static void cpu_pop_mode(LttvCPUState *cpust)
2012 {
2013 if(cpust->mode_stack->len <= 1)
2014 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
2015 else
2016 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
2017 }
2018
2019 /* clears the stack and sets the state passed as argument */
2020 static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
2021 {
2022 g_array_set_size(bdevst->mode_stack, 1);
2023 ((GQuark *)bdevst->mode_stack->data)[0] = state;
2024 }
2025
2026 static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
2027 {
2028 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
2029 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
2030 }
2031
2032 static void bdev_pop_mode(LttvBdevState *bdevst)
2033 {
2034 if(bdevst->mode_stack->len <= 1)
2035 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
2036 else
2037 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
2038 }
2039
2040 static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
2041 {
2042 g_array_set_size(irqst->mode_stack, 1);
2043 ((GQuark *)irqst->mode_stack->data)[0] = state;
2044 }
2045
2046 static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
2047 {
2048 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
2049 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
2050 }
2051
2052 static void irq_pop_mode(LttvIRQState *irqst)
2053 {
2054 if(irqst->mode_stack->len <= 1)
2055 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
2056 else
2057 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
2058 }
2059
2060 static void push_state(LttvEvent *event,
2061 LttvTraceState *ts, LttvExecutionMode t,
2062 guint state_id)
2063 {
2064 LttvExecutionState *es;
2065 gint cpu;
2066
2067 cpu = lttv_traceset_get_cpuid_from_event(event);
2068 g_assert(cpu >= 0);
2069
2070 #ifdef HASH_TABLE_DEBUG
2071 hash_table_check(ts->processes);
2072 #endif
2073 LttvProcessState *process = ts->running_process[cpu];
2074
2075 guint depth = process->execution_stack->len;
2076
2077 process->execution_stack =
2078 g_array_set_size(process->execution_stack, depth + 1);
2079 /* Keep in sync */
2080 process->state =
2081 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
2082
2083 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
2084 es->t = t;
2085 es->n = state_id;
2086 es->entry = es->change = lttv_event_get_timestamp(event);
2087 es->cum_cpu_time = ltt_time_zero;
2088 es->s = process->state->s;
2089 process->state = es;
2090 }
2091
2092 /* pop state
2093 * return 1 when empty, else 0 */
2094 int
2095 lttv_state_pop_state_cleanup(LttvProcessState *process, LttvEvent *event)
2096 {
2097 guint depth = process->execution_stack->len;
2098
2099 if(depth == 1){
2100 return 1;
2101 }
2102
2103 process->execution_stack =
2104 g_array_set_size(process->execution_stack, depth - 1);
2105 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2106 depth - 2);
2107 process->state->change = lttv_event_get_timestamp(event);
2108
2109 return 0;
2110 }
2111
2112 static void pop_state(LttvEvent *event,
2113 LttvTraceState *ts, LttvExecutionMode t)
2114 {
2115 LttvProcessState *process;
2116 gint cpu;
2117
2118 cpu = lttv_traceset_get_cpuid_from_event(event);
2119 g_assert(cpu >= 0);
2120 process = ts->running_process[cpu];
2121
2122 guint depth = process->execution_stack->len;
2123
2124 if(process->state->t != t){
2125 g_info("Different execution mode type: ignore it\n"
2126 );
2127
2128 g_info("process state has %s when pop_int is %s\n",
2129 g_quark_to_string(process->state->t),
2130 g_quark_to_string(t));
2131 g_info("{ %u, %u, %s, %s, %s }\n",
2132 process->pid,
2133 process->ppid,
2134 g_quark_to_string(process->name),
2135 g_quark_to_string(process->brand),
2136 g_quark_to_string(process->state->s));
2137 return;
2138 }
2139
2140 if(depth == 1){
2141 //TODO ybrosseau readd debug
2142 //g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2143 // tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2144 g_info("Trying to pop last state on stack: ignore it\n");
2145 return;
2146 }
2147
2148 process->execution_stack =
2149 g_array_set_size(process->execution_stack, depth - 1);
2150
2151 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2152 depth - 2);
2153 process->state->change = lttv_event_get_timestamp(event);
2154
2155 if((process->state->t == LTTV_STATE_MODE_UNKNOWN) && (t == LTTV_STATE_SYSCALL)) {
2156 //Force state at running
2157 process->state->t = LTTV_STATE_USER_MODE;
2158 process->state->s = LTTV_STATE_RUN;
2159 }
2160 }
2161
2162 struct search_result {
2163 const LttTime *time; /* Requested time */
2164 LttTime *best; /* Best result */
2165 };
2166
2167 /* Return a new and initialized LttvProcessState structure */
2168
2169 LttvProcessState *lttv_state_create_process(LttvTraceState *tcs,
2170 LttvProcessState *parent, guint cpu, guint pid,
2171 guint tgid, GQuark name, const LttTime *timestamp)
2172 {
2173 LttvProcessState *process = g_new(LttvProcessState, 1);
2174
2175 LttvExecutionState *es;
2176
2177 char buffer[128];
2178
2179 process->pid = pid;
2180 process->tgid = tgid;
2181 process->cpu = cpu;
2182 process->name = name;
2183 process->brand = LTTV_STATE_UNBRANDED;
2184 //process->last_cpu = tfs->cpu_name;
2185 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2186 process->type = LTTV_STATE_USER_THREAD;
2187
2188 g_info("Process %u, core %p", process->pid, process);
2189 g_hash_table_insert(tcs->processes, process, process);
2190
2191 if(parent) {
2192 process->ppid = parent->pid;
2193 process->creation_time = *timestamp;
2194 }
2195
2196 /* No parent. This process exists but we are missing all information about
2197 its creation. The birth time is set to zero but we remember the time of
2198 insertion */
2199
2200 else {
2201 process->ppid = 0;
2202 process->creation_time = ltt_time_zero;
2203 }
2204
2205 process->insertion_time = *timestamp;
2206 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2207 process->creation_time.tv_nsec);
2208 process->pid_time = g_quark_from_string(buffer);
2209 process->cpu = cpu;
2210 process->free_events = 0;
2211 //process->last_cpu = tfs->cpu_name;
2212 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2213 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2214 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2215 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2216 es = process->state = &g_array_index(process->execution_stack,
2217 LttvExecutionState, 0);
2218 es->t = LTTV_STATE_USER_MODE;
2219 es->n = LTTV_STATE_SUBMODE_NONE;
2220 es->entry = *timestamp;
2221 //g_assert(timestamp->tv_sec != 0);
2222 es->change = *timestamp;
2223 es->cum_cpu_time = ltt_time_zero;
2224 es->s = LTTV_STATE_RUN;
2225
2226 es = process->state = &g_array_index(process->execution_stack,
2227 LttvExecutionState, 1);
2228 es->t = LTTV_STATE_SYSCALL;
2229 es->n = LTTV_STATE_SUBMODE_NONE;
2230 es->entry = *timestamp;
2231 //g_assert(timestamp->tv_sec != 0);
2232 es->change = *timestamp;
2233 es->cum_cpu_time = ltt_time_zero;
2234 es->s = LTTV_STATE_WAIT_FORK;
2235
2236 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2237 #ifdef BABEL_CLEANUP
2238 //process->user_stack = g_array_sized_new(FALSE, FALSE,
2239 // sizeof(guint64), 0);
2240 #endif
2241 process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
2242
2243 return process;
2244 }
2245
2246 LttvProcessState *
2247 lttv_state_find_process(LttvTraceState *ts, guint cpu, guint pid)
2248 {
2249 LttvProcessState key;
2250 LttvProcessState *process;
2251
2252 key.pid = pid;
2253 key.cpu = cpu;
2254 process = g_hash_table_lookup(ts->processes, &key);
2255 return process;
2256 }
2257
2258 LttvProcessState *lttv_state_find_process_or_create(LttvTraceState *ts,
2259 guint cpu, guint pid, const LttTime *timestamp)
2260 {
2261 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2262 LttvExecutionState *es;
2263
2264 /* Put ltt_time_zero creation time for unexisting processes */
2265 if(unlikely(process == NULL)) {
2266 process = lttv_state_create_process(ts,
2267 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2268 /* We are not sure is it's a kernel thread or normal thread, put the
2269 * bottom stack state to unknown */
2270 process->execution_stack =
2271 g_array_set_size(process->execution_stack, 1);
2272 process->state = es =
2273 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2274 es->t = LTTV_STATE_MODE_UNKNOWN;
2275 es->s = LTTV_STATE_UNNAMED;
2276 }
2277 return process;
2278 }
2279
2280 /* FIXME : this function should be called when we receive an event telling that
2281 * release_task has been called in the kernel. In happens generally when
2282 * the parent waits for its child termination, but may also happens in special
2283 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2284 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2285 * of a killed thread group, but isn't the leader.
2286 */
2287 static int exit_process(LttvEvent *event, LttvProcessState *process)
2288 {
2289 LttvTraceState *ts = event->state;
2290 LttvProcessState key;
2291
2292 /* Wait for both schedule with exit dead and process free to happen.
2293 * They can happen in any order. */
2294 if (++(process->free_events) < 2)
2295 return 0;
2296
2297 key.pid = process->pid;
2298 key.cpu = process->cpu;
2299 g_hash_table_remove(ts->processes, &key);
2300 g_array_free(process->execution_stack, TRUE);
2301
2302 /* the following also clears the content */
2303 g_hash_table_destroy(process->fds);
2304
2305 g_free(process);
2306 return 1;
2307 }
2308
2309
2310 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2311 {
2312 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2313
2314 /* the following also clears the content */
2315 g_hash_table_destroy(((LttvProcessState *)value)->fds);
2316
2317 g_free(value);
2318 }
2319
2320
2321 static void lttv_state_free_process_table(GHashTable *processes)
2322 {
2323 g_hash_table_foreach(processes, free_process_state, NULL);
2324 g_hash_table_destroy(processes);
2325 }
2326
2327
2328 static gboolean syscall_entry(void *hook_data, void *call_data)
2329 {
2330 LttvEvent *event;
2331 guint cpu;
2332 LttvTraceState *ts;
2333 LttvProcessState *process;
2334 LttvExecutionSubmode submode;
2335 char syscall_name[200];
2336
2337 event = (LttvEvent *) call_data;
2338 if (strncmp(lttv_traceset_get_name_from_event(event),
2339 "sys_", sizeof("sys_") - 1) != 0)
2340 return FALSE;
2341
2342 strncpy(syscall_name,lttv_traceset_get_name_from_event(event)+4,200);
2343
2344 cpu = lttv_traceset_get_cpuid_from_event(event);
2345 ts = event->state;
2346 process = ts->running_process[cpu];
2347
2348 submode = g_quark_from_string(syscall_name);
2349 /* There can be no system call from PID 0 : unknown state */
2350 if(process->pid != 0)
2351 push_state(event, ts, LTTV_STATE_SYSCALL, submode);
2352 return FALSE;
2353 }
2354
2355
2356 static gboolean syscall_exit(void *hook_data, void *call_data)
2357 {
2358 LttvEvent *event;
2359 guint cpu;
2360 LttvTraceState *ts;
2361 LttvProcessState *process;
2362
2363
2364 event = (LttvEvent *) call_data;
2365 if (strcmp(lttv_traceset_get_name_from_event(event),
2366 "exit_syscall") != 0)
2367 return FALSE;
2368
2369 cpu = lttv_traceset_get_cpuid_from_event(event);
2370 ts = event->state;
2371 process = ts->running_process[cpu];
2372
2373 /* There can be no system call from PID 0 : unknown state */
2374 if (process->pid != 0)
2375 pop_state(event, ts, LTTV_STATE_SYSCALL);
2376 return FALSE;
2377 }
2378
2379 #ifdef BABEL_CLEANUP
2380 static gboolean trap_entry(void *hook_data, void *call_data)
2381 {
2382 LttvTracefileState *s = (LttvTracefileState *)call_data;
2383 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2384 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2385 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2386 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2387 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2388
2389 LttvExecutionSubmode submode;
2390
2391 guint64 trap = ltt_event_get_long_unsigned(e, f);
2392
2393 expand_trap_table(ts, trap);
2394
2395 submode = nt->trap_names[trap];
2396
2397 push_state(s, LTTV_STATE_TRAP, submode);
2398
2399 /* update cpu status */
2400 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2401
2402 /* update trap status */
2403 g_array_append_val(s->cpu_state->trap_stack, trap);
2404 ts->trap_states[trap].running++;
2405
2406 return FALSE;
2407 }
2408
2409 static gboolean trap_exit(void *hook_data, void *call_data)
2410 {
2411 LttvTracefileState *s = (LttvTracefileState *)call_data;
2412 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2413
2414 pop_state(s, LTTV_STATE_TRAP);
2415
2416 /* update cpu status */
2417 cpu_pop_mode(s->cpu_state);
2418
2419 /* update trap status */
2420 if (s->cpu_state->trap_stack->len > 0) {
2421 gint last = g_array_index(s->cpu_state->trap_stack, gint,
2422 s->cpu_state->trap_stack->len-1);
2423 if(ts->trap_states[last].running)
2424 ts->trap_states[last].running--;
2425 g_array_remove_index(s->cpu_state->trap_stack,
2426 s->cpu_state->trap_stack->len-1);
2427 }
2428 return FALSE;
2429 }
2430 #endif /* BABEL_CLEANUP */
2431
2432 static gboolean irq_entry(void *hook_data, void *call_data)
2433 {
2434 LttvEvent *event;
2435 guint cpu;
2436 LttvTraceState *ts;
2437
2438 LttvExecutionSubmode submode;
2439 LttvNameTables *nt;
2440 guint64 irq;
2441
2442 event = (LttvEvent *) call_data;
2443 if (strcmp(lttv_traceset_get_name_from_event(event),
2444 "irq_handler_entry") != 0)
2445 return FALSE;
2446
2447 cpu = lttv_traceset_get_cpuid_from_event(event);
2448 ts = event->state;
2449
2450 nt = ts->name_tables;
2451 irq = lttv_event_get_long(event, "irq");
2452
2453 expand_irq_table(ts, irq);
2454
2455 submode = nt->irq_names[irq];
2456
2457 /* Do something with the info about being in user or system mode when int? */
2458 push_state(event, ts, LTTV_STATE_IRQ, submode);
2459
2460 /* update cpu status */
2461 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_IRQ);
2462
2463 /* update irq status */
2464 g_array_append_val(ts->cpu_states[cpu].irq_stack, irq);
2465 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2466
2467 return FALSE;
2468 }
2469
2470 static gboolean soft_irq_exit(void *hook_data, void *call_data)
2471 {
2472 LttvEvent *event;
2473 guint cpu;
2474 LttvTraceState *ts;
2475
2476 LttvCPUState *cpu_state;
2477
2478 event = (LttvEvent *) call_data;
2479 if (strcmp(lttv_traceset_get_name_from_event(event),
2480 "softirq_exit") != 0)
2481 return FALSE;
2482
2483 cpu = lttv_traceset_get_cpuid_from_event(event);
2484 ts = event->state;
2485
2486 cpu_state = &(ts->cpu_states[cpu]);
2487 pop_state(event, ts, LTTV_STATE_SOFT_IRQ);
2488
2489 /* update cpu status */
2490 cpu_pop_mode(cpu_state);
2491
2492 /* update softirq status */
2493 if (cpu_state->softirq_stack->len > 0) {
2494 gint last = g_array_index(cpu_state->softirq_stack, gint, cpu_state->softirq_stack->len-1);
2495 if(ts->soft_irq_states[last].running)
2496 ts->soft_irq_states[last].running--;
2497 g_array_remove_index(cpu_state->softirq_stack, cpu_state->softirq_stack->len-1);
2498 }
2499 return FALSE;
2500 }
2501
2502 static gboolean irq_exit(void *hook_data, void *call_data)
2503 {
2504 LttvEvent *event;
2505 guint cpu;
2506 LttvTraceState *ts;
2507
2508 LttvCPUState *cpu_state;
2509
2510 event = (LttvEvent *) call_data;
2511 if (strcmp(lttv_traceset_get_name_from_event(event),
2512 "irq_handler_exit") != 0)
2513 return FALSE;
2514
2515 cpu = lttv_traceset_get_cpuid_from_event(event);
2516 ts = event->state;
2517 cpu_state = &(ts->cpu_states[cpu]);
2518
2519 pop_state(event, ts, LTTV_STATE_IRQ);
2520
2521 /* update cpu status */
2522 cpu_pop_mode(cpu_state);
2523
2524 /* update irq status */
2525 if (cpu_state->irq_stack->len > 0) {
2526 gint last = g_array_index(cpu_state->irq_stack, gint, cpu_state->irq_stack->len-1);
2527 g_array_remove_index(cpu_state->irq_stack, cpu_state->irq_stack->len-1);
2528 irq_pop_mode(&ts->irq_states[last]);
2529 }
2530
2531 return FALSE;
2532 }
2533
2534 static gboolean soft_irq_raise(void *hook_data, void *call_data)
2535 {
2536 LttvEvent *event;
2537 //guint cpu;
2538 LttvTraceState *ts;
2539
2540
2541 guint64 softirq;
2542 event = (LttvEvent *) call_data;
2543 if (strcmp(lttv_traceset_get_name_from_event(event),
2544 "softirq_raise") != 0)
2545 return FALSE;
2546
2547 //cpu = lttv_traceset_get_cpuid_from_event(event);
2548 ts = event->state;
2549 softirq = lttv_event_get_long_unsigned(event, "vec");
2550
2551 expand_soft_irq_table(ts, softirq);
2552
2553 /* update softirq status */
2554 /* a soft irq raises are not cumulative */
2555 ts->soft_irq_states[softirq].pending=1;
2556
2557 return FALSE;
2558 }
2559
2560 static gboolean soft_irq_entry(void *hook_data, void *call_data)
2561 {
2562 LttvEvent *event;
2563 guint cpu;
2564 LttvTraceState *ts;
2565 LttvExecutionSubmode submode;
2566 LttvNameTables *nt;
2567 guint64 softirq;
2568
2569 event = (LttvEvent *) call_data;
2570 if (strcmp(lttv_traceset_get_name_from_event(event),
2571 "softirq_entry") != 0)
2572 return FALSE;
2573
2574 cpu = lttv_traceset_get_cpuid_from_event(event);
2575 ts = event->state;
2576
2577
2578
2579
2580 softirq = lttv_event_get_long_unsigned(event, "vec");
2581 expand_soft_irq_table(ts, softirq);
2582 nt = ts->name_tables;
2583 submode = nt->soft_irq_names[softirq];
2584
2585 /* Do something with the info about being in user or system mode when int? */
2586 push_state(event, ts, LTTV_STATE_SOFT_IRQ, submode);
2587
2588 /* update cpu status */
2589 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_SOFT_IRQ);
2590
2591 /* update softirq status */
2592 g_array_append_val(ts->cpu_states[cpu].softirq_stack, softirq);
2593 if (ts->soft_irq_states[softirq].pending)
2594 ts->soft_irq_states[softirq].pending--;
2595 ts->soft_irq_states[softirq].running++;
2596
2597 return FALSE;
2598 }
2599
2600 static gboolean enum_interrupt(void *hook_data, void *call_data)
2601 {
2602 LttvEvent *event;
2603 LttvTraceState *ts;
2604
2605 LttvNameTables *nt;
2606
2607
2608 GQuark action;
2609 guint irq;
2610 event = (LttvEvent *) call_data;
2611 if (strcmp(lttv_traceset_get_name_from_event(event),
2612 "lttng_statedump_interrupt") != 0)
2613 return FALSE;
2614 ts = event->state;
2615
2616 nt = ts->name_tables;
2617 irq = lttv_event_get_long_unsigned(event, "irq");
2618 action = g_quark_from_string(lttv_event_get_string(event,
2619 "action"));
2620 expand_irq_table(ts, irq);
2621 nt->irq_names[irq] = action;
2622
2623 return FALSE;
2624 }
2625
2626 #ifdef BABEL_CLEANUP
2627 static gboolean bdev_request_issue(void *hook_data, void *call_data)
2628 {
2629 LttvEvent *event;
2630 LttvTraceState *ts;
2631
2632 guint major;
2633 guint minor;
2634 guint oper;
2635 guint32 devcode;
2636 gpointer bdev;
2637
2638 event = (LttvEvent *) call_data;
2639 if (strcmp(lttv_traceset_get_name_from_event(event),
2640 "block_rq_issue") != 0)
2641 return FALSE;
2642
2643 ts = event->state;
2644 major = lttv_event_get_long_unsigned(event,);
2645
2646 minor = lttv_event_get_long_unsigned(event,);
2647
2648 oper = lttv_event_get_long_unsigned(event,);
2649
2650 devcode = MKDEV(major,minor);
2651
2652 /* have we seen this block device before? */
2653 bdev = get_hashed_bdevstate(ts, devcode);
2654 if(oper == 0)
2655 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2656 else
2657 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2658
2659 return FALSE;
2660 }
2661
2662 static gboolean bdev_request_complete(void *hook_data, void *call_data)
2663 {
2664 LttvTracefileState *s = (LttvTracefileState *)call_data;
2665 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2666 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2667 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2668
2669 guint major = ltt_event_get_long_unsigned(e,
2670 lttv_trace_get_hook_field(th, 0));
2671 guint minor = ltt_event_get_long_unsigned(e,
2672 lttv_trace_get_hook_field(th, 1));
2673 //guint oper = ltt_event_get_long_unsigned(e,
2674 // lttv_trace_get_hook_field(th, 2));
2675 guint32 devcode = MKDEV(major,minor);
2676
2677 /* have we seen this block device before? */
2678 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2679
2680 /* update block device */
2681 bdev_pop_mode(bdev);
2682
2683 return FALSE;
2684 }
2685 #endif
2686 #ifdef BABEL_CLEANUP
2687 // We dont have the syscall table in LTTng 2.0
2688 static gboolean dump_syscall(void *hook_data, void *call_data)
2689 {
2690 LttvTracefileState *s = (LttvTracefileState *)call_data;
2691 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2692 LttvNameTables *nt = ts->name_tables;
2693 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2694 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2695 guint id;
2696 char *symbol;
2697
2698 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2699 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2700
2701 expand_syscall_table(ts, id);
2702 nt->syscall_names[id] = g_quark_from_string(symbol);
2703
2704 return FALSE;
2705 }
2706
2707 static gboolean dump_kprobe(void *hook_data, void *call_data)
2708 {
2709 LttvTracefileState *s = (LttvTracefileState *)call_data;
2710 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2711 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2712 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2713 guint64 ip;
2714 char *symbol;
2715
2716 ip = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2717 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 1));
2718
2719 expand_kprobe_table(ts, ip, symbol);
2720
2721 return FALSE;
2722 }
2723 #endif
2724 #ifdef BABEL_CLEANUP
2725 static gboolean dump_softirq(void *hook_data, void *call_data)
2726 {
2727
2728 LttvTracefileState *s = (LttvTracefileState *)call_data;
2729 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2730 LttvNameTables *nt = ts->name_tables;
2731 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2732 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2733 guint id;
2734 char *symbol;
2735
2736 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2737 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2738
2739 expand_soft_irq_table(ts, id);
2740 nt->soft_irq_names[id] = g_quark_from_string(symbol);
2741
2742 return FALSE;
2743
2744 }
2745 #endif
2746 static gboolean sched_try_wakeup(void *hook_data, void *call_data)
2747 {
2748 LttvEvent *event;
2749 LttvTraceState *ts;
2750 LttvProcessState *process;
2751 gint woken_pid;
2752 guint woken_cpu;
2753 LttTime timestamp;
2754
2755 event = (LttvEvent *) call_data;
2756 if (strcmp(lttv_traceset_get_name_from_event(event),
2757 "sched_wakeup") != 0)
2758 return FALSE;
2759
2760 ts = event->state;
2761
2762 woken_pid = lttv_event_get_long(event, "tid");
2763 woken_cpu = lttv_event_get_long(event, "target_cpu");
2764
2765 timestamp = lttv_event_get_timestamp(event);
2766 process = lttv_state_find_process_or_create(
2767 ts,
2768 woken_cpu, woken_pid,
2769 &timestamp);
2770
2771 if (process->state->s == LTTV_STATE_WAIT || process->state->s == LTTV_STATE_WAIT_FORK)
2772 {
2773 process->state->s = LTTV_STATE_WAIT_CPU;
2774 process->state->change = timestamp;
2775 }
2776
2777 g_debug("Wakeup: process %d on CPU %u\n", woken_pid, woken_cpu);
2778
2779 return FALSE;
2780 }
2781
2782 static gboolean schedchange(void *hook_data, void *call_data)
2783 {
2784 LttvEvent *event;
2785 guint cpu;
2786 LttvTraceState *ts;
2787 LttvProcessState *process;
2788
2789
2790 //LttvProcessState *old_process = ts->running_process[cpu];
2791
2792 guint pid_in, pid_out;
2793 gint64 state_out;
2794 //TODO ybrosseau 2012-07-13: manage this 20 in a constact or dynamically
2795 char next_comm[20];
2796 LttTime timestamp;
2797 event = (LttvEvent *) call_data;
2798 if (strcmp(lttv_traceset_get_name_from_event(event),
2799 "sched_switch") != 0)
2800 return FALSE;
2801
2802 cpu = lttv_traceset_get_cpuid_from_event(event);
2803 ts = event->state;
2804 process = ts->running_process[cpu];
2805 pid_out = lttv_event_get_long(event, "prev_tid");
2806 pid_in = lttv_event_get_long(event, "next_tid");
2807 state_out = lttv_event_get_long(event, "prev_state");
2808
2809 strncpy(next_comm, lttv_event_get_string(event, "next_comm"), 20);
2810 next_comm[20-1] = '\0';
2811
2812 timestamp = lttv_event_get_timestamp(event);
2813
2814 if(likely(process != NULL)) {
2815
2816 /* We could not know but it was not the idle process executing.
2817 This should only happen at the beginning, before the first schedule
2818 event, and when the initial information (current process for each CPU)
2819 is missing. It is not obvious how we could, after the fact, compensate
2820 the wrongly attributed statistics. */
2821
2822 //This test only makes sense once the state is known and if there is no
2823 //missing events. We need to silently ignore schedchange coming after a
2824 //process_free, or it causes glitches. (FIXME)
2825 //if(unlikely(process->pid != pid_out)) {
2826 // g_assert(process->pid == 0);
2827 //}
2828 if(process->pid == 0
2829 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2830 if(pid_out == 0) {
2831 /*
2832 * Scheduling out of pid 0 at beginning of the trace.
2833 * We are typically in system call mode at this point although
2834 * (FIXME) we might be in a trap handler.
2835 */
2836 g_assert(process->execution_stack->len == 1);
2837 process->state->t = LTTV_STATE_SYSCALL;
2838 process->state->s = LTTV_STATE_WAIT;
2839 process->state->change = timestamp;
2840 process->state->entry = timestamp;
2841 }
2842 } else {
2843 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2844 process->state->s = LTTV_STATE_ZOMBIE;
2845 process->state->change = timestamp;
2846 } else {
2847 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2848 else process->state->s = LTTV_STATE_WAIT;
2849 process->state->change = timestamp;
2850 }
2851
2852 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
2853 /* see sched.h for states */
2854 if (!exit_process(event, process)) {
2855 process->state->s = LTTV_STATE_DEAD;
2856 process->state->change = timestamp;
2857 }
2858 }
2859 }
2860 }
2861 process = ts->running_process[cpu] = lttv_state_find_process_or_create(
2862 ts,
2863 cpu, pid_in,
2864 &timestamp);
2865 process->state->s = LTTV_STATE_RUN;
2866 process->cpu = cpu;
2867 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2868 process->state->change = timestamp;
2869 process->name = g_quark_from_string(next_comm);
2870
2871 /* update cpu status */
2872 if(pid_in == 0)
2873 /* going to idle task */
2874 cpu_set_base_mode(&(ts->cpu_states[cpu]), LTTV_CPU_IDLE);
2875 else {
2876 /* scheduling a real task.
2877 * we must be careful here:
2878 * if we just schedule()'ed to a process that is
2879 * in a trap, we must put the cpu in trap mode
2880 */
2881 cpu_set_base_mode(&(ts->cpu_states[cpu]), LTTV_CPU_BUSY);
2882 if(process->state->t == LTTV_STATE_TRAP)
2883 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_TRAP);
2884 }
2885
2886 return FALSE;
2887 }
2888
2889 static gboolean process_fork(void *hook_data, void *call_data)
2890 {
2891 LttvEvent *event;
2892 LttvTraceState *ts;
2893 LttvProcessState *process;
2894 LttvProcessState *child_process;
2895 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2896 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2897 //LttvProcessState *zombie_process;
2898 guint cpu;
2899 LttTime timestamp;
2900
2901 event = (LttvEvent *) call_data;
2902 if (strcmp(lttv_traceset_get_name_from_event(event),
2903 "sched_process_fork") != 0)
2904 return FALSE;
2905 cpu = lttv_traceset_get_cpuid_from_event(event);
2906 ts = event->state;
2907 process = ts->running_process[cpu];
2908 timestamp = lttv_event_get_timestamp(event);
2909
2910 /* Skip Parent PID param */
2911
2912 /* Child PID */
2913 child_pid = lttv_event_get_long(event, "child_tid");
2914 //ts->target_pid = child_pid;
2915
2916 /* Child TGID */
2917
2918 child_tgid = 0;
2919
2920 /* Mathieu : it seems like the process might have been scheduled in before the
2921 * fork, and, in a rare case, might be the current process. This might happen
2922 * in a SMP case where we don't have enough precision on the clocks.
2923 *
2924 * Test reenabled after precision fixes on time. (Mathieu) */
2925 #if 0
2926 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2927
2928 if(unlikely(zombie_process != NULL)) {
2929 /* Reutilisation of PID. Only now we are sure that the old PID
2930 * has been released. FIXME : should know when release_task happens instead.
2931 */
2932 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2933 guint i;
2934 for(i=0; i< num_cpus; i++) {
2935 g_assert(zombie_process != ts->running_process[i]);
2936 }
2937
2938 exit_process(s, zombie_process);
2939 }
2940 #endif //0
2941 g_assert(process->pid != child_pid);
2942 // FIXME : Add this test in the "known state" section
2943 // g_assert(process->pid == parent_pid);
2944 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2945 if(child_process == NULL) {
2946 child_process = lttv_state_create_process(ts, process, cpu,
2947 child_pid, child_tgid,
2948 LTTV_STATE_UNNAMED, &timestamp);
2949 } else {
2950 /* The process has already been created : due to time imprecision between
2951 * multiple CPUs : it has been scheduled in before creation. Note that we
2952 * shouldn't have this kind of imprecision.
2953 *
2954 * Simply put a correct parent.
2955 */
2956 g_error("Process %u has been created at [%lu.%09lu] "
2957 "and inserted at [%lu.%09lu] before \n"
2958 "fork on cpu %u[%lu.%09lu].\n"
2959 "Probably an unsynchronized TSC problem on the traced machine.",
2960 child_pid,
2961 child_process->creation_time.tv_sec,
2962 child_process->creation_time.tv_nsec,
2963 child_process->insertion_time.tv_sec,
2964 child_process->insertion_time.tv_nsec,
2965 cpu, timestamp.tv_sec, timestamp.tv_nsec);
2966 //g_assert(0); /* This is a problematic case : the process has been created
2967 // before the fork event */
2968 child_process->ppid = process->pid;
2969 child_process->tgid = child_tgid;
2970 }
2971 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2972 child_process->name = process->name;
2973 child_process->brand = process->brand;
2974
2975 return FALSE;
2976 }
2977
2978 #ifdef BABEL_CLEANUP
2979 //NO KTHREAD_CREATE in LTTng 2.0
2980 /* We stamp a newly created process as kernel_thread.
2981 * The thread should not be running yet. */
2982 static gboolean process_kernel_thread(void *hook_data, void *call_data)
2983 {
2984 LttvTracefileState *s = (LttvTracefileState *)call_data;
2985 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2986 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2987 guint pid;
2988 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2989 LttvProcessState *process;
2990 LttvExecutionState *es;
2991
2992 /* PID */
2993 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2994 //s->parent.target_pid = pid;
2995
2996 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2997 &ltt_time_zero);
2998 if (process->state->s != LTTV_STATE_DEAD) {
2999 process->execution_stack =
3000 g_array_set_size(process->execution_stack, 1);
3001 es = process->state =
3002 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3003 es->t = LTTV_STATE_SYSCALL;
3004 }
3005 process->type = LTTV_STATE_KERNEL_THREAD;
3006
3007 return FALSE;
3008 }
3009 #endif
3010 static gboolean process_exit(void *hook_data, void *call_data)
3011 {
3012 LttvEvent *event;
3013 LttvTraceState *ts;
3014 guint pid;
3015 guint cpu;
3016 LttvProcessState *process; // = ts->running_process[cpu];
3017
3018 event = (LttvEvent *) call_data;
3019 if (strcmp(lttv_traceset_get_name_from_event(event),
3020 "sched_process_exit") != 0)
3021 return FALSE;
3022 cpu = lttv_traceset_get_cpuid_from_event(event);
3023 ts = event->state;
3024 process = ts->running_process[cpu];
3025
3026 pid = lttv_event_get_long(event, "tid");
3027 //s->parent.target_pid = pid;
3028
3029 // FIXME : Add this test in the "known state" section
3030 // g_assert(process->pid == pid);
3031
3032 process = lttv_state_find_process(ts, ANY_CPU, pid);
3033 if(likely(process != NULL)) {
3034 process->state->s = LTTV_STATE_EXIT;
3035 }
3036 return FALSE;
3037 }
3038
3039 static gboolean process_free(void *hook_data, void *call_data)
3040 {
3041 LttvEvent *event;
3042 LttvTraceState *ts;
3043 guint cpu;
3044 guint release_pid;
3045 LttvProcessState *process;
3046
3047 event = (LttvEvent *) call_data;
3048 if (strcmp(lttv_traceset_get_name_from_event(event),
3049 "sched_process_free") != 0)
3050 return FALSE;
3051 cpu = lttv_traceset_get_cpuid_from_event(event);
3052 ts = event->state;
3053 process = ts->running_process[cpu];
3054
3055 /* PID of the process to release */
3056 release_pid = lttv_event_get_long(event, "_tid");
3057 //s->parent.target_pid = release_pid;
3058
3059 g_assert(release_pid != 0);
3060
3061 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
3062 if(likely(process != NULL))
3063 exit_process(event, process);
3064 return FALSE;
3065 //DISABLED
3066 #if 0
3067 if(likely(process != NULL)) {
3068 /* release_task is happening at kernel level : we can now safely release
3069 * the data structure of the process */
3070 //This test is fun, though, as it may happen that
3071 //at time t : CPU 0 : process_free
3072 //at time t+150ns : CPU 1 : schedule out
3073 //Clearly due to time imprecision, we disable it. (Mathieu)
3074 //If this weird case happen, we have no choice but to put the
3075 //Currently running process on the cpu to 0.
3076 //I re-enable it following time precision fixes. (Mathieu)
3077 //Well, in the case where an process is freed by a process on another CPU
3078 //and still scheduled, it happens that this is the schedchange that will
3079 //drop the last reference count. Do not free it here!
3080 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3081 guint i;
3082 for(i=0; i< num_cpus; i++) {
3083 //g_assert(process != ts->running_process[i]);
3084 if(process == ts->running_process[i]) {
3085 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3086 break;
3087 }
3088 }
3089 if(i == num_cpus) /* process is not scheduled */
3090 exit_process(s, process);
3091 }
3092
3093 return FALSE;
3094 #endif //DISABLED
3095 }
3096
3097
3098 static gboolean process_exec(void *hook_data, void *call_data)
3099 {
3100 LttvEvent *event;
3101 LttvTraceState *ts;
3102 guint cpu;
3103 //gchar *name;
3104 LttvProcessState *process;
3105
3106 event = (LttvEvent *) call_data;
3107 if (strcmp(lttv_traceset_get_name_from_event(event),
3108 "sys_execve") != 0)
3109 return FALSE;
3110 cpu = lttv_traceset_get_cpuid_from_event(event);
3111 ts = event->state;
3112 process = ts->running_process[cpu];
3113
3114 #if 0//how to use a sequence that must be transformed in a string
3115 /* PID of the process to release */
3116 guint64 name_len = ltt_event_field_element_number(e,
3117 lttv_trace_get_hook_field(th, 0));
3118 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3119 LttField *child = ltt_event_field_element_select(e,
3120 lttv_trace_get_hook_field(th, 0), 0);
3121 gchar *name_begin =
3122 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
3123 gchar *null_term_name = g_new(gchar, name_len+1);
3124 memcpy(null_term_name, name_begin, name_len);
3125 null_term_name[name_len] = '\0';
3126 process->name = g_quark_from_string(null_term_name);
3127 #endif //0
3128
3129 process->name = g_quark_from_string(lttv_event_get_string(event,
3130 "filename"));
3131 process->brand = LTTV_STATE_UNBRANDED;
3132 //g_free(null_term_name);
3133 return FALSE;
3134 }
3135 #ifdef BABEL_CLEANUP
3136 static gboolean thread_brand(void *hook_data, void *call_data)
3137 {
3138 LttvTracefileState *s = (LttvTracefileState *)call_data;
3139 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3140 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3141 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3142 gchar *name;
3143 guint cpu = s->cpu;
3144 LttvProcessState *process = ts->running_process[cpu];
3145
3146 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3147 process->brand = g_quark_from_string(name);
3148
3149 return FALSE;
3150 }
3151 #endif
3152 #if 0
3153 // TODO We only have sys_open, without the FD
3154 // manage to do somehting better
3155 static gboolean fs_open(void *hook_data, void *call_data)
3156 {
3157 LttvTracefileState *s = (LttvTracefileState *)call_data;
3158 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
3159 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3160 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3161 struct marker_field *f;
3162 guint cpu = s->cpu;
3163 int fd;
3164 char *filename;
3165 LttvProcessState *process = ts->running_process[cpu];
3166
3167 f = lttv_trace_get_hook_field(th, 0);
3168 fd = ltt_event_get_int(e, f);
3169
3170 f = lttv_trace_get_hook_field(th, 1);
3171 filename = ltt_event_get_string(e, f);
3172
3173 g_hash_table_insert(process->fds, (gpointer)(long)fd,
3174 (gpointer)(unsigned long)g_quark_from_string(filename));
3175
3176 return FALSE;
3177 }
3178 #endif
3179 static void print_stack(LttvProcessState *process)
3180 {
3181 LttvExecutionState *es;
3182 int i;
3183
3184 g_debug("Execution stack for process %u %s:\n",
3185 process->pid, g_quark_to_string(process->name));
3186
3187 for (i = 0; i < process->execution_stack->len; i++) {
3188 es = &g_array_index(process->execution_stack,
3189 LttvExecutionState, i);
3190 g_debug("Depth %d mode %s submode %s status %s\n",
3191 i, g_quark_to_string(es->t),
3192 g_quark_to_string(es->n),
3193 g_quark_to_string(es->s));
3194 }
3195
3196 }
3197
3198 static void fix_process(gpointer key, gpointer value, gpointer user_data)
3199 {
3200 LttvProcessState *process;
3201 LttvExecutionState *es;
3202 process = (LttvProcessState *)value;
3203 LttTime *timestamp = (LttTime*)user_data;
3204
3205 print_stack(process);
3206
3207 if(process->type == LTTV_STATE_KERNEL_THREAD) {
3208 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3209 if(es->t == LTTV_STATE_MAYBE_SYSCALL) {
3210 es->t = LTTV_STATE_SYSCALL;
3211 es->n = LTTV_STATE_SUBMODE_NONE;
3212 es->entry = *timestamp;
3213 es->change = *timestamp;
3214 es->cum_cpu_time = ltt_time_zero;
3215 if(es->s == LTTV_STATE_UNNAMED)
3216 es->s = LTTV_STATE_WAIT;
3217 }
3218 } else {
3219 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3220 if(es->t == LTTV_STATE_MAYBE_USER_MODE) {
3221 es->t = LTTV_STATE_USER_MODE;
3222 es->n = LTTV_STATE_SUBMODE_NONE;
3223 es->entry = *timestamp;
3224 //g_assert(timestamp->tv_sec != 0);
3225 es->change = *timestamp;
3226 es->cum_cpu_time = ltt_time_zero;
3227 if(es->s == LTTV_STATE_UNNAMED)
3228 es->s = LTTV_STATE_RUN;
3229
3230 if(process->execution_stack->len == 1) {
3231 /* Still in bottom unknown mode, means we either:
3232 * - never did a system call
3233 * - are scheduled out from user mode.
3234 * May be either in user mode, syscall mode, running or waiting.*/
3235 /* CHECK : we may be tagging syscall mode when being user mode
3236 * (should be fixed now) */
3237 if (es->s == LTTV_STATE_WAIT_CPU) {
3238 /* nothing to do: scheduled out from userspace */
3239 } else {
3240 process->execution_stack =
3241 g_array_set_size(process->execution_stack, 2);
3242 es = process->state = &g_array_index(process->execution_stack,
3243 LttvExecutionState, 1);
3244 es->t = LTTV_STATE_SYSCALL;
3245 es->n = LTTV_STATE_SUBMODE_NONE;
3246 es->entry = *timestamp;
3247 //g_assert(timestamp->tv_sec != 0);
3248 es->change = *timestamp;
3249 es->cum_cpu_time = ltt_time_zero;
3250 if(es->s == LTTV_STATE_WAIT_FORK)
3251 es->s = LTTV_STATE_WAIT;
3252 }
3253 }
3254 }
3255 }
3256 }
3257
3258 static gboolean statedump_end(void *hook_data, void *call_data)
3259 {
3260 LttvEvent *event;
3261 LttvTraceState *ts;
3262 LttTime timestamp;
3263 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3264 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3265 event = (LttvEvent *) call_data;
3266 if (strcmp(lttv_traceset_get_name_from_event(event),
3267 "lttng_statedump_end") != 0)
3268 return FALSE;
3269
3270 ts = event->state;
3271 timestamp = lttv_event_get_timestamp(event);
3272
3273 /* For all processes */
3274 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3275 /* else, if stack[0] is unknown, set to user mode, running */
3276
3277 g_hash_table_foreach(ts->processes, fix_process, &timestamp);
3278
3279 return FALSE;
3280 }
3281
3282 static gboolean enum_process_state(void *hook_data, void *call_data)
3283 {
3284 LttvEvent *event;
3285 LttvTraceState *ts;
3286 LttTime timestamp;
3287 guint parent_pid;
3288 guint pid;
3289 guint tgid;
3290 gchar * command;
3291 guint cpu;
3292 LttvProcessState *parent_process;
3293 LttvProcessState *process;
3294
3295 guint type;
3296 LttvExecutionState *es;
3297 guint i, nb_cpus;
3298
3299 event = (LttvEvent *) call_data;
3300 if (strcmp(lttv_traceset_get_name_from_event(event),
3301 "lttng_statedump_process_state") != 0)
3302 return FALSE;
3303 cpu = lttv_traceset_get_cpuid_from_event(event);
3304 ts = event->state;
3305 process = ts->running_process[cpu];
3306 timestamp = lttv_event_get_timestamp(event);
3307
3308 /* PID */
3309 pid = lttv_event_get_long(event, "tid");
3310 //s->parent.target_pid = pid;
3311
3312 /* Parent PID */
3313 parent_pid = lttv_event_get_long(event, "ppid");
3314
3315 /* Command name */
3316 command = lttv_event_get_string(event, "name");
3317
3318 /* type */
3319
3320 type = lttv_event_get_long(event, "type");
3321
3322 //FIXME: type is rarely used, enum must match possible types.
3323
3324 /* Skip mode 4th param */
3325
3326 /* Skip submode 5th param */
3327
3328 /* Skip status 6th param */
3329 /* TGID */
3330 tgid = lttv_event_get_long(event, "pid");
3331
3332 if(pid == 0) {
3333 nb_cpus = lttv_trace_get_num_cpu(ts->trace);
3334 for(i=0; i<nb_cpus; i++) {
3335 process = lttv_state_find_process(ts, i, pid);
3336 g_assert(process != NULL);
3337
3338 process->ppid = parent_pid;
3339 process->tgid = tgid;
3340 process->name = g_quark_from_string(command);
3341 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3342 process->type = LTTV_STATE_KERNEL_THREAD;
3343 }
3344
3345 } else {
3346 /* The process might exist if a process was forked while performing the
3347 * state dump. */
3348 process = lttv_state_find_process(ts, ANY_CPU, pid);
3349 if(process == NULL) {
3350 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3351 process = lttv_state_create_process(ts, parent_process, cpu,
3352 pid, tgid, g_quark_from_string(command),
3353 &timestamp);
3354
3355 /* Keep the stack bottom : a running user mode */
3356 /* Disabled because of inconsistencies in the current statedump states. */
3357 //if(type == LTTV_STATE_KERNEL_THREAD) {
3358 if(type == 1) {
3359 /* Only keep the bottom
3360 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3361 /* Will cause expected trap when in fact being syscall (even after end of
3362 * statedump event)
3363 * Will cause expected interrupt when being syscall. (only before end of
3364 * statedump event) */
3365 // This will cause a "popping last state on stack, ignoring it."
3366 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3367 es = process->state = &g_array_index(process->execution_stack,
3368 LttvExecutionState, 0);
3369 process->type = LTTV_STATE_KERNEL_THREAD;
3370 es->t = LTTV_STATE_MAYBE_SYSCALL;
3371 es->s = LTTV_STATE_UNNAMED;
3372 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3373 //es->s = status;
3374 //es->n = submode;
3375 } else {
3376 /* User space process :
3377 * bottom : user mode
3378 * either currently running or scheduled out.
3379 * can be scheduled out because interrupted in (user mode or in syscall)
3380 * or because of an explicit call to the scheduler in syscall. Note that
3381 * the scheduler call comes after the irq_exit, so never in interrupt
3382 * context. */
3383 // temp workaround : set size to 1 : only have user mode bottom of stack.
3384 // will cause g_info message of expected syscall mode when in fact being
3385 // in user mode. Can also cause expected trap when in fact being user
3386 // mode in the event of a page fault reenabling interrupts in the handler.
3387 // Expected syscall and trap can also happen after the end of statedump
3388 // This will cause a "popping last state on stack, ignoring it."
3389 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3390 es = process->state = &g_array_index(process->execution_stack,
3391 LttvExecutionState, 0);
3392 es->t = LTTV_STATE_MAYBE_USER_MODE;
3393 es->s = LTTV_STATE_UNNAMED;
3394 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3395 //es->s = status;
3396 //es->n = submode;
3397 }
3398 #if 0
3399 /* UNKNOWN STATE */
3400 {
3401 es = process->state = &g_array_index(process->execution_stack,
3402 LttvExecutionState, 1);
3403 es->t = LTTV_STATE_MODE_UNKNOWN;
3404 es->s = LTTV_STATE_UNNAMED;
3405 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3406 }
3407 #endif //0
3408 } else {
3409 /* The process has already been created :
3410 * Probably was forked while dumping the process state or
3411 * was simply scheduled in prior to get the state dump event.
3412 */
3413 process->ppid = parent_pid;
3414 process->tgid = tgid;
3415 process->name = g_quark_from_string(command);
3416 process->type = type;
3417 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3418 #if 0
3419 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3420 if(type == LTTV_STATE_KERNEL_THREAD)
3421 es->t = LTTV_STATE_SYSCALL;
3422 else
3423 es->t = LTTV_STATE_USER_MODE;
3424 }
3425 #endif //0
3426 /* Don't mess around with the stack, it will eventually become
3427 * ok after the end of state dump. */
3428 }
3429 }
3430
3431 return FALSE;
3432 }
3433
3434
3435
3436 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3437 {
3438 LttvTraceset *traceset = (LttvTraceset *)(call_data);
3439
3440 lttv_state_add_event_hooks(traceset);
3441
3442 return 0;
3443 }
3444
3445 void lttv_state_add_event_hooks(LttvTraceset *traceset)
3446 {
3447 gboolean result;
3448
3449 LttvAttributeValue value;
3450 LttvHooks*event_hook;
3451 #ifdef BABEL_CLEANUP
3452 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
3453 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
3454 LTTV_POINTER, &value);
3455 g_assert(result);
3456 event_hook = *(value.v_pointer);
3457 #endif
3458 //TODO ybrosseau 2012-07-12: Validate that using traceset hooks instead of the global one is valid
3459 //Use traceset hooks
3460 event_hook = lttv_traceset_get_hooks(traceset);
3461 g_assert(event_hook);
3462
3463 lttv_hooks_add(event_hook,syscall_entry , NULL, LTTV_PRIO_STATE);
3464 lttv_hooks_add(event_hook,syscall_exit , NULL, LTTV_PRIO_STATE);
3465 lttv_hooks_add(event_hook,irq_entry , NULL, LTTV_PRIO_STATE);
3466 lttv_hooks_add(event_hook,irq_exit , NULL, LTTV_PRIO_STATE);
3467 lttv_hooks_add(event_hook,soft_irq_raise , NULL, LTTV_PRIO_STATE);
3468 lttv_hooks_add(event_hook,soft_irq_entry , NULL, LTTV_PRIO_STATE);
3469 lttv_hooks_add(event_hook,soft_irq_exit , NULL, LTTV_PRIO_STATE);
3470 lttv_hooks_add(event_hook,schedchange , NULL, LTTV_PRIO_STATE);
3471 lttv_hooks_add(event_hook,sched_try_wakeup , NULL, LTTV_PRIO_STATE);
3472 lttv_hooks_add(event_hook,process_exit , NULL, LTTV_PRIO_STATE);
3473 lttv_hooks_add(event_hook,process_free , NULL, LTTV_PRIO_STATE);
3474 lttv_hooks_add(event_hook,process_fork , NULL, LTTV_PRIO_STATE);
3475 lttv_hooks_add(event_hook,process_exec , NULL, LTTV_PRIO_STATE);
3476 lttv_hooks_add(event_hook,enum_process_state , NULL, LTTV_PRIO_STATE);
3477 lttv_hooks_add(event_hook,statedump_end , NULL, LTTV_PRIO_STATE);
3478 lttv_hooks_add(event_hook,enum_interrupt , NULL, LTTV_PRIO_STATE);
3479
3480 #ifdef BABEL_CLEANUP //For the whole function this time
3481 guint i, j, k, nb_trace;
3482 LttvTraceState *ts;
3483 GArray *hooks;
3484 // LttvTraceHook *th;
3485 LttvAttributeValue val;
3486
3487 nb_trace = lttv_traceset_number(traceset);
3488 for (i = 0 ; i < nb_trace ; i++) {
3489 ts = lttv_traceset_get(traceset, i)-;
3490
3491 /* Find the eventtype id for the following events and register the
3492 associated by id hooks. */
3493
3494 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 20);
3495 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3496 //hn = 0;
3497
3498 lttv_trace_find_hook(tss->parent.t,
3499 LTT_CHANNEL_KERNEL,
3500 LTT_EVENT_SYSCALL_ENTRY,
3501 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3502 syscall_entry, NULL, &hooks);
3503
3504 lttv_trace_find_hook(ts->parent.t,
3505 LTT_CHANNEL_KERNEL,
3506 LTT_EVENT_SYSCALL_EXIT,
3507 NULL,
3508 syscall_exit, NULL, &hooks);
3509
3510 #ifdef BABEL_CLEANUP
3511 lttv_trace_find_hook(ts->parent.t,
3512 LTT_CHANNEL_KERNEL,
3513 LTT_EVENT_TRAP_ENTRY,
3514 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3515 trap_entry, NULL, &hooks);
3516
3517 lttv_trace_find_hook(ts->parent.t,
3518 LTT_CHANNEL_KERNEL,
3519 LTT_EVENT_TRAP_EXIT,
3520 NULL,
3521 trap_exit, NULL, &hooks);
3522 #endif /* BABEL_CLEANUP */
3523
3524 lttv_trace_find_hook(ts->parent.t,
3525 LTT_CHANNEL_KERNEL,
3526 LTT_EVENT_PAGE_FAULT_ENTRY,
3527 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3528 trap_entry, NULL, &hooks);
3529
3530 lttv_trace_find_hook(ts->parent.t,
3531 LTT_CHANNEL_KERNEL,
3532 LTT_EVENT_PAGE_FAULT_EXIT,
3533 NULL,
3534 trap_exit, NULL, &hooks);
3535
3536 #ifdef BABEL_CLEANUP
3537 lttv_trace_find_hook(ts->parent.t,
3538 LTT_CHANNEL_KERNEL,
3539 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
3540 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3541 trap_entry, NULL, &hooks);
3542
3543 lttv_trace_find_hook(ts->parent.t,
3544 LTT_CHANNEL_KERNEL,
3545 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
3546 NULL,
3547 trap_exit, NULL, &hooks);
3548 #endif /* BABEL_CLEANUP */
3549
3550 lttv_trace_find_hook(ts->parent.t,
3551 LTT_CHANNEL_KERNEL,
3552 LTT_EVENT_IRQ_ENTRY,
3553 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3554 irq_entry, NULL, &hooks);
3555
3556 lttv_trace_find_hook(ts->parent.t,
3557 LTT_CHANNEL_KERNEL,
3558 LTT_EVENT_IRQ_EXIT,
3559 NULL,
3560 irq_exit, NULL, &hooks);
3561
3562 lttv_trace_find_hook(ts->parent.t,
3563 LTT_CHANNEL_KERNEL,
3564 LTT_EVENT_SOFT_IRQ_RAISE,
3565 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3566 soft_irq_raise, NULL, &hooks);
3567
3568 lttv_trace_find_hook(ts->parent.t,
3569 LTT_CHANNEL_KERNEL,
3570 LTT_EVENT_SOFT_IRQ_ENTRY,
3571 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3572 soft_irq_entry, NULL, &hooks);
3573
3574 lttv_trace_find_hook(ts->parent.t,
3575 LTT_CHANNEL_KERNEL,
3576 LTT_EVENT_SOFT_IRQ_EXIT,
3577 NULL,
3578 soft_irq_exit, NULL, &hooks);
3579
3580 lttv_trace_find_hook(ts->parent.t,
3581 LTT_CHANNEL_KERNEL,
3582 LTT_EVENT_SCHED_SCHEDULE,
3583 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3584 LTT_FIELD_PREV_STATE),
3585 schedchange, NULL, &hooks);
3586
3587 lttv_trace_find_hook(ts->parent.t,
3588 LTT_CHANNEL_KERNEL,
3589 LTT_EVENT_SCHED_TRY_WAKEUP,
3590 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_CPU_ID, LTT_FIELD_STATE),
3591 sched_try_wakeup, NULL, &hooks);
3592
3593 lttv_trace_find_hook(ts->parent.t,
3594 LTT_CHANNEL_KERNEL,
3595 LTT_EVENT_PROCESS_FORK,
3596 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3597 LTT_FIELD_CHILD_TGID),
3598 process_fork, NULL, &hooks);
3599
3600 lttv_trace_find_hook(ts->parent.t,
3601 LTT_CHANNEL_KERNEL,
3602 LTT_EVENT_KTHREAD_CREATE,
3603 FIELD_ARRAY(LTT_FIELD_PID),
3604 process_kernel_thread, NULL, &hooks);
3605
3606 lttv_trace_find_hook(ts->parent.t,
3607 LTT_CHANNEL_KERNEL,
3608 LTT_EVENT_PROCESS_EXIT,
3609 FIELD_ARRAY(LTT_FIELD_PID),
3610 process_exit, NULL, &hooks);
3611
3612 lttv_trace_find_hook(ts->parent.t,
3613 LTT_CHANNEL_KERNEL,
3614 LTT_EVENT_PROCESS_FREE,
3615 FIELD_ARRAY(LTT_FIELD_PID),
3616 process_free, NULL, &hooks);
3617
3618 lttv_trace_find_hook(ts->parent.t,
3619 LTT_CHANNEL_FS,
3620 LTT_EVENT_EXEC,
3621 FIELD_ARRAY(LTT_FIELD_FILENAME),
3622 process_exec, NULL, &hooks);
3623
3624 lttv_trace_find_hook(ts->parent.t,
3625 LTT_CHANNEL_USERSPACE,
3626 LTT_EVENT_THREAD_BRAND,
3627 FIELD_ARRAY(LTT_FIELD_NAME),
3628 thread_brand, NULL, &hooks);
3629
3630 /* statedump-related hooks */
3631 lttv_trace_find_hook(ts->parent.t,
3632 LTT_CHANNEL_TASK_STATE,
3633 LTT_EVENT_PROCESS_STATE,
3634 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3635 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3636 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3637 enum_process_state, NULL, &hooks);
3638
3639 lttv_trace_find_hook(ts->parent.t,
3640 LTT_CHANNEL_GLOBAL_STATE,
3641 LTT_EVENT_STATEDUMP_END,
3642 NULL,
3643 statedump_end, NULL, &hooks);
3644
3645 lttv_trace_find_hook(ts->parent.t,
3646 LTT_CHANNEL_IRQ_STATE,
3647 LTT_EVENT_LIST_INTERRUPT,
3648 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3649 enum_interrupt, NULL, &hooks);
3650
3651 lttv_trace_find_hook(ts->parent.t,
3652 LTT_CHANNEL_BLOCK,
3653 LTT_EVENT_REQUEST_ISSUE,
3654 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3655 bdev_request_issue, NULL, &hooks);
3656
3657 lttv_trace_find_hook(ts->parent.t,
3658 LTT_CHANNEL_BLOCK,
3659 LTT_EVENT_REQUEST_COMPLETE,
3660 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3661 bdev_request_complete, NULL, &hooks);
3662
3663 lttv_trace_find_hook(ts->parent.t,
3664 LTT_CHANNEL_USERSPACE,
3665 LTT_EVENT_FUNCTION_ENTRY,
3666 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3667 function_entry, NULL, &hooks);
3668
3669 lttv_trace_find_hook(ts->parent.t,
3670 LTT_CHANNEL_USERSPACE,
3671 LTT_EVENT_FUNCTION_EXIT,
3672 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3673 function_exit, NULL, &hooks);
3674
3675 lttv_trace_find_hook(ts->parent.t,
3676 LTT_CHANNEL_SYSCALL_STATE,
3677 LTT_EVENT_SYS_CALL_TABLE,
3678 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3679 dump_syscall, NULL, &hooks);
3680
3681 lttv_trace_find_hook(ts->parent.t,
3682 LTT_CHANNEL_KPROBE_STATE,
3683 LTT_EVENT_KPROBE_TABLE,
3684 FIELD_ARRAY(LTT_FIELD_IP, LTT_FIELD_SYMBOL),
3685 dump_kprobe, NULL, &hooks);
3686
3687 lttv_trace_find_hook(ts->parent.t,
3688 LTT_CHANNEL_SOFTIRQ_STATE,
3689 LTT_EVENT_SOFTIRQ_VEC,
3690 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3691 dump_softirq, NULL, &hooks);
3692
3693 lttv_trace_find_hook(ts->parent.t,
3694 LTT_CHANNEL_FS,
3695 LTT_EVENT_OPEN,
3696 FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME),
3697 fs_open, NULL, &hooks);
3698
3699 /* Add these hooks to each event_by_id hooks list */
3700
3701 nb_tracefile = ts->parent.tracefiles->len;
3702
3703 for(j = 0 ; j < nb_tracefile ; j++) {
3704 tfs =
3705 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3706 LttvTracefileContext*, j));
3707
3708 for(k = 0 ; k < hooks->len ; k++) {
3709 th = &g_array_index(hooks, LttvTraceHook, k);
3710 if (th->mdata == tfs->parent.tf->mdata)
3711 lttv_hooks_add(
3712 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3713 th->h,
3714 th,
3715 LTTV_PRIO_STATE);
3716 }
3717 }
3718 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3719 *(val.v_pointer) = hooks;
3720 }
3721 #endif
3722 }
3723
3724 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3725 {
3726
3727 LttvTraceset *traceset = (LttvTraceset*)(call_data);
3728
3729 lttv_state_remove_event_hooks(traceset);
3730
3731 return 0;
3732 }
3733
3734 void lttv_state_remove_event_hooks(LttvTraceset *traceset)
3735 {
3736
3737 guint i, j, k, nb_trace, nb_tracefile;
3738
3739 //LttvTraceState *ts;
3740
3741 //GArray *hooks;
3742
3743 //LttvTraceHook *th;
3744
3745 //LttvAttributeValue val;
3746
3747 LttvHooks*event_hook;
3748 //TODO ybrosseau 2012-07-17 validate this. Reversed what's done in the add
3749 event_hook = lttv_traceset_get_hooks(traceset);
3750
3751 g_assert(event_hook);
3752
3753
3754 lttv_hooks_remove(event_hook,syscall_entry );
3755 lttv_hooks_remove(event_hook,syscall_exit);
3756 lttv_hooks_remove(event_hook,irq_entry );
3757 lttv_hooks_remove(event_hook,irq_exit );
3758 lttv_hooks_remove(event_hook,soft_irq_raise);
3759 lttv_hooks_remove(event_hook,soft_irq_entry);
3760 lttv_hooks_remove(event_hook,soft_irq_exit);
3761 lttv_hooks_remove(event_hook,schedchange);
3762 lttv_hooks_remove(event_hook,sched_try_wakeup);
3763 lttv_hooks_remove(event_hook,process_exit);
3764 lttv_hooks_remove(event_hook,process_free);
3765 lttv_hooks_remove(event_hook,process_exec);
3766 lttv_hooks_remove(event_hook,enum_process_state);
3767 lttv_hooks_remove(event_hook,statedump_end);
3768 lttv_hooks_remove(event_hook,enum_interrupt);
3769 #ifdef BABEL_CLEANUP
3770 nb_trace = lttv_traceset_number(traceset);
3771 for(i = 0 ; i < nb_trace ; i++) {
3772 ts = lttv_traceset_get(i);
3773
3774 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3775 hooks = *(val.v_pointer);
3776
3777 /* Remove these hooks from each event_by_id hooks list */
3778
3779 nb_tracefile = ts->parent.tracefiles->len;
3780
3781 for(j = 0 ; j < nb_tracefile ; j++) {
3782 tfs =
3783 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3784 LttvTracefileContext*, j));
3785
3786 for(k = 0 ; k < hooks->len ; k++) {
3787 th = &g_array_index(hooks, LttvTraceHook, k);
3788 if (th->mdata == tfs->parent.tf->mdata)
3789 lttv_hooks_remove_data(
3790 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3791 th->h,
3792 th);
3793 }
3794 }
3795 lttv_trace_hook_remove_all(&hooks);
3796 g_array_free(hooks, TRUE);
3797 }
3798 #endif
3799 }
3800
3801
3802 static gboolean state_save_event_hook(void *hook_data, void *call_data)
3803 {
3804 guint *event_count = (guint*)hook_data;
3805
3806 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3807 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3808 return FALSE;
3809 else
3810 *event_count = 0;
3811
3812 LttvEvent *event = (LttvEvent *)call_data;
3813
3814 LttvTraceset *traceset = lttv_trace_get_traceset(event->state->trace);
3815
3816 LttvAttribute *saved_states_tree, *saved_state_tree;
3817
3818 LttvAttributeValue value;
3819 LttTime currentTime;
3820 guint i;
3821 currentTime = lttv_event_get_timestamp(event);
3822 int nb_trace = lttv_traceset_number(traceset);
3823 for(i = 0 ; i < nb_trace ; i++) {
3824
3825 LttvTrace *trace = lttv_traceset_get(traceset, i);
3826 LttvTraceState *tstate = trace->state;
3827 saved_states_tree = lttv_attribute_find_subdir(trace->a,
3828 LTTV_STATE_SAVED_STATES);
3829
3830 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3831 value = lttv_attribute_add(saved_states_tree,
3832 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3833 *(value.v_gobject) = (GObject *)saved_state_tree;
3834
3835
3836 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3837 *(value.v_time) = currentTime;
3838
3839 lttv_state_save(tstate, saved_state_tree);
3840 g_debug("Saving state at time %lu.%lu", currentTime.tv_sec,
3841 currentTime.tv_nsec);
3842
3843 *(tstate->max_time_state_recomputed_in_seek) = currentTime;
3844 }
3845 return FALSE;
3846 }
3847
3848 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3849 {
3850 #warning "Would we move max_time to traceset"
3851 LttvTrace *trace = (LttvTrace *)(call_data);
3852 LttvTraceState *tcs = trace->state;
3853 TimeInterval time_span = lttv_traceset_get_time_span_real(lttv_trace_get_traceset(trace));
3854
3855 *(tcs->max_time_state_recomputed_in_seek) = time_span.end_time;
3856
3857 return FALSE;
3858 }
3859 #ifdef BABEL_CLEANUP
3860 guint lttv_state_current_cpu(LttvTracefileState *tfs)
3861 {
3862 return tfs->cpu;
3863 }
3864
3865 #endif //BABEL_CLEANUP
3866
3867 #if 0
3868 static gboolean block_start(void *hook_data, void *call_data)
3869 {
3870 LttvTracefileState *self = (LttvTracefileState *)call_data;
3871
3872 LttvTracefileState *tfcs;
3873
3874 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3875
3876 LttEventPosition *ep;
3877
3878 guint i, nb_block, nb_event, nb_tracefile;
3879
3880 LttTracefile *tf;
3881
3882 LttvAttribute *saved_states_tree, *saved_state_tree;
3883
3884 LttvAttributeValue value;
3885
3886 ep = ltt_event_position_new();
3887
3888 nb_tracefile = tcs->parent.tracefiles->len;
3889
3890 /* Count the number of events added since the last block end in any
3891 tracefile. */
3892
3893 for(i = 0 ; i < nb_tracefile ; i++) {
3894 tfcs =
3895 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3896 LttvTracefileContext, i));
3897 ltt_event_position(tfcs->parent.e, ep);
3898 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3899 tcs->nb_event += nb_event - tfcs->saved_position;
3900 tfcs->saved_position = nb_event;
3901 }
3902 g_free(ep);
3903
3904 if(tcs->nb_event >= tcs->save_interval) {
3905 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3906 LTTV_STATE_SAVED_STATES);
3907 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3908 value = lttv_attribute_add(saved_states_tree,
3909 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3910 *(value.v_gobject) = (GObject *)saved_state_tree;
3911 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3912 *(value.v_time) = self->parent.timestamp;
3913 lttv_state_save(tcs, saved_state_tree);
3914 tcs->nb_event = 0;
3915 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3916 self->parent.timestamp.tv_nsec);
3917 }
3918 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3919 return FALSE;
3920 }
3921 #endif //0
3922
3923 #if 0
3924 static gboolean block_end(void *hook_data, void *call_data)
3925 {
3926 LttvTracefileState *self = (LttvTracefileState *)call_data;
3927
3928 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3929
3930 LttTracefile *tf;
3931
3932 LttEventPosition *ep;
3933
3934 guint nb_block, nb_event;
3935
3936 ep = ltt_event_position_new();
3937 ltt_event_position(self->parent.e, ep);
3938 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3939 tcs->nb_event += nb_event - self->saved_position + 1;
3940 self->saved_position = 0;
3941 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3942 g_free(ep);
3943
3944 return FALSE;
3945 }
3946 #endif //0
3947 #if 0
3948 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3949 {
3950 LttvTraceset *traceset = self->parent.ts;
3951
3952 guint i, j, nb_trace, nb_tracefile;
3953
3954 LttvTraceState *ts;
3955
3956 LttvTracefileState *tfs;
3957
3958 LttvTraceHook hook_start, hook_end;
3959
3960 nb_trace = lttv_traceset_number(traceset);
3961 for(i = 0 ; i < nb_trace ; i++) {
3962 ts = (LttvTraceState *)self->parent.traces[i];
3963
3964 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3965 NULL, NULL, block_start, &hook_start);
3966 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3967 NULL, NULL, block_end, &hook_end);
3968
3969 nb_tracefile = ts->parent.tracefiles->len;
3970
3971 for(j = 0 ; j < nb_tracefile ; j++) {
3972 tfs =
3973 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3974 LttvTracefileContext, j));
3975 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3976 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3977 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3978 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3979 }
3980 }
3981 }
3982 #endif //0
3983
3984 void lttv_state_save_add_event_hooks(LttvTraceset *traceset)
3985 {
3986
3987 guint i, j, nb_trace, nb_tracefile;
3988
3989 LttvTraceState *ts;
3990
3991 LttvTracefileState *tfs;
3992
3993
3994 if(!traceset->has_precomputed_states) {
3995 guint *event_count = g_new(guint, 1);
3996
3997 *event_count = 0;
3998 lttv_hooks_add(traceset->event_hooks,
3999 state_save_event_hook,
4000 event_count,
4001 LTTV_PRIO_STATE);
4002
4003 #ifdef BABEL_CLEANUP
4004 nb_trace = lttv_traceset_number(traceset);
4005 for(i = 0 ; i < nb_trace ; i++) {
4006
4007 ts = (LttvTraceState *)self->parent.traces[i];
4008 nb_tracefile = ts->parent.tracefiles->len;
4009
4010 if(ts->has_precomputed_states) continue;
4011
4012 guint *event_count = g_new(guint, 1);
4013 *event_count = 0;
4014
4015 for(j = 0 ; j < nb_tracefile ; j++) {
4016 tfs =
4017 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4018 LttvTracefileContext*, j));
4019 lttv_hooks_add(tfs->parent.event,
4020 state_save_event_hook,
4021 event_count,
4022 LTTV_PRIO_STATE);
4023
4024 }
4025 }
4026 #endif
4027 lttv_process_traceset_begin(traceset,
4028 NULL, NULL, NULL, NULL, NULL);
4029 }
4030
4031 }
4032
4033 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
4034 {
4035 LttvTraceset *ts = (LttvTraceset*)(call_data);
4036
4037 lttv_state_save_add_event_hooks(ts);
4038
4039 return 0;
4040 }
4041
4042
4043 #if 0
4044 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4045 {
4046 LttvTraceset *traceset = self->parent.ts;
4047
4048 guint i, j, nb_trace, nb_tracefile;
4049
4050 LttvTraceState *ts;
4051
4052 LttvTracefileState *tfs;
4053
4054 LttvTraceHook hook_start, hook_end;
4055
4056 nb_trace = lttv_traceset_number(traceset);
4057 for(i = 0 ; i < nb_trace ; i++) {
4058 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
4059
4060 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
4061 NULL, NULL, block_start, &hook_start);
4062
4063 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
4064 NULL, NULL, block_end, &hook_end);
4065
4066 nb_tracefile = ts->parent.tracefiles->len;
4067
4068 for(j = 0 ; j < nb_tracefile ; j++) {
4069 tfs =
4070 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
4071 LttvTracefileContext, j));
4072 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4073 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
4074 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4075 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
4076 }
4077 }
4078 }
4079 #endif //0
4080
4081 void lttv_state_save_remove_event_hooks(LttvTraceset *traceset)
4082 {
4083
4084 guint i, j, nb_trace, nb_tracefile;
4085
4086 LttvTraceState *ts;
4087
4088 LttvTracefileState *tfs;
4089
4090 LttvHooks *after_trace = lttv_hooks_new();
4091 guint *event_count = NULL;
4092
4093 lttv_hooks_add(after_trace,
4094 state_save_after_trace_hook,
4095 NULL,
4096 LTTV_PRIO_STATE);
4097
4098
4099 lttv_process_traceset_end(traceset,
4100 NULL, after_trace, NULL, NULL);
4101
4102 lttv_hooks_destroy(after_trace);
4103
4104 //nb_trace = lttv_traceset_number(traceset);
4105
4106 event_count = lttv_hooks_remove(traceset->event_hooks,
4107 state_save_event_hook);
4108
4109 if(event_count) g_free(event_count);
4110
4111 #ifdef BABEL_CLEANUP
4112 for(i = 0 ; i < nb_trace ; i++) {
4113
4114 ts = (LttvTraceState *)self->parent.traces[i];
4115 nb_tracefile = ts->parent.tracefiles->len;
4116
4117 if(ts->has_precomputed_states) continue;
4118
4119 guint *event_count = NULL;
4120
4121 for(j = 0 ; j < nb_tracefile ; j++) {
4122 tfs =
4123 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4124 LttvTracefileContext*, j));
4125 event_count = lttv_hooks_remove(tfs->parent.event,
4126 state_save_event_hook);
4127 }
4128 if(event_count) g_free(event_count);
4129 }
4130 #endif
4131 }
4132
4133 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
4134 {
4135 LttvTraceset *ts = (LttvTraceset*)(call_data);
4136
4137 lttv_state_save_remove_event_hooks(ts);
4138
4139 return 0;
4140 }
4141
4142
4143 void lttv_state_traceset_seek_time(LttvTraceset *traceset, LttTime t)
4144 {
4145 lttv_state_traceset_seek_time_closest(traceset,
4146 t);
4147 lttv_process_traceset_middle(traceset, t, G_MAXUINT,
4148 NULL);
4149 }
4150
4151 void lttv_state_traceset_seek_position(LttvTraceset *traceset, LttvTracesetPosition *position)
4152 {
4153 LttTime t = lttv_traceset_position_get_time(position);
4154
4155 lttv_state_traceset_seek_time_closest(traceset,
4156 t);
4157 lttv_process_traceset_middle(traceset,
4158 ltt_time_infinite,
4159 G_MAXUINT,
4160 position);
4161 }
4162
4163 void lttv_state_traceset_seek_time_closest(LttvTraceset *traceset, LttTime t)
4164 {
4165 guint i, nb_trace;
4166
4167 int min_pos, mid_pos, max_pos;
4168
4169 guint call_rest = 0;
4170 guint resto_start = 0;
4171 guint resto_at = 0;
4172
4173 LttvAttributeValue value;
4174
4175 LttvAttributeType type;
4176
4177 LttvAttributeName name;
4178
4179 gboolean is_named;
4180
4181 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree = NULL;
4182
4183 LttTime closest_tree_time, restored_time;
4184 guint first_restored_time = 1;
4185
4186 //g_tree_destroy(self->parent.pqueue);
4187 //self->parent.pqueue = g_tree_new(compare_tracefile);
4188
4189 g_debug("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
4190
4191 nb_trace = lttv_traceset_number(traceset);
4192 for(i = 0 ; i < nb_trace ; i++) {
4193
4194 LttvTrace *trace = lttv_traceset_get(traceset, i);
4195 LttvTraceState *tstate = trace->state;
4196
4197 if(ltt_time_compare(t, *(tstate->max_time_state_recomputed_in_seek)) < 0) {
4198 saved_states_tree = lttv_attribute_find_subdir(trace->a,
4199 LTTV_STATE_SAVED_STATES);
4200 min_pos = -1;
4201
4202 if(saved_states_tree) {
4203 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
4204 mid_pos = max_pos / 2;
4205 while(min_pos < max_pos) {
4206 type = lttv_attribute_get(saved_states_tree, mid_pos,
4207 &name, &value, &is_named);
4208 g_assert(type == LTTV_GOBJECT);
4209 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
4210 type = lttv_attribute_get_by_name(saved_state_tree,
4211 LTTV_STATE_TIME, &value);
4212 g_assert(type == LTTV_TIME);
4213 if(ltt_time_compare(*(value.v_time), t) < 0) {
4214 min_pos = mid_pos;
4215 closest_tree = saved_state_tree;
4216 closest_tree_time = *(value.v_time);
4217 }
4218 else max_pos = mid_pos - 1;
4219
4220 mid_pos = (min_pos + max_pos + 1) / 2;
4221 }
4222 }
4223
4224 /* restore the closest earlier saved state */
4225 if(min_pos != -1) {
4226 if(first_restored_time || (ltt_time_compare(restored_time, closest_tree_time) == 0)) {
4227 first_restored_time = 0;
4228 lttv_state_restore(tstate, closest_tree);
4229
4230 restored_time = closest_tree_time;
4231 call_rest = 1;
4232 } else {
4233 g_debug("State: restored time mismatch between traces");
4234 resto_start = 1;
4235 break;
4236 }
4237
4238 }
4239
4240 /* There is no saved state, yet we want to have it. Restart at T0 */
4241 else {
4242 resto_start = 1;
4243 break;
4244 }
4245 }
4246 /* We want to seek quickly without restoring/updating the state */
4247 else {
4248 resto_at = 1;
4249 break;
4250 }
4251 }
4252
4253 if(resto_start || resto_at) {
4254 // Restore init state and seek so
4255 for(i = 0 ; i < nb_trace ; i++) {
4256
4257 LttvTrace *trace = lttv_traceset_get(traceset, i);
4258 LttvTraceState *tstate = trace->state;
4259
4260 restore_init_state(tstate);
4261 }
4262
4263 // If t > max saved state
4264 if(resto_at) {
4265 lttv_process_traceset_seek_time(traceset, t);
4266 } else if (resto_start) {
4267 // If no saved state
4268 lttv_process_traceset_seek_time(traceset, ltt_time_zero);
4269 } else {
4270 g_assert(FALSE);
4271 }
4272 g_info("NOT Calling restore");
4273
4274 } else {
4275 // Seek at checkpoint
4276 lttv_process_traceset_seek_time(traceset, restored_time);
4277
4278
4279 }
4280
4281
4282 }
4283
4284 #ifdef BABEL_CLEANUP
4285 static void traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
4286 {
4287 }
4288
4289
4290 static void traceset_state_finalize (LttvTracesetState *self)
4291 {
4292 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
4293 finalize(G_OBJECT(self));
4294 }
4295
4296
4297 static void traceset_state_class_init (LttvTracesetContextClass *klass)
4298 {
4299 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4300
4301 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
4302 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
4303 klass->fini = (void (*)(LttvTracesetContext *self))fini;
4304 klass->new_traceset_context = new_traceset_context;
4305 klass->new_trace_context = new_trace_context;
4306 klass->new_tracefile_context = new_tracefile_context;
4307 }
4308
4309
4310 GType lttv_traceset_state_get_type(void)
4311 {
4312 static GType type = 0;
4313 if (type == 0) {
4314 static const GTypeInfo info = {
4315 sizeof (LttvTracesetStateClass),
4316 NULL, /* base_init */
4317 NULL, /* base_finalize */
4318 (GClassInitFunc) traceset_state_class_init, /* class_init */
4319 NULL, /* class_finalize */
4320 NULL, /* class_data */
4321 sizeof (LttvTracesetState),
4322 0, /* n_preallocs */
4323 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
4324 NULL /* value handling */
4325 };
4326
4327 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
4328 &info, 0);
4329 }
4330 return type;
4331 }
4332
4333 #endif
4334 #if BABEL_CLEANUP
4335 static void trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
4336 {
4337 }
4338
4339
4340 static void trace_state_finalize (LttvTraceState *self)
4341 {
4342 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
4343 finalize(G_OBJECT(self));
4344 }
4345
4346
4347 static void trace_state_class_init (LttvTraceStateClass *klass)
4348 {
4349 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4350
4351 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
4352 klass->state_save = state_save;
4353 klass->state_restore = state_restore;
4354 klass->state_saved_free = state_saved_free;
4355 }
4356
4357
4358 GType lttv_trace_state_get_type(void)
4359 {
4360 static GType type = 0;
4361 if (type == 0) {
4362 static const GTypeInfo info = {
4363 sizeof (LttvTraceStateClass),
4364 NULL, /* base_init */
4365 NULL, /* base_finalize */
4366 (GClassInitFunc) trace_state_class_init, /* class_init */
4367 NULL, /* class_finalize */
4368 NULL, /* class_data */
4369 sizeof (LttvTraceState),
4370 0, /* n_preallocs */
4371 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
4372 NULL /* value handling */
4373 };
4374
4375 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
4376 "LttvTraceStateType", &info, 0);
4377 }
4378 return type;
4379 }
4380
4381
4382 static void tracefile_state_instance_init (GTypeInstance *instance,
4383 gpointer g_class)
4384 {
4385 }
4386
4387
4388 static void tracefile_state_finalize (LttvTracefileState *self)
4389 {
4390 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
4391 finalize(G_OBJECT(self));
4392 }
4393
4394
4395 static void tracefile_state_class_init (LttvTracefileStateClass *klass)
4396 {
4397 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4398
4399 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
4400 }
4401
4402
4403 GType lttv_tracefile_state_get_type(void)
4404 {
4405 static GType type = 0;
4406 if (type == 0) {
4407 static const GTypeInfo info = {
4408 sizeof (LttvTracefileStateClass),
4409 NULL, /* base_init */
4410 NULL, /* base_finalize */
4411 (GClassInitFunc) tracefile_state_class_init, /* class_init */
4412 NULL, /* class_finalize */
4413 NULL, /* class_data */
4414 sizeof (LttvTracefileState),
4415 0, /* n_preallocs */
4416 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
4417 NULL /* value handling */
4418 };
4419
4420 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
4421 "LttvTracefileStateType", &info, 0);
4422 }
4423 return type;
4424 }
4425
4426 #endif
4427 static void module_init(void)
4428 {
4429 LTTV_STATE_UNNAMED = g_quark_from_string("");
4430 LTTV_STATE_UNBRANDED = g_quark_from_string("");
4431 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
4432 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
4433 LTTV_STATE_MAYBE_USER_MODE = g_quark_from_string("MAYBE_USER_MODE");
4434 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
4435 LTTV_STATE_MAYBE_SYSCALL = g_quark_from_string("MAYBE_SYSCALL");
4436 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
4437 LTTV_STATE_MAYBE_TRAP = g_quark_from_string("MAYBE_TRAP");
4438 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
4439 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
4440 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
4441 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
4442 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
4443 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
4444 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
4445 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
4446 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
4447 LTTV_STATE_RUN = g_quark_from_string("RUN");
4448 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
4449 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
4450 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
4451 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
4452 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
4453 LTTV_STATE_PROCESS = g_quark_from_string("process");
4454 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
4455 LTTV_STATE_POSITION = g_quark_from_string("position");
4456 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
4457 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
4458 LTTV_STATE_TIME = g_quark_from_string("time");
4459 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
4460 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
4461 LTTV_STATE_TRACE_STATE_USE_COUNT =
4462 g_quark_from_string("trace_state_use_count");
4463 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
4464 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
4465 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
4466 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
4467 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
4468 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
4469
4470 LTT_CHANNEL_FD_STATE = g_quark_from_string("fd_state");
4471 LTT_CHANNEL_GLOBAL_STATE = g_quark_from_string("global_state");
4472 LTT_CHANNEL_IRQ_STATE = g_quark_from_string("irq_state");
4473 LTT_CHANNEL_MODULE_STATE = g_quark_from_string("module_state");
4474 LTT_CHANNEL_NETIF_STATE = g_quark_from_string("netif_state");
4475 LTT_CHANNEL_SOFTIRQ_STATE = g_quark_from_string("softirq_state");
4476 LTT_CHANNEL_SWAP_STATE = g_quark_from_string("swap_state");
4477 LTT_CHANNEL_SYSCALL_STATE = g_quark_from_string("syscall_state");
4478 LTT_CHANNEL_TASK_STATE = g_quark_from_string("task_state");
4479 LTT_CHANNEL_VM_STATE = g_quark_from_string("vm_state");
4480 LTT_CHANNEL_KPROBE_STATE = g_quark_from_string("kprobe_state");
4481 LTT_CHANNEL_FS = g_quark_from_string("fs");
4482 LTT_CHANNEL_KERNEL = g_quark_from_string("kernel");
4483 LTT_CHANNEL_MM = g_quark_from_string("mm");
4484 LTT_CHANNEL_USERSPACE = g_quark_from_string("userspace");
4485 LTT_CHANNEL_BLOCK = g_quark_from_string("block");
4486
4487 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
4488 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
4489 //LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
4490 //LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
4491 LTT_EVENT_PAGE_FAULT_ENTRY = g_quark_from_string("page_fault_entry");
4492 LTT_EVENT_PAGE_FAULT_EXIT = g_quark_from_string("page_fault_exit");
4493 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY = g_quark_from_string("page_fault_nosem_entry");
4494 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT = g_quark_from_string("page_fault_nosem_exit");
4495 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
4496 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
4497 LTT_EVENT_SOFT_IRQ_RAISE = g_quark_from_string("softirq_raise");
4498 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
4499 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
4500 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
4501 LTT_EVENT_SCHED_TRY_WAKEUP = g_quark_from_string("sched_try_wakeup");
4502 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
4503 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
4504 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
4505 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
4506 LTT_EVENT_EXEC = g_quark_from_string("exec");
4507 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
4508 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
4509 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4510 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
4511 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
4512 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4513 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
4514 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");
4515 LTT_EVENT_SYS_CALL_TABLE = g_quark_from_string("sys_call_table");
4516 LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec");
4517 LTT_EVENT_KPROBE_TABLE = g_quark_from_string("kprobe_table");
4518 LTT_EVENT_KPROBE = g_quark_from_string("kprobe");
4519 LTT_EVENT_OPEN = g_quark_from_string("open");
4520 LTT_EVENT_READ = g_quark_from_string("read");
4521 LTT_EVENT_POLL_EVENT = g_quark_from_string("poll_event");
4522
4523 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4524 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4525 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
4526 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
4527 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4528 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4529 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
4530 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4531 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4532 LTT_FIELD_PID = g_quark_from_string("pid");
4533 LTT_FIELD_TGID = g_quark_from_string("tgid");
4534 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
4535 LTT_FIELD_FILENAME = g_quark_from_string("filename");
4536 LTT_FIELD_NAME = g_quark_from_string("name");
4537 LTT_FIELD_TYPE = g_quark_from_string("type");
4538 LTT_FIELD_MODE = g_quark_from_string("mode");
4539 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4540 LTT_FIELD_STATUS = g_quark_from_string("status");
4541 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4542 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
4543 LTT_FIELD_MAJOR = g_quark_from_string("major");
4544 LTT_FIELD_MINOR = g_quark_from_string("minor");
4545 LTT_FIELD_OPERATION = g_quark_from_string("direction");
4546 LTT_FIELD_ACTION = g_quark_from_string("action");
4547 LTT_FIELD_ID = g_quark_from_string("id");
4548 LTT_FIELD_ADDRESS = g_quark_from_string("address");
4549 LTT_FIELD_SYMBOL = g_quark_from_string("symbol");
4550 LTT_FIELD_IP = g_quark_from_string("ip");
4551 LTT_FIELD_FD = g_quark_from_string("fd");
4552 LTT_FIELD_STATE = g_quark_from_string("state");
4553 LTT_FIELD_CPU_ID = g_quark_from_string("cpu_id");
4554
4555 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4556 LTTV_CPU_IDLE = g_quark_from_string("idle");
4557 LTTV_CPU_BUSY = g_quark_from_string("busy");
4558 LTTV_CPU_IRQ = g_quark_from_string("irq");
4559 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
4560 LTTV_CPU_TRAP = g_quark_from_string("trap");
4561
4562 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4563 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4564 LTTV_IRQ_BUSY = g_quark_from_string("busy");
4565
4566 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4567 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4568 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4569 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
4570 }
4571
4572 static void module_destroy()
4573 {
4574 }
4575
4576
4577 LTTV_MODULE("state", "State computation", \
4578 "Update the system state, possibly saving it at intervals", \
4579 module_init, module_destroy)
4580
4581
4582
This page took 0.191748 seconds and 4 git commands to generate.