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