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