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