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