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