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