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