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