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