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