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