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