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