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