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