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