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