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