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