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