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