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