Fix first restoration point and set the right state when we pop from syscall
[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);
aedb80c1 2150
90e19f82
AM
2151 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2152 depth - 2);
7a4bdb54 2153 process->state->change = lttv_event_get_timestamp(event);
aedb80c1
YB
2154
2155 if((process->state->t == LTTV_STATE_MODE_UNKNOWN) && (t == LTTV_STATE_SYSCALL)) {
2156 //Force state at running
2157 process->state->t = LTTV_STATE_USER_MODE;
2158 process->state->s = LTTV_STATE_RUN;
2159 }
dc877563 2160}
2161
6806b3c6 2162struct search_result {
90e19f82
AM
2163 const LttTime *time; /* Requested time */
2164 LttTime *best; /* Best result */
6806b3c6 2165};
2166
8c108c1c 2167/* Return a new and initialized LttvProcessState structure */
dc877563 2168
90e19f82
AM
2169LttvProcessState *lttv_state_create_process(LttvTraceState *tcs,
2170 LttvProcessState *parent, guint cpu, guint pid,
2171 guint tgid, GQuark name, const LttTime *timestamp)
2172{
2173 LttvProcessState *process = g_new(LttvProcessState, 1);
2174
2175 LttvExecutionState *es;
2176
2177 char buffer[128];
2178
2179 process->pid = pid;
2180 process->tgid = tgid;
2181 process->cpu = cpu;
2182 process->name = name;
2183 process->brand = LTTV_STATE_UNBRANDED;
2184 //process->last_cpu = tfs->cpu_name;
2185 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2186 process->type = LTTV_STATE_USER_THREAD;
90e19f82
AM
2187
2188 g_info("Process %u, core %p", process->pid, process);
2189 g_hash_table_insert(tcs->processes, process, process);
2190
2191 if(parent) {
2192 process->ppid = parent->pid;
2193 process->creation_time = *timestamp;
2194 }
2195
2196 /* No parent. This process exists but we are missing all information about
2197 its creation. The birth time is set to zero but we remember the time of
2198 insertion */
2199
2200 else {
2201 process->ppid = 0;
2202 process->creation_time = ltt_time_zero;
2203 }
2204
2205 process->insertion_time = *timestamp;
2206 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2207 process->creation_time.tv_nsec);
2208 process->pid_time = g_quark_from_string(buffer);
2209 process->cpu = cpu;
2210 process->free_events = 0;
2211 //process->last_cpu = tfs->cpu_name;
2212 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2213 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2214 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2215 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2216 es = process->state = &g_array_index(process->execution_stack,
2217 LttvExecutionState, 0);
2218 es->t = LTTV_STATE_USER_MODE;
2219 es->n = LTTV_STATE_SUBMODE_NONE;
2220 es->entry = *timestamp;
2221 //g_assert(timestamp->tv_sec != 0);
2222 es->change = *timestamp;
2223 es->cum_cpu_time = ltt_time_zero;
2224 es->s = LTTV_STATE_RUN;
2225
2226 es = process->state = &g_array_index(process->execution_stack,
2227 LttvExecutionState, 1);
2228 es->t = LTTV_STATE_SYSCALL;
2229 es->n = LTTV_STATE_SUBMODE_NONE;
2230 es->entry = *timestamp;
2231 //g_assert(timestamp->tv_sec != 0);
2232 es->change = *timestamp;
2233 es->cum_cpu_time = ltt_time_zero;
2234 es->s = LTTV_STATE_WAIT_FORK;
2235
2236 /* Allocate an empty function call stack. If it's empty, use 0x0. */
7a4bdb54
YB
2237#ifdef BABEL_CLEANUP
2238 //process->user_stack = g_array_sized_new(FALSE, FALSE,
2239 // sizeof(guint64), 0);
2240#endif
90e19f82
AM
2241 process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
2242
2243 return process;
dc877563 2244}
2245
2a2fa4f0 2246LttvProcessState *
90e19f82
AM
2247lttv_state_find_process(LttvTraceState *ts, guint cpu, guint pid)
2248{
2249 LttvProcessState key;
2250 LttvProcessState *process;
2251
2252 key.pid = pid;
2253 key.cpu = cpu;
2254 process = g_hash_table_lookup(ts->processes, &key);
2255 return process;
2256}
2257
2258LttvProcessState *lttv_state_find_process_or_create(LttvTraceState *ts,
2259 guint cpu, guint pid, const LttTime *timestamp)
2260{
2261 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2262 LttvExecutionState *es;
2263
2264 /* Put ltt_time_zero creation time for unexisting processes */
2265 if(unlikely(process == NULL)) {
2266 process = lttv_state_create_process(ts,
2267 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2268 /* We are not sure is it's a kernel thread or normal thread, put the
2269 * bottom stack state to unknown */
2270 process->execution_stack =
2271 g_array_set_size(process->execution_stack, 1);
2272 process->state = es =
2273 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2274 es->t = LTTV_STATE_MODE_UNKNOWN;
2275 es->s = LTTV_STATE_UNNAMED;
2276 }
2277 return process;
2a2fa4f0 2278}
2279
41c7f803 2280/* FIXME : this function should be called when we receive an event telling that
2281 * release_task has been called in the kernel. In happens generally when
8c108c1c 2282 * the parent waits for its child termination, but may also happens in special
41c7f803 2283 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2284 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
5567bd2b 2285 * of a killed thread group, but isn't the leader.
41c7f803 2286 */
7a4bdb54 2287static int exit_process(LttvEvent *event, LttvProcessState *process)
dc877563 2288{
7a4bdb54 2289 LttvTraceState *ts = event->state;
90e19f82 2290 LttvProcessState key;
ba576a78 2291
90e19f82
AM
2292 /* Wait for both schedule with exit dead and process free to happen.
2293 * They can happen in any order. */
2294 if (++(process->free_events) < 2)
2295 return 0;
2fe13145 2296
90e19f82
AM
2297 key.pid = process->pid;
2298 key.cpu = process->cpu;
2299 g_hash_table_remove(ts->processes, &key);
2300 g_array_free(process->execution_stack, TRUE);
8c108c1c 2301
90e19f82
AM
2302 /* the following also clears the content */
2303 g_hash_table_destroy(process->fds);
8c108c1c 2304
90e19f82
AM
2305 g_free(process);
2306 return 1;
dc877563 2307}
2308
2309
b445142a 2310static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 2311{
90e19f82 2312 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
8c108c1c 2313
90e19f82
AM
2314 /* the following also clears the content */
2315 g_hash_table_destroy(((LttvProcessState *)value)->fds);
8c108c1c 2316
90e19f82 2317 g_free(value);
dc877563 2318}
2319
2320
308711e5 2321static void lttv_state_free_process_table(GHashTable *processes)
dc877563 2322{
90e19f82
AM
2323 g_hash_table_foreach(processes, free_process_state, NULL);
2324 g_hash_table_destroy(processes);
dc877563 2325}
2326
2327
b445142a 2328static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 2329{
7a4bdb54
YB
2330 LttvEvent *event;
2331 guint cpu;
2332 LttvTraceState *ts;
2333 LttvProcessState *process;
90e19f82 2334 LttvExecutionSubmode submode;
7a4bdb54
YB
2335 char syscall_name[200];
2336
2337 event = (LttvEvent *) call_data;
2338 if (strncmp(lttv_traceset_get_name_from_event(event),
2339 "sys_", sizeof("sys_") - 1) != 0)
2340 return FALSE;
b445142a 2341
7a4bdb54
YB
2342 strncpy(syscall_name,lttv_traceset_get_name_from_event(event)+4,200);
2343
2344 cpu = lttv_traceset_get_cpuid_from_event(event);
2345 ts = event->state;
2346 process = ts->running_process[cpu];
2347
2348 submode = g_quark_from_string(syscall_name);
90e19f82
AM
2349 /* There can be no system call from PID 0 : unknown state */
2350 if(process->pid != 0)
7a4bdb54 2351 push_state(event, ts, LTTV_STATE_SYSCALL, submode);
90e19f82 2352 return FALSE;
dc877563 2353}
2354
2355
b445142a 2356static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 2357{
7a4bdb54
YB
2358 LttvEvent *event;
2359 guint cpu;
2360 LttvTraceState *ts;
2361 LttvProcessState *process;
2362
2363
2364 event = (LttvEvent *) call_data;
2365 if (strcmp(lttv_traceset_get_name_from_event(event),
2366 "exit_syscall") != 0)
2367 return FALSE;
2368
2369 cpu = lttv_traceset_get_cpuid_from_event(event);
2370 ts = event->state;
2371 process = ts->running_process[cpu];
dc877563 2372
90e19f82 2373 /* There can be no system call from PID 0 : unknown state */
7a4bdb54
YB
2374 if (process->pid != 0)
2375 pop_state(event, ts, LTTV_STATE_SYSCALL);
90e19f82 2376 return FALSE;
dc877563 2377}
2378
7a4bdb54 2379#ifdef BABEL_CLEANUP
b445142a 2380static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 2381{
90e19f82
AM
2382 LttvTracefileState *s = (LttvTracefileState *)call_data;
2383 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2384 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2385 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2386 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2387 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
dc877563 2388
90e19f82 2389 LttvExecutionSubmode submode;
b445142a 2390
90e19f82 2391 guint64 trap = ltt_event_get_long_unsigned(e, f);
5e96e7e3 2392
90e19f82 2393 expand_trap_table(ts, trap);
b0e00636 2394
90e19f82 2395 submode = nt->trap_names[trap];
5e96e7e3 2396
90e19f82 2397 push_state(s, LTTV_STATE_TRAP, submode);
d3d99fde 2398
90e19f82
AM
2399 /* update cpu status */
2400 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
d3d99fde 2401
90e19f82
AM
2402 /* update trap status */
2403 g_array_append_val(s->cpu_state->trap_stack, trap);
2404 ts->trap_states[trap].running++;
a81d2a59 2405
90e19f82 2406 return FALSE;
dc877563 2407}
2408
b445142a 2409static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 2410{
90e19f82
AM
2411 LttvTracefileState *s = (LttvTracefileState *)call_data;
2412 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
dc877563 2413
90e19f82 2414 pop_state(s, LTTV_STATE_TRAP);
d3d99fde 2415
90e19f82
AM
2416 /* update cpu status */
2417 cpu_pop_mode(s->cpu_state);
d3d99fde 2418
90e19f82
AM
2419 /* update trap status */
2420 if (s->cpu_state->trap_stack->len > 0) {
2421 gint last = g_array_index(s->cpu_state->trap_stack, gint,
2422 s->cpu_state->trap_stack->len-1);
2423 if(ts->trap_states[last].running)
2424 ts->trap_states[last].running--;
2425 g_array_remove_index(s->cpu_state->trap_stack,
2426 s->cpu_state->trap_stack->len-1);
2427 }
2428 return FALSE;
dc877563 2429}
7a4bdb54 2430#endif /* BABEL_CLEANUP */
dc877563 2431
b445142a 2432static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 2433{
7a4bdb54
YB
2434 LttvEvent *event;
2435 guint cpu;
2436 LttvTraceState *ts;
dc877563 2437
90e19f82 2438 LttvExecutionSubmode submode;
7a4bdb54
YB
2439 LttvNameTables *nt;
2440 guint64 irq;
2441
2442 event = (LttvEvent *) call_data;
2443 if (strcmp(lttv_traceset_get_name_from_event(event),
2444 "irq_handler_entry") != 0)
2445 return FALSE;
2446
2447 cpu = lttv_traceset_get_cpuid_from_event(event);
2448 ts = event->state;
2449
2450 nt = ts->name_tables;
fc26eb1b 2451 irq = lttv_event_get_long(event, "irq");
b445142a 2452
90e19f82 2453 expand_irq_table(ts, irq);
b0e00636 2454
90e19f82 2455 submode = nt->irq_names[irq];
b445142a 2456
90e19f82 2457 /* Do something with the info about being in user or system mode when int? */
7a4bdb54 2458 push_state(event, ts, LTTV_STATE_IRQ, submode);
598026ba 2459
90e19f82 2460 /* update cpu status */
7a4bdb54 2461 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_IRQ);
598026ba 2462
90e19f82 2463 /* update irq status */
7a4bdb54 2464 g_array_append_val(ts->cpu_states[cpu].irq_stack, irq);
90e19f82 2465 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
5e563da0 2466
90e19f82 2467 return FALSE;
dc877563 2468}
2469
302efbad 2470static gboolean soft_irq_exit(void *hook_data, void *call_data)
2471{
7a4bdb54
YB
2472 LttvEvent *event;
2473 guint cpu;
2474 LttvTraceState *ts;
302efbad 2475
7a4bdb54
YB
2476 LttvCPUState *cpu_state;
2477
2478 event = (LttvEvent *) call_data;
2479 if (strcmp(lttv_traceset_get_name_from_event(event),
2480 "softirq_exit") != 0)
2481 return FALSE;
2482
2483 cpu = lttv_traceset_get_cpuid_from_event(event);
2484 ts = event->state;
2485
2486 cpu_state = &(ts->cpu_states[cpu]);
2487 pop_state(event, ts, LTTV_STATE_SOFT_IRQ);
302efbad 2488
90e19f82 2489 /* update cpu status */
7a4bdb54 2490 cpu_pop_mode(cpu_state);
d34141ca 2491
90e19f82 2492 /* update softirq status */
7a4bdb54
YB
2493 if (cpu_state->softirq_stack->len > 0) {
2494 gint last = g_array_index(cpu_state->softirq_stack, gint, cpu_state->softirq_stack->len-1);
90e19f82
AM
2495 if(ts->soft_irq_states[last].running)
2496 ts->soft_irq_states[last].running--;
7a4bdb54 2497 g_array_remove_index(cpu_state->softirq_stack, cpu_state->softirq_stack->len-1);
90e19f82
AM
2498 }
2499 return FALSE;
0305fe77 2500}
dc877563 2501
b445142a 2502static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 2503{
7a4bdb54
YB
2504 LttvEvent *event;
2505 guint cpu;
2506 LttvTraceState *ts;
2507
2508 LttvCPUState *cpu_state;
2509
2510 event = (LttvEvent *) call_data;
2511 if (strcmp(lttv_traceset_get_name_from_event(event),
2512 "irq_handler_exit") != 0)
2513 return FALSE;
dc877563 2514
7a4bdb54
YB
2515 cpu = lttv_traceset_get_cpuid_from_event(event);
2516 ts = event->state;
2517 cpu_state = &(ts->cpu_states[cpu]);
2518
2519 pop_state(event, ts, LTTV_STATE_IRQ);
598026ba 2520
90e19f82 2521 /* update cpu status */
7a4bdb54 2522 cpu_pop_mode(cpu_state);
598026ba 2523
90e19f82 2524 /* update irq status */
7a4bdb54
YB
2525 if (cpu_state->irq_stack->len > 0) {
2526 gint last = g_array_index(cpu_state->irq_stack, gint, cpu_state->irq_stack->len-1);
2527 g_array_remove_index(cpu_state->irq_stack, cpu_state->irq_stack->len-1);
90e19f82
AM
2528 irq_pop_mode(&ts->irq_states[last]);
2529 }
8743690d 2530
90e19f82 2531 return FALSE;
dc877563 2532}
2533
a970363f 2534static gboolean soft_irq_raise(void *hook_data, void *call_data)
2535{
7a4bdb54
YB
2536 LttvEvent *event;
2537 //guint cpu;
2538 LttvTraceState *ts;
2539
2540
2541 guint64 softirq;
2542 event = (LttvEvent *) call_data;
2543 if (strcmp(lttv_traceset_get_name_from_event(event),
2544 "softirq_raise") != 0)
2545 return FALSE;
e865422c 2546
7a4bdb54
YB
2547 //cpu = lttv_traceset_get_cpuid_from_event(event);
2548 ts = event->state;
2549 softirq = lttv_event_get_long_unsigned(event, "vec");
a970363f 2550
df6c9904
MD
2551 expand_soft_irq_table(ts, softirq);
2552
90e19f82
AM
2553 /* update softirq status */
2554 /* a soft irq raises are not cumulative */
2555 ts->soft_irq_states[softirq].pending=1;
a970363f 2556
90e19f82 2557 return FALSE;
a970363f 2558}
2559
faf074a3 2560static gboolean soft_irq_entry(void *hook_data, void *call_data)
2561{
7a4bdb54
YB
2562 LttvEvent *event;
2563 guint cpu;
2564 LttvTraceState *ts;
90e19f82 2565 LttvExecutionSubmode submode;
7a4bdb54
YB
2566 LttvNameTables *nt;
2567 guint64 softirq;
2568
2569 event = (LttvEvent *) call_data;
2570 if (strcmp(lttv_traceset_get_name_from_event(event),
b68bfc99 2571 "softirq_entry") != 0)
7a4bdb54
YB
2572 return FALSE;
2573
2574 cpu = lttv_traceset_get_cpuid_from_event(event);
2575 ts = event->state;
2576
2577
2578
2579
2580 softirq = lttv_event_get_long_unsigned(event, "vec");
90e19f82 2581 expand_soft_irq_table(ts, softirq);
7a4bdb54 2582 nt = ts->name_tables;
90e19f82 2583 submode = nt->soft_irq_names[softirq];
faf074a3 2584
90e19f82 2585 /* Do something with the info about being in user or system mode when int? */
7a4bdb54 2586 push_state(event, ts, LTTV_STATE_SOFT_IRQ, submode);
0305fe77 2587
90e19f82 2588 /* update cpu status */
7a4bdb54 2589 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_SOFT_IRQ);
d34141ca 2590
90e19f82 2591 /* update softirq status */
7a4bdb54
YB
2592 g_array_append_val(ts->cpu_states[cpu].softirq_stack, softirq);
2593 if (ts->soft_irq_states[softirq].pending)
90e19f82
AM
2594 ts->soft_irq_states[softirq].pending--;
2595 ts->soft_irq_states[softirq].running++;
0305fe77 2596
90e19f82 2597 return FALSE;
faf074a3 2598}
2599
38b73700 2600static gboolean enum_interrupt(void *hook_data, void *call_data)
2601{
7a4bdb54
YB
2602 LttvEvent *event;
2603 LttvTraceState *ts;
38b73700 2604
7a4bdb54
YB
2605 LttvNameTables *nt;
2606
2607
2608 GQuark action;
2609 guint irq;
2610 event = (LttvEvent *) call_data;
2611 if (strcmp(lttv_traceset_get_name_from_event(event),
2612 "lttng_statedump_interrupt") != 0)
2613 return FALSE;
2614 ts = event->state;
38b73700 2615
7a4bdb54
YB
2616 nt = ts->name_tables;
2617 irq = lttv_event_get_long_unsigned(event, "irq");
2618 action = g_quark_from_string(lttv_event_get_string(event,
2619 "action"));
90e19f82
AM
2620 expand_irq_table(ts, irq);
2621 nt->irq_names[irq] = action;
38b73700 2622
90e19f82 2623 return FALSE;
38b73700 2624}
2625
7a4bdb54 2626#ifdef BABEL_CLEANUP
27811799 2627static gboolean bdev_request_issue(void *hook_data, void *call_data)
2628{
7a4bdb54
YB
2629 LttvEvent *event;
2630 LttvTraceState *ts;
27811799 2631
7a4bdb54
YB
2632 guint major;
2633 guint minor;
2634 guint oper;
2635 guint32 devcode;
2636 gpointer bdev;
27811799 2637
7a4bdb54
YB
2638 event = (LttvEvent *) call_data;
2639 if (strcmp(lttv_traceset_get_name_from_event(event),
2640 "block_rq_issue") != 0)
2641 return FALSE;
27811799 2642
7a4bdb54
YB
2643 ts = event->state;
2644 major = lttv_event_get_long_unsigned(event,);
2645
2646 minor = lttv_event_get_long_unsigned(event,);
2647
2648 oper = lttv_event_get_long_unsigned(event,);
2649
2650 devcode = MKDEV(major,minor);
2651
2652 /* have we seen this block device before? */
2653 bdev = get_hashed_bdevstate(ts, devcode);
90e19f82
AM
2654 if(oper == 0)
2655 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2656 else
2657 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
27811799 2658
90e19f82 2659 return FALSE;
27811799 2660}
2661
2662static gboolean bdev_request_complete(void *hook_data, void *call_data)
2663{
90e19f82
AM
2664 LttvTracefileState *s = (LttvTracefileState *)call_data;
2665 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2666 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2667 LttvTraceHook *th = (LttvTraceHook *)hook_data;
27811799 2668
90e19f82
AM
2669 guint major = ltt_event_get_long_unsigned(e,
2670 lttv_trace_get_hook_field(th, 0));
2671 guint minor = ltt_event_get_long_unsigned(e,
2672 lttv_trace_get_hook_field(th, 1));
2673 //guint oper = ltt_event_get_long_unsigned(e,
2674 // lttv_trace_get_hook_field(th, 2));
59dc1f2a 2675 guint32 devcode = MKDEV(major,minor);
27811799 2676
90e19f82
AM
2677 /* have we seen this block device before? */
2678 gpointer bdev = get_hashed_bdevstate(ts, devcode);
27811799 2679
90e19f82
AM
2680 /* update block device */
2681 bdev_pop_mode(bdev);
27811799 2682
90e19f82 2683 return FALSE;
27811799 2684}
7a4bdb54
YB
2685#endif
2686#ifdef BABEL_CLEANUP
2687// We dont have the syscall table in LTTng 2.0
cf453ac7 2688static gboolean dump_syscall(void *hook_data, void *call_data)
2689{
90e19f82
AM
2690 LttvTracefileState *s = (LttvTracefileState *)call_data;
2691 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2692 LttvNameTables *nt = ts->name_tables;
2693 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2694 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2695 guint id;
90e19f82 2696 char *symbol;
cf453ac7 2697
90e19f82 2698 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
90e19f82 2699 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
cf453ac7 2700
90e19f82
AM
2701 expand_syscall_table(ts, id);
2702 nt->syscall_names[id] = g_quark_from_string(symbol);
cf453ac7 2703
90e19f82 2704 return FALSE;
cf453ac7 2705}
2706
2d0d580c 2707static gboolean dump_kprobe(void *hook_data, void *call_data)
2708{
90e19f82
AM
2709 LttvTracefileState *s = (LttvTracefileState *)call_data;
2710 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2711 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2712 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2713 guint64 ip;
2714 char *symbol;
2d0d580c 2715
90e19f82
AM
2716 ip = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2717 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 1));
2d0d580c 2718
90e19f82 2719 expand_kprobe_table(ts, ip, symbol);
2d0d580c 2720
90e19f82 2721 return FALSE;
2d0d580c 2722}
7a4bdb54
YB
2723#endif
2724#ifdef BABEL_CLEANUP
dc6b2467 2725static gboolean dump_softirq(void *hook_data, void *call_data)
2726{
7a4bdb54 2727
90e19f82
AM
2728 LttvTracefileState *s = (LttvTracefileState *)call_data;
2729 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2730 LttvNameTables *nt = ts->name_tables;
2731 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2732 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2733 guint id;
90e19f82 2734 char *symbol;
dc6b2467 2735
90e19f82 2736 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
90e19f82 2737 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
eb8871e7 2738
90e19f82
AM
2739 expand_soft_irq_table(ts, id);
2740 nt->soft_irq_names[id] = g_quark_from_string(symbol);
dc6b2467 2741
90e19f82 2742 return FALSE;
dc6b2467 2743
7a4bdb54
YB
2744}
2745#endif
0fb145c4
MD
2746static gboolean sched_try_wakeup(void *hook_data, void *call_data)
2747{
7a4bdb54
YB
2748 LttvEvent *event;
2749 LttvTraceState *ts;
90e19f82
AM
2750 LttvProcessState *process;
2751 gint woken_pid;
2752 guint woken_cpu;
7a4bdb54
YB
2753 LttTime timestamp;
2754
2755 event = (LttvEvent *) call_data;
2756 if (strcmp(lttv_traceset_get_name_from_event(event),
2757 "sched_wakeup") != 0)
2758 return FALSE;
068572ab 2759
7a4bdb54 2760 ts = event->state;
068572ab 2761
7a4bdb54 2762 woken_pid = lttv_event_get_long(event, "tid");
fc26eb1b 2763 woken_cpu = lttv_event_get_long(event, "target_cpu");
7a4bdb54
YB
2764
2765 timestamp = lttv_event_get_timestamp(event);
90e19f82 2766 process = lttv_state_find_process_or_create(
7a4bdb54
YB
2767 ts,
2768 woken_cpu, woken_pid,
2769 &timestamp);
6b1f0e27
FG
2770
2771 if (process->state->s == LTTV_STATE_WAIT || process->state->s == LTTV_STATE_WAIT_FORK)
2772 {
2773 process->state->s = LTTV_STATE_WAIT_CPU;
7a4bdb54 2774 process->state->change = timestamp;
6b1f0e27 2775 }
068572ab 2776
90e19f82 2777 g_debug("Wakeup: process %d on CPU %u\n", woken_pid, woken_cpu);
068572ab 2778
90e19f82 2779 return FALSE;
068572ab
CS
2780}
2781
b445142a 2782static gboolean schedchange(void *hook_data, void *call_data)
dc877563 2783{
7a4bdb54
YB
2784 LttvEvent *event;
2785 guint cpu;
2786 LttvTraceState *ts;
2787 LttvProcessState *process;
2788
2789
90e19f82
AM
2790 //LttvProcessState *old_process = ts->running_process[cpu];
2791
90e19f82
AM
2792 guint pid_in, pid_out;
2793 gint64 state_out;
d7f9f37b
YB
2794 //TODO ybrosseau 2012-07-13: manage this 20 in a constact or dynamically
2795 char next_comm[20];
7a4bdb54
YB
2796 LttTime timestamp;
2797 event = (LttvEvent *) call_data;
2798 if (strcmp(lttv_traceset_get_name_from_event(event),
2799 "sched_switch") != 0)
2800 return FALSE;
90e19f82 2801
7a4bdb54
YB
2802 cpu = lttv_traceset_get_cpuid_from_event(event);
2803 ts = event->state;
2804 process = ts->running_process[cpu];
58b4e4ae
YB
2805 pid_out = lttv_event_get_long(event, "prev_tid");
2806 pid_in = lttv_event_get_long(event, "next_tid");
7a4bdb54 2807 state_out = lttv_event_get_long(event, "prev_state");
90e19f82 2808
d7f9f37b
YB
2809 strncpy(next_comm, lttv_event_get_string(event, "next_comm"), 20);
2810 next_comm[20-1] = '\0';
2811
7a4bdb54
YB
2812 timestamp = lttv_event_get_timestamp(event);
2813
90e19f82
AM
2814 if(likely(process != NULL)) {
2815
2816 /* We could not know but it was not the idle process executing.
2817 This should only happen at the beginning, before the first schedule
2818 event, and when the initial information (current process for each CPU)
2819 is missing. It is not obvious how we could, after the fact, compensate
2820 the wrongly attributed statistics. */
2821
2822 //This test only makes sense once the state is known and if there is no
2823 //missing events. We need to silently ignore schedchange coming after a
2824 //process_free, or it causes glitches. (FIXME)
2825 //if(unlikely(process->pid != pid_out)) {
2826 // g_assert(process->pid == 0);
2827 //}
2828 if(process->pid == 0
2829 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2830 if(pid_out == 0) {
f044974e
MD
2831 /*
2832 * Scheduling out of pid 0 at beginning of the trace.
2833 * We are typically in system call mode at this point although
2834 * (FIXME) we might be in a trap handler.
2835 */
90e19f82
AM
2836 g_assert(process->execution_stack->len == 1);
2837 process->state->t = LTTV_STATE_SYSCALL;
2838 process->state->s = LTTV_STATE_WAIT;
7a4bdb54
YB
2839 process->state->change = timestamp;
2840 process->state->entry = timestamp;
90e19f82
AM
2841 }
2842 } else {
2843 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2844 process->state->s = LTTV_STATE_ZOMBIE;
7a4bdb54 2845 process->state->change = timestamp;
90e19f82
AM
2846 } else {
2847 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2848 else process->state->s = LTTV_STATE_WAIT;
7a4bdb54 2849 process->state->change = timestamp;
90e19f82
AM
2850 }
2851
2852 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
2853 /* see sched.h for states */
7a4bdb54 2854 if (!exit_process(event, process)) {
90e19f82 2855 process->state->s = LTTV_STATE_DEAD;
7a4bdb54 2856 process->state->change = timestamp;
2fe13145 2857 }
90e19f82
AM
2858 }
2859 }
2860 }
2861 process = ts->running_process[cpu] = lttv_state_find_process_or_create(
7a4bdb54 2862 ts,
90e19f82 2863 cpu, pid_in,
7a4bdb54 2864 &timestamp);
90e19f82
AM
2865 process->state->s = LTTV_STATE_RUN;
2866 process->cpu = cpu;
348c6ba8 2867 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
7a4bdb54 2868 process->state->change = timestamp;
d7f9f37b 2869 process->name = g_quark_from_string(next_comm);
90e19f82
AM
2870
2871 /* update cpu status */
2872 if(pid_in == 0)
2873 /* going to idle task */
7a4bdb54 2874 cpu_set_base_mode(&(ts->cpu_states[cpu]), LTTV_CPU_IDLE);
90e19f82
AM
2875 else {
2876 /* scheduling a real task.
2877 * we must be careful here:
2878 * if we just schedule()'ed to a process that is
2879 * in a trap, we must put the cpu in trap mode
2880 */
7a4bdb54 2881 cpu_set_base_mode(&(ts->cpu_states[cpu]), LTTV_CPU_BUSY);
90e19f82 2882 if(process->state->t == LTTV_STATE_TRAP)
7a4bdb54 2883 cpu_push_mode(&(ts->cpu_states[cpu]), LTTV_CPU_TRAP);
90e19f82
AM
2884 }
2885
2886 return FALSE;
dc877563 2887}
2888
eed2ef37 2889static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2890{
7a4bdb54
YB
2891 LttvEvent *event;
2892 LttvTraceState *ts;
2893 LttvProcessState *process;
2894 LttvProcessState *child_process;
90e19f82
AM
2895 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2896 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2897 //LttvProcessState *zombie_process;
7a4bdb54
YB
2898 guint cpu;
2899 LttTime timestamp;
90e19f82 2900
7a4bdb54
YB
2901 event = (LttvEvent *) call_data;
2902 if (strcmp(lttv_traceset_get_name_from_event(event),
2903 "sched_process_fork") != 0)
2904 return FALSE;
2905 cpu = lttv_traceset_get_cpuid_from_event(event);
2906 ts = event->state;
2907 process = ts->running_process[cpu];
2908 timestamp = lttv_event_get_timestamp(event);
2909
e865422c 2910 /* Skip Parent PID param */
90e19f82
AM
2911
2912 /* Child PID */
7b20eed1 2913 child_pid = lttv_event_get_long(event, "child_tid");
7a4bdb54 2914 //ts->target_pid = child_pid;
90e19f82
AM
2915
2916 /* Child TGID */
7a4bdb54
YB
2917
2918 child_tgid = 0;
90e19f82
AM
2919
2920 /* Mathieu : it seems like the process might have been scheduled in before the
2921 * fork, and, in a rare case, might be the current process. This might happen
2922 * in a SMP case where we don't have enough precision on the clocks.
2923 *
2924 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2925#if 0
90e19f82
AM
2926 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2927
2928 if(unlikely(zombie_process != NULL)) {
2929 /* Reutilisation of PID. Only now we are sure that the old PID
2930 * has been released. FIXME : should know when release_task happens instead.
2931 */
2932 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2933 guint i;
2934 for(i=0; i< num_cpus; i++) {
2935 g_assert(zombie_process != ts->running_process[i]);
2936 }
2937
2938 exit_process(s, zombie_process);
2939 }
791dffa6 2940#endif //0
90e19f82
AM
2941 g_assert(process->pid != child_pid);
2942 // FIXME : Add this test in the "known state" section
2943 // g_assert(process->pid == parent_pid);
2944 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2945 if(child_process == NULL) {
2946 child_process = lttv_state_create_process(ts, process, cpu,
2947 child_pid, child_tgid,
7a4bdb54 2948 LTTV_STATE_UNNAMED, &timestamp);
90e19f82
AM
2949 } else {
2950 /* The process has already been created : due to time imprecision between
2951 * multiple CPUs : it has been scheduled in before creation. Note that we
2952 * shouldn't have this kind of imprecision.
2953 *
2954 * Simply put a correct parent.
2955 */
2956 g_error("Process %u has been created at [%lu.%09lu] "
2957 "and inserted at [%lu.%09lu] before \n"
2958 "fork on cpu %u[%lu.%09lu].\n"
2959 "Probably an unsynchronized TSC problem on the traced machine.",
2960 child_pid,
2961 child_process->creation_time.tv_sec,
2962 child_process->creation_time.tv_nsec,
2963 child_process->insertion_time.tv_sec,
2964 child_process->insertion_time.tv_nsec,
7a4bdb54 2965 cpu, timestamp.tv_sec, timestamp.tv_nsec);
90e19f82
AM
2966 //g_assert(0); /* This is a problematic case : the process has been created
2967 // before the fork event */
2968 child_process->ppid = process->pid;
2969 child_process->tgid = child_tgid;
2970 }
2971 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2972 child_process->name = process->name;
2973 child_process->brand = process->brand;
2974
2975 return FALSE;
dc877563 2976}
2977
7a4bdb54
YB
2978#ifdef BABEL_CLEANUP
2979//NO KTHREAD_CREATE in LTTng 2.0
89f8741a 2980/* We stamp a newly created process as kernel_thread.
2981 * The thread should not be running yet. */
7bfd7820 2982static gboolean process_kernel_thread(void *hook_data, void *call_data)
2983{
90e19f82
AM
2984 LttvTracefileState *s = (LttvTracefileState *)call_data;
2985 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2986 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2987 guint pid;
2988 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2989 LttvProcessState *process;
2990 LttvExecutionState *es;
7bfd7820 2991
90e19f82
AM
2992 /* PID */
2993 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
7a4bdb54 2994 //s->parent.target_pid = pid;
7bfd7820 2995
90e19f82
AM
2996 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2997 &ltt_time_zero);
2998 if (process->state->s != LTTV_STATE_DEAD) {
2999 process->execution_stack =
3000 g_array_set_size(process->execution_stack, 1);
3001 es = process->state =
3002 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3003 es->t = LTTV_STATE_SYSCALL;
3004 }
3005 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 3006
90e19f82 3007 return FALSE;
7bfd7820 3008}
7a4bdb54 3009#endif
eed2ef37 3010static gboolean process_exit(void *hook_data, void *call_data)
dc877563 3011{
7a4bdb54
YB
3012 LttvEvent *event;
3013 LttvTraceState *ts;
90e19f82 3014 guint pid;
7a4bdb54 3015 guint cpu;
90e19f82 3016 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 3017
7a4bdb54
YB
3018 event = (LttvEvent *) call_data;
3019 if (strcmp(lttv_traceset_get_name_from_event(event),
3020 "sched_process_exit") != 0)
3021 return FALSE;
3022 cpu = lttv_traceset_get_cpuid_from_event(event);
3023 ts = event->state;
3024 process = ts->running_process[cpu];
3025
fc26eb1b 3026 pid = lttv_event_get_long(event, "tid");
7a4bdb54 3027 //s->parent.target_pid = pid;
eed2ef37 3028
90e19f82
AM
3029 // FIXME : Add this test in the "known state" section
3030 // g_assert(process->pid == pid);
eed2ef37 3031
90e19f82
AM
3032 process = lttv_state_find_process(ts, ANY_CPU, pid);
3033 if(likely(process != NULL)) {
3034 process->state->s = LTTV_STATE_EXIT;
3035 }
3036 return FALSE;
2cdc690b 3037}
3038
eed2ef37 3039static gboolean process_free(void *hook_data, void *call_data)
2da61677 3040{
7a4bdb54
YB
3041 LttvEvent *event;
3042 LttvTraceState *ts;
3043 guint cpu;
90e19f82
AM
3044 guint release_pid;
3045 LttvProcessState *process;
3046
7a4bdb54
YB
3047 event = (LttvEvent *) call_data;
3048 if (strcmp(lttv_traceset_get_name_from_event(event),
3049 "sched_process_free") != 0)
3050 return FALSE;
3051 cpu = lttv_traceset_get_cpuid_from_event(event);
3052 ts = event->state;
3053 process = ts->running_process[cpu];
3054
90e19f82 3055 /* PID of the process to release */
fc26eb1b 3056 release_pid = lttv_event_get_long(event, "_tid");
7a4bdb54 3057 //s->parent.target_pid = release_pid;
90e19f82
AM
3058
3059 g_assert(release_pid != 0);
3060
3061 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
3062 if(likely(process != NULL))
7a4bdb54 3063 exit_process(event, process);
90e19f82 3064 return FALSE;
2fe13145 3065//DISABLED
7a4bdb54 3066#if 0
90e19f82
AM
3067 if(likely(process != NULL)) {
3068 /* release_task is happening at kernel level : we can now safely release
3069 * the data structure of the process */
3070 //This test is fun, though, as it may happen that
3071 //at time t : CPU 0 : process_free
3072 //at time t+150ns : CPU 1 : schedule out
3073 //Clearly due to time imprecision, we disable it. (Mathieu)
3074 //If this weird case happen, we have no choice but to put the
3075 //Currently running process on the cpu to 0.
3076 //I re-enable it following time precision fixes. (Mathieu)
3077 //Well, in the case where an process is freed by a process on another CPU
3078 //and still scheduled, it happens that this is the schedchange that will
3079 //drop the last reference count. Do not free it here!
3080 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3081 guint i;
3082 for(i=0; i< num_cpus; i++) {
3083 //g_assert(process != ts->running_process[i]);
3084 if(process == ts->running_process[i]) {
3085 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3086 break;
3087 }
3088 }
3089 if(i == num_cpus) /* process is not scheduled */
3090 exit_process(s, process);
3091 }
3092
3093 return FALSE;
7a4bdb54 3094#endif //DISABLED
2da61677 3095}
3096
f4b88a7d 3097
3098static gboolean process_exec(void *hook_data, void *call_data)
7a4bdb54
YB
3099{
3100 LttvEvent *event;
3101 LttvTraceState *ts;
3102 guint cpu;
90e19f82 3103 //gchar *name;
7a4bdb54
YB
3104 LttvProcessState *process;
3105
3106 event = (LttvEvent *) call_data;
3107 if (strcmp(lttv_traceset_get_name_from_event(event),
3108 "sys_execve") != 0)
3109 return FALSE;
3110 cpu = lttv_traceset_get_cpuid_from_event(event);
3111 ts = event->state;
3112 process = ts->running_process[cpu];
f4b88a7d 3113
f63ebe51 3114#if 0//how to use a sequence that must be transformed in a string
90e19f82
AM
3115 /* PID of the process to release */
3116 guint64 name_len = ltt_event_field_element_number(e,
3117 lttv_trace_get_hook_field(th, 0));
3118 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3119 LttField *child = ltt_event_field_element_select(e,
3120 lttv_trace_get_hook_field(th, 0), 0);
3121 gchar *name_begin =
3122 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
3123 gchar *null_term_name = g_new(gchar, name_len+1);
3124 memcpy(null_term_name, name_begin, name_len);
3125 null_term_name[name_len] = '\0';
3126 process->name = g_quark_from_string(null_term_name);
f63ebe51 3127#endif //0
3128
7a4bdb54
YB
3129 process->name = g_quark_from_string(lttv_event_get_string(event,
3130 "filename"));
90e19f82
AM
3131 process->brand = LTTV_STATE_UNBRANDED;
3132 //g_free(null_term_name);
3133 return FALSE;
f4b88a7d 3134}
7a4bdb54 3135#ifdef BABEL_CLEANUP
7b5f6cf1 3136static gboolean thread_brand(void *hook_data, void *call_data)
3137{
90e19f82
AM
3138 LttvTracefileState *s = (LttvTracefileState *)call_data;
3139 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3140 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3141 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3142 gchar *name;
3143 guint cpu = s->cpu;
3144 LttvProcessState *process = ts->running_process[cpu];
7b5f6cf1 3145
90e19f82
AM
3146 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3147 process->brand = g_quark_from_string(name);
7b5f6cf1 3148
90e19f82 3149 return FALSE;
7b5f6cf1 3150}
7a4bdb54
YB
3151#endif
3152#if 0
3153 // TODO We only have sys_open, without the FD
3154 // manage to do somehting better
8c108c1c
PMF
3155static gboolean fs_open(void *hook_data, void *call_data)
3156{
90e19f82
AM
3157 LttvTracefileState *s = (LttvTracefileState *)call_data;
3158 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
3159 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3160 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3161 struct marker_field *f;
3162 guint cpu = s->cpu;
3163 int fd;
3164 char *filename;
3165 LttvProcessState *process = ts->running_process[cpu];
8c108c1c 3166
90e19f82
AM
3167 f = lttv_trace_get_hook_field(th, 0);
3168 fd = ltt_event_get_int(e, f);
8c108c1c 3169
90e19f82
AM
3170 f = lttv_trace_get_hook_field(th, 1);
3171 filename = ltt_event_get_string(e, f);
8c108c1c 3172
90e19f82
AM
3173 g_hash_table_insert(process->fds, (gpointer)(long)fd,
3174 (gpointer)(unsigned long)g_quark_from_string(filename));
8c108c1c 3175
90e19f82 3176 return FALSE;
8c108c1c 3177}
7a4bdb54 3178#endif
9ba16662
MD
3179static void print_stack(LttvProcessState *process)
3180{
3181 LttvExecutionState *es;
3182 int i;
3183
3184 g_debug("Execution stack for process %u %s:\n",
90e19f82 3185 process->pid, g_quark_to_string(process->name));
9ba16662
MD
3186
3187 for (i = 0; i < process->execution_stack->len; i++) {
3188 es = &g_array_index(process->execution_stack,
90e19f82 3189 LttvExecutionState, i);
9ba16662 3190 g_debug("Depth %d mode %s submode %s status %s\n",
90e19f82
AM
3191 i, g_quark_to_string(es->t),
3192 g_quark_to_string(es->n),
3193 g_quark_to_string(es->s));
9ba16662
MD
3194 }
3195
3196}
3197
90e19f82
AM
3198static void fix_process(gpointer key, gpointer value, gpointer user_data)
3199{
3200 LttvProcessState *process;
3201 LttvExecutionState *es;
3202 process = (LttvProcessState *)value;
3203 LttTime *timestamp = (LttTime*)user_data;
3204
3205 print_stack(process);
3206
3207 if(process->type == LTTV_STATE_KERNEL_THREAD) {
3208 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
f044974e 3209 if(es->t == LTTV_STATE_MAYBE_SYSCALL) {
90e19f82
AM
3210 es->t = LTTV_STATE_SYSCALL;
3211 es->n = LTTV_STATE_SUBMODE_NONE;
3212 es->entry = *timestamp;
3213 es->change = *timestamp;
3214 es->cum_cpu_time = ltt_time_zero;
3215 if(es->s == LTTV_STATE_UNNAMED)
3216 es->s = LTTV_STATE_WAIT;
3217 }
9ba16662 3218 } else {
90e19f82 3219 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
f044974e 3220 if(es->t == LTTV_STATE_MAYBE_USER_MODE) {
90e19f82
AM
3221 es->t = LTTV_STATE_USER_MODE;
3222 es->n = LTTV_STATE_SUBMODE_NONE;
3223 es->entry = *timestamp;
3224 //g_assert(timestamp->tv_sec != 0);
3225 es->change = *timestamp;
3226 es->cum_cpu_time = ltt_time_zero;
3227 if(es->s == LTTV_STATE_UNNAMED)
3228 es->s = LTTV_STATE_RUN;
3229
3230 if(process->execution_stack->len == 1) {
3231 /* Still in bottom unknown mode, means we either:
3232 * - never did a system call
3233 * - are scheduled out from user mode.
3234 * May be either in user mode, syscall mode, running or waiting.*/
3235 /* CHECK : we may be tagging syscall mode when being user mode
3236 * (should be fixed now) */
3237 if (es->s == LTTV_STATE_WAIT_CPU) {
3238 /* nothing to do: scheduled out from userspace */
3239 } else {
3240 process->execution_stack =
3241 g_array_set_size(process->execution_stack, 2);
3242 es = process->state = &g_array_index(process->execution_stack,
3243 LttvExecutionState, 1);
3244 es->t = LTTV_STATE_SYSCALL;
3245 es->n = LTTV_STATE_SUBMODE_NONE;
3246 es->entry = *timestamp;
3247 //g_assert(timestamp->tv_sec != 0);
3248 es->change = *timestamp;
3249 es->cum_cpu_time = ltt_time_zero;
3250 if(es->s == LTTV_STATE_WAIT_FORK)
3251 es->s = LTTV_STATE_WAIT;
3252 }
3253 }
3254 }
9ba16662 3255 }
c3b3b60b 3256}
3257
3258static gboolean statedump_end(void *hook_data, void *call_data)
3259{
7a4bdb54
YB
3260 LttvEvent *event;
3261 LttvTraceState *ts;
3262 LttTime timestamp;
90e19f82
AM
3263 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3264 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
7a4bdb54
YB
3265 event = (LttvEvent *) call_data;
3266 if (strcmp(lttv_traceset_get_name_from_event(event),
3267 "lttng_statedump_end") != 0)
3268 return FALSE;
3269
3270 ts = event->state;
3271 timestamp = lttv_event_get_timestamp(event);
c3b3b60b 3272
90e19f82
AM
3273 /* For all processes */
3274 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3275 /* else, if stack[0] is unknown, set to user mode, running */
0ceef9de 3276
7a4bdb54 3277 g_hash_table_foreach(ts->processes, fix_process, &timestamp);
90e19f82
AM
3278
3279 return FALSE;
c3b3b60b 3280}
3281
b3fd4c02 3282static gboolean enum_process_state(void *hook_data, void *call_data)
3283{
7a4bdb54
YB
3284 LttvEvent *event;
3285 LttvTraceState *ts;
3286 LttTime timestamp;
90e19f82
AM
3287 guint parent_pid;
3288 guint pid;
3289 guint tgid;
3290 gchar * command;
7a4bdb54 3291 guint cpu;
90e19f82 3292 LttvProcessState *parent_process;
7a4bdb54
YB
3293 LttvProcessState *process;
3294
3295 guint type;
90e19f82
AM
3296 LttvExecutionState *es;
3297 guint i, nb_cpus;
3298
7a4bdb54
YB
3299 event = (LttvEvent *) call_data;
3300 if (strcmp(lttv_traceset_get_name_from_event(event),
3301 "lttng_statedump_process_state") != 0)
3302 return FALSE;
3303 cpu = lttv_traceset_get_cpuid_from_event(event);
3304 ts = event->state;
3305 process = ts->running_process[cpu];
3306 timestamp = lttv_event_get_timestamp(event);
3307
90e19f82 3308 /* PID */
fc26eb1b 3309 pid = lttv_event_get_long(event, "tid");
7a4bdb54 3310 //s->parent.target_pid = pid;
90e19f82
AM
3311
3312 /* Parent PID */
fc26eb1b 3313 parent_pid = lttv_event_get_long(event, "ppid");
90e19f82
AM
3314
3315 /* Command name */
7a4bdb54 3316 command = lttv_event_get_string(event, "name");
90e19f82
AM
3317
3318 /* type */
7a4bdb54 3319
fc26eb1b 3320 type = lttv_event_get_long(event, "type");
90e19f82
AM
3321
3322 //FIXME: type is rarely used, enum must match possible types.
3323
e865422c 3324 /* Skip mode 4th param */
90e19f82 3325
e865422c 3326 /* Skip submode 5th param */
90e19f82 3327
e865422c 3328 /* Skip status 6th param */
90e19f82 3329 /* TGID */
fc26eb1b 3330 tgid = lttv_event_get_long(event, "pid");
7a4bdb54 3331
90e19f82 3332 if(pid == 0) {
7a4bdb54 3333 nb_cpus = lttv_trace_get_num_cpu(ts->trace);
90e19f82
AM
3334 for(i=0; i<nb_cpus; i++) {
3335 process = lttv_state_find_process(ts, i, pid);
3336 g_assert(process != NULL);
3337
3338 process->ppid = parent_pid;
3339 process->tgid = tgid;
3340 process->name = g_quark_from_string(command);
3341 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3342 process->type = LTTV_STATE_KERNEL_THREAD;
3343 }
3344
3345 } else {
3346 /* The process might exist if a process was forked while performing the
3347 * state dump. */
3348 process = lttv_state_find_process(ts, ANY_CPU, pid);
3349 if(process == NULL) {
3350 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3351 process = lttv_state_create_process(ts, parent_process, cpu,
3352 pid, tgid, g_quark_from_string(command),
7a4bdb54 3353 &timestamp);
90e19f82
AM
3354
3355 /* Keep the stack bottom : a running user mode */
3356 /* Disabled because of inconsistencies in the current statedump states. */
7a4bdb54
YB
3357 //if(type == LTTV_STATE_KERNEL_THREAD) {
3358 if(type == 1) {
90e19f82
AM
3359 /* Only keep the bottom
3360 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3361 /* Will cause expected trap when in fact being syscall (even after end of
3362 * statedump event)
3363 * Will cause expected interrupt when being syscall. (only before end of
3364 * statedump event) */
3365 // This will cause a "popping last state on stack, ignoring it."
3366 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3367 es = process->state = &g_array_index(process->execution_stack,
3368 LttvExecutionState, 0);
3369 process->type = LTTV_STATE_KERNEL_THREAD;
f044974e 3370 es->t = LTTV_STATE_MAYBE_SYSCALL;
90e19f82
AM
3371 es->s = LTTV_STATE_UNNAMED;
3372 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
f044974e
MD
3373 //es->s = status;
3374 //es->n = submode;
90e19f82
AM
3375 } else {
3376 /* User space process :
3377 * bottom : user mode
3378 * either currently running or scheduled out.
3379 * can be scheduled out because interrupted in (user mode or in syscall)
3380 * or because of an explicit call to the scheduler in syscall. Note that
3381 * the scheduler call comes after the irq_exit, so never in interrupt
3382 * context. */
3383 // temp workaround : set size to 1 : only have user mode bottom of stack.
3384 // will cause g_info message of expected syscall mode when in fact being
3385 // in user mode. Can also cause expected trap when in fact being user
3386 // mode in the event of a page fault reenabling interrupts in the handler.
3387 // Expected syscall and trap can also happen after the end of statedump
3388 // This will cause a "popping last state on stack, ignoring it."
3389 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3390 es = process->state = &g_array_index(process->execution_stack,
3391 LttvExecutionState, 0);
f044974e 3392 es->t = LTTV_STATE_MAYBE_USER_MODE;
90e19f82
AM
3393 es->s = LTTV_STATE_UNNAMED;
3394 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
f044974e
MD
3395 //es->s = status;
3396 //es->n = submode;
90e19f82
AM
3397 }
3398 #if 0
3399 /* UNKNOWN STATE */
3400 {
3401 es = process->state = &g_array_index(process->execution_stack,
3402 LttvExecutionState, 1);
3403 es->t = LTTV_STATE_MODE_UNKNOWN;
3404 es->s = LTTV_STATE_UNNAMED;
3405 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3406 }
3407 #endif //0
3408 } else {
3409 /* The process has already been created :
3410 * Probably was forked while dumping the process state or
3411 * was simply scheduled in prior to get the state dump event.
3412 */
3413 process->ppid = parent_pid;
3414 process->tgid = tgid;
3415 process->name = g_quark_from_string(command);
3416 process->type = type;
3417 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 3418#if 0
90e19f82
AM
3419 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3420 if(type == LTTV_STATE_KERNEL_THREAD)
3421 es->t = LTTV_STATE_SYSCALL;
3422 else
3423 es->t = LTTV_STATE_USER_MODE;
3424 }
cab321cf 3425#endif //0
90e19f82
AM
3426 /* Don't mess around with the stack, it will eventually become
3427 * ok after the end of state dump. */
3428 }
3429 }
3430
3431 return FALSE;
b3fd4c02 3432}
f4b88a7d 3433
7a4bdb54
YB
3434
3435
58c88a41 3436gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3437{
7a4bdb54 3438 LttvTraceset *traceset = (LttvTraceset *)(call_data);
58c88a41 3439
7a4bdb54 3440 lttv_state_add_event_hooks(traceset);
58c88a41 3441
90e19f82 3442 return 0;
58c88a41 3443}
dc877563 3444
7a4bdb54 3445void lttv_state_add_event_hooks(LttvTraceset *traceset)
dc877563 3446{
7a4bdb54
YB
3447 gboolean result;
3448
3449 LttvAttributeValue value;
3450 LttvHooks*event_hook;
a7598d50 3451#ifdef BABEL_CLEANUP
7a4bdb54
YB
3452 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
3453 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
3454 LTTV_POINTER, &value);
3455 g_assert(result);
3456 event_hook = *(value.v_pointer);
a7598d50
YB
3457#endif
3458 //TODO ybrosseau 2012-07-12: Validate that using traceset hooks instead of the global one is valid
3459 //Use traceset hooks
3460 event_hook = lttv_traceset_get_hooks(traceset);
7a4bdb54
YB
3461 g_assert(event_hook);
3462
3463 lttv_hooks_add(event_hook,syscall_entry , NULL, LTTV_PRIO_STATE);
3464 lttv_hooks_add(event_hook,syscall_exit , NULL, LTTV_PRIO_STATE);
3465 lttv_hooks_add(event_hook,irq_entry , NULL, LTTV_PRIO_STATE);
3466 lttv_hooks_add(event_hook,irq_exit , NULL, LTTV_PRIO_STATE);
3467 lttv_hooks_add(event_hook,soft_irq_raise , NULL, LTTV_PRIO_STATE);
3468 lttv_hooks_add(event_hook,soft_irq_entry , NULL, LTTV_PRIO_STATE);
3469 lttv_hooks_add(event_hook,soft_irq_exit , NULL, LTTV_PRIO_STATE);
3470 lttv_hooks_add(event_hook,schedchange , NULL, LTTV_PRIO_STATE);
3471 lttv_hooks_add(event_hook,sched_try_wakeup , NULL, LTTV_PRIO_STATE);
3472 lttv_hooks_add(event_hook,process_exit , NULL, LTTV_PRIO_STATE);
7b20eed1
YB
3473 lttv_hooks_add(event_hook,process_free , NULL, LTTV_PRIO_STATE);
3474 lttv_hooks_add(event_hook,process_fork , NULL, LTTV_PRIO_STATE);
7a4bdb54
YB
3475 lttv_hooks_add(event_hook,process_exec , NULL, LTTV_PRIO_STATE);
3476 lttv_hooks_add(event_hook,enum_process_state , NULL, LTTV_PRIO_STATE);
3477 lttv_hooks_add(event_hook,statedump_end , NULL, LTTV_PRIO_STATE);
3478 lttv_hooks_add(event_hook,enum_interrupt , NULL, LTTV_PRIO_STATE);
3479
3480#ifdef BABEL_CLEANUP //For the whole function this time
3481 guint i, j, k, nb_trace;
90e19f82 3482 LttvTraceState *ts;
90e19f82 3483 GArray *hooks;
7a4bdb54 3484 // LttvTraceHook *th;
90e19f82
AM
3485 LttvAttributeValue val;
3486
3487 nb_trace = lttv_traceset_number(traceset);
7a4bdb54
YB
3488 for (i = 0 ; i < nb_trace ; i++) {
3489 ts = lttv_traceset_get(traceset, i)-;
90e19f82
AM
3490
3491 /* Find the eventtype id for the following events and register the
3492 associated by id hooks. */
3493
3494 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 20);
3495 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3496 //hn = 0;
3497
7a4bdb54 3498 lttv_trace_find_hook(tss->parent.t,
90e19f82
AM
3499 LTT_CHANNEL_KERNEL,
3500 LTT_EVENT_SYSCALL_ENTRY,
3501 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3502 syscall_entry, NULL, &hooks);
3503
3504 lttv_trace_find_hook(ts->parent.t,
3505 LTT_CHANNEL_KERNEL,
3506 LTT_EVENT_SYSCALL_EXIT,
3507 NULL,
3508 syscall_exit, NULL, &hooks);
3509
7a4bdb54 3510#ifdef BABEL_CLEANUP
90e19f82
AM
3511 lttv_trace_find_hook(ts->parent.t,
3512 LTT_CHANNEL_KERNEL,
3513 LTT_EVENT_TRAP_ENTRY,
3514 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3515 trap_entry, NULL, &hooks);
3516
3517 lttv_trace_find_hook(ts->parent.t,
3518 LTT_CHANNEL_KERNEL,
3519 LTT_EVENT_TRAP_EXIT,
3520 NULL,
3521 trap_exit, NULL, &hooks);
7a4bdb54 3522#endif /* BABEL_CLEANUP */
90e19f82
AM
3523
3524 lttv_trace_find_hook(ts->parent.t,
3525 LTT_CHANNEL_KERNEL,
3526 LTT_EVENT_PAGE_FAULT_ENTRY,
3527 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3528 trap_entry, NULL, &hooks);
3529
3530 lttv_trace_find_hook(ts->parent.t,
3531 LTT_CHANNEL_KERNEL,
3532 LTT_EVENT_PAGE_FAULT_EXIT,
3533 NULL,
3534 trap_exit, NULL, &hooks);
3535
7a4bdb54 3536#ifdef BABEL_CLEANUP
90e19f82
AM
3537 lttv_trace_find_hook(ts->parent.t,
3538 LTT_CHANNEL_KERNEL,
3539 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
3540 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3541 trap_entry, NULL, &hooks);
3542
3543 lttv_trace_find_hook(ts->parent.t,
3544 LTT_CHANNEL_KERNEL,
3545 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
3546 NULL,
3547 trap_exit, NULL, &hooks);
7a4bdb54 3548#endif /* BABEL_CLEANUP */
90e19f82
AM
3549
3550 lttv_trace_find_hook(ts->parent.t,
3551 LTT_CHANNEL_KERNEL,
3552 LTT_EVENT_IRQ_ENTRY,
3553 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3554 irq_entry, NULL, &hooks);
3555
3556 lttv_trace_find_hook(ts->parent.t,
3557 LTT_CHANNEL_KERNEL,
3558 LTT_EVENT_IRQ_EXIT,
3559 NULL,
3560 irq_exit, NULL, &hooks);
3561
3562 lttv_trace_find_hook(ts->parent.t,
3563 LTT_CHANNEL_KERNEL,
3564 LTT_EVENT_SOFT_IRQ_RAISE,
3565 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3566 soft_irq_raise, NULL, &hooks);
3567
3568 lttv_trace_find_hook(ts->parent.t,
3569 LTT_CHANNEL_KERNEL,
3570 LTT_EVENT_SOFT_IRQ_ENTRY,
3571 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3572 soft_irq_entry, NULL, &hooks);
3573
3574 lttv_trace_find_hook(ts->parent.t,
3575 LTT_CHANNEL_KERNEL,
3576 LTT_EVENT_SOFT_IRQ_EXIT,
3577 NULL,
3578 soft_irq_exit, NULL, &hooks);
3579
3580 lttv_trace_find_hook(ts->parent.t,
3581 LTT_CHANNEL_KERNEL,
3582 LTT_EVENT_SCHED_SCHEDULE,
3583 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3584 LTT_FIELD_PREV_STATE),
3585 schedchange, NULL, &hooks);
3586
3587 lttv_trace_find_hook(ts->parent.t,
3588 LTT_CHANNEL_KERNEL,
3589 LTT_EVENT_SCHED_TRY_WAKEUP,
3590 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_CPU_ID, LTT_FIELD_STATE),
3591 sched_try_wakeup, NULL, &hooks);
3592
3593 lttv_trace_find_hook(ts->parent.t,
3594 LTT_CHANNEL_KERNEL,
3595 LTT_EVENT_PROCESS_FORK,
3596 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3597 LTT_FIELD_CHILD_TGID),
3598 process_fork, NULL, &hooks);
3599
3600 lttv_trace_find_hook(ts->parent.t,
3601 LTT_CHANNEL_KERNEL,
3602 LTT_EVENT_KTHREAD_CREATE,
3603 FIELD_ARRAY(LTT_FIELD_PID),
3604 process_kernel_thread, NULL, &hooks);
3605
3606 lttv_trace_find_hook(ts->parent.t,
3607 LTT_CHANNEL_KERNEL,
3608 LTT_EVENT_PROCESS_EXIT,
3609 FIELD_ARRAY(LTT_FIELD_PID),
3610 process_exit, NULL, &hooks);
3611
3612 lttv_trace_find_hook(ts->parent.t,
3613 LTT_CHANNEL_KERNEL,
3614 LTT_EVENT_PROCESS_FREE,
3615 FIELD_ARRAY(LTT_FIELD_PID),
3616 process_free, NULL, &hooks);
3617
3618 lttv_trace_find_hook(ts->parent.t,
3619 LTT_CHANNEL_FS,
3620 LTT_EVENT_EXEC,
3621 FIELD_ARRAY(LTT_FIELD_FILENAME),
3622 process_exec, NULL, &hooks);
3623
3624 lttv_trace_find_hook(ts->parent.t,
3625 LTT_CHANNEL_USERSPACE,
3626 LTT_EVENT_THREAD_BRAND,
3627 FIELD_ARRAY(LTT_FIELD_NAME),
3628 thread_brand, NULL, &hooks);
3629
3630 /* statedump-related hooks */
3631 lttv_trace_find_hook(ts->parent.t,
3632 LTT_CHANNEL_TASK_STATE,
3633 LTT_EVENT_PROCESS_STATE,
3634 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3635 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3636 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3637 enum_process_state, NULL, &hooks);
3638
3639 lttv_trace_find_hook(ts->parent.t,
3640 LTT_CHANNEL_GLOBAL_STATE,
3641 LTT_EVENT_STATEDUMP_END,
3642 NULL,
3643 statedump_end, NULL, &hooks);
3644
3645 lttv_trace_find_hook(ts->parent.t,
3646 LTT_CHANNEL_IRQ_STATE,
3647 LTT_EVENT_LIST_INTERRUPT,
3648 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3649 enum_interrupt, NULL, &hooks);
3650
3651 lttv_trace_find_hook(ts->parent.t,
3652 LTT_CHANNEL_BLOCK,
3653 LTT_EVENT_REQUEST_ISSUE,
3654 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3655 bdev_request_issue, NULL, &hooks);
3656
3657 lttv_trace_find_hook(ts->parent.t,
3658 LTT_CHANNEL_BLOCK,
3659 LTT_EVENT_REQUEST_COMPLETE,
3660 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3661 bdev_request_complete, NULL, &hooks);
3662
3663 lttv_trace_find_hook(ts->parent.t,
3664 LTT_CHANNEL_USERSPACE,
3665 LTT_EVENT_FUNCTION_ENTRY,
3666 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3667 function_entry, NULL, &hooks);
3668
3669 lttv_trace_find_hook(ts->parent.t,
3670 LTT_CHANNEL_USERSPACE,
3671 LTT_EVENT_FUNCTION_EXIT,
3672 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3673 function_exit, NULL, &hooks);
3674
3675 lttv_trace_find_hook(ts->parent.t,
3676 LTT_CHANNEL_SYSCALL_STATE,
3677 LTT_EVENT_SYS_CALL_TABLE,
3678 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3679 dump_syscall, NULL, &hooks);
3680
3681 lttv_trace_find_hook(ts->parent.t,
3682 LTT_CHANNEL_KPROBE_STATE,
3683 LTT_EVENT_KPROBE_TABLE,
3684 FIELD_ARRAY(LTT_FIELD_IP, LTT_FIELD_SYMBOL),
3685 dump_kprobe, NULL, &hooks);
3686
3687 lttv_trace_find_hook(ts->parent.t,
3688 LTT_CHANNEL_SOFTIRQ_STATE,
3689 LTT_EVENT_SOFTIRQ_VEC,
3690 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3691 dump_softirq, NULL, &hooks);
3692
3693 lttv_trace_find_hook(ts->parent.t,
3694 LTT_CHANNEL_FS,
3695 LTT_EVENT_OPEN,
3696 FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME),
3697 fs_open, NULL, &hooks);
3698
3699 /* Add these hooks to each event_by_id hooks list */
3700
3701 nb_tracefile = ts->parent.tracefiles->len;
3702
3703 for(j = 0 ; j < nb_tracefile ; j++) {
3704 tfs =
3705 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3706 LttvTracefileContext*, j));
3707
3708 for(k = 0 ; k < hooks->len ; k++) {
3709 th = &g_array_index(hooks, LttvTraceHook, k);
3710 if (th->mdata == tfs->parent.tf->mdata)
3711 lttv_hooks_add(
3712 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3713 th->h,
3714 th,
3715 LTTV_PRIO_STATE);
3716 }
3717 }
3718 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3719 *(val.v_pointer) = hooks;
3720 }
7a4bdb54 3721#endif
dc877563 3722}
3723
58c88a41 3724gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3725{
58c88a41 3726
58b4e4ae
YB
3727 LttvTraceset *traceset = (LttvTraceset*)(call_data);
3728
3729 lttv_state_remove_event_hooks(traceset);
3730
90e19f82 3731 return 0;
58c88a41 3732}
58b4e4ae
YB
3733
3734void lttv_state_remove_event_hooks(LttvTraceset *traceset)
dc877563 3735{
dc877563 3736
90e19f82 3737 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3738
58b4e4ae 3739 //LttvTraceState *ts;
dc877563 3740
58b4e4ae 3741 //GArray *hooks;
dc877563 3742
58b4e4ae 3743 //LttvTraceHook *th;
dc877563 3744
58b4e4ae 3745 //LttvAttributeValue val;
dc877563 3746
58b4e4ae
YB
3747 LttvHooks*event_hook;
3748 //TODO ybrosseau 2012-07-17 validate this. Reversed what's done in the add
3749 event_hook = lttv_traceset_get_hooks(traceset);
dc877563 3750
58b4e4ae
YB
3751 g_assert(event_hook);
3752
3753
3754 lttv_hooks_remove(event_hook,syscall_entry );
3755 lttv_hooks_remove(event_hook,syscall_exit);
3756 lttv_hooks_remove(event_hook,irq_entry );
3757 lttv_hooks_remove(event_hook,irq_exit );
3758 lttv_hooks_remove(event_hook,soft_irq_raise);
3759 lttv_hooks_remove(event_hook,soft_irq_entry);
3760 lttv_hooks_remove(event_hook,soft_irq_exit);
3761 lttv_hooks_remove(event_hook,schedchange);
3762 lttv_hooks_remove(event_hook,sched_try_wakeup);
3763 lttv_hooks_remove(event_hook,process_exit);
3764 lttv_hooks_remove(event_hook,process_free);
3765 lttv_hooks_remove(event_hook,process_exec);
3766 lttv_hooks_remove(event_hook,enum_process_state);
3767 lttv_hooks_remove(event_hook,statedump_end);
3768 lttv_hooks_remove(event_hook,enum_interrupt);
3769#ifdef BABEL_CLEANUP
90e19f82
AM
3770 nb_trace = lttv_traceset_number(traceset);
3771 for(i = 0 ; i < nb_trace ; i++) {
58b4e4ae 3772 ts = lttv_traceset_get(i);
7df20ca4 3773
90e19f82
AM
3774 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3775 hooks = *(val.v_pointer);
dc877563 3776
90e19f82 3777 /* Remove these hooks from each event_by_id hooks list */
dc877563 3778
90e19f82 3779 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3780
90e19f82
AM
3781 for(j = 0 ; j < nb_tracefile ; j++) {
3782 tfs =
3783 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3784 LttvTracefileContext*, j));
dc877563 3785
90e19f82
AM
3786 for(k = 0 ; k < hooks->len ; k++) {
3787 th = &g_array_index(hooks, LttvTraceHook, k);
3788 if (th->mdata == tfs->parent.tf->mdata)
3789 lttv_hooks_remove_data(
3790 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3791 th->h,
3792 th);
3793 }
3794 }
3795 lttv_trace_hook_remove_all(&hooks);
3796 g_array_free(hooks, TRUE);
3797 }
7a4bdb54 3798#endif
58b4e4ae
YB
3799}
3800
3801
eed2ef37 3802static gboolean state_save_event_hook(void *hook_data, void *call_data)
3803{
90e19f82
AM
3804 guint *event_count = (guint*)hook_data;
3805
3806 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3807 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3808 return FALSE;
3809 else
3810 *event_count = 0;
eed2ef37 3811
58b4e4ae 3812 LttvEvent *event = (LttvEvent *)call_data;
eed2ef37 3813
58b4e4ae 3814 LttvTraceset *traceset = lttv_trace_get_traceset(event->state->trace);
eed2ef37 3815
90e19f82 3816 LttvAttribute *saved_states_tree, *saved_state_tree;
eed2ef37 3817
90e19f82 3818 LttvAttributeValue value;
58b4e4ae
YB
3819 LttTime currentTime;
3820 guint i;
3821 currentTime = lttv_event_get_timestamp(event);
3822 int nb_trace = lttv_traceset_number(traceset);
3823 for(i = 0 ; i < nb_trace ; i++) {
eed2ef37 3824
58b4e4ae
YB
3825 LttvTrace *trace = lttv_traceset_get(traceset, i);
3826 LttvTraceState *tstate = trace->state;
3827 saved_states_tree = lttv_attribute_find_subdir(trace->a,
3828 LTTV_STATE_SAVED_STATES);
3829
3830 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3831 value = lttv_attribute_add(saved_states_tree,
3832 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3833 *(value.v_gobject) = (GObject *)saved_state_tree;
eed2ef37 3834
eed2ef37 3835
58b4e4ae
YB
3836 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3837 *(value.v_time) = currentTime;
3838
3839 lttv_state_save(tstate, saved_state_tree);
3840 g_debug("Saving state at time %lu.%lu", currentTime.tv_sec,
3841 currentTime.tv_nsec);
3842
3843 *(tstate->max_time_state_recomputed_in_seek) = currentTime;
3844 }
90e19f82 3845 return FALSE;
eed2ef37 3846}
3847
14aecf75 3848static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3849{
58b4e4ae
YB
3850#warning "Would we move max_time to traceset"
3851 LttvTrace *trace = (LttvTrace *)(call_data);
3852 LttvTraceState *tcs = trace->state;
3853 TimeInterval time_span = lttv_traceset_get_time_span_real(lttv_trace_get_traceset(trace));
14aecf75 3854
58b4e4ae 3855 *(tcs->max_time_state_recomputed_in_seek) = time_span.end_time;
90e19f82
AM
3856
3857 return FALSE;
14aecf75 3858}
58b4e4ae 3859#ifdef BABEL_CLEANUP
ae3d0f50 3860guint lttv_state_current_cpu(LttvTracefileState *tfs)
3861{
90e19f82 3862 return tfs->cpu;
ae3d0f50 3863}
3864
7a4bdb54 3865#endif //BABEL_CLEANUP
ae3d0f50 3866
eed2ef37 3867#if 0
08b1c66e 3868static gboolean block_start(void *hook_data, void *call_data)
308711e5 3869{
90e19f82 3870 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 3871
90e19f82 3872 LttvTracefileState *tfcs;
dbb7bb09 3873
90e19f82 3874 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
308711e5 3875
90e19f82 3876 LttEventPosition *ep;
308711e5 3877
90e19f82 3878 guint i, nb_block, nb_event, nb_tracefile;
308711e5 3879
90e19f82 3880 LttTracefile *tf;
308711e5 3881
90e19f82 3882 LttvAttribute *saved_states_tree, *saved_state_tree;
308711e5 3883
90e19f82 3884 LttvAttributeValue value;
eed2ef37 3885
90e19f82 3886 ep = ltt_event_position_new();
dbb7bb09 3887
90e19f82 3888 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 3889
90e19f82
AM
3890 /* Count the number of events added since the last block end in any
3891 tracefile. */
308711e5 3892
90e19f82
AM
3893 for(i = 0 ; i < nb_tracefile ; i++) {
3894 tfcs =
3895 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3896 LttvTracefileContext, i));
3897 ltt_event_position(tfcs->parent.e, ep);
3898 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3899 tcs->nb_event += nb_event - tfcs->saved_position;
3900 tfcs->saved_position = nb_event;
3901 }
3902 g_free(ep);
3903
3904 if(tcs->nb_event >= tcs->save_interval) {
3905 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3906 LTTV_STATE_SAVED_STATES);
3907 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3908 value = lttv_attribute_add(saved_states_tree,
3909 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3910 *(value.v_gobject) = (GObject *)saved_state_tree;
3911 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3912 *(value.v_time) = self->parent.timestamp;
3913 lttv_state_save(tcs, saved_state_tree);
3914 tcs->nb_event = 0;
3915 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3916 self->parent.timestamp.tv_nsec);
3917 }
3918 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3919 return FALSE;
308711e5 3920}
eed2ef37 3921#endif //0
308711e5 3922
eed2ef37 3923#if 0
08b1c66e 3924static gboolean block_end(void *hook_data, void *call_data)
3925{
90e19f82 3926 LttvTracefileState *self = (LttvTracefileState *)call_data;
08b1c66e 3927
90e19f82 3928 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
08b1c66e 3929
90e19f82 3930 LttTracefile *tf;
08b1c66e 3931
90e19f82 3932 LttEventPosition *ep;
08b1c66e 3933
90e19f82 3934 guint nb_block, nb_event;
08b1c66e 3935
90e19f82
AM
3936 ep = ltt_event_position_new();
3937 ltt_event_position(self->parent.e, ep);
3938 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3939 tcs->nb_event += nb_event - self->saved_position + 1;
3940 self->saved_position = 0;
3941 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3942 g_free(ep);
00e74b69 3943
90e19f82 3944 return FALSE;
08b1c66e 3945}
eed2ef37 3946#endif //0
3947#if 0
308711e5 3948void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3949{
90e19f82 3950 LttvTraceset *traceset = self->parent.ts;
308711e5 3951
90e19f82 3952 guint i, j, nb_trace, nb_tracefile;
308711e5 3953
90e19f82 3954 LttvTraceState *ts;
308711e5 3955
90e19f82 3956 LttvTracefileState *tfs;
308711e5 3957
90e19f82 3958 LttvTraceHook hook_start, hook_end;
308711e5 3959
90e19f82
AM
3960 nb_trace = lttv_traceset_number(traceset);
3961 for(i = 0 ; i < nb_trace ; i++) {
3962 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3963
90e19f82
AM
3964 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3965 NULL, NULL, block_start, &hook_start);
3966 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3967 NULL, NULL, block_end, &hook_end);
308711e5 3968
90e19f82 3969 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3970
90e19f82
AM
3971 for(j = 0 ; j < nb_tracefile ; j++) {
3972 tfs =
3973 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3974 LttvTracefileContext, j));
3975 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3976 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3977 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3978 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3979 }
3980 }
eed2ef37 3981}
3982#endif //0
58b4e4ae
YB
3983
3984void lttv_state_save_add_event_hooks(LttvTraceset *traceset)
eed2ef37 3985{
eed2ef37 3986
90e19f82 3987 guint i, j, nb_trace, nb_tracefile;
eed2ef37 3988
90e19f82 3989 LttvTraceState *ts;
eed2ef37 3990
90e19f82 3991 LttvTracefileState *tfs;
eed2ef37 3992
58b4e4ae
YB
3993
3994 if(!traceset->has_precomputed_states) {
3995 guint *event_count = g_new(guint, 1);
3996
3997 *event_count = 0;
3998 lttv_hooks_add(traceset->event_hooks,
3999 state_save_event_hook,
4000 event_count,
4001 LTTV_PRIO_STATE);
4002
4003#ifdef BABEL_CLEANUP
90e19f82
AM
4004 nb_trace = lttv_traceset_number(traceset);
4005 for(i = 0 ; i < nb_trace ; i++) {
eed2ef37 4006
90e19f82
AM
4007 ts = (LttvTraceState *)self->parent.traces[i];
4008 nb_tracefile = ts->parent.tracefiles->len;
eed2ef37 4009
90e19f82 4010 if(ts->has_precomputed_states) continue;
ce05e187 4011
90e19f82
AM
4012 guint *event_count = g_new(guint, 1);
4013 *event_count = 0;
3054461a 4014
90e19f82
AM
4015 for(j = 0 ; j < nb_tracefile ; j++) {
4016 tfs =
4017 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4018 LttvTracefileContext*, j));
4019 lttv_hooks_add(tfs->parent.event,
4020 state_save_event_hook,
4021 event_count,
4022 LTTV_PRIO_STATE);
4023
4024 }
4025 }
58b4e4ae
YB
4026#endif
4027 lttv_process_traceset_begin(traceset,
4028 NULL, NULL, NULL, NULL, NULL);
4029 }
eed2ef37 4030
308711e5 4031}
4032
b56b5fec 4033gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
4034{
58b4e4ae 4035 LttvTraceset *ts = (LttvTraceset*)(call_data);
b56b5fec 4036
58b4e4ae 4037 lttv_state_save_add_event_hooks(ts);
b56b5fec 4038
90e19f82 4039 return 0;
b56b5fec 4040}
58b4e4ae 4041
308711e5 4042
eed2ef37 4043#if 0
308711e5 4044void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4045{
90e19f82 4046 LttvTraceset *traceset = self->parent.ts;
308711e5 4047
90e19f82 4048 guint i, j, nb_trace, nb_tracefile;
308711e5 4049
90e19f82 4050 LttvTraceState *ts;
308711e5 4051
90e19f82 4052 LttvTracefileState *tfs;
308711e5 4053
90e19f82 4054 LttvTraceHook hook_start, hook_end;
308711e5 4055
90e19f82
AM
4056 nb_trace = lttv_traceset_number(traceset);
4057 for(i = 0 ; i < nb_trace ; i++) {
4058 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 4059
90e19f82
AM
4060 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
4061 NULL, NULL, block_start, &hook_start);
08b1c66e 4062
90e19f82
AM
4063 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
4064 NULL, NULL, block_end, &hook_end);
308711e5 4065
90e19f82 4066 nb_tracefile = ts->parent.tracefiles->len;
308711e5 4067
90e19f82
AM
4068 for(j = 0 ; j < nb_tracefile ; j++) {
4069 tfs =
4070 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
4071 LttvTracefileContext, j));
4072 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4073 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
4074 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4075 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
4076 }
4077 }
308711e5 4078}
eed2ef37 4079#endif //0
58b4e4ae
YB
4080
4081void lttv_state_save_remove_event_hooks(LttvTraceset *traceset)
eed2ef37 4082{
eed2ef37 4083
90e19f82 4084 guint i, j, nb_trace, nb_tracefile;
eed2ef37 4085
90e19f82 4086 LttvTraceState *ts;
eed2ef37 4087
90e19f82 4088 LttvTracefileState *tfs;
eed2ef37 4089
90e19f82 4090 LttvHooks *after_trace = lttv_hooks_new();
58b4e4ae 4091 guint *event_count = NULL;
14aecf75 4092
90e19f82
AM
4093 lttv_hooks_add(after_trace,
4094 state_save_after_trace_hook,
4095 NULL,
4096 LTTV_PRIO_STATE);
4097
4098
58b4e4ae
YB
4099 lttv_process_traceset_end(traceset,
4100 NULL, after_trace, NULL, NULL);
eed2ef37 4101
90e19f82
AM
4102 lttv_hooks_destroy(after_trace);
4103
58b4e4ae
YB
4104 //nb_trace = lttv_traceset_number(traceset);
4105
4106 event_count = lttv_hooks_remove(traceset->event_hooks,
4107 state_save_event_hook);
4108
4109 if(event_count) g_free(event_count);
4110
4111#ifdef BABEL_CLEANUP
90e19f82 4112 for(i = 0 ; i < nb_trace ; i++) {
eed2ef37 4113
90e19f82
AM
4114 ts = (LttvTraceState *)self->parent.traces[i];
4115 nb_tracefile = ts->parent.tracefiles->len;
eed2ef37 4116
90e19f82 4117 if(ts->has_precomputed_states) continue;
ce05e187 4118
90e19f82 4119 guint *event_count = NULL;
eed2ef37 4120
90e19f82
AM
4121 for(j = 0 ; j < nb_tracefile ; j++) {
4122 tfs =
4123 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4124 LttvTracefileContext*, j));
4125 event_count = lttv_hooks_remove(tfs->parent.event,
4126 state_save_event_hook);
4127 }
4128 if(event_count) g_free(event_count);
4129 }
58b4e4ae 4130#endif
eed2ef37 4131}
308711e5 4132
b56b5fec 4133gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
4134{
58b4e4ae 4135 LttvTraceset *ts = (LttvTraceset*)(call_data);
b56b5fec 4136
58b4e4ae 4137 lttv_state_save_remove_event_hooks(ts);
b56b5fec 4138
90e19f82 4139 return 0;
b56b5fec 4140}
308711e5 4141
58b4e4ae
YB
4142
4143void lttv_state_traceset_seek_time(LttvTraceset *traceset, LttTime t)
308711e5 4144{
58b4e4ae
YB
4145 lttv_state_traceset_seek_time_closest(traceset,
4146 t);
4147 lttv_process_traceset_middle(traceset, t, G_MAXUINT,
4148 NULL);
4149}
90e19f82 4150
58b4e4ae
YB
4151void lttv_state_traceset_seek_position(LttvTraceset *traceset, LttvTracesetPosition *position)
4152{
4153 LttTime t = lttv_traceset_position_get_time(position);
4154
4155 lttv_state_traceset_seek_time_closest(traceset,
4156 t);
4157 lttv_process_traceset_middle(traceset,
4158 ltt_time_infinite,
4159 G_MAXUINT,
4160 position);
4161}
4162
4163void lttv_state_traceset_seek_time_closest(LttvTraceset *traceset, LttTime t)
4164{
90e19f82 4165 guint i, nb_trace;
308711e5 4166
90e19f82 4167 int min_pos, mid_pos, max_pos;
308711e5 4168
90e19f82 4169 guint call_rest = 0;
58b4e4ae
YB
4170 guint resto_start = 0;
4171 guint resto_at = 0;
728d0c3e 4172
90e19f82 4173 LttvAttributeValue value;
308711e5 4174
90e19f82 4175 LttvAttributeType type;
308711e5 4176
90e19f82 4177 LttvAttributeName name;
308711e5 4178
90e19f82 4179 gboolean is_named;
308711e5 4180
90e19f82 4181 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree = NULL;
58b4e4ae
YB
4182
4183 LttTime closest_tree_time, restored_time;
aedb80c1 4184 guint first_restored_time = 1;
c0cb4d12 4185
90e19f82
AM
4186 //g_tree_destroy(self->parent.pqueue);
4187 //self->parent.pqueue = g_tree_new(compare_tracefile);
308711e5 4188
aedb80c1 4189 g_debug("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
308711e5 4190
90e19f82
AM
4191 nb_trace = lttv_traceset_number(traceset);
4192 for(i = 0 ; i < nb_trace ; i++) {
2a2fa4f0 4193
58b4e4ae
YB
4194 LttvTrace *trace = lttv_traceset_get(traceset, i);
4195 LttvTraceState *tstate = trace->state;
4196
4197 if(ltt_time_compare(t, *(tstate->max_time_state_recomputed_in_seek)) < 0) {
4198 saved_states_tree = lttv_attribute_find_subdir(trace->a,
90e19f82
AM
4199 LTTV_STATE_SAVED_STATES);
4200 min_pos = -1;
dd025f91 4201
90e19f82
AM
4202 if(saved_states_tree) {
4203 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
4204 mid_pos = max_pos / 2;
4205 while(min_pos < max_pos) {
4206 type = lttv_attribute_get(saved_states_tree, mid_pos,
4207 &name, &value, &is_named);
4208 g_assert(type == LTTV_GOBJECT);
4209 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
4210 type = lttv_attribute_get_by_name(saved_state_tree,
4211 LTTV_STATE_TIME, &value);
4212 g_assert(type == LTTV_TIME);
4213 if(ltt_time_compare(*(value.v_time), t) < 0) {
4214 min_pos = mid_pos;
4215 closest_tree = saved_state_tree;
58b4e4ae 4216 closest_tree_time = *(value.v_time);
90e19f82
AM
4217 }
4218 else max_pos = mid_pos - 1;
dd025f91 4219
90e19f82
AM
4220 mid_pos = (min_pos + max_pos + 1) / 2;
4221 }
4222 }
dd025f91 4223
90e19f82
AM
4224 /* restore the closest earlier saved state */
4225 if(min_pos != -1) {
aedb80c1
YB
4226 if(first_restored_time || (ltt_time_compare(restored_time, closest_tree_time) == 0)) {
4227 first_restored_time = 0;
58b4e4ae
YB
4228 lttv_state_restore(tstate, closest_tree);
4229
4230 restored_time = closest_tree_time;
4231 call_rest = 1;
4232 } else {
4233 g_debug("State: restored time mismatch between traces");
4234 resto_start = 1;
4235 break;
4236 }
4237
90e19f82
AM
4238 }
4239
4240 /* There is no saved state, yet we want to have it. Restart at T0 */
4241 else {
58b4e4ae
YB
4242 resto_start = 1;
4243 break;
90e19f82
AM
4244 }
4245 }
4246 /* We want to seek quickly without restoring/updating the state */
4247 else {
58b4e4ae
YB
4248 resto_at = 1;
4249 break;
90e19f82
AM
4250 }
4251 }
58b4e4ae
YB
4252
4253 if(resto_start || resto_at) {
4254 // Restore init state and seek so
4255 for(i = 0 ; i < nb_trace ; i++) {
4256
4257 LttvTrace *trace = lttv_traceset_get(traceset, i);
4258 LttvTraceState *tstate = trace->state;
4259
4260 restore_init_state(tstate);
4261 }
4262
4263 // If t > max saved state
4264 if(resto_at) {
4265 lttv_process_traceset_seek_time(traceset, t);
4266 } else if (resto_start) {
4267 // If no saved state
4268 lttv_process_traceset_seek_time(traceset, ltt_time_zero);
4269 } else {
4270 g_assert(FALSE);
4271 }
4272 g_info("NOT Calling restore");
4273
4274 } else {
4275 // Seek at checkpoint
4276 lttv_process_traceset_seek_time(traceset, restored_time);
4277
4278
4279 }
4280
4281
308711e5 4282}
58b4e4ae 4283
7a4bdb54 4284#ifdef BABEL_CLEANUP
90e19f82 4285static void traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
308711e5 4286{
4287}
4288
4289
90e19f82 4290static void traceset_state_finalize (LttvTracesetState *self)
308711e5 4291{
90e19f82
AM
4292 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
4293 finalize(G_OBJECT(self));
308711e5 4294}
4295
4296
90e19f82 4297static void traceset_state_class_init (LttvTracesetContextClass *klass)
308711e5 4298{
90e19f82 4299 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
308711e5 4300
90e19f82
AM
4301 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
4302 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
4303 klass->fini = (void (*)(LttvTracesetContext *self))fini;
4304 klass->new_traceset_context = new_traceset_context;
4305 klass->new_trace_context = new_trace_context;
4306 klass->new_tracefile_context = new_tracefile_context;
308711e5 4307}
4308
4309
90e19f82 4310GType lttv_traceset_state_get_type(void)
308711e5 4311{
90e19f82
AM
4312 static GType type = 0;
4313 if (type == 0) {
4314 static const GTypeInfo info = {
4315 sizeof (LttvTracesetStateClass),
4316 NULL, /* base_init */
4317 NULL, /* base_finalize */
4318 (GClassInitFunc) traceset_state_class_init, /* class_init */
4319 NULL, /* class_finalize */
4320 NULL, /* class_data */
4321 sizeof (LttvTracesetState),
4322 0, /* n_preallocs */
4323 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
4324 NULL /* value handling */
4325 };
308711e5 4326
90e19f82
AM
4327 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
4328 &info, 0);
4329 }
4330 return type;
308711e5 4331}
4332
7a4bdb54
YB
4333#endif
4334#if BABEL_CLEANUP
90e19f82 4335static void trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
308711e5 4336{
4337}
4338
4339
90e19f82 4340static void trace_state_finalize (LttvTraceState *self)
308711e5 4341{
90e19f82
AM
4342 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
4343 finalize(G_OBJECT(self));
308711e5 4344}
4345
4346
90e19f82 4347static void trace_state_class_init (LttvTraceStateClass *klass)
308711e5 4348{
90e19f82 4349 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
308711e5 4350
90e19f82
AM
4351 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
4352 klass->state_save = state_save;
4353 klass->state_restore = state_restore;
4354 klass->state_saved_free = state_saved_free;
308711e5 4355}
4356
4357
90e19f82 4358GType lttv_trace_state_get_type(void)
308711e5 4359{
90e19f82
AM
4360 static GType type = 0;
4361 if (type == 0) {
4362 static const GTypeInfo info = {
4363 sizeof (LttvTraceStateClass),
4364 NULL, /* base_init */
4365 NULL, /* base_finalize */
4366 (GClassInitFunc) trace_state_class_init, /* class_init */
4367 NULL, /* class_finalize */
4368 NULL, /* class_data */
4369 sizeof (LttvTraceState),
4370 0, /* n_preallocs */
4371 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
4372 NULL /* value handling */
4373 };
308711e5 4374
90e19f82
AM
4375 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
4376 "LttvTraceStateType", &info, 0);
4377 }
4378 return type;
308711e5 4379}
4380
4381
90e19f82
AM
4382static void tracefile_state_instance_init (GTypeInstance *instance,
4383 gpointer g_class)
308711e5 4384{
4385}
4386
4387
90e19f82 4388static void tracefile_state_finalize (LttvTracefileState *self)
308711e5 4389{
90e19f82
AM
4390 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
4391 finalize(G_OBJECT(self));
308711e5 4392}
4393
4394
90e19f82 4395static void tracefile_state_class_init (LttvTracefileStateClass *klass)
308711e5 4396{
90e19f82 4397 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
308711e5 4398
90e19f82 4399 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
308711e5 4400}
4401
4402
90e19f82 4403GType lttv_tracefile_state_get_type(void)
308711e5 4404{
90e19f82
AM
4405 static GType type = 0;
4406 if (type == 0) {
4407 static const GTypeInfo info = {
4408 sizeof (LttvTracefileStateClass),
4409 NULL, /* base_init */
4410 NULL, /* base_finalize */
4411 (GClassInitFunc) tracefile_state_class_init, /* class_init */
4412 NULL, /* class_finalize */
4413 NULL, /* class_data */
4414 sizeof (LttvTracefileState),
4415 0, /* n_preallocs */
4416 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
4417 NULL /* value handling */
4418 };
308711e5 4419
90e19f82
AM
4420 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
4421 "LttvTracefileStateType", &info, 0);
4422 }
4423 return type;
308711e5 4424}
4425
7a4bdb54
YB
4426#endif
4427static void module_init(void)
ffd54a90 4428{
90e19f82
AM
4429 LTTV_STATE_UNNAMED = g_quark_from_string("");
4430 LTTV_STATE_UNBRANDED = g_quark_from_string("");
4431 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
4432 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
f044974e 4433 LTTV_STATE_MAYBE_USER_MODE = g_quark_from_string("MAYBE_USER_MODE");
90e19f82 4434 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
f044974e 4435 LTTV_STATE_MAYBE_SYSCALL = g_quark_from_string("MAYBE_SYSCALL");
90e19f82 4436 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
f044974e 4437 LTTV_STATE_MAYBE_TRAP = g_quark_from_string("MAYBE_TRAP");
90e19f82
AM
4438 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
4439 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
4440 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
4441 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
4442 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
4443 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
4444 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
4445 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
4446 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
4447 LTTV_STATE_RUN = g_quark_from_string("RUN");
4448 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
4449 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
4450 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
4451 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
4452 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
4453 LTTV_STATE_PROCESS = g_quark_from_string("process");
4454 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
7a4bdb54 4455 LTTV_STATE_POSITION = g_quark_from_string("position");
90e19f82
AM
4456 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
4457 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
4458 LTTV_STATE_TIME = g_quark_from_string("time");
4459 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
4460 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
4461 LTTV_STATE_TRACE_STATE_USE_COUNT =
4462 g_quark_from_string("trace_state_use_count");
4463 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
4464 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
4465 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
4466 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
4467 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
4468 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
4469
4470 LTT_CHANNEL_FD_STATE = g_quark_from_string("fd_state");
4471 LTT_CHANNEL_GLOBAL_STATE = g_quark_from_string("global_state");
4472 LTT_CHANNEL_IRQ_STATE = g_quark_from_string("irq_state");
4473 LTT_CHANNEL_MODULE_STATE = g_quark_from_string("module_state");
4474 LTT_CHANNEL_NETIF_STATE = g_quark_from_string("netif_state");
4475 LTT_CHANNEL_SOFTIRQ_STATE = g_quark_from_string("softirq_state");
4476 LTT_CHANNEL_SWAP_STATE = g_quark_from_string("swap_state");
4477 LTT_CHANNEL_SYSCALL_STATE = g_quark_from_string("syscall_state");
4478 LTT_CHANNEL_TASK_STATE = g_quark_from_string("task_state");
4479 LTT_CHANNEL_VM_STATE = g_quark_from_string("vm_state");
4480 LTT_CHANNEL_KPROBE_STATE = g_quark_from_string("kprobe_state");
4481 LTT_CHANNEL_FS = g_quark_from_string("fs");
4482 LTT_CHANNEL_KERNEL = g_quark_from_string("kernel");
4483 LTT_CHANNEL_MM = g_quark_from_string("mm");
4484 LTT_CHANNEL_USERSPACE = g_quark_from_string("userspace");
4485 LTT_CHANNEL_BLOCK = g_quark_from_string("block");
4486
4487 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
4488 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
7a4bdb54
YB
4489 //LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
4490 //LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
90e19f82
AM
4491 LTT_EVENT_PAGE_FAULT_ENTRY = g_quark_from_string("page_fault_entry");
4492 LTT_EVENT_PAGE_FAULT_EXIT = g_quark_from_string("page_fault_exit");
4493 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY = g_quark_from_string("page_fault_nosem_entry");
4494 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT = g_quark_from_string("page_fault_nosem_exit");
4495 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
4496 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
4497 LTT_EVENT_SOFT_IRQ_RAISE = g_quark_from_string("softirq_raise");
4498 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
4499 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
4500 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
4501 LTT_EVENT_SCHED_TRY_WAKEUP = g_quark_from_string("sched_try_wakeup");
4502 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
4503 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
4504 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
4505 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
4506 LTT_EVENT_EXEC = g_quark_from_string("exec");
4507 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
4508 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
4509 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4510 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
4511 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
4512 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4513 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
4514 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");
4515 LTT_EVENT_SYS_CALL_TABLE = g_quark_from_string("sys_call_table");
4516 LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec");
4517 LTT_EVENT_KPROBE_TABLE = g_quark_from_string("kprobe_table");
4518 LTT_EVENT_KPROBE = g_quark_from_string("kprobe");
4519 LTT_EVENT_OPEN = g_quark_from_string("open");
4520 LTT_EVENT_READ = g_quark_from_string("read");
4521 LTT_EVENT_POLL_EVENT = g_quark_from_string("poll_event");
4522
4523 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4524 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4525 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
4526 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
4527 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4528 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4529 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
4530 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4531 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4532 LTT_FIELD_PID = g_quark_from_string("pid");
4533 LTT_FIELD_TGID = g_quark_from_string("tgid");
4534 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
4535 LTT_FIELD_FILENAME = g_quark_from_string("filename");
4536 LTT_FIELD_NAME = g_quark_from_string("name");
4537 LTT_FIELD_TYPE = g_quark_from_string("type");
4538 LTT_FIELD_MODE = g_quark_from_string("mode");
4539 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4540 LTT_FIELD_STATUS = g_quark_from_string("status");
4541 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4542 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
4543 LTT_FIELD_MAJOR = g_quark_from_string("major");
4544 LTT_FIELD_MINOR = g_quark_from_string("minor");
4545 LTT_FIELD_OPERATION = g_quark_from_string("direction");
4546 LTT_FIELD_ACTION = g_quark_from_string("action");
4547 LTT_FIELD_ID = g_quark_from_string("id");
4548 LTT_FIELD_ADDRESS = g_quark_from_string("address");
4549 LTT_FIELD_SYMBOL = g_quark_from_string("symbol");
4550 LTT_FIELD_IP = g_quark_from_string("ip");
4551 LTT_FIELD_FD = g_quark_from_string("fd");
4552 LTT_FIELD_STATE = g_quark_from_string("state");
4553 LTT_FIELD_CPU_ID = g_quark_from_string("cpu_id");
4554
4555 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4556 LTTV_CPU_IDLE = g_quark_from_string("idle");
4557 LTTV_CPU_BUSY = g_quark_from_string("busy");
4558 LTTV_CPU_IRQ = g_quark_from_string("irq");
4559 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
4560 LTTV_CPU_TRAP = g_quark_from_string("trap");
4561
4562 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4563 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4564 LTTV_IRQ_BUSY = g_quark_from_string("busy");
4565
4566 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4567 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4568 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4569 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
ffd54a90 4570}
dc877563 4571
08b1c66e 4572static void module_destroy()
ffd54a90 4573{
4574}
dc877563 4575
4576
08b1c66e 4577LTTV_MODULE("state", "State computation", \
90e19f82
AM
4578 "Update the system state, possibly saving it at intervals", \
4579 module_init, module_destroy)
08b1c66e 4580
dc877563 4581
4582
This page took 0.339848 seconds and 4 git commands to generate.