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