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