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