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