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