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