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