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