Move "active" code out of debug statements
[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 int retval;
1711
1712 tracefiles_tree = lttv_attribute_find_subdir(container,
1713 LTTV_STATE_TRACEFILES);
1714
1715 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1716 &value);
1717 g_assert(type == LTTV_POINTER);
1718 lttv_state_free_process_table(self->processes);
1719 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1720
1721 /* Add the currently running processes array */
1722 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1723 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1724 &value);
1725 g_assert(type == LTTV_POINTER);
1726 running_process = *(value.v_pointer);
1727 for(i=0;i<nb_cpus;i++) {
1728 pid = running_process[i];
1729 self->running_process[i] = lttv_state_find_process(self, i, pid);
1730 g_assert(self->running_process[i] != NULL);
1731 }
1732
1733 nb_tracefile = self->parent.tracefiles->len;
1734
1735 //g_tree_destroy(tsc->pqueue);
1736 //tsc->pqueue = g_tree_new(compare_tracefile);
1737
1738 /* restore cpu resource states */
1739 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1740 g_assert(type == LTTV_POINTER);
1741 lttv_state_free_cpu_states(self->cpu_states, nb_cpus);
1742 self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus);
1743
1744 /* restore irq resource states */
1745 nb_irqs = self->name_tables->nb_irqs;
1746 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1747 g_assert(type == LTTV_POINTER);
1748 lttv_state_free_irq_states(self->irq_states, nb_irqs);
1749 self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs);
1750
1751 /* restore soft irq resource states */
1752 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1753 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1754 g_assert(type == LTTV_POINTER);
1755 lttv_state_free_soft_irq_states(self->soft_irq_states, nb_soft_irqs);
1756 self->soft_irq_states = lttv_state_copy_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1757
1758 /* restore trap resource states */
1759 nb_traps = self->name_tables->nb_traps;
1760 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_TRAPS, &value);
1761 g_assert(type == LTTV_POINTER);
1762 lttv_state_free_trap_states(self->trap_states, nb_traps);
1763 self->trap_states = lttv_state_copy_trap_states(*(value.v_pointer), nb_traps);
1764
1765 /* restore the blkdev states */
1766 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1767 g_assert(type == LTTV_POINTER);
1768 lttv_state_free_blkdev_hashtable(self->bdev_states);
1769 self->bdev_states = lttv_state_copy_blkdev_hashtable(*(value.v_pointer));
1770
1771 for(i = 0 ; i < nb_tracefile ; i++) {
1772 tfcs =
1773 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1774 LttvTracefileContext*, i));
1775 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1776 g_assert(type == LTTV_GOBJECT);
1777 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1778 #if 0
1779 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1780 &value);
1781 g_assert(type == LTTV_UINT);
1782 pid = *(value.v_uint);
1783 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
1784 #endif //0
1785 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1786 &value);
1787 g_assert(type == LTTV_POINTER);
1788 //g_assert(*(value.v_pointer) != NULL);
1789 ep = *(value.v_pointer);
1790 g_assert(tfcs->parent.t_context != NULL);
1791
1792 tfcs->cpu_state = &self->cpu_states[tfcs->cpu];
1793
1794 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
1795 g_tree_remove(tsc->pqueue, tfc);
1796
1797 if(ep != NULL) {
1798 retval= ltt_tracefile_seek_position(tfc->tf, ep);
1799 g_assert_cmpint(retval, ==, 0);
1800 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
1801 g_assert_cmpint(ltt_time_compare(tfc->timestamp, ltt_time_infinite), !=, 0);
1802 g_tree_insert(tsc->pqueue, tfc, tfc);
1803 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1804 } else {
1805 tfc->timestamp = ltt_time_infinite;
1806 }
1807 }
1808 }
1809
1810
1811 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
1812 {
1813 guint i, nb_tracefile, nb_cpus, nb_irqs, nb_soft_irqs;
1814
1815 LttvTracefileState *tfcs;
1816
1817 LttvAttribute *tracefiles_tree, *tracefile_tree;
1818
1819 guint *running_process;
1820
1821 LttvAttributeType type;
1822
1823 LttvAttributeValue value;
1824
1825 LttvAttributeName name;
1826
1827 gboolean is_named;
1828
1829 tracefiles_tree = lttv_attribute_find_subdir(container,
1830 LTTV_STATE_TRACEFILES);
1831 g_object_ref(G_OBJECT(tracefiles_tree));
1832 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
1833
1834 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1835 &value);
1836 g_assert(type == LTTV_POINTER);
1837 lttv_state_free_process_table(*(value.v_pointer));
1838 *(value.v_pointer) = NULL;
1839 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1840
1841 /* Free running processes array */
1842 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1843 &value);
1844 g_assert(type == LTTV_POINTER);
1845 running_process = *(value.v_pointer);
1846 g_free(running_process);
1847
1848 /* free cpu resource states */
1849 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS_COUNT, &value);
1850 g_assert(type == LTTV_UINT);
1851 nb_cpus = *value.v_uint;
1852 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1853 g_assert(type == LTTV_POINTER);
1854 lttv_state_free_cpu_states(*(value.v_pointer), nb_cpus);
1855
1856 /* free irq resource states */
1857 nb_irqs = self->name_tables->nb_irqs;
1858 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1859 g_assert(type == LTTV_POINTER);
1860 lttv_state_free_irq_states(*(value.v_pointer), nb_irqs);
1861
1862 /* free softirq resource states */
1863 nb_soft_irqs = self->name_tables->nb_soft_irqs;
1864 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_SOFT_IRQS, &value);
1865 g_assert(type == LTTV_POINTER);
1866 lttv_state_free_soft_irq_states(*(value.v_pointer), nb_soft_irqs);
1867
1868 /* free the blkdev states */
1869 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_BLKDEVS, &value);
1870 g_assert(type == LTTV_POINTER);
1871 lttv_state_free_blkdev_hashtable(*(value.v_pointer));
1872
1873 nb_tracefile = self->parent.tracefiles->len;
1874
1875 for(i = 0 ; i < nb_tracefile ; i++) {
1876 tfcs =
1877 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1878 LttvTracefileContext*, i));
1879 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1880 g_assert(type == LTTV_GOBJECT);
1881 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1882
1883 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1884 &value);
1885 g_assert(type == LTTV_POINTER);
1886 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
1887 }
1888 g_object_unref(G_OBJECT(tracefiles_tree));
1889 }
1890
1891
1892 static void free_saved_state(LttvTraceState *self)
1893 {
1894 guint i, nb;
1895
1896 LttvAttributeType type;
1897
1898 LttvAttributeValue value;
1899
1900 LttvAttributeName name;
1901
1902 gboolean is_named;
1903
1904 LttvAttribute *saved_states;
1905
1906 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1907 LTTV_STATE_SAVED_STATES);
1908
1909 nb = lttv_attribute_get_number(saved_states);
1910 for(i = 0 ; i < nb ; i++) {
1911 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
1912 g_assert(type == LTTV_GOBJECT);
1913 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1914 }
1915
1916 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
1917 }
1918
1919
1920 static void
1921 create_max_time(LttvTraceState *tcs)
1922 {
1923 LttvAttributeValue v;
1924
1925 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1926 LTTV_POINTER, &v);
1927 g_assert(*(v.v_pointer) == NULL);
1928 *(v.v_pointer) = g_new(LttTime,1);
1929 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
1930 }
1931
1932
1933 static void
1934 get_max_time(LttvTraceState *tcs)
1935 {
1936 LttvAttributeValue v;
1937
1938 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1939 LTTV_POINTER, &v);
1940 g_assert(*(v.v_pointer) != NULL);
1941 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1942 }
1943
1944
1945 static void
1946 free_max_time(LttvTraceState *tcs)
1947 {
1948 LttvAttributeValue v;
1949
1950 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1951 LTTV_POINTER, &v);
1952 g_free(*(v.v_pointer));
1953 *(v.v_pointer) = NULL;
1954 }
1955
1956 static void
1957 create_name_tables(LttvTraceState *tcs)
1958 {
1959 int i;
1960
1961 GString *fe_name = g_string_new("");
1962
1963 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1964
1965 LttvAttributeValue v;
1966
1967 GArray *hooks;
1968
1969 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1970 LTTV_POINTER, &v);
1971 g_assert(*(v.v_pointer) == NULL);
1972 *(v.v_pointer) = name_tables;
1973
1974 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1);
1975
1976 if(!lttv_trace_find_hook(tcs->parent.t,
1977 LTT_CHANNEL_KERNEL,
1978 LTT_EVENT_SYSCALL_ENTRY,
1979 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
1980 NULL, NULL, &hooks)) {
1981
1982 // th = lttv_trace_hook_get_first(&th);
1983 //
1984 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1985 // nb = ltt_type_element_number(t);
1986 //
1987 // name_tables->syscall_names = g_new(GQuark, nb);
1988 // name_tables->nb_syscalls = nb;
1989 //
1990 // for(i = 0 ; i < nb ; i++) {
1991 // name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1992 // if(!name_tables->syscall_names[i]) {
1993 // GString *string = g_string_new("");
1994 // g_string_printf(string, "syscall %u", i);
1995 // name_tables->syscall_names[i] = g_quark_from_string(string->str);
1996 // g_string_free(string, TRUE);
1997 // }
1998 // }
1999
2000 name_tables->nb_syscalls = 256;
2001 name_tables->syscall_names = g_new(GQuark, 256);
2002 for(i = 0 ; i < 256 ; i++) {
2003 g_string_printf(fe_name, "syscall %d", i);
2004 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
2005 }
2006 } else {
2007 name_tables->syscall_names = NULL;
2008 name_tables->nb_syscalls = 0;
2009 }
2010 lttv_trace_hook_remove_all(&hooks);
2011
2012 if(!lttv_trace_find_hook(tcs->parent.t,
2013 LTT_CHANNEL_KERNEL,
2014 LTT_EVENT_TRAP_ENTRY,
2015 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
2016 NULL, NULL, &hooks) ||
2017 !lttv_trace_find_hook(tcs->parent.t,
2018 LTT_CHANNEL_KERNEL,
2019 LTT_EVENT_PAGE_FAULT_ENTRY,
2020 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
2021 NULL, NULL, &hooks)) {
2022
2023 // th = lttv_trace_hook_get_first(&th);
2024 //
2025 // t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
2026 // //nb = ltt_type_element_number(t);
2027 //
2028 // name_tables->trap_names = g_new(GQuark, nb);
2029 // for(i = 0 ; i < nb ; i++) {
2030 // name_tables->trap_names[i] = g_quark_from_string(
2031 // ltt_enum_string_get(t, i));
2032 // }
2033
2034 name_tables->nb_traps = 256;
2035 name_tables->trap_names = g_new(GQuark, 256);
2036 for(i = 0 ; i < 256 ; i++) {
2037 g_string_printf(fe_name, "trap %d", i);
2038 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
2039 }
2040 } else {
2041 name_tables->trap_names = NULL;
2042 name_tables->nb_traps = 0;
2043 }
2044 lttv_trace_hook_remove_all(&hooks);
2045
2046 if(!lttv_trace_find_hook(tcs->parent.t,
2047 LTT_CHANNEL_KERNEL,
2048 LTT_EVENT_IRQ_ENTRY,
2049 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
2050 NULL, NULL, &hooks)) {
2051
2052 /*
2053 name_tables->irq_names = g_new(GQuark, nb);
2054 for(i = 0 ; i < nb ; i++) {
2055 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2056 }
2057 */
2058
2059 name_tables->nb_irqs = 256;
2060 name_tables->irq_names = g_new(GQuark, 256);
2061 for(i = 0 ; i < 256 ; i++) {
2062 g_string_printf(fe_name, "irq %d", i);
2063 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
2064 }
2065 } else {
2066 name_tables->nb_irqs = 0;
2067 name_tables->irq_names = NULL;
2068 }
2069 lttv_trace_hook_remove_all(&hooks);
2070 /*
2071 name_tables->soft_irq_names = g_new(GQuark, nb);
2072 for(i = 0 ; i < nb ; i++) {
2073 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
2074 }
2075 */
2076
2077 /* the kernel is limited to 32 statically defined softirqs */
2078 name_tables->nb_soft_irqs = 32;
2079 name_tables->soft_irq_names = g_new(GQuark, name_tables->nb_soft_irqs);
2080 for(i = 0 ; i < name_tables->nb_soft_irqs ; i++) {
2081 g_string_printf(fe_name, "softirq %d", i);
2082 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
2083 }
2084 g_array_free(hooks, TRUE);
2085
2086 g_string_free(fe_name, TRUE);
2087
2088 #if (__SIZEOF_LONG__ == 4)
2089 name_tables->kprobe_hash = g_hash_table_new_full(guint64_hash, guint64_equal,
2090 g_free, NULL);
2091 #else
2092 name_tables->kprobe_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
2093 #endif
2094 }
2095
2096
2097 static void
2098 get_name_tables(LttvTraceState *tcs)
2099 {
2100 LttvAttributeValue v;
2101
2102 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
2103 LTTV_POINTER, &v);
2104 g_assert(*(v.v_pointer) != NULL);
2105 tcs->name_tables = (LttvNameTables *)*(v.v_pointer);
2106 }
2107
2108
2109 static void
2110 free_name_tables(LttvTraceState *tcs)
2111 {
2112 LttvNameTables *name_tables;
2113
2114 LttvAttributeValue v;
2115
2116 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
2117 LTTV_POINTER, &v);
2118 name_tables = (LttvNameTables *)*(v.v_pointer);
2119 *(v.v_pointer) = NULL;
2120
2121 // g_free(name_tables->eventtype_names);
2122 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
2123 if(name_tables->trap_names) g_free(name_tables->trap_names);
2124 if(name_tables->irq_names) g_free(name_tables->irq_names);
2125 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
2126 g_hash_table_destroy(name_tables->kprobe_hash);
2127 g_free(name_tables);
2128 }
2129
2130 #ifdef HASH_TABLE_DEBUG
2131
2132 static void test_process(gpointer key, gpointer value, gpointer user_data)
2133 {
2134 LttvProcessState *process = (LttvProcessState *)value;
2135
2136 /* Test for process corruption */
2137 guint stack_len = process->execution_stack->len;
2138 }
2139
2140 static void hash_table_check(GHashTable *table)
2141 {
2142 g_hash_table_foreach(table, test_process, NULL);
2143 }
2144
2145
2146 #endif
2147
2148 /* clears the stack and sets the state passed as argument */
2149 static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
2150 {
2151 g_array_set_size(cpust->mode_stack, 1);
2152 ((GQuark *)cpust->mode_stack->data)[0] = state;
2153 }
2154
2155 static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
2156 {
2157 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
2158 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
2159 }
2160
2161 static void cpu_pop_mode(LttvCPUState *cpust)
2162 {
2163 if(cpust->mode_stack->len <= 1)
2164 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
2165 else
2166 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
2167 }
2168
2169 /* clears the stack and sets the state passed as argument */
2170 static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
2171 {
2172 g_array_set_size(bdevst->mode_stack, 1);
2173 ((GQuark *)bdevst->mode_stack->data)[0] = state;
2174 }
2175
2176 static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
2177 {
2178 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
2179 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
2180 }
2181
2182 static void bdev_pop_mode(LttvBdevState *bdevst)
2183 {
2184 if(bdevst->mode_stack->len <= 1)
2185 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
2186 else
2187 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
2188 }
2189
2190 static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
2191 {
2192 g_array_set_size(irqst->mode_stack, 1);
2193 ((GQuark *)irqst->mode_stack->data)[0] = state;
2194 }
2195
2196 static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
2197 {
2198 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
2199 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
2200 }
2201
2202 static void irq_pop_mode(LttvIRQState *irqst)
2203 {
2204 if(irqst->mode_stack->len <= 1)
2205 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
2206 else
2207 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
2208 }
2209
2210 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
2211 guint state_id)
2212 {
2213 LttvExecutionState *es;
2214
2215 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2216 guint cpu = tfs->cpu;
2217
2218 #ifdef HASH_TABLE_DEBUG
2219 hash_table_check(ts->processes);
2220 #endif
2221 LttvProcessState *process = ts->running_process[cpu];
2222
2223 guint depth = process->execution_stack->len;
2224
2225 process->execution_stack =
2226 g_array_set_size(process->execution_stack, depth + 1);
2227 /* Keep in sync */
2228 process->state =
2229 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
2230
2231 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
2232 es->t = t;
2233 es->n = state_id;
2234 es->entry = es->change = tfs->parent.timestamp;
2235 es->cum_cpu_time = ltt_time_zero;
2236 es->s = process->state->s;
2237 process->state = es;
2238 }
2239
2240 /* pop state
2241 * return 1 when empty, else 0 */
2242 int lttv_state_pop_state_cleanup(LttvProcessState *process,
2243 LttvTracefileState *tfs)
2244 {
2245 guint depth = process->execution_stack->len;
2246
2247 if(depth == 1){
2248 return 1;
2249 }
2250
2251 process->execution_stack =
2252 g_array_set_size(process->execution_stack, depth - 1);
2253 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2254 depth - 2);
2255 process->state->change = tfs->parent.timestamp;
2256
2257 return 0;
2258 }
2259
2260 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
2261 {
2262 guint cpu = tfs->cpu;
2263 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2264 LttvProcessState *process = ts->running_process[cpu];
2265
2266 guint depth = process->execution_stack->len;
2267
2268 if(process->state->t != t){
2269 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
2270 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2271 g_info("process state has %s when pop_int is %s\n",
2272 g_quark_to_string(process->state->t),
2273 g_quark_to_string(t));
2274 g_info("{ %u, %u, %s, %s, %s }\n",
2275 process->pid,
2276 process->ppid,
2277 g_quark_to_string(process->name),
2278 g_quark_to_string(process->brand),
2279 g_quark_to_string(process->state->s));
2280 return;
2281 }
2282
2283 if(depth == 1){
2284 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
2285 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2286 return;
2287 }
2288
2289 process->execution_stack =
2290 g_array_set_size(process->execution_stack, depth - 1);
2291 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
2292 depth - 2);
2293 process->state->change = tfs->parent.timestamp;
2294 }
2295
2296 struct search_result {
2297 const LttTime *time; /* Requested time */
2298 LttTime *best; /* Best result */
2299 };
2300
2301 static gint search_usertrace(gconstpointer a, gconstpointer b)
2302 {
2303 const LttTime *elem_time = (const LttTime*)a;
2304 /* Explicit non const cast */
2305 struct search_result *res = (struct search_result *)b;
2306
2307 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
2308 /* The usertrace was created before the schedchange */
2309 /* Get larger keys */
2310 return 1;
2311 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
2312 /* The usertrace was created after the schedchange time */
2313 /* Get smaller keys */
2314 if(res->best) {
2315 if(ltt_time_compare(*elem_time, *res->best) < 0) {
2316 res->best = (LttTime *)elem_time;
2317 }
2318 } else {
2319 res->best = (LttTime *)elem_time;
2320 }
2321 return -1;
2322 }
2323 return 0;
2324 }
2325
2326 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
2327 guint pid, const LttTime *timestamp)
2328 {
2329 LttvTracefileState *tfs = NULL;
2330 struct search_result res;
2331 /* Find the usertrace associated with a pid and time interval.
2332 * Search in the usertraces by PID (within a hash) and then, for each
2333 * corresponding element of the array, find the first one with creation
2334 * timestamp the lowest, but higher or equal to "timestamp". */
2335 res.time = timestamp;
2336 res.best = NULL;
2337 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces,
2338 GUINT_TO_POINTER(pid));
2339 if(usertrace_tree) {
2340 g_tree_search(usertrace_tree, search_usertrace, &res);
2341 if(res.best)
2342 tfs = g_tree_lookup(usertrace_tree, res.best);
2343 }
2344
2345 return tfs;
2346 }
2347
2348 /* Return a new and initialized LttvProcessState structure */
2349
2350 LttvProcessState *
2351 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
2352 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
2353 {
2354 LttvProcessState *process = g_new(LttvProcessState, 1);
2355
2356 LttvExecutionState *es;
2357
2358 char buffer[128];
2359
2360 process->pid = pid;
2361 process->tgid = tgid;
2362 process->cpu = cpu;
2363 process->name = name;
2364 process->brand = LTTV_STATE_UNBRANDED;
2365 //process->last_cpu = tfs->cpu_name;
2366 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2367 process->type = LTTV_STATE_USER_THREAD;
2368 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2369 process->current_function = 0; //function 0x0 by default.
2370
2371 g_info("Process %u, core %p", process->pid, process);
2372 g_hash_table_insert(tcs->processes, process, process);
2373
2374 if(parent) {
2375 process->ppid = parent->pid;
2376 process->creation_time = *timestamp;
2377 }
2378
2379 /* No parent. This process exists but we are missing all information about
2380 its creation. The birth time is set to zero but we remember the time of
2381 insertion */
2382
2383 else {
2384 process->ppid = 0;
2385 process->creation_time = ltt_time_zero;
2386 }
2387
2388 process->insertion_time = *timestamp;
2389 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2390 process->creation_time.tv_nsec);
2391 process->pid_time = g_quark_from_string(buffer);
2392 process->cpu = cpu;
2393 process->free_events = 0;
2394 //process->last_cpu = tfs->cpu_name;
2395 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2396 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2397 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2398 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2399 es = process->state = &g_array_index(process->execution_stack,
2400 LttvExecutionState, 0);
2401 es->t = LTTV_STATE_USER_MODE;
2402 es->n = LTTV_STATE_SUBMODE_NONE;
2403 es->entry = *timestamp;
2404 //g_assert(timestamp->tv_sec != 0);
2405 es->change = *timestamp;
2406 es->cum_cpu_time = ltt_time_zero;
2407 es->s = LTTV_STATE_RUN;
2408
2409 es = process->state = &g_array_index(process->execution_stack,
2410 LttvExecutionState, 1);
2411 es->t = LTTV_STATE_SYSCALL;
2412 es->n = LTTV_STATE_SUBMODE_NONE;
2413 es->entry = *timestamp;
2414 //g_assert(timestamp->tv_sec != 0);
2415 es->change = *timestamp;
2416 es->cum_cpu_time = ltt_time_zero;
2417 es->s = LTTV_STATE_WAIT_FORK;
2418
2419 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2420 process->user_stack = g_array_sized_new(FALSE, FALSE,
2421 sizeof(guint64), 0);
2422
2423 process->fds = g_hash_table_new(g_direct_hash, g_direct_equal);
2424
2425 return process;
2426 }
2427
2428 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
2429 guint pid)
2430 {
2431 LttvProcessState key;
2432 LttvProcessState *process;
2433
2434 key.pid = pid;
2435 key.cpu = cpu;
2436 process = g_hash_table_lookup(ts->processes, &key);
2437 return process;
2438 }
2439
2440 LttvProcessState *
2441 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
2442 const LttTime *timestamp)
2443 {
2444 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2445 LttvExecutionState *es;
2446
2447 /* Put ltt_time_zero creation time for unexisting processes */
2448 if(unlikely(process == NULL)) {
2449 process = lttv_state_create_process(ts,
2450 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2451 /* We are not sure is it's a kernel thread or normal thread, put the
2452 * bottom stack state to unknown */
2453 process->execution_stack =
2454 g_array_set_size(process->execution_stack, 1);
2455 process->state = es =
2456 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2457 es->t = LTTV_STATE_MODE_UNKNOWN;
2458 es->s = LTTV_STATE_UNNAMED;
2459 }
2460 return process;
2461 }
2462
2463 /* FIXME : this function should be called when we receive an event telling that
2464 * release_task has been called in the kernel. In happens generally when
2465 * the parent waits for its child termination, but may also happens in special
2466 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2467 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2468 * of a killed thread group, but isn't the leader.
2469 */
2470 static int exit_process(LttvTracefileState *tfs, LttvProcessState *process)
2471 {
2472 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2473 LttvProcessState key;
2474
2475 /* Wait for both schedule with exit dead and process free to happen.
2476 * They can happen in any order. */
2477 if (++(process->free_events) < 2)
2478 return 0;
2479
2480 key.pid = process->pid;
2481 key.cpu = process->cpu;
2482 g_hash_table_remove(ts->processes, &key);
2483 g_array_free(process->execution_stack, TRUE);
2484 g_array_free(process->user_stack, TRUE);
2485
2486 /* the following also clears the content */
2487 g_hash_table_destroy(process->fds);
2488
2489 g_free(process);
2490 return 1;
2491 }
2492
2493
2494 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2495 {
2496 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2497 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
2498
2499 /* the following also clears the content */
2500 g_hash_table_destroy(((LttvProcessState *)value)->fds);
2501
2502 g_free(value);
2503 }
2504
2505
2506 static void lttv_state_free_process_table(GHashTable *processes)
2507 {
2508 g_hash_table_foreach(processes, free_process_state, NULL);
2509 g_hash_table_destroy(processes);
2510 }
2511
2512
2513 static gboolean syscall_entry(void *hook_data, void *call_data)
2514 {
2515 LttvTracefileState *s = (LttvTracefileState *)call_data;
2516 guint cpu = s->cpu;
2517 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2518 LttvProcessState *process = ts->running_process[cpu];
2519 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2520 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2521 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2522 LttvExecutionSubmode submode;
2523 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2524
2525 guint syscall = ltt_event_get_unsigned(e, f);
2526 expand_syscall_table(ts, syscall);
2527 submode = nt->syscall_names[syscall];
2528 /* There can be no system call from PID 0 : unknown state */
2529 if(process->pid != 0)
2530 push_state(s, LTTV_STATE_SYSCALL, submode);
2531 return FALSE;
2532 }
2533
2534
2535 static gboolean syscall_exit(void *hook_data, void *call_data)
2536 {
2537 LttvTracefileState *s = (LttvTracefileState *)call_data;
2538 guint cpu = s->cpu;
2539 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2540 LttvProcessState *process = ts->running_process[cpu];
2541
2542 /* There can be no system call from PID 0 : unknown state */
2543 if(process->pid != 0)
2544 pop_state(s, LTTV_STATE_SYSCALL);
2545 return FALSE;
2546 }
2547
2548
2549 static gboolean trap_entry(void *hook_data, void *call_data)
2550 {
2551 LttvTracefileState *s = (LttvTracefileState *)call_data;
2552 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2553 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2554 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2555 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2556 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2557
2558 LttvExecutionSubmode submode;
2559
2560 guint64 trap = ltt_event_get_long_unsigned(e, f);
2561
2562 expand_trap_table(ts, trap);
2563
2564 submode = nt->trap_names[trap];
2565
2566 push_state(s, LTTV_STATE_TRAP, submode);
2567
2568 /* update cpu status */
2569 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2570
2571 /* update trap status */
2572 g_array_append_val(s->cpu_state->trap_stack, trap);
2573 ts->trap_states[trap].running++;
2574
2575 return FALSE;
2576 }
2577
2578 static gboolean trap_exit(void *hook_data, void *call_data)
2579 {
2580 LttvTracefileState *s = (LttvTracefileState *)call_data;
2581 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2582
2583 pop_state(s, LTTV_STATE_TRAP);
2584
2585 /* update cpu status */
2586 cpu_pop_mode(s->cpu_state);
2587
2588 /* update trap status */
2589 if (s->cpu_state->trap_stack->len > 0) {
2590 gint last = g_array_index(s->cpu_state->trap_stack, gint, s->cpu_state->trap_stack->len-1);
2591 if(ts->trap_states[last].running)
2592 ts->trap_states[last].running--;
2593 g_array_remove_index(s->cpu_state->trap_stack, s->cpu_state->trap_stack->len-1);
2594 }
2595 return FALSE;
2596 }
2597
2598 static gboolean irq_entry(void *hook_data, void *call_data)
2599 {
2600 LttvTracefileState *s = (LttvTracefileState *)call_data;
2601 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2602 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2603 //guint8 ev_id = ltt_event_eventtype_id(e);
2604 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2605 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2606 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2607
2608 LttvExecutionSubmode submode;
2609 guint64 irq = ltt_event_get_long_unsigned(e, f);
2610
2611 expand_irq_table(ts, irq);
2612
2613 submode = nt->irq_names[irq];
2614
2615 /* Do something with the info about being in user or system mode when int? */
2616 push_state(s, LTTV_STATE_IRQ, submode);
2617
2618 /* update cpu status */
2619 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2620
2621 /* update irq status */
2622 g_array_append_val(s->cpu_state->irq_stack, irq);
2623 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2624
2625 return FALSE;
2626 }
2627
2628 static gboolean soft_irq_exit(void *hook_data, void *call_data)
2629 {
2630 LttvTracefileState *s = (LttvTracefileState *)call_data;
2631 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2632
2633 pop_state(s, LTTV_STATE_SOFT_IRQ);
2634
2635 /* update cpu status */
2636 cpu_pop_mode(s->cpu_state);
2637
2638 /* update softirq status */
2639 if (s->cpu_state->softirq_stack->len > 0) {
2640 gint last = g_array_index(s->cpu_state->softirq_stack, gint, s->cpu_state->softirq_stack->len-1);
2641 if(ts->soft_irq_states[last].running)
2642 ts->soft_irq_states[last].running--;
2643 g_array_remove_index(s->cpu_state->softirq_stack, s->cpu_state->softirq_stack->len-1);
2644 }
2645 return FALSE;
2646 }
2647
2648 static gboolean irq_exit(void *hook_data, void *call_data)
2649 {
2650 LttvTracefileState *s = (LttvTracefileState *)call_data;
2651 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2652
2653 pop_state(s, LTTV_STATE_IRQ);
2654
2655 /* update cpu status */
2656 cpu_pop_mode(s->cpu_state);
2657
2658 /* update irq status */
2659 if (s->cpu_state->irq_stack->len > 0) {
2660 gint last = g_array_index(s->cpu_state->irq_stack, gint, s->cpu_state->irq_stack->len-1);
2661 g_array_remove_index(s->cpu_state->irq_stack, s->cpu_state->irq_stack->len-1);
2662 irq_pop_mode(&ts->irq_states[last]);
2663 }
2664
2665 return FALSE;
2666 }
2667
2668 static gboolean soft_irq_raise(void *hook_data, void *call_data)
2669 {
2670 LttvTracefileState *s = (LttvTracefileState *)call_data;
2671 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2672 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2673 //guint8 ev_id = ltt_event_eventtype_id(e);
2674 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2675 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2676 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2677
2678 LttvExecutionSubmode submode;
2679 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2680 guint64 nb_softirqs = nt->nb_soft_irqs;
2681
2682 if(softirq < nb_softirqs) {
2683 submode = nt->soft_irq_names[softirq];
2684 } else {
2685 /* Fixup an incomplete irq table */
2686 GString *string = g_string_new("");
2687 g_string_printf(string, "softirq %" PRIu64, softirq);
2688 submode = g_quark_from_string(string->str);
2689 g_string_free(string, TRUE);
2690 }
2691
2692 /* update softirq status */
2693 /* a soft irq raises are not cumulative */
2694 ts->soft_irq_states[softirq].pending=1;
2695
2696 return FALSE;
2697 }
2698
2699 static gboolean soft_irq_entry(void *hook_data, void *call_data)
2700 {
2701 LttvTracefileState *s = (LttvTracefileState *)call_data;
2702 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2703 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2704 //guint8 ev_id = ltt_event_eventtype_id(e);
2705 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2706 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2707 LttvExecutionSubmode submode;
2708 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2709 expand_soft_irq_table(ts, softirq);
2710 LttvNameTables *nt = ((LttvTraceState *)(s->parent.t_context))->name_tables;
2711 submode = nt->soft_irq_names[softirq];
2712
2713 /* Do something with the info about being in user or system mode when int? */
2714 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2715
2716 /* update cpu status */
2717 cpu_push_mode(s->cpu_state, LTTV_CPU_SOFT_IRQ);
2718
2719 /* update softirq status */
2720 g_array_append_val(s->cpu_state->softirq_stack, softirq);
2721 if(ts->soft_irq_states[softirq].pending)
2722 ts->soft_irq_states[softirq].pending--;
2723 ts->soft_irq_states[softirq].running++;
2724
2725 return FALSE;
2726 }
2727
2728 static gboolean enum_interrupt(void *hook_data, void *call_data)
2729 {
2730 LttvTracefileState *s = (LttvTracefileState *)call_data;
2731 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2732 LttvNameTables *nt = ts->name_tables;
2733 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2734 //guint8 ev_id = ltt_event_eventtype_id(e);
2735 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2736
2737 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2738 lttv_trace_get_hook_field(th, 0)));
2739 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2740
2741 expand_irq_table(ts, irq);
2742 nt->irq_names[irq] = action;
2743
2744 return FALSE;
2745 }
2746
2747
2748 static gboolean bdev_request_issue(void *hook_data, void *call_data)
2749 {
2750 LttvTracefileState *s = (LttvTracefileState *)call_data;
2751 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2752 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2753 //guint8 ev_id = ltt_event_eventtype_id(e);
2754 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2755
2756 guint major = ltt_event_get_long_unsigned(e,
2757 lttv_trace_get_hook_field(th, 0));
2758 guint minor = ltt_event_get_long_unsigned(e,
2759 lttv_trace_get_hook_field(th, 1));
2760 guint oper = ltt_event_get_long_unsigned(e,
2761 lttv_trace_get_hook_field(th, 2));
2762 guint16 devcode = MKDEV(major,minor);
2763
2764 /* have we seen this block device before? */
2765 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2766
2767 if(oper == 0)
2768 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2769 else
2770 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2771
2772 return FALSE;
2773 }
2774
2775 static gboolean bdev_request_complete(void *hook_data, void *call_data)
2776 {
2777 LttvTracefileState *s = (LttvTracefileState *)call_data;
2778 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2779 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2780 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2781
2782 guint major = ltt_event_get_long_unsigned(e,
2783 lttv_trace_get_hook_field(th, 0));
2784 guint minor = ltt_event_get_long_unsigned(e,
2785 lttv_trace_get_hook_field(th, 1));
2786 //guint oper = ltt_event_get_long_unsigned(e,
2787 // lttv_trace_get_hook_field(th, 2));
2788 guint16 devcode = MKDEV(major,minor);
2789
2790 /* have we seen this block device before? */
2791 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2792
2793 /* update block device */
2794 bdev_pop_mode(bdev);
2795
2796 return FALSE;
2797 }
2798
2799 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2800 {
2801 guint64 *new_func;
2802
2803 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2804 guint cpu = tfs->cpu;
2805 LttvProcessState *process = ts->running_process[cpu];
2806
2807 guint depth = process->user_stack->len;
2808
2809 process->user_stack =
2810 g_array_set_size(process->user_stack, depth + 1);
2811
2812 new_func = &g_array_index(process->user_stack, guint64, depth);
2813 *new_func = funcptr;
2814 process->current_function = funcptr;
2815 }
2816
2817 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2818 {
2819 guint cpu = tfs->cpu;
2820 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2821 LttvProcessState *process = ts->running_process[cpu];
2822
2823 if(process->current_function != funcptr){
2824 g_info("Different functions (%lu.%09lu): ignore it\n",
2825 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2826 g_info("process state has %" PRIu64 " when pop_function is %" PRIu64 "\n",
2827 process->current_function, funcptr);
2828 g_info("{ %u, %u, %s, %s, %s }\n",
2829 process->pid,
2830 process->ppid,
2831 g_quark_to_string(process->name),
2832 g_quark_to_string(process->brand),
2833 g_quark_to_string(process->state->s));
2834 return;
2835 }
2836 guint depth = process->user_stack->len;
2837
2838 if(depth == 0){
2839 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2840 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2841 return;
2842 }
2843
2844 process->user_stack =
2845 g_array_set_size(process->user_stack, depth - 1);
2846 process->current_function =
2847 g_array_index(process->user_stack, guint64, depth - 2);
2848 }
2849
2850
2851 static gboolean function_entry(void *hook_data, void *call_data)
2852 {
2853 LttvTracefileState *s = (LttvTracefileState *)call_data;
2854 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2855 //guint8 ev_id = ltt_event_eventtype_id(e);
2856 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2857 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2858 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2859
2860 push_function(s, funcptr);
2861 return FALSE;
2862 }
2863
2864 static gboolean function_exit(void *hook_data, void *call_data)
2865 {
2866 LttvTracefileState *s = (LttvTracefileState *)call_data;
2867 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2868 //guint8 ev_id = ltt_event_eventtype_id(e);
2869 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2870 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2871 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2872
2873 pop_function(s, funcptr);
2874 return FALSE;
2875 }
2876
2877 static gboolean dump_syscall(void *hook_data, void *call_data)
2878 {
2879 LttvTracefileState *s = (LttvTracefileState *)call_data;
2880 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2881 LttvNameTables *nt = ts->name_tables;
2882 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2883 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2884 guint id;
2885 guint64 address;
2886 char *symbol;
2887
2888 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2889 address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2890 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2891
2892 expand_syscall_table(ts, id);
2893 nt->syscall_names[id] = g_quark_from_string(symbol);
2894
2895 return FALSE;
2896 }
2897
2898 static gboolean dump_kprobe(void *hook_data, void *call_data)
2899 {
2900 LttvTracefileState *s = (LttvTracefileState *)call_data;
2901 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2902 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2903 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2904 guint64 ip;
2905 char *symbol;
2906
2907 ip = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2908 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 1));
2909
2910 expand_kprobe_table(ts, ip, symbol);
2911
2912 return FALSE;
2913 }
2914
2915 static gboolean dump_softirq(void *hook_data, void *call_data)
2916 {
2917 LttvTracefileState *s = (LttvTracefileState *)call_data;
2918 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2919 LttvNameTables *nt = ts->name_tables;
2920 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2921 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2922 guint id;
2923 guint64 address;
2924 char *symbol;
2925
2926 id = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2927 address = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2928 symbol = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2929
2930 expand_soft_irq_table(ts, id);
2931 nt->soft_irq_names[id] = g_quark_from_string(symbol);
2932
2933 return FALSE;
2934 }
2935
2936 static gboolean schedchange(void *hook_data, void *call_data)
2937 {
2938 LttvTracefileState *s = (LttvTracefileState *)call_data;
2939 guint cpu = s->cpu;
2940 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2941 LttvProcessState *process = ts->running_process[cpu];
2942 //LttvProcessState *old_process = ts->running_process[cpu];
2943
2944 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2945 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2946 guint pid_in, pid_out;
2947 gint64 state_out;
2948
2949 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2950 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2951 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
2952
2953 if(likely(process != NULL)) {
2954
2955 /* We could not know but it was not the idle process executing.
2956 This should only happen at the beginning, before the first schedule
2957 event, and when the initial information (current process for each CPU)
2958 is missing. It is not obvious how we could, after the fact, compensate
2959 the wrongly attributed statistics. */
2960
2961 //This test only makes sense once the state is known and if there is no
2962 //missing events. We need to silently ignore schedchange coming after a
2963 //process_free, or it causes glitches. (FIXME)
2964 //if(unlikely(process->pid != pid_out)) {
2965 // g_assert(process->pid == 0);
2966 //}
2967 if(process->pid == 0
2968 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2969 if(pid_out == 0) {
2970 /* Scheduling out of pid 0 at beginning of the trace :
2971 * we know for sure it is in syscall mode at this point. */
2972 g_assert(process->execution_stack->len == 1);
2973 process->state->t = LTTV_STATE_SYSCALL;
2974 process->state->s = LTTV_STATE_WAIT;
2975 process->state->change = s->parent.timestamp;
2976 process->state->entry = s->parent.timestamp;
2977 }
2978 } else {
2979 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2980 process->state->s = LTTV_STATE_ZOMBIE;
2981 process->state->change = s->parent.timestamp;
2982 } else {
2983 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2984 else process->state->s = LTTV_STATE_WAIT;
2985 process->state->change = s->parent.timestamp;
2986 }
2987
2988 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
2989 /* see sched.h for states */
2990 if (!exit_process(s, process)) {
2991 process->state->s = LTTV_STATE_DEAD;
2992 process->state->change = s->parent.timestamp;
2993 }
2994 }
2995 }
2996 }
2997 process = ts->running_process[cpu] =
2998 lttv_state_find_process_or_create(
2999 (LttvTraceState*)s->parent.t_context,
3000 cpu, pid_in,
3001 &s->parent.timestamp);
3002 process->state->s = LTTV_STATE_RUN;
3003 process->cpu = cpu;
3004 if(process->usertrace)
3005 process->usertrace->cpu = cpu;
3006 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
3007 process->state->change = s->parent.timestamp;
3008
3009 /* update cpu status */
3010 if(pid_in == 0)
3011 /* going to idle task */
3012 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
3013 else {
3014 /* scheduling a real task.
3015 * we must be careful here:
3016 * if we just schedule()'ed to a process that is
3017 * in a trap, we must put the cpu in trap mode
3018 */
3019 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
3020 if(process->state->t == LTTV_STATE_TRAP)
3021 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
3022 }
3023
3024 return FALSE;
3025 }
3026
3027 static gboolean process_fork(void *hook_data, void *call_data)
3028 {
3029 LttvTracefileState *s = (LttvTracefileState *)call_data;
3030 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3031 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3032 guint parent_pid;
3033 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
3034 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
3035 //LttvProcessState *zombie_process;
3036 guint cpu = s->cpu;
3037 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3038 LttvProcessState *process = ts->running_process[cpu];
3039 LttvProcessState *child_process;
3040 struct marker_field *f;
3041
3042 /* Parent PID */
3043 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3044
3045 /* Child PID */
3046 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
3047 s->parent.target_pid = child_pid;
3048
3049 /* Child TGID */
3050 f = lttv_trace_get_hook_field(th, 2);
3051 if (likely(f))
3052 child_tgid = ltt_event_get_unsigned(e, f);
3053 else
3054 child_tgid = 0;
3055
3056 /* Mathieu : it seems like the process might have been scheduled in before the
3057 * fork, and, in a rare case, might be the current process. This might happen
3058 * in a SMP case where we don't have enough precision on the clocks.
3059 *
3060 * Test reenabled after precision fixes on time. (Mathieu) */
3061 #if 0
3062 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
3063
3064 if(unlikely(zombie_process != NULL)) {
3065 /* Reutilisation of PID. Only now we are sure that the old PID
3066 * has been released. FIXME : should know when release_task happens instead.
3067 */
3068 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3069 guint i;
3070 for(i=0; i< num_cpus; i++) {
3071 g_assert(zombie_process != ts->running_process[i]);
3072 }
3073
3074 exit_process(s, zombie_process);
3075 }
3076 #endif //0
3077 g_assert(process->pid != child_pid);
3078 // FIXME : Add this test in the "known state" section
3079 // g_assert(process->pid == parent_pid);
3080 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
3081 if(child_process == NULL) {
3082 child_process = lttv_state_create_process(ts, process, cpu,
3083 child_pid, child_tgid,
3084 LTTV_STATE_UNNAMED, &s->parent.timestamp);
3085 } else {
3086 /* The process has already been created : due to time imprecision between
3087 * multiple CPUs : it has been scheduled in before creation. Note that we
3088 * shouldn't have this kind of imprecision.
3089 *
3090 * Simply put a correct parent.
3091 */
3092 g_error("Process %u has been created at [%lu.%09lu] "
3093 "and inserted at [%lu.%09lu] before \n"
3094 "fork on cpu %u[%lu.%09lu].\n"
3095 "Probably an unsynchronized TSC problem on the traced machine.",
3096 child_pid,
3097 child_process->creation_time.tv_sec,
3098 child_process->creation_time.tv_nsec,
3099 child_process->insertion_time.tv_sec,
3100 child_process->insertion_time.tv_nsec,
3101 cpu, ltt_event_time(e).tv_sec, ltt_event_time(e).tv_nsec);
3102 //g_assert(0); /* This is a problematic case : the process has been created
3103 // before the fork event */
3104 child_process->ppid = process->pid;
3105 child_process->tgid = child_tgid;
3106 }
3107 g_assert(child_process->name == LTTV_STATE_UNNAMED);
3108 child_process->name = process->name;
3109 child_process->brand = process->brand;
3110
3111 return FALSE;
3112 }
3113
3114 /* We stamp a newly created process as kernel_thread.
3115 * The thread should not be running yet. */
3116 static gboolean process_kernel_thread(void *hook_data, void *call_data)
3117 {
3118 LttvTracefileState *s = (LttvTracefileState *)call_data;
3119 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3120 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3121 guint pid;
3122 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3123 LttvProcessState *process;
3124 LttvExecutionState *es;
3125
3126 /* PID */
3127 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
3128 s->parent.target_pid = pid;
3129
3130 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
3131 &ltt_time_zero);
3132 if (process->state->s != LTTV_STATE_DEAD) {
3133 process->execution_stack =
3134 g_array_set_size(process->execution_stack, 1);
3135 es = process->state =
3136 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3137 es->t = LTTV_STATE_SYSCALL;
3138 }
3139 process->type = LTTV_STATE_KERNEL_THREAD;
3140
3141 return FALSE;
3142 }
3143
3144 static gboolean process_exit(void *hook_data, void *call_data)
3145 {
3146 LttvTracefileState *s = (LttvTracefileState *)call_data;
3147 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3148 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3149 guint pid;
3150 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3151 LttvProcessState *process; // = ts->running_process[cpu];
3152
3153 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3154 s->parent.target_pid = pid;
3155
3156 // FIXME : Add this test in the "known state" section
3157 // g_assert(process->pid == pid);
3158
3159 process = lttv_state_find_process(ts, ANY_CPU, pid);
3160 if(likely(process != NULL)) {
3161 process->state->s = LTTV_STATE_EXIT;
3162 }
3163 return FALSE;
3164 }
3165
3166 static gboolean process_free(void *hook_data, void *call_data)
3167 {
3168 LttvTracefileState *s = (LttvTracefileState *)call_data;
3169 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3170 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3171 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3172 guint release_pid;
3173 LttvProcessState *process;
3174
3175 /* PID of the process to release */
3176 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3177 s->parent.target_pid = release_pid;
3178
3179 g_assert(release_pid != 0);
3180
3181 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
3182 if(likely(process != NULL))
3183 exit_process(s, process);
3184 return FALSE;
3185 //DISABLED
3186 if(likely(process != NULL)) {
3187 /* release_task is happening at kernel level : we can now safely release
3188 * the data structure of the process */
3189 //This test is fun, though, as it may happen that
3190 //at time t : CPU 0 : process_free
3191 //at time t+150ns : CPU 1 : schedule out
3192 //Clearly due to time imprecision, we disable it. (Mathieu)
3193 //If this weird case happen, we have no choice but to put the
3194 //Currently running process on the cpu to 0.
3195 //I re-enable it following time precision fixes. (Mathieu)
3196 //Well, in the case where an process is freed by a process on another CPU
3197 //and still scheduled, it happens that this is the schedchange that will
3198 //drop the last reference count. Do not free it here!
3199 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3200 guint i;
3201 for(i=0; i< num_cpus; i++) {
3202 //g_assert(process != ts->running_process[i]);
3203 if(process == ts->running_process[i]) {
3204 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
3205 break;
3206 }
3207 }
3208 if(i == num_cpus) /* process is not scheduled */
3209 exit_process(s, process);
3210 }
3211
3212 return FALSE;
3213 }
3214
3215
3216 static gboolean process_exec(void *hook_data, void *call_data)
3217 {
3218 LttvTracefileState *s = (LttvTracefileState *)call_data;
3219 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3220 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3221 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3222 //gchar *name;
3223 guint cpu = s->cpu;
3224 LttvProcessState *process = ts->running_process[cpu];
3225
3226 #if 0//how to use a sequence that must be transformed in a string
3227 /* PID of the process to release */
3228 guint64 name_len = ltt_event_field_element_number(e,
3229 lttv_trace_get_hook_field(th, 0));
3230 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3231 LttField *child = ltt_event_field_element_select(e,
3232 lttv_trace_get_hook_field(th, 0), 0);
3233 gchar *name_begin =
3234 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
3235 gchar *null_term_name = g_new(gchar, name_len+1);
3236 memcpy(null_term_name, name_begin, name_len);
3237 null_term_name[name_len] = '\0';
3238 process->name = g_quark_from_string(null_term_name);
3239 #endif //0
3240
3241 process->name = g_quark_from_string(ltt_event_get_string(e,
3242 lttv_trace_get_hook_field(th, 0)));
3243 process->brand = LTTV_STATE_UNBRANDED;
3244 //g_free(null_term_name);
3245 return FALSE;
3246 }
3247
3248 static gboolean thread_brand(void *hook_data, void *call_data)
3249 {
3250 LttvTracefileState *s = (LttvTracefileState *)call_data;
3251 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3252 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3253 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3254 gchar *name;
3255 guint cpu = s->cpu;
3256 LttvProcessState *process = ts->running_process[cpu];
3257
3258 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
3259 process->brand = g_quark_from_string(name);
3260
3261 return FALSE;
3262 }
3263
3264 static gboolean fs_open(void *hook_data, void *call_data)
3265 {
3266 LttvTracefileState *s = (LttvTracefileState *)call_data;
3267 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
3268 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3269 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3270 struct marker_field *f;
3271 guint cpu = s->cpu;
3272 int fd;
3273 char *filename;
3274 LttvProcessState *process = ts->running_process[cpu];
3275
3276 f = lttv_trace_get_hook_field(th, 0);
3277 fd = ltt_event_get_int(e, f);
3278
3279 f = lttv_trace_get_hook_field(th, 1);
3280 filename = ltt_event_get_string(e, f);
3281
3282 g_hash_table_insert(process->fds, (gpointer)(long)fd,
3283 (gpointer)(unsigned long)g_quark_from_string(filename));
3284
3285 return FALSE;
3286 }
3287
3288 static void fix_process(gpointer key, gpointer value,
3289 gpointer user_data)
3290 {
3291 LttvProcessState *process;
3292 LttvExecutionState *es;
3293 process = (LttvProcessState *)value;
3294 LttTime *timestamp = (LttTime*)user_data;
3295
3296 if(process->type == LTTV_STATE_KERNEL_THREAD) {
3297 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3298 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3299 es->t = LTTV_STATE_SYSCALL;
3300 es->n = LTTV_STATE_SUBMODE_NONE;
3301 es->entry = *timestamp;
3302 es->change = *timestamp;
3303 es->cum_cpu_time = ltt_time_zero;
3304 if(es->s == LTTV_STATE_UNNAMED)
3305 es->s = LTTV_STATE_WAIT;
3306 }
3307 } else {
3308 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
3309 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3310 es->t = LTTV_STATE_USER_MODE;
3311 es->n = LTTV_STATE_SUBMODE_NONE;
3312 es->entry = *timestamp;
3313 //g_assert(timestamp->tv_sec != 0);
3314 es->change = *timestamp;
3315 es->cum_cpu_time = ltt_time_zero;
3316 if(es->s == LTTV_STATE_UNNAMED)
3317 es->s = LTTV_STATE_RUN;
3318
3319 if(process->execution_stack->len == 1) {
3320 /* Still in bottom unknown mode, means never did a system call
3321 * May be either in user mode, syscall mode, running or waiting.*/
3322 /* FIXME : we may be tagging syscall mode when being user mode */
3323 process->execution_stack =
3324 g_array_set_size(process->execution_stack, 2);
3325 es = process->state = &g_array_index(process->execution_stack,
3326 LttvExecutionState, 1);
3327 es->t = LTTV_STATE_SYSCALL;
3328 es->n = LTTV_STATE_SUBMODE_NONE;
3329 es->entry = *timestamp;
3330 //g_assert(timestamp->tv_sec != 0);
3331 es->change = *timestamp;
3332 es->cum_cpu_time = ltt_time_zero;
3333 if(es->s == LTTV_STATE_WAIT_FORK)
3334 es->s = LTTV_STATE_WAIT;
3335 }
3336 }
3337 }
3338 }
3339
3340 static gboolean statedump_end(void *hook_data, void *call_data)
3341 {
3342 LttvTracefileState *s = (LttvTracefileState *)call_data;
3343 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3344 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
3345 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3346 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
3347
3348 /* For all processes */
3349 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
3350 /* else, if stack[0] is unknown, set to user mode, running */
3351
3352 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
3353
3354 return FALSE;
3355 }
3356
3357 static gboolean enum_process_state(void *hook_data, void *call_data)
3358 {
3359 LttvTracefileState *s = (LttvTracefileState *)call_data;
3360 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
3361 //It's slow : optimise later by doing this before reading trace.
3362 LttvTraceHook *th = (LttvTraceHook *)hook_data;
3363 guint parent_pid;
3364 guint pid;
3365 guint tgid;
3366 gchar * command;
3367 guint cpu = s->cpu;
3368 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
3369 LttvProcessState *process = ts->running_process[cpu];
3370 LttvProcessState *parent_process;
3371 struct marker_field *f;
3372 GQuark type, mode, submode, status;
3373 LttvExecutionState *es;
3374 guint i, nb_cpus;
3375
3376 /* PID */
3377 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
3378 s->parent.target_pid = pid;
3379
3380 /* Parent PID */
3381 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
3382
3383 /* Command name */
3384 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
3385
3386 /* type */
3387 f = lttv_trace_get_hook_field(th, 3);
3388 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3389
3390 //FIXME: type is rarely used, enum must match possible types.
3391
3392 /* mode */
3393 f = lttv_trace_get_hook_field(th, 4);
3394 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
3395
3396 /* submode */
3397 f = lttv_trace_get_hook_field(th, 5);
3398 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3399
3400 /* status */
3401 f = lttv_trace_get_hook_field(th, 6);
3402 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
3403
3404 /* TGID */
3405 f = lttv_trace_get_hook_field(th, 7);
3406 if(f)
3407 tgid = ltt_event_get_unsigned(e, f);
3408 else
3409 tgid = 0;
3410
3411 if(pid == 0) {
3412 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3413 for(i=0; i<nb_cpus; i++) {
3414 process = lttv_state_find_process(ts, i, pid);
3415 g_assert(process != NULL);
3416
3417 process->ppid = parent_pid;
3418 process->tgid = tgid;
3419 process->name = g_quark_from_string(command);
3420 es =
3421 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3422 process->type = LTTV_STATE_KERNEL_THREAD;
3423 }
3424
3425 } else {
3426 /* The process might exist if a process was forked while performing the
3427 * state dump. */
3428 process = lttv_state_find_process(ts, ANY_CPU, pid);
3429 if(process == NULL) {
3430 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3431 process = lttv_state_create_process(ts, parent_process, cpu,
3432 pid, tgid, g_quark_from_string(command),
3433 &s->parent.timestamp);
3434
3435 /* Keep the stack bottom : a running user mode */
3436 /* Disabled because of inconsistencies in the current statedump states. */
3437 if(type == LTTV_STATE_KERNEL_THREAD) {
3438 /* Only keep the bottom
3439 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3440 /* Will cause expected trap when in fact being syscall (even after end of
3441 * statedump event)
3442 * Will cause expected interrupt when being syscall. (only before end of
3443 * statedump event) */
3444 // This will cause a "popping last state on stack, ignoring it."
3445 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3446 es = process->state = &g_array_index(process->execution_stack,
3447 LttvExecutionState, 0);
3448 process->type = LTTV_STATE_KERNEL_THREAD;
3449 es->t = LTTV_STATE_MODE_UNKNOWN;
3450 es->s = LTTV_STATE_UNNAMED;
3451 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3452 #if 0
3453 es->t = LTTV_STATE_SYSCALL;
3454 es->s = status;
3455 es->n = submode;
3456 #endif //0
3457 } else {
3458 /* User space process :
3459 * bottom : user mode
3460 * either currently running or scheduled out.
3461 * can be scheduled out because interrupted in (user mode or in syscall)
3462 * or because of an explicit call to the scheduler in syscall. Note that
3463 * the scheduler call comes after the irq_exit, so never in interrupt
3464 * context. */
3465 // temp workaround : set size to 1 : only have user mode bottom of stack.
3466 // will cause g_info message of expected syscall mode when in fact being
3467 // in user mode. Can also cause expected trap when in fact being user
3468 // mode in the event of a page fault reenabling interrupts in the handler.
3469 // Expected syscall and trap can also happen after the end of statedump
3470 // This will cause a "popping last state on stack, ignoring it."
3471 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3472 es = process->state = &g_array_index(process->execution_stack,
3473 LttvExecutionState, 0);
3474 es->t = LTTV_STATE_MODE_UNKNOWN;
3475 es->s = LTTV_STATE_UNNAMED;
3476 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3477 #if 0
3478 es->t = LTTV_STATE_USER_MODE;
3479 es->s = status;
3480 es->n = submode;
3481 #endif //0
3482 }
3483 #if 0
3484 /* UNKNOWN STATE */
3485 {
3486 es = process->state = &g_array_index(process->execution_stack,
3487 LttvExecutionState, 1);
3488 es->t = LTTV_STATE_MODE_UNKNOWN;
3489 es->s = LTTV_STATE_UNNAMED;
3490 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3491 }
3492 #endif //0
3493 } else {
3494 /* The process has already been created :
3495 * Probably was forked while dumping the process state or
3496 * was simply scheduled in prior to get the state dump event.
3497 */
3498 process->ppid = parent_pid;
3499 process->tgid = tgid;
3500 process->name = g_quark_from_string(command);
3501 process->type = type;
3502 es =
3503 &g_array_index(process->execution_stack, LttvExecutionState, 0);
3504 #if 0
3505 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3506 if(type == LTTV_STATE_KERNEL_THREAD)
3507 es->t = LTTV_STATE_SYSCALL;
3508 else
3509 es->t = LTTV_STATE_USER_MODE;
3510 }
3511 #endif //0
3512 /* Don't mess around with the stack, it will eventually become
3513 * ok after the end of state dump. */
3514 }
3515 }
3516
3517 return FALSE;
3518 }
3519
3520 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3521 {
3522 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3523
3524 lttv_state_add_event_hooks(tss);
3525
3526 return 0;
3527 }
3528
3529 void lttv_state_add_event_hooks(LttvTracesetState *self)
3530 {
3531 LttvTraceset *traceset = self->parent.ts;
3532
3533 guint i, j, k, nb_trace, nb_tracefile;
3534
3535 LttvTraceState *ts;
3536
3537 LttvTracefileState *tfs;
3538
3539 GArray *hooks;
3540
3541 LttvTraceHook *th;
3542
3543 LttvAttributeValue val;
3544
3545 nb_trace = lttv_traceset_number(traceset);
3546 for(i = 0 ; i < nb_trace ; i++) {
3547 ts = (LttvTraceState *)self->parent.traces[i];
3548
3549 /* Find the eventtype id for the following events and register the
3550 associated by id hooks. */
3551
3552 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 20);
3553 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3554 //hn = 0;
3555
3556 lttv_trace_find_hook(ts->parent.t,
3557 LTT_CHANNEL_KERNEL,
3558 LTT_EVENT_SYSCALL_ENTRY,
3559 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3560 syscall_entry, NULL, &hooks);
3561
3562 lttv_trace_find_hook(ts->parent.t,
3563 LTT_CHANNEL_KERNEL,
3564 LTT_EVENT_SYSCALL_EXIT,
3565 NULL,
3566 syscall_exit, NULL, &hooks);
3567
3568 lttv_trace_find_hook(ts->parent.t,
3569 LTT_CHANNEL_KERNEL,
3570 LTT_EVENT_TRAP_ENTRY,
3571 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3572 trap_entry, NULL, &hooks);
3573
3574 lttv_trace_find_hook(ts->parent.t,
3575 LTT_CHANNEL_KERNEL,
3576 LTT_EVENT_TRAP_EXIT,
3577 NULL,
3578 trap_exit, NULL, &hooks);
3579
3580 lttv_trace_find_hook(ts->parent.t,
3581 LTT_CHANNEL_KERNEL,
3582 LTT_EVENT_PAGE_FAULT_ENTRY,
3583 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3584 trap_entry, NULL, &hooks);
3585
3586 lttv_trace_find_hook(ts->parent.t,
3587 LTT_CHANNEL_KERNEL,
3588 LTT_EVENT_PAGE_FAULT_EXIT,
3589 NULL,
3590 trap_exit, NULL, &hooks);
3591
3592 lttv_trace_find_hook(ts->parent.t,
3593 LTT_CHANNEL_KERNEL,
3594 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY,
3595 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3596 trap_entry, NULL, &hooks);
3597
3598 lttv_trace_find_hook(ts->parent.t,
3599 LTT_CHANNEL_KERNEL,
3600 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT,
3601 NULL,
3602 trap_exit, NULL, &hooks);
3603
3604 lttv_trace_find_hook(ts->parent.t,
3605 LTT_CHANNEL_KERNEL,
3606 LTT_EVENT_IRQ_ENTRY,
3607 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3608 irq_entry, NULL, &hooks);
3609
3610 lttv_trace_find_hook(ts->parent.t,
3611 LTT_CHANNEL_KERNEL,
3612 LTT_EVENT_IRQ_EXIT,
3613 NULL,
3614 irq_exit, NULL, &hooks);
3615
3616 lttv_trace_find_hook(ts->parent.t,
3617 LTT_CHANNEL_KERNEL,
3618 LTT_EVENT_SOFT_IRQ_RAISE,
3619 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3620 soft_irq_raise, NULL, &hooks);
3621
3622 lttv_trace_find_hook(ts->parent.t,
3623 LTT_CHANNEL_KERNEL,
3624 LTT_EVENT_SOFT_IRQ_ENTRY,
3625 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3626 soft_irq_entry, NULL, &hooks);
3627
3628 lttv_trace_find_hook(ts->parent.t,
3629 LTT_CHANNEL_KERNEL,
3630 LTT_EVENT_SOFT_IRQ_EXIT,
3631 NULL,
3632 soft_irq_exit, NULL, &hooks);
3633
3634 lttv_trace_find_hook(ts->parent.t,
3635 LTT_CHANNEL_KERNEL,
3636 LTT_EVENT_SCHED_SCHEDULE,
3637 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3638 LTT_FIELD_PREV_STATE),
3639 schedchange, NULL, &hooks);
3640
3641 lttv_trace_find_hook(ts->parent.t,
3642 LTT_CHANNEL_KERNEL,
3643 LTT_EVENT_PROCESS_FORK,
3644 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3645 LTT_FIELD_CHILD_TGID),
3646 process_fork, NULL, &hooks);
3647
3648 lttv_trace_find_hook(ts->parent.t,
3649 LTT_CHANNEL_KERNEL,
3650 LTT_EVENT_KTHREAD_CREATE,
3651 FIELD_ARRAY(LTT_FIELD_PID),
3652 process_kernel_thread, NULL, &hooks);
3653
3654 lttv_trace_find_hook(ts->parent.t,
3655 LTT_CHANNEL_KERNEL,
3656 LTT_EVENT_PROCESS_EXIT,
3657 FIELD_ARRAY(LTT_FIELD_PID),
3658 process_exit, NULL, &hooks);
3659
3660 lttv_trace_find_hook(ts->parent.t,
3661 LTT_CHANNEL_KERNEL,
3662 LTT_EVENT_PROCESS_FREE,
3663 FIELD_ARRAY(LTT_FIELD_PID),
3664 process_free, NULL, &hooks);
3665
3666 lttv_trace_find_hook(ts->parent.t,
3667 LTT_CHANNEL_FS,
3668 LTT_EVENT_EXEC,
3669 FIELD_ARRAY(LTT_FIELD_FILENAME),
3670 process_exec, NULL, &hooks);
3671
3672 lttv_trace_find_hook(ts->parent.t,
3673 LTT_CHANNEL_USERSPACE,
3674 LTT_EVENT_THREAD_BRAND,
3675 FIELD_ARRAY(LTT_FIELD_NAME),
3676 thread_brand, NULL, &hooks);
3677
3678 /* statedump-related hooks */
3679 lttv_trace_find_hook(ts->parent.t,
3680 LTT_CHANNEL_TASK_STATE,
3681 LTT_EVENT_PROCESS_STATE,
3682 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3683 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3684 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3685 enum_process_state, NULL, &hooks);
3686
3687 lttv_trace_find_hook(ts->parent.t,
3688 LTT_CHANNEL_GLOBAL_STATE,
3689 LTT_EVENT_STATEDUMP_END,
3690 NULL,
3691 statedump_end, NULL, &hooks);
3692
3693 lttv_trace_find_hook(ts->parent.t,
3694 LTT_CHANNEL_IRQ_STATE,
3695 LTT_EVENT_LIST_INTERRUPT,
3696 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3697 enum_interrupt, NULL, &hooks);
3698
3699 lttv_trace_find_hook(ts->parent.t,
3700 LTT_CHANNEL_BLOCK,
3701 LTT_EVENT_REQUEST_ISSUE,
3702 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3703 bdev_request_issue, NULL, &hooks);
3704
3705 lttv_trace_find_hook(ts->parent.t,
3706 LTT_CHANNEL_BLOCK,
3707 LTT_EVENT_REQUEST_COMPLETE,
3708 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3709 bdev_request_complete, NULL, &hooks);
3710
3711 lttv_trace_find_hook(ts->parent.t,
3712 LTT_CHANNEL_USERSPACE,
3713 LTT_EVENT_FUNCTION_ENTRY,
3714 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3715 function_entry, NULL, &hooks);
3716
3717 lttv_trace_find_hook(ts->parent.t,
3718 LTT_CHANNEL_USERSPACE,
3719 LTT_EVENT_FUNCTION_EXIT,
3720 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3721 function_exit, NULL, &hooks);
3722
3723 lttv_trace_find_hook(ts->parent.t,
3724 LTT_CHANNEL_SYSCALL_STATE,
3725 LTT_EVENT_SYS_CALL_TABLE,
3726 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3727 dump_syscall, NULL, &hooks);
3728
3729 lttv_trace_find_hook(ts->parent.t,
3730 LTT_CHANNEL_KPROBE_STATE,
3731 LTT_EVENT_KPROBE_TABLE,
3732 FIELD_ARRAY(LTT_FIELD_IP, LTT_FIELD_SYMBOL),
3733 dump_kprobe, NULL, &hooks);
3734
3735 lttv_trace_find_hook(ts->parent.t,
3736 LTT_CHANNEL_SOFTIRQ_STATE,
3737 LTT_EVENT_SOFTIRQ_VEC,
3738 FIELD_ARRAY(LTT_FIELD_ID, LTT_FIELD_ADDRESS, LTT_FIELD_SYMBOL),
3739 dump_softirq, NULL, &hooks);
3740
3741 lttv_trace_find_hook(ts->parent.t,
3742 LTT_CHANNEL_FS,
3743 LTT_EVENT_OPEN,
3744 FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME),
3745 fs_open, NULL, &hooks);
3746
3747 /* Add these hooks to each event_by_id hooks list */
3748
3749 nb_tracefile = ts->parent.tracefiles->len;
3750
3751 for(j = 0 ; j < nb_tracefile ; j++) {
3752 tfs =
3753 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3754 LttvTracefileContext*, j));
3755
3756 for(k = 0 ; k < hooks->len ; k++) {
3757 th = &g_array_index(hooks, LttvTraceHook, k);
3758 if (th->mdata == tfs->parent.tf->mdata)
3759 lttv_hooks_add(
3760 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3761 th->h,
3762 th,
3763 LTTV_PRIO_STATE);
3764 }
3765 }
3766 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3767 *(val.v_pointer) = hooks;
3768 }
3769 }
3770
3771 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3772 {
3773 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3774
3775 lttv_state_remove_event_hooks(tss);
3776
3777 return 0;
3778 }
3779
3780 void lttv_state_remove_event_hooks(LttvTracesetState *self)
3781 {
3782 LttvTraceset *traceset = self->parent.ts;
3783
3784 guint i, j, k, nb_trace, nb_tracefile;
3785
3786 LttvTraceState *ts;
3787
3788 LttvTracefileState *tfs;
3789
3790 GArray *hooks;
3791
3792 LttvTraceHook *th;
3793
3794 LttvAttributeValue val;
3795
3796 nb_trace = lttv_traceset_number(traceset);
3797 for(i = 0 ; i < nb_trace ; i++) {
3798 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3799
3800 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3801 hooks = *(val.v_pointer);
3802
3803 /* Remove these hooks from each event_by_id hooks list */
3804
3805 nb_tracefile = ts->parent.tracefiles->len;
3806
3807 for(j = 0 ; j < nb_tracefile ; j++) {
3808 tfs =
3809 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3810 LttvTracefileContext*, j));
3811
3812 for(k = 0 ; k < hooks->len ; k++) {
3813 th = &g_array_index(hooks, LttvTraceHook, k);
3814 if (th->mdata == tfs->parent.tf->mdata)
3815 lttv_hooks_remove_data(
3816 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3817 th->h,
3818 th);
3819 }
3820 }
3821 lttv_trace_hook_remove_all(&hooks);
3822 g_array_free(hooks, TRUE);
3823 }
3824 }
3825
3826 static gboolean state_save_event_hook(void *hook_data, void *call_data)
3827 {
3828 guint *event_count = (guint*)hook_data;
3829
3830 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3831 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3832 return FALSE;
3833 else
3834 *event_count = 0;
3835
3836 LttvTracefileState *self = (LttvTracefileState *)call_data;
3837
3838 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3839
3840 LttvAttribute *saved_states_tree, *saved_state_tree;
3841
3842 LttvAttributeValue value;
3843
3844 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3845 LTTV_STATE_SAVED_STATES);
3846 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3847 value = lttv_attribute_add(saved_states_tree,
3848 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3849 *(value.v_gobject) = (GObject *)saved_state_tree;
3850 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3851 *(value.v_time) = self->parent.timestamp;
3852 lttv_state_save(tcs, saved_state_tree);
3853 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3854 self->parent.timestamp.tv_nsec);
3855
3856 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3857
3858 return FALSE;
3859 }
3860
3861 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3862 {
3863 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3864
3865 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3866
3867 return FALSE;
3868 }
3869
3870 guint lttv_state_current_cpu(LttvTracefileState *tfs)
3871 {
3872 return tfs->cpu;
3873 }
3874
3875
3876
3877 #if 0
3878 static gboolean block_start(void *hook_data, void *call_data)
3879 {
3880 LttvTracefileState *self = (LttvTracefileState *)call_data;
3881
3882 LttvTracefileState *tfcs;
3883
3884 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3885
3886 LttEventPosition *ep;
3887
3888 guint i, nb_block, nb_event, nb_tracefile;
3889
3890 LttTracefile *tf;
3891
3892 LttvAttribute *saved_states_tree, *saved_state_tree;
3893
3894 LttvAttributeValue value;
3895
3896 ep = ltt_event_position_new();
3897
3898 nb_tracefile = tcs->parent.tracefiles->len;
3899
3900 /* Count the number of events added since the last block end in any
3901 tracefile. */
3902
3903 for(i = 0 ; i < nb_tracefile ; i++) {
3904 tfcs =
3905 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3906 LttvTracefileContext, i));
3907 ltt_event_position(tfcs->parent.e, ep);
3908 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3909 tcs->nb_event += nb_event - tfcs->saved_position;
3910 tfcs->saved_position = nb_event;
3911 }
3912 g_free(ep);
3913
3914 if(tcs->nb_event >= tcs->save_interval) {
3915 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3916 LTTV_STATE_SAVED_STATES);
3917 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3918 value = lttv_attribute_add(saved_states_tree,
3919 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3920 *(value.v_gobject) = (GObject *)saved_state_tree;
3921 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3922 *(value.v_time) = self->parent.timestamp;
3923 lttv_state_save(tcs, saved_state_tree);
3924 tcs->nb_event = 0;
3925 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3926 self->parent.timestamp.tv_nsec);
3927 }
3928 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3929 return FALSE;
3930 }
3931 #endif //0
3932
3933 #if 0
3934 static gboolean block_end(void *hook_data, void *call_data)
3935 {
3936 LttvTracefileState *self = (LttvTracefileState *)call_data;
3937
3938 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3939
3940 LttTracefile *tf;
3941
3942 LttEventPosition *ep;
3943
3944 guint nb_block, nb_event;
3945
3946 ep = ltt_event_position_new();
3947 ltt_event_position(self->parent.e, ep);
3948 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3949 tcs->nb_event += nb_event - self->saved_position + 1;
3950 self->saved_position = 0;
3951 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3952 g_free(ep);
3953
3954 return FALSE;
3955 }
3956 #endif //0
3957 #if 0
3958 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3959 {
3960 LttvTraceset *traceset = self->parent.ts;
3961
3962 guint i, j, nb_trace, nb_tracefile;
3963
3964 LttvTraceState *ts;
3965
3966 LttvTracefileState *tfs;
3967
3968 LttvTraceHook hook_start, hook_end;
3969
3970 nb_trace = lttv_traceset_number(traceset);
3971 for(i = 0 ; i < nb_trace ; i++) {
3972 ts = (LttvTraceState *)self->parent.traces[i];
3973
3974 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3975 NULL, NULL, block_start, &hook_start);
3976 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3977 NULL, NULL, block_end, &hook_end);
3978
3979 nb_tracefile = ts->parent.tracefiles->len;
3980
3981 for(j = 0 ; j < nb_tracefile ; j++) {
3982 tfs =
3983 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3984 LttvTracefileContext, j));
3985 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3986 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3987 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3988 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3989 }
3990 }
3991 }
3992 #endif //0
3993
3994 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3995 {
3996 LttvTraceset *traceset = self->parent.ts;
3997
3998 guint i, j, nb_trace, nb_tracefile;
3999
4000 LttvTraceState *ts;
4001
4002 LttvTracefileState *tfs;
4003
4004
4005 nb_trace = lttv_traceset_number(traceset);
4006 for(i = 0 ; i < nb_trace ; i++) {
4007
4008 ts = (LttvTraceState *)self->parent.traces[i];
4009 nb_tracefile = ts->parent.tracefiles->len;
4010
4011 if(ts->has_precomputed_states) continue;
4012
4013 guint *event_count = g_new(guint, 1);
4014 *event_count = 0;
4015
4016 for(j = 0 ; j < nb_tracefile ; j++) {
4017 tfs =
4018 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4019 LttvTracefileContext*, j));
4020 lttv_hooks_add(tfs->parent.event,
4021 state_save_event_hook,
4022 event_count,
4023 LTTV_PRIO_STATE);
4024
4025 }
4026 }
4027
4028 lttv_process_traceset_begin(&self->parent,
4029 NULL, NULL, NULL, NULL, NULL);
4030
4031 }
4032
4033 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
4034 {
4035 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
4036
4037 lttv_state_save_add_event_hooks(tss);
4038
4039 return 0;
4040 }
4041
4042
4043 #if 0
4044 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4045 {
4046 LttvTraceset *traceset = self->parent.ts;
4047
4048 guint i, j, nb_trace, nb_tracefile;
4049
4050 LttvTraceState *ts;
4051
4052 LttvTracefileState *tfs;
4053
4054 LttvTraceHook hook_start, hook_end;
4055
4056 nb_trace = lttv_traceset_number(traceset);
4057 for(i = 0 ; i < nb_trace ; i++) {
4058 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
4059
4060 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
4061 NULL, NULL, block_start, &hook_start);
4062
4063 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
4064 NULL, NULL, block_end, &hook_end);
4065
4066 nb_tracefile = ts->parent.tracefiles->len;
4067
4068 for(j = 0 ; j < nb_tracefile ; j++) {
4069 tfs =
4070 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
4071 LttvTracefileContext, j));
4072 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4073 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
4074 lttv_hooks_remove_data(lttv_hooks_by_id_find(
4075 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
4076 }
4077 }
4078 }
4079 #endif //0
4080
4081 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
4082 {
4083 LttvTraceset *traceset = self->parent.ts;
4084
4085 guint i, j, nb_trace, nb_tracefile;
4086
4087 LttvTraceState *ts;
4088
4089 LttvTracefileState *tfs;
4090
4091 LttvHooks *after_trace = lttv_hooks_new();
4092
4093 lttv_hooks_add(after_trace,
4094 state_save_after_trace_hook,
4095 NULL,
4096 LTTV_PRIO_STATE);
4097
4098
4099 lttv_process_traceset_end(&self->parent,
4100 NULL, after_trace, NULL, NULL, NULL);
4101
4102 lttv_hooks_destroy(after_trace);
4103
4104 nb_trace = lttv_traceset_number(traceset);
4105 for(i = 0 ; i < nb_trace ; i++) {
4106
4107 ts = (LttvTraceState *)self->parent.traces[i];
4108 nb_tracefile = ts->parent.tracefiles->len;
4109
4110 if(ts->has_precomputed_states) continue;
4111
4112 guint *event_count = NULL;
4113
4114 for(j = 0 ; j < nb_tracefile ; j++) {
4115 tfs =
4116 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
4117 LttvTracefileContext*, j));
4118 event_count = lttv_hooks_remove(tfs->parent.event,
4119 state_save_event_hook);
4120 }
4121 if(event_count) g_free(event_count);
4122 }
4123 }
4124
4125 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
4126 {
4127 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
4128
4129 lttv_state_save_remove_event_hooks(tss);
4130
4131 return 0;
4132 }
4133
4134 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
4135 {
4136 LttvTraceset *traceset = self->parent.ts;
4137
4138 guint i, nb_trace;
4139
4140 int min_pos, mid_pos, max_pos;
4141
4142 guint call_rest = 0;
4143
4144 LttvTraceState *tcs;
4145
4146 LttvAttributeValue value;
4147
4148 LttvAttributeType type;
4149
4150 LttvAttributeName name;
4151
4152 gboolean is_named;
4153
4154 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree = NULL;
4155
4156 //g_tree_destroy(self->parent.pqueue);
4157 //self->parent.pqueue = g_tree_new(compare_tracefile);
4158
4159 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
4160
4161 nb_trace = lttv_traceset_number(traceset);
4162 for(i = 0 ; i < nb_trace ; i++) {
4163 tcs = (LttvTraceState *)self->parent.traces[i];
4164
4165 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
4166 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
4167 LTTV_STATE_SAVED_STATES);
4168 min_pos = -1;
4169
4170 if(saved_states_tree) {
4171 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
4172 mid_pos = max_pos / 2;
4173 while(min_pos < max_pos) {
4174 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
4175 &is_named);
4176 g_assert(type == LTTV_GOBJECT);
4177 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
4178 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
4179 &value);
4180 g_assert(type == LTTV_TIME);
4181 if(ltt_time_compare(*(value.v_time), t) < 0) {
4182 min_pos = mid_pos;
4183 closest_tree = saved_state_tree;
4184 }
4185 else max_pos = mid_pos - 1;
4186
4187 mid_pos = (min_pos + max_pos + 1) / 2;
4188 }
4189 }
4190
4191 /* restore the closest earlier saved state */
4192 if(min_pos != -1) {
4193 lttv_state_restore(tcs, closest_tree);
4194 call_rest = 1;
4195 }
4196
4197 /* There is no saved state, yet we want to have it. Restart at T0 */
4198 else {
4199 restore_init_state(tcs);
4200 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
4201 }
4202 }
4203 /* We want to seek quickly without restoring/updating the state */
4204 else {
4205 restore_init_state(tcs);
4206 lttv_process_trace_seek_time(&(tcs->parent), t);
4207 }
4208 }
4209 if(!call_rest) g_info("NOT Calling restore");
4210 }
4211
4212
4213 static void
4214 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
4215 {
4216 }
4217
4218
4219 static void
4220 traceset_state_finalize (LttvTracesetState *self)
4221 {
4222 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
4223 finalize(G_OBJECT(self));
4224 }
4225
4226
4227 static void
4228 traceset_state_class_init (LttvTracesetContextClass *klass)
4229 {
4230 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4231
4232 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
4233 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
4234 klass->fini = (void (*)(LttvTracesetContext *self))fini;
4235 klass->new_traceset_context = new_traceset_context;
4236 klass->new_trace_context = new_trace_context;
4237 klass->new_tracefile_context = new_tracefile_context;
4238 }
4239
4240
4241 GType
4242 lttv_traceset_state_get_type(void)
4243 {
4244 static GType type = 0;
4245 if (type == 0) {
4246 static const GTypeInfo info = {
4247 sizeof (LttvTracesetStateClass),
4248 NULL, /* base_init */
4249 NULL, /* base_finalize */
4250 (GClassInitFunc) traceset_state_class_init, /* class_init */
4251 NULL, /* class_finalize */
4252 NULL, /* class_data */
4253 sizeof (LttvTracesetState),
4254 0, /* n_preallocs */
4255 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
4256 NULL /* value handling */
4257 };
4258
4259 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
4260 &info, 0);
4261 }
4262 return type;
4263 }
4264
4265
4266 static void
4267 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
4268 {
4269 }
4270
4271
4272 static void
4273 trace_state_finalize (LttvTraceState *self)
4274 {
4275 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
4276 finalize(G_OBJECT(self));
4277 }
4278
4279
4280 static void
4281 trace_state_class_init (LttvTraceStateClass *klass)
4282 {
4283 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4284
4285 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
4286 klass->state_save = state_save;
4287 klass->state_restore = state_restore;
4288 klass->state_saved_free = state_saved_free;
4289 }
4290
4291
4292 GType
4293 lttv_trace_state_get_type(void)
4294 {
4295 static GType type = 0;
4296 if (type == 0) {
4297 static const GTypeInfo info = {
4298 sizeof (LttvTraceStateClass),
4299 NULL, /* base_init */
4300 NULL, /* base_finalize */
4301 (GClassInitFunc) trace_state_class_init, /* class_init */
4302 NULL, /* class_finalize */
4303 NULL, /* class_data */
4304 sizeof (LttvTraceState),
4305 0, /* n_preallocs */
4306 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
4307 NULL /* value handling */
4308 };
4309
4310 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
4311 "LttvTraceStateType", &info, 0);
4312 }
4313 return type;
4314 }
4315
4316
4317 static void
4318 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
4319 {
4320 }
4321
4322
4323 static void
4324 tracefile_state_finalize (LttvTracefileState *self)
4325 {
4326 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
4327 finalize(G_OBJECT(self));
4328 }
4329
4330
4331 static void
4332 tracefile_state_class_init (LttvTracefileStateClass *klass)
4333 {
4334 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
4335
4336 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
4337 }
4338
4339
4340 GType
4341 lttv_tracefile_state_get_type(void)
4342 {
4343 static GType type = 0;
4344 if (type == 0) {
4345 static const GTypeInfo info = {
4346 sizeof (LttvTracefileStateClass),
4347 NULL, /* base_init */
4348 NULL, /* base_finalize */
4349 (GClassInitFunc) tracefile_state_class_init, /* class_init */
4350 NULL, /* class_finalize */
4351 NULL, /* class_data */
4352 sizeof (LttvTracefileState),
4353 0, /* n_preallocs */
4354 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
4355 NULL /* value handling */
4356 };
4357
4358 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
4359 "LttvTracefileStateType", &info, 0);
4360 }
4361 return type;
4362 }
4363
4364
4365 static void module_init()
4366 {
4367 LTTV_STATE_UNNAMED = g_quark_from_string("");
4368 LTTV_STATE_UNBRANDED = g_quark_from_string("");
4369 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
4370 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
4371 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
4372 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
4373 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
4374 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
4375 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
4376 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
4377 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
4378 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
4379 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
4380 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
4381 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
4382 LTTV_STATE_RUN = g_quark_from_string("RUN");
4383 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
4384 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
4385 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
4386 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
4387 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
4388 LTTV_STATE_PROCESS = g_quark_from_string("process");
4389 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
4390 LTTV_STATE_EVENT = g_quark_from_string("event");
4391 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
4392 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
4393 LTTV_STATE_TIME = g_quark_from_string("time");
4394 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
4395 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
4396 LTTV_STATE_TRACE_STATE_USE_COUNT =
4397 g_quark_from_string("trace_state_use_count");
4398 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
4399 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
4400 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
4401 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
4402 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
4403 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
4404
4405 LTT_CHANNEL_FD_STATE = g_quark_from_string("fd_state");
4406 LTT_CHANNEL_GLOBAL_STATE = g_quark_from_string("global_state");
4407 LTT_CHANNEL_IRQ_STATE = g_quark_from_string("irq_state");
4408 LTT_CHANNEL_MODULE_STATE = g_quark_from_string("module_state");
4409 LTT_CHANNEL_NETIF_STATE = g_quark_from_string("netif_state");
4410 LTT_CHANNEL_SOFTIRQ_STATE = g_quark_from_string("softirq_state");
4411 LTT_CHANNEL_SWAP_STATE = g_quark_from_string("swap_state");
4412 LTT_CHANNEL_SYSCALL_STATE = g_quark_from_string("syscall_state");
4413 LTT_CHANNEL_TASK_STATE = g_quark_from_string("task_state");
4414 LTT_CHANNEL_VM_STATE = g_quark_from_string("vm_state");
4415 LTT_CHANNEL_KPROBE_STATE = g_quark_from_string("kprobe_state");
4416 LTT_CHANNEL_FS = g_quark_from_string("fs");
4417 LTT_CHANNEL_KERNEL = g_quark_from_string("kernel");
4418 LTT_CHANNEL_MM = g_quark_from_string("mm");
4419 LTT_CHANNEL_USERSPACE = g_quark_from_string("userspace");
4420 LTT_CHANNEL_BLOCK = g_quark_from_string("block");
4421
4422 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
4423 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
4424 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
4425 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
4426 LTT_EVENT_PAGE_FAULT_ENTRY = g_quark_from_string("page_fault_entry");
4427 LTT_EVENT_PAGE_FAULT_EXIT = g_quark_from_string("page_fault_exit");
4428 LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY = g_quark_from_string("page_fault_nosem_entry");
4429 LTT_EVENT_PAGE_FAULT_NOSEM_EXIT = g_quark_from_string("page_fault_nosem_exit");
4430 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
4431 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
4432 LTT_EVENT_SOFT_IRQ_RAISE = g_quark_from_string("softirq_raise");
4433 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
4434 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
4435 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
4436 LTT_EVENT_SCHED_TRY_WAKEUP = g_quark_from_string("sched_try_wakeup");
4437 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
4438 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
4439 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
4440 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
4441 LTT_EVENT_EXEC = g_quark_from_string("exec");
4442 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
4443 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
4444 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4445 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
4446 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
4447 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4448 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
4449 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");
4450 LTT_EVENT_SYS_CALL_TABLE = g_quark_from_string("sys_call_table");
4451 LTT_EVENT_SOFTIRQ_VEC = g_quark_from_string("softirq_vec");
4452 LTT_EVENT_KPROBE_TABLE = g_quark_from_string("kprobe_table");
4453 LTT_EVENT_KPROBE = g_quark_from_string("kprobe");
4454 LTT_EVENT_OPEN = g_quark_from_string("open");
4455 LTT_EVENT_READ = g_quark_from_string("read");
4456 LTT_EVENT_POLL_EVENT = g_quark_from_string("poll_event");
4457
4458 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4459 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4460 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
4461 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
4462 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4463 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4464 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
4465 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4466 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4467 LTT_FIELD_PID = g_quark_from_string("pid");
4468 LTT_FIELD_TGID = g_quark_from_string("tgid");
4469 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
4470 LTT_FIELD_FILENAME = g_quark_from_string("filename");
4471 LTT_FIELD_NAME = g_quark_from_string("name");
4472 LTT_FIELD_TYPE = g_quark_from_string("type");
4473 LTT_FIELD_MODE = g_quark_from_string("mode");
4474 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4475 LTT_FIELD_STATUS = g_quark_from_string("status");
4476 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4477 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
4478 LTT_FIELD_MAJOR = g_quark_from_string("major");
4479 LTT_FIELD_MINOR = g_quark_from_string("minor");
4480 LTT_FIELD_OPERATION = g_quark_from_string("direction");
4481 LTT_FIELD_ACTION = g_quark_from_string("action");
4482 LTT_FIELD_ID = g_quark_from_string("id");
4483 LTT_FIELD_ADDRESS = g_quark_from_string("address");
4484 LTT_FIELD_SYMBOL = g_quark_from_string("symbol");
4485 LTT_FIELD_IP = g_quark_from_string("ip");
4486 LTT_FIELD_FD = g_quark_from_string("fd");
4487
4488 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4489 LTTV_CPU_IDLE = g_quark_from_string("idle");
4490 LTTV_CPU_BUSY = g_quark_from_string("busy");
4491 LTTV_CPU_IRQ = g_quark_from_string("irq");
4492 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
4493 LTTV_CPU_TRAP = g_quark_from_string("trap");
4494
4495 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4496 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4497 LTTV_IRQ_BUSY = g_quark_from_string("busy");
4498
4499 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4500 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4501 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4502 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
4503 }
4504
4505 static void module_destroy()
4506 {
4507 }
4508
4509
4510 LTTV_MODULE("state", "State computation", \
4511 "Update the system state, possibly saving it at intervals", \
4512 module_init, module_destroy)
4513
4514
4515
This page took 0.188632 seconds and 5 git commands to generate.