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