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