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