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