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