type cast FIELD_ARRAY
[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 LttvTraceHook th;
1620
1621 GString *fe_name = g_string_new("");
1622
1623 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1624
1625 LttvAttributeValue v;
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 if(!lttv_trace_find_hook(tcs->parent.t,
1633 LTT_EVENT_SYSCALL_ENTRY,
1634 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
1635 NULL, NULL)) {
1636
1637 // th = lttv_trace_hook_get_first(&th);
1638 //
1639 // t = ltt_field_type(th->f1);
1640 // nb = ltt_type_element_number(t);
1641 //
1642 lttv_trace_hook_destroy(&th);
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
1667 if(!lttv_trace_find_hook(tcs->parent.t,
1668 LTT_EVENT_TRAP_ENTRY,
1669 LTT_FIELD_TRAP_ID, 0, 0,
1670 NULL, NULL, &th)) {
1671
1672 // th = lttv_trace_hook_get_first(&th);
1673 //
1674 // t = ltt_field_type(th->f1);
1675 // //nb = ltt_type_element_number(t);
1676 //
1677 lttv_trace_hook_destroy(&th);
1678
1679 // name_tables->trap_names = g_new(GQuark, nb);
1680 // for(i = 0 ; i < nb ; i++) {
1681 // name_tables->trap_names[i] = g_quark_from_string(
1682 // ltt_enum_string_get(t, i));
1683 // }
1684
1685 name_tables->nb_traps = 256;
1686 name_tables->trap_names = g_new(GQuark, 256);
1687 for(i = 0 ; i < 256 ; i++) {
1688 g_string_printf(fe_name, "trap %d", i);
1689 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1690 }
1691 } else {
1692 name_tables->trap_names = NULL;
1693 name_tables->nb_traps = 0;
1694 }
1695
1696 if(!lttv_trace_find_hook(tcs->parent.t,
1697 LTT_EVENT_IRQ_ENTRY,
1698 LTT_FIELD_IRQ_ID, 0, 0,
1699 NULL, NULL, &th)) {
1700
1701 lttv_trace_hook_destroy(&th);
1702
1703 /*
1704 name_tables->irq_names = g_new(GQuark, nb);
1705 for(i = 0 ; i < nb ; i++) {
1706 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1707 }
1708 */
1709
1710 name_tables->nb_irqs = 256;
1711 name_tables->irq_names = g_new(GQuark, 256);
1712 for(i = 0 ; i < 256 ; i++) {
1713 g_string_printf(fe_name, "irq %d", i);
1714 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1715 }
1716 } else {
1717 name_tables->nb_irqs = 0;
1718 name_tables->irq_names = NULL;
1719 }
1720 /*
1721 name_tables->soft_irq_names = g_new(GQuark, nb);
1722 for(i = 0 ; i < nb ; i++) {
1723 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1724 }
1725 */
1726
1727 name_tables->nb_softirqs = 256;
1728 name_tables->soft_irq_names = g_new(GQuark, 256);
1729 for(i = 0 ; i < 256 ; i++) {
1730 g_string_printf(fe_name, "softirq %d", i);
1731 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1732 }
1733
1734
1735 g_string_free(fe_name, TRUE);
1736 }
1737
1738
1739 static void
1740 get_name_tables(LttvTraceState *tcs)
1741 {
1742 LttvNameTables *name_tables;
1743
1744 LttvAttributeValue v;
1745
1746 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1747 LTTV_POINTER, &v);
1748 g_assert(*(v.v_pointer) != NULL);
1749 name_tables = (LttvNameTables *)*(v.v_pointer);
1750 //tcs->eventtype_names = name_tables->eventtype_names;
1751 tcs->syscall_names = name_tables->syscall_names;
1752 tcs->nb_syscalls = name_tables->nb_syscalls;
1753 tcs->trap_names = name_tables->trap_names;
1754 tcs->nb_traps = name_tables->nb_traps;
1755 tcs->irq_names = name_tables->irq_names;
1756 tcs->soft_irq_names = name_tables->soft_irq_names;
1757 tcs->nb_irqs = name_tables->nb_irqs;
1758 tcs->nb_softirqs = name_tables->nb_softirqs;
1759 }
1760
1761
1762 static void
1763 free_name_tables(LttvTraceState *tcs)
1764 {
1765 LttvNameTables *name_tables;
1766
1767 LttvAttributeValue v;
1768
1769 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1770 LTTV_POINTER, &v);
1771 name_tables = (LttvNameTables *)*(v.v_pointer);
1772 *(v.v_pointer) = NULL;
1773
1774 // g_free(name_tables->eventtype_names);
1775 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1776 if(name_tables->trap_names) g_free(name_tables->trap_names);
1777 if(name_tables->irq_names) g_free(name_tables->irq_names);
1778 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1779 if(name_tables) g_free(name_tables);
1780 }
1781
1782 #ifdef HASH_TABLE_DEBUG
1783
1784 static void test_process(gpointer key, gpointer value, gpointer user_data)
1785 {
1786 LttvProcessState *process = (LttvProcessState *)value;
1787
1788 /* Test for process corruption */
1789 guint stack_len = process->execution_stack->len;
1790 }
1791
1792 static void hash_table_check(GHashTable *table)
1793 {
1794 g_hash_table_foreach(table, test_process, NULL);
1795 }
1796
1797
1798 #endif
1799
1800 /* clears the stack and sets the state passed as argument */
1801 static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1802 {
1803 g_array_set_size(cpust->mode_stack, 1);
1804 ((GQuark *)cpust->mode_stack->data)[0] = state;
1805 }
1806
1807 static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1808 {
1809 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1810 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1811 }
1812
1813 static void cpu_pop_mode(LttvCPUState *cpust)
1814 {
1815 if(cpust->mode_stack->len <= 1)
1816 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1817 else
1818 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1819 }
1820
1821 /* clears the stack and sets the state passed as argument */
1822 static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
1823 {
1824 g_array_set_size(bdevst->mode_stack, 1);
1825 ((GQuark *)bdevst->mode_stack->data)[0] = state;
1826 }
1827
1828 static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
1829 {
1830 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
1831 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
1832 }
1833
1834 static void bdev_pop_mode(LttvBdevState *bdevst)
1835 {
1836 if(bdevst->mode_stack->len <= 1)
1837 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
1838 else
1839 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
1840 }
1841
1842 static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
1843 {
1844 g_array_set_size(irqst->mode_stack, 1);
1845 ((GQuark *)irqst->mode_stack->data)[0] = state;
1846 }
1847
1848 static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
1849 {
1850 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
1851 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
1852 }
1853
1854 static void irq_pop_mode(LttvIRQState *irqst)
1855 {
1856 if(irqst->mode_stack->len <= 1)
1857 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
1858 else
1859 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
1860 }
1861
1862 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1863 guint state_id)
1864 {
1865 LttvExecutionState *es;
1866
1867 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1868 guint cpu = tfs->cpu;
1869
1870 #ifdef HASH_TABLE_DEBUG
1871 hash_table_check(ts->processes);
1872 #endif
1873 LttvProcessState *process = ts->running_process[cpu];
1874
1875 guint depth = process->execution_stack->len;
1876
1877 process->execution_stack =
1878 g_array_set_size(process->execution_stack, depth + 1);
1879 /* Keep in sync */
1880 process->state =
1881 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1882
1883 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1884 es->t = t;
1885 es->n = state_id;
1886 es->entry = es->change = tfs->parent.timestamp;
1887 es->cum_cpu_time = ltt_time_zero;
1888 es->s = process->state->s;
1889 process->state = es;
1890 }
1891
1892 /* pop state
1893 * return 1 when empty, else 0 */
1894 int lttv_state_pop_state_cleanup(LttvProcessState *process,
1895 LttvTracefileState *tfs)
1896 {
1897 guint depth = process->execution_stack->len;
1898
1899 if(depth == 1){
1900 return 1;
1901 }
1902
1903 process->execution_stack =
1904 g_array_set_size(process->execution_stack, depth - 1);
1905 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1906 depth - 2);
1907 process->state->change = tfs->parent.timestamp;
1908
1909 return 0;
1910 }
1911
1912 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1913 {
1914 guint cpu = tfs->cpu;
1915 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1916 LttvProcessState *process = ts->running_process[cpu];
1917
1918 guint depth = process->execution_stack->len;
1919
1920 if(process->state->t != t){
1921 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1922 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1923 g_info("process state has %s when pop_int is %s\n",
1924 g_quark_to_string(process->state->t),
1925 g_quark_to_string(t));
1926 g_info("{ %u, %u, %s, %s, %s }\n",
1927 process->pid,
1928 process->ppid,
1929 g_quark_to_string(process->name),
1930 g_quark_to_string(process->brand),
1931 g_quark_to_string(process->state->s));
1932 return;
1933 }
1934
1935 if(depth == 1){
1936 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1937 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1938 return;
1939 }
1940
1941 process->execution_stack =
1942 g_array_set_size(process->execution_stack, depth - 1);
1943 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1944 depth - 2);
1945 process->state->change = tfs->parent.timestamp;
1946 }
1947
1948 struct search_result {
1949 const LttTime *time; /* Requested time */
1950 LttTime *best; /* Best result */
1951 };
1952
1953 static gint search_usertrace(gconstpointer a, gconstpointer b)
1954 {
1955 const LttTime *elem_time = (const LttTime*)a;
1956 /* Explicit non const cast */
1957 struct search_result *res = (struct search_result *)b;
1958
1959 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1960 /* The usertrace was created before the schedchange */
1961 /* Get larger keys */
1962 return 1;
1963 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1964 /* The usertrace was created after the schedchange time */
1965 /* Get smaller keys */
1966 if(res->best) {
1967 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1968 res->best = (LttTime *)elem_time;
1969 }
1970 } else {
1971 res->best = (LttTime *)elem_time;
1972 }
1973 return -1;
1974 }
1975 return 0;
1976 }
1977
1978 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1979 guint pid, const LttTime *timestamp)
1980 {
1981 LttvTracefileState *tfs = NULL;
1982 struct search_result res;
1983 /* Find the usertrace associated with a pid and time interval.
1984 * Search in the usertraces by PID (within a hash) and then, for each
1985 * corresponding element of the array, find the first one with creation
1986 * timestamp the lowest, but higher or equal to "timestamp". */
1987 res.time = timestamp;
1988 res.best = NULL;
1989 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1990 if(usertrace_tree) {
1991 g_tree_search(usertrace_tree, search_usertrace, &res);
1992 if(res.best)
1993 tfs = g_tree_lookup(usertrace_tree, res.best);
1994 }
1995
1996 return tfs;
1997 }
1998
1999
2000 LttvProcessState *
2001 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
2002 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
2003 {
2004 LttvProcessState *process = g_new(LttvProcessState, 1);
2005
2006 LttvExecutionState *es;
2007
2008 char buffer[128];
2009
2010 process->pid = pid;
2011 process->tgid = tgid;
2012 process->cpu = cpu;
2013 process->name = name;
2014 process->brand = LTTV_STATE_UNBRANDED;
2015 //process->last_cpu = tfs->cpu_name;
2016 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2017 process->type = LTTV_STATE_USER_THREAD;
2018 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2019 process->current_function = 0; //function 0x0 by default.
2020
2021 g_info("Process %u, core %p", process->pid, process);
2022 g_hash_table_insert(tcs->processes, process, process);
2023
2024 if(parent) {
2025 process->ppid = parent->pid;
2026 process->creation_time = *timestamp;
2027 }
2028
2029 /* No parent. This process exists but we are missing all information about
2030 its creation. The birth time is set to zero but we remember the time of
2031 insertion */
2032
2033 else {
2034 process->ppid = 0;
2035 process->creation_time = ltt_time_zero;
2036 }
2037
2038 process->insertion_time = *timestamp;
2039 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2040 process->creation_time.tv_nsec);
2041 process->pid_time = g_quark_from_string(buffer);
2042 process->cpu = cpu;
2043 //process->last_cpu = tfs->cpu_name;
2044 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2045 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2046 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2047 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2048 es = process->state = &g_array_index(process->execution_stack,
2049 LttvExecutionState, 0);
2050 es->t = LTTV_STATE_USER_MODE;
2051 es->n = LTTV_STATE_SUBMODE_NONE;
2052 es->entry = *timestamp;
2053 //g_assert(timestamp->tv_sec != 0);
2054 es->change = *timestamp;
2055 es->cum_cpu_time = ltt_time_zero;
2056 es->s = LTTV_STATE_RUN;
2057
2058 es = process->state = &g_array_index(process->execution_stack,
2059 LttvExecutionState, 1);
2060 es->t = LTTV_STATE_SYSCALL;
2061 es->n = LTTV_STATE_SUBMODE_NONE;
2062 es->entry = *timestamp;
2063 //g_assert(timestamp->tv_sec != 0);
2064 es->change = *timestamp;
2065 es->cum_cpu_time = ltt_time_zero;
2066 es->s = LTTV_STATE_WAIT_FORK;
2067
2068 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2069 process->user_stack = g_array_sized_new(FALSE, FALSE,
2070 sizeof(guint64), 0);
2071
2072 return process;
2073 }
2074
2075 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
2076 guint pid)
2077 {
2078 LttvProcessState key;
2079 LttvProcessState *process;
2080
2081 key.pid = pid;
2082 key.cpu = cpu;
2083 process = g_hash_table_lookup(ts->processes, &key);
2084 return process;
2085 }
2086
2087 LttvProcessState *
2088 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
2089 const LttTime *timestamp)
2090 {
2091 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2092 LttvExecutionState *es;
2093
2094 /* Put ltt_time_zero creation time for unexisting processes */
2095 if(unlikely(process == NULL)) {
2096 process = lttv_state_create_process(ts,
2097 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2098 /* We are not sure is it's a kernel thread or normal thread, put the
2099 * bottom stack state to unknown */
2100 process->execution_stack =
2101 g_array_set_size(process->execution_stack, 1);
2102 process->state = es =
2103 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2104 es->t = LTTV_STATE_MODE_UNKNOWN;
2105 es->s = LTTV_STATE_UNNAMED;
2106 }
2107 return process;
2108 }
2109
2110 /* FIXME : this function should be called when we receive an event telling that
2111 * release_task has been called in the kernel. In happens generally when
2112 * the parent waits for its child terminaison, but may also happen in special
2113 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2114 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2115 * of a killed thread ground, but isn't the leader.
2116 */
2117 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
2118 {
2119 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2120 LttvProcessState key;
2121
2122 key.pid = process->pid;
2123 key.cpu = process->cpu;
2124 g_hash_table_remove(ts->processes, &key);
2125 g_array_free(process->execution_stack, TRUE);
2126 g_array_free(process->user_stack, TRUE);
2127 g_free(process);
2128 }
2129
2130
2131 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2132 {
2133 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2134 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
2135 g_free(value);
2136 }
2137
2138
2139 static void lttv_state_free_process_table(GHashTable *processes)
2140 {
2141 g_hash_table_foreach(processes, free_process_state, NULL);
2142 g_hash_table_destroy(processes);
2143 }
2144
2145
2146 static gboolean syscall_entry(void *hook_data, void *call_data)
2147 {
2148 LttvTracefileState *s = (LttvTracefileState *)call_data;
2149 guint cpu = s->cpu;
2150 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2151 LttvProcessState *process = ts->running_process[cpu];
2152 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2153 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2154 struct marker_field *f = th->f1;
2155
2156 LttvExecutionSubmode submode;
2157
2158 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2159 guint syscall = ltt_event_get_unsigned(e, f);
2160
2161 if(syscall < nb_syscalls) {
2162 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2163 syscall];
2164 } else {
2165 /* Fixup an incomplete syscall table */
2166 GString *string = g_string_new("");
2167 g_string_printf(string, "syscall %u", syscall);
2168 submode = g_quark_from_string(string->str);
2169 g_string_free(string, TRUE);
2170 }
2171 /* There can be no system call from PID 0 : unknown state */
2172 if(process->pid != 0)
2173 push_state(s, LTTV_STATE_SYSCALL, submode);
2174 return FALSE;
2175 }
2176
2177
2178 static gboolean syscall_exit(void *hook_data, void *call_data)
2179 {
2180 LttvTracefileState *s = (LttvTracefileState *)call_data;
2181 guint cpu = s->cpu;
2182 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2183 LttvProcessState *process = ts->running_process[cpu];
2184
2185 /* There can be no system call from PID 0 : unknown state */
2186 if(process->pid != 0)
2187 pop_state(s, LTTV_STATE_SYSCALL);
2188 return FALSE;
2189 }
2190
2191
2192 static gboolean trap_entry(void *hook_data, void *call_data)
2193 {
2194 LttvTracefileState *s = (LttvTracefileState *)call_data;
2195 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2196 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2197 struct marker_field *f = th->f1;
2198
2199 LttvExecutionSubmode submode;
2200
2201 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2202 guint64 trap = ltt_event_get_long_unsigned(e, f);
2203
2204 if(trap < nb_traps) {
2205 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2206 } else {
2207 /* Fixup an incomplete trap table */
2208 GString *string = g_string_new("");
2209 g_string_printf(string, "trap %llu", trap);
2210 submode = g_quark_from_string(string->str);
2211 g_string_free(string, TRUE);
2212 }
2213
2214 push_state(s, LTTV_STATE_TRAP, submode);
2215
2216 /* update cpu status */
2217 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2218
2219 return FALSE;
2220 }
2221
2222 static gboolean trap_exit(void *hook_data, void *call_data)
2223 {
2224 LttvTracefileState *s = (LttvTracefileState *)call_data;
2225
2226 pop_state(s, LTTV_STATE_TRAP);
2227
2228 /* update cpu status */
2229 cpu_pop_mode(s->cpu_state);
2230
2231 return FALSE;
2232 }
2233
2234 static gboolean irq_entry(void *hook_data, void *call_data)
2235 {
2236 LttvTracefileState *s = (LttvTracefileState *)call_data;
2237 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2238 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2239 //guint8 ev_id = ltt_event_eventtype_id(e);
2240 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2241 g_assert(th->f1 != NULL);
2242 struct marker_field *f = th->f1;
2243
2244 LttvExecutionSubmode submode;
2245 guint64 irq = ltt_event_get_long_unsigned(e, f);
2246 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
2247
2248 if(irq < nb_irqs) {
2249 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2250 } else {
2251 /* Fixup an incomplete irq table */
2252 GString *string = g_string_new("");
2253 g_string_printf(string, "irq %llu", irq);
2254 submode = g_quark_from_string(string->str);
2255 g_string_free(string, TRUE);
2256 }
2257
2258 /* Do something with the info about being in user or system mode when int? */
2259 push_state(s, LTTV_STATE_IRQ, submode);
2260
2261 /* update cpu status */
2262 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2263
2264 /* update irq status */
2265 s->cpu_state->last_irq = irq;
2266 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2267
2268 return FALSE;
2269 }
2270
2271 static gboolean soft_irq_exit(void *hook_data, void *call_data)
2272 {
2273 LttvTracefileState *s = (LttvTracefileState *)call_data;
2274
2275 pop_state(s, LTTV_STATE_SOFT_IRQ);
2276 return FALSE;
2277 }
2278
2279
2280
2281 static gboolean irq_exit(void *hook_data, void *call_data)
2282 {
2283 LttvTracefileState *s = (LttvTracefileState *)call_data;
2284 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2285
2286 pop_state(s, LTTV_STATE_IRQ);
2287
2288 /* update cpu status */
2289 cpu_pop_mode(s->cpu_state);
2290
2291 /* update irq status */
2292 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2293
2294 return FALSE;
2295 }
2296
2297 static gboolean soft_irq_entry(void *hook_data, void *call_data)
2298 {
2299 LttvTracefileState *s = (LttvTracefileState *)call_data;
2300 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2301 //guint8 ev_id = ltt_event_eventtype_id(e);
2302 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2303 g_assert(th->f1 != NULL);
2304 struct marker_field *f = th->f1;
2305
2306 LttvExecutionSubmode submode;
2307 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2308 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
2309
2310 if(softirq < nb_softirqs) {
2311 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2312 } else {
2313 /* Fixup an incomplete irq table */
2314 GString *string = g_string_new("");
2315 g_string_printf(string, "softirq %llu", softirq);
2316 submode = g_quark_from_string(string->str);
2317 g_string_free(string, TRUE);
2318 }
2319
2320 /* Do something with the info about being in user or system mode when int? */
2321 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2322 return FALSE;
2323 }
2324
2325 static gboolean enum_interrupt(void *hook_data, void *call_data)
2326 {
2327 LttvTracefileState *s = (LttvTracefileState *)call_data;
2328 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2329 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2330 //guint8 ev_id = ltt_event_eventtype_id(e);
2331 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2332
2333 GQuark action = g_quark_from_string(ltt_event_get_string(e, th->f1));
2334 guint irq = ltt_event_get_long_unsigned(e, th->f2);
2335
2336 ts->irq_names[irq] = action;
2337
2338 return FALSE;
2339 }
2340
2341
2342 static gboolean bdev_request_issue(void *hook_data, void *call_data)
2343 {
2344 LttvTracefileState *s = (LttvTracefileState *)call_data;
2345 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2346 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2347 //guint8 ev_id = ltt_event_eventtype_id(e);
2348 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2349
2350 guint major = ltt_event_get_long_unsigned(e, th->f1);
2351 guint minor = ltt_event_get_long_unsigned(e, th->f2);
2352 guint oper = ltt_event_get_long_unsigned(e, th->f3);
2353 guint16 devcode = MKDEV(major,minor);
2354
2355 /* have we seen this block device before? */
2356 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2357
2358 if(oper == 0)
2359 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2360 else
2361 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2362
2363 return FALSE;
2364 }
2365
2366 static gboolean bdev_request_complete(void *hook_data, void *call_data)
2367 {
2368 LttvTracefileState *s = (LttvTracefileState *)call_data;
2369 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2370 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2371 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2372
2373 guint major = ltt_event_get_long_unsigned(e, th->f1);
2374 guint minor = ltt_event_get_long_unsigned(e, th->f2);
2375 //guint oper = ltt_event_get_long_unsigned(e, th->f3);
2376 guint16 devcode = MKDEV(major,minor);
2377
2378 /* have we seen this block device before? */
2379 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2380
2381 /* update block device */
2382 bdev_pop_mode(bdev);
2383
2384 return FALSE;
2385 }
2386
2387 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2388 {
2389 guint64 *new_func;
2390
2391 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2392 guint cpu = tfs->cpu;
2393 LttvProcessState *process = ts->running_process[cpu];
2394
2395 guint depth = process->user_stack->len;
2396
2397 process->user_stack =
2398 g_array_set_size(process->user_stack, depth + 1);
2399
2400 new_func = &g_array_index(process->user_stack, guint64, depth);
2401 *new_func = funcptr;
2402 process->current_function = funcptr;
2403 }
2404
2405 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2406 {
2407 guint cpu = tfs->cpu;
2408 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2409 LttvProcessState *process = ts->running_process[cpu];
2410
2411 if(process->current_function != funcptr){
2412 g_info("Different functions (%lu.%09lu): ignore it\n",
2413 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2414 g_info("process state has %llu when pop_function is %llu\n",
2415 process->current_function, funcptr);
2416 g_info("{ %u, %u, %s, %s, %s }\n",
2417 process->pid,
2418 process->ppid,
2419 g_quark_to_string(process->name),
2420 g_quark_to_string(process->brand),
2421 g_quark_to_string(process->state->s));
2422 return;
2423 }
2424 guint depth = process->user_stack->len;
2425
2426 if(depth == 0){
2427 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2428 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2429 return;
2430 }
2431
2432 process->user_stack =
2433 g_array_set_size(process->user_stack, depth - 1);
2434 process->current_function =
2435 g_array_index(process->user_stack, guint64, depth - 2);
2436 }
2437
2438
2439 static gboolean function_entry(void *hook_data, void *call_data)
2440 {
2441 LttvTracefileState *s = (LttvTracefileState *)call_data;
2442 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2443 //guint8 ev_id = ltt_event_eventtype_id(e);
2444 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2445 g_assert(th->f1 != NULL);
2446 struct marker_field *f = th->f1;
2447 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2448
2449 push_function(s, funcptr);
2450 return FALSE;
2451 }
2452
2453 static gboolean function_exit(void *hook_data, void *call_data)
2454 {
2455 LttvTracefileState *s = (LttvTracefileState *)call_data;
2456 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2457 //guint8 ev_id = ltt_event_eventtype_id(e);
2458 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2459 g_assert(th->f1 != NULL);
2460 struct marker_field *f = th->f1;
2461 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2462
2463 pop_function(s, funcptr);
2464 return FALSE;
2465 }
2466
2467 static gboolean schedchange(void *hook_data, void *call_data)
2468 {
2469 LttvTracefileState *s = (LttvTracefileState *)call_data;
2470 guint cpu = s->cpu;
2471 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2472 LttvProcessState *process = ts->running_process[cpu];
2473 //LttvProcessState *old_process = ts->running_process[cpu];
2474
2475 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2476 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2477 guint pid_in, pid_out;
2478 gint64 state_out;
2479
2480 pid_out = ltt_event_get_unsigned(e, th->f1);
2481 pid_in = ltt_event_get_unsigned(e, th->f2);
2482 state_out = ltt_event_get_long_int(e, th->f3);
2483
2484 if(likely(process != NULL)) {
2485
2486 /* We could not know but it was not the idle process executing.
2487 This should only happen at the beginning, before the first schedule
2488 event, and when the initial information (current process for each CPU)
2489 is missing. It is not obvious how we could, after the fact, compensate
2490 the wrongly attributed statistics. */
2491
2492 //This test only makes sense once the state is known and if there is no
2493 //missing events. We need to silently ignore schedchange coming after a
2494 //process_free, or it causes glitches. (FIXME)
2495 //if(unlikely(process->pid != pid_out)) {
2496 // g_assert(process->pid == 0);
2497 //}
2498 if(process->pid == 0
2499 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2500 if(pid_out == 0) {
2501 /* Scheduling out of pid 0 at beginning of the trace :
2502 * we know for sure it is in syscall mode at this point. */
2503 g_assert(process->execution_stack->len == 1);
2504 process->state->t = LTTV_STATE_SYSCALL;
2505 process->state->s = LTTV_STATE_WAIT;
2506 process->state->change = s->parent.timestamp;
2507 process->state->entry = s->parent.timestamp;
2508 }
2509 } else {
2510 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2511 process->state->s = LTTV_STATE_ZOMBIE;
2512 process->state->change = s->parent.timestamp;
2513 } else {
2514 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2515 else process->state->s = LTTV_STATE_WAIT;
2516 process->state->change = s->parent.timestamp;
2517 }
2518
2519 if(state_out == 32 || state_out == 128)
2520 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
2521 /* see sched.h for states */
2522 }
2523 }
2524 process = ts->running_process[cpu] =
2525 lttv_state_find_process_or_create(
2526 (LttvTraceState*)s->parent.t_context,
2527 cpu, pid_in,
2528 &s->parent.timestamp);
2529 process->state->s = LTTV_STATE_RUN;
2530 process->cpu = cpu;
2531 if(process->usertrace)
2532 process->usertrace->cpu = cpu;
2533 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2534 process->state->change = s->parent.timestamp;
2535
2536 /* update cpu status */
2537 if(pid_in == 0)
2538 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
2539 else
2540 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
2541
2542 return FALSE;
2543 }
2544
2545 static gboolean process_fork(void *hook_data, void *call_data)
2546 {
2547 LttvTracefileState *s = (LttvTracefileState *)call_data;
2548 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2549 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2550 guint parent_pid;
2551 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2552 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2553 //LttvProcessState *zombie_process;
2554 guint cpu = s->cpu;
2555 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2556 LttvProcessState *process = ts->running_process[cpu];
2557 LttvProcessState *child_process;
2558
2559 /* Parent PID */
2560 parent_pid = ltt_event_get_unsigned(e, th->f1);
2561
2562 /* Child PID */
2563 child_pid = ltt_event_get_unsigned(e, th->f2);
2564 s->parent.target_pid = child_pid;
2565
2566 /* Child TGID */
2567 if(th->f3) child_tgid = ltt_event_get_unsigned(e, th->f3);
2568 else child_tgid = 0;
2569
2570 /* Mathieu : it seems like the process might have been scheduled in before the
2571 * fork, and, in a rare case, might be the current process. This might happen
2572 * in a SMP case where we don't have enough precision on the clocks.
2573 *
2574 * Test reenabled after precision fixes on time. (Mathieu) */
2575 #if 0
2576 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2577
2578 if(unlikely(zombie_process != NULL)) {
2579 /* Reutilisation of PID. Only now we are sure that the old PID
2580 * has been released. FIXME : should know when release_task happens instead.
2581 */
2582 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2583 guint i;
2584 for(i=0; i< num_cpus; i++) {
2585 g_assert(zombie_process != ts->running_process[i]);
2586 }
2587
2588 exit_process(s, zombie_process);
2589 }
2590 #endif //0
2591 g_assert(process->pid != child_pid);
2592 // FIXME : Add this test in the "known state" section
2593 // g_assert(process->pid == parent_pid);
2594 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2595 if(child_process == NULL) {
2596 child_process = lttv_state_create_process(ts, process, cpu,
2597 child_pid, child_tgid,
2598 LTTV_STATE_UNNAMED, &s->parent.timestamp);
2599 } else {
2600 /* The process has already been created : due to time imprecision between
2601 * multiple CPUs : it has been scheduled in before creation. Note that we
2602 * shouldn't have this kind of imprecision.
2603 *
2604 * Simply put a correct parent.
2605 */
2606 g_assert(0); /* This is a problematic case : the process has been created
2607 before the fork event */
2608 child_process->ppid = process->pid;
2609 child_process->tgid = child_tgid;
2610 }
2611 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2612 child_process->name = process->name;
2613 child_process->brand = process->brand;
2614
2615 return FALSE;
2616 }
2617
2618 /* We stamp a newly created process as kernel_thread.
2619 * The thread should not be running yet. */
2620 static gboolean process_kernel_thread(void *hook_data, void *call_data)
2621 {
2622 LttvTracefileState *s = (LttvTracefileState *)call_data;
2623 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2624 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2625 guint pid;
2626 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2627 LttvProcessState *process;
2628 LttvExecutionState *es;
2629
2630 /* PID */
2631 pid = (guint)ltt_event_get_long_unsigned(e, th->f1);
2632 s->parent.target_pid = pid;
2633
2634 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2635 &ltt_time_zero);
2636 process->execution_stack =
2637 g_array_set_size(process->execution_stack, 1);
2638 es = process->state =
2639 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2640 es->t = LTTV_STATE_SYSCALL;
2641 process->type = LTTV_STATE_KERNEL_THREAD;
2642
2643 return FALSE;
2644 }
2645
2646 static gboolean process_exit(void *hook_data, void *call_data)
2647 {
2648 LttvTracefileState *s = (LttvTracefileState *)call_data;
2649 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2650 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2651 guint pid;
2652 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2653 LttvProcessState *process; // = ts->running_process[cpu];
2654
2655 pid = ltt_event_get_unsigned(e, th->f1);
2656 s->parent.target_pid = pid;
2657
2658 // FIXME : Add this test in the "known state" section
2659 // g_assert(process->pid == pid);
2660
2661 process = lttv_state_find_process(ts, ANY_CPU, pid);
2662 if(likely(process != NULL)) {
2663 process->state->s = LTTV_STATE_EXIT;
2664 }
2665 return FALSE;
2666 }
2667
2668 static gboolean process_free(void *hook_data, void *call_data)
2669 {
2670 LttvTracefileState *s = (LttvTracefileState *)call_data;
2671 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2672 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2673 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2674 guint release_pid;
2675 LttvProcessState *process;
2676
2677 /* PID of the process to release */
2678 release_pid = ltt_event_get_unsigned(e, th->f1);
2679 s->parent.target_pid = release_pid;
2680
2681 g_assert(release_pid != 0);
2682
2683 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2684
2685 if(likely(process != NULL)) {
2686 /* release_task is happening at kernel level : we can now safely release
2687 * the data structure of the process */
2688 //This test is fun, though, as it may happen that
2689 //at time t : CPU 0 : process_free
2690 //at time t+150ns : CPU 1 : schedule out
2691 //Clearly due to time imprecision, we disable it. (Mathieu)
2692 //If this weird case happen, we have no choice but to put the
2693 //Currently running process on the cpu to 0.
2694 //I re-enable it following time precision fixes. (Mathieu)
2695 //Well, in the case where an process is freed by a process on another CPU
2696 //and still scheduled, it happens that this is the schedchange that will
2697 //drop the last reference count. Do not free it here!
2698 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2699 guint i;
2700 for(i=0; i< num_cpus; i++) {
2701 //g_assert(process != ts->running_process[i]);
2702 if(process == ts->running_process[i]) {
2703 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2704 break;
2705 }
2706 }
2707 if(i == num_cpus) /* process is not scheduled */
2708 exit_process(s, process);
2709 }
2710
2711 return FALSE;
2712 }
2713
2714
2715 static gboolean process_exec(void *hook_data, void *call_data)
2716 {
2717 LttvTracefileState *s = (LttvTracefileState *)call_data;
2718 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2719 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2720 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2721 //gchar *name;
2722 guint cpu = s->cpu;
2723 LttvProcessState *process = ts->running_process[cpu];
2724
2725 #if 0//how to use a sequence that must be transformed in a string
2726 /* PID of the process to release */
2727 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
2728 //name = ltt_event_get_string(e, thf->f1);
2729 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
2730 gchar *name_begin =
2731 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
2732 gchar *null_term_name = g_new(gchar, name_len+1);
2733 memcpy(null_term_name, name_begin, name_len);
2734 null_term_name[name_len] = '\0';
2735 process->name = g_quark_from_string(null_term_name);
2736 #endif //0
2737
2738 process->name = g_quark_from_string(ltt_event_get_string(e, th->f1));
2739 process->brand = LTTV_STATE_UNBRANDED;
2740 //g_free(null_term_name);
2741 return FALSE;
2742 }
2743
2744 static gboolean thread_brand(void *hook_data, void *call_data)
2745 {
2746 LttvTracefileState *s = (LttvTracefileState *)call_data;
2747 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2748 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2749 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2750 gchar *name;
2751 guint cpu = s->cpu;
2752 LttvProcessState *process = ts->running_process[cpu];
2753
2754 name = ltt_event_get_string(e, th->f1);
2755 process->brand = g_quark_from_string(name);
2756
2757 return FALSE;
2758 }
2759
2760 static void fix_process(gpointer key, gpointer value,
2761 gpointer user_data)
2762 {
2763 LttvProcessState *process;
2764 LttvExecutionState *es;
2765 process = (LttvProcessState *)value;
2766 LttTime *timestamp = (LttTime*)user_data;
2767
2768 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2769 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2770 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2771 es->t = LTTV_STATE_SYSCALL;
2772 es->n = LTTV_STATE_SUBMODE_NONE;
2773 es->entry = *timestamp;
2774 es->change = *timestamp;
2775 es->cum_cpu_time = ltt_time_zero;
2776 if(es->s == LTTV_STATE_UNNAMED)
2777 es->s = LTTV_STATE_WAIT;
2778 }
2779 } else {
2780 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2781 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2782 es->t = LTTV_STATE_USER_MODE;
2783 es->n = LTTV_STATE_SUBMODE_NONE;
2784 es->entry = *timestamp;
2785 //g_assert(timestamp->tv_sec != 0);
2786 es->change = *timestamp;
2787 es->cum_cpu_time = ltt_time_zero;
2788 if(es->s == LTTV_STATE_UNNAMED)
2789 es->s = LTTV_STATE_RUN;
2790
2791 if(process->execution_stack->len == 1) {
2792 /* Still in bottom unknown mode, means never did a system call
2793 * May be either in user mode, syscall mode, running or waiting.*/
2794 /* FIXME : we may be tagging syscall mode when being user mode */
2795 process->execution_stack =
2796 g_array_set_size(process->execution_stack, 2);
2797 es = process->state = &g_array_index(process->execution_stack,
2798 LttvExecutionState, 1);
2799 es->t = LTTV_STATE_SYSCALL;
2800 es->n = LTTV_STATE_SUBMODE_NONE;
2801 es->entry = *timestamp;
2802 //g_assert(timestamp->tv_sec != 0);
2803 es->change = *timestamp;
2804 es->cum_cpu_time = ltt_time_zero;
2805 if(es->s == LTTV_STATE_WAIT_FORK)
2806 es->s = LTTV_STATE_WAIT;
2807 }
2808 }
2809 }
2810 }
2811
2812 static gboolean statedump_end(void *hook_data, void *call_data)
2813 {
2814 LttvTracefileState *s = (LttvTracefileState *)call_data;
2815 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2816 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2817 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2818 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2819
2820 /* For all processes */
2821 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2822 /* else, if stack[0] is unknown, set to user mode, running */
2823
2824 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
2825
2826 return FALSE;
2827 }
2828
2829 static gboolean enum_process_state(void *hook_data, void *call_data)
2830 {
2831 LttvTracefileState *s = (LttvTracefileState *)call_data;
2832 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2833 //It's slow : optimise later by doing this before reading trace.
2834 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2835 guint parent_pid;
2836 guint pid;
2837 guint tgid;
2838 gchar * command;
2839 guint cpu = s->cpu;
2840 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2841 LttvProcessState *process = ts->running_process[cpu];
2842 LttvProcessState *parent_process;
2843 struct marker_field *f4, *f5, *f6, *f7, *f8;
2844 GQuark type, mode, submode, status;
2845 LttvExecutionState *es;
2846 guint i, nb_cpus;
2847 struct marker_info *mi;
2848
2849 /* PID */
2850 pid = ltt_event_get_unsigned(e, th->f1);
2851 s->parent.target_pid = pid;
2852
2853 /* Parent PID */
2854 parent_pid = ltt_event_get_unsigned(e, th->f2);
2855
2856 /* Command name */
2857 command = ltt_event_get_string(e, th->f3);
2858
2859 /* type */
2860 mi = marker_get_info_from_id(ts->parent.t, e->event_id);
2861 f4 = marker_get_field(mi, 3);
2862 g_assert(f4->name == LTT_FIELD_TYPE);
2863 type = ltt_enum_string_get(ltt_field_type(f4),
2864 ltt_event_get_unsigned(e, f4));
2865
2866 /* mode */
2867 f5 = marker_get_field(mi, 4);
2868 g_assert(f5->name == LTT_FIELD_MODE);
2869 mode = ltt_enum_string_get(ltt_field_type(f5),
2870 ltt_event_get_unsigned(e, f5));
2871
2872 /* submode */
2873 f6 = marker_get_field(mi, 5);
2874 g_assert(f6->name == LTT_FIELD_SUBMODE);
2875 submode = ltt_enum_string_get(ltt_field_type(f6),
2876 ltt_event_get_unsigned(e, f6));
2877
2878 /* status */
2879 f7 = marker_get_field(mi, 6);
2880 g_assert(f7->name == LTT_FIELD_STATUS);
2881 status = ltt_enum_string_get(ltt_field_type(f7),
2882 ltt_event_get_unsigned(e, f7));
2883
2884 /* TGID */
2885 f8 = marker_get_field(mi, 7);
2886 g_assert(f8->name == LTT_FIELD_TGID);
2887 if(f8) tgid = ltt_event_get_unsigned(e, f8);
2888 else tgid = 0;
2889
2890
2891 if(pid == 0) {
2892 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2893 for(i=0; i<nb_cpus; i++) {
2894 process = lttv_state_find_process(ts, i, pid);
2895 g_assert(process != NULL);
2896
2897 process->ppid = parent_pid;
2898 process->tgid = tgid;
2899 process->name = g_quark_from_string(command);
2900 es =
2901 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2902 process->type = LTTV_STATE_KERNEL_THREAD;
2903 }
2904
2905 } else {
2906 /* The process might exist if a process was forked while performing the
2907 * state dump. */
2908 process = lttv_state_find_process(ts, ANY_CPU, pid);
2909 if(process == NULL) {
2910 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2911 process = lttv_state_create_process(ts, parent_process, cpu,
2912 pid, tgid, g_quark_from_string(command),
2913 &s->parent.timestamp);
2914
2915 /* Keep the stack bottom : a running user mode */
2916 /* Disabled because of inconsistencies in the current statedump states. */
2917 if(type == LTTV_STATE_KERNEL_THREAD) {
2918 /* Only keep the bottom
2919 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2920 /* Will cause expected trap when in fact being syscall (even after end of
2921 * statedump event)
2922 * Will cause expected interrupt when being syscall. (only before end of
2923 * statedump event) */
2924 // This will cause a "popping last state on stack, ignoring it."
2925 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2926 es = process->state = &g_array_index(process->execution_stack,
2927 LttvExecutionState, 0);
2928 process->type = LTTV_STATE_KERNEL_THREAD;
2929 es->t = LTTV_STATE_MODE_UNKNOWN;
2930 es->s = LTTV_STATE_UNNAMED;
2931 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2932 #if 0
2933 es->t = LTTV_STATE_SYSCALL;
2934 es->s = status;
2935 es->n = submode;
2936 #endif //0
2937 } else {
2938 /* User space process :
2939 * bottom : user mode
2940 * either currently running or scheduled out.
2941 * can be scheduled out because interrupted in (user mode or in syscall)
2942 * or because of an explicit call to the scheduler in syscall. Note that
2943 * the scheduler call comes after the irq_exit, so never in interrupt
2944 * context. */
2945 // temp workaround : set size to 1 : only have user mode bottom of stack.
2946 // will cause g_info message of expected syscall mode when in fact being
2947 // in user mode. Can also cause expected trap when in fact being user
2948 // mode in the event of a page fault reenabling interrupts in the handler.
2949 // Expected syscall and trap can also happen after the end of statedump
2950 // This will cause a "popping last state on stack, ignoring it."
2951 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2952 es = process->state = &g_array_index(process->execution_stack,
2953 LttvExecutionState, 0);
2954 es->t = LTTV_STATE_MODE_UNKNOWN;
2955 es->s = LTTV_STATE_UNNAMED;
2956 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2957 #if 0
2958 es->t = LTTV_STATE_USER_MODE;
2959 es->s = status;
2960 es->n = submode;
2961 #endif //0
2962 }
2963 #if 0
2964 /* UNKNOWN STATE */
2965 {
2966 es = process->state = &g_array_index(process->execution_stack,
2967 LttvExecutionState, 1);
2968 es->t = LTTV_STATE_MODE_UNKNOWN;
2969 es->s = LTTV_STATE_UNNAMED;
2970 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2971 }
2972 #endif //0
2973 } else {
2974 /* The process has already been created :
2975 * Probably was forked while dumping the process state or
2976 * was simply scheduled in prior to get the state dump event.
2977 */
2978 process->ppid = parent_pid;
2979 process->tgid = tgid;
2980 process->name = g_quark_from_string(command);
2981 process->type = type;
2982 es =
2983 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2984 #if 0
2985 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2986 if(type == LTTV_STATE_KERNEL_THREAD)
2987 es->t = LTTV_STATE_SYSCALL;
2988 else
2989 es->t = LTTV_STATE_USER_MODE;
2990 }
2991 #endif //0
2992 /* Don't mess around with the stack, it will eventually become
2993 * ok after the end of state dump. */
2994 }
2995 }
2996
2997 return FALSE;
2998 }
2999
3000 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3001 {
3002 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3003
3004 lttv_state_add_event_hooks(tss);
3005
3006 return 0;
3007 }
3008
3009 void lttv_state_add_event_hooks(LttvTracesetState *self)
3010 {
3011 LttvTraceset *traceset = self->parent.ts;
3012
3013 guint i, j, k, nb_trace, nb_tracefile;
3014
3015 LttvTraceState *ts;
3016
3017 LttvTracefileState *tfs;
3018
3019 GArray *hooks;
3020
3021 LttvTraceHook *th;
3022
3023 LttvAttributeValue val;
3024
3025 gint ret;
3026 gint hn;
3027
3028 nb_trace = lttv_traceset_number(traceset);
3029 for(i = 0 ; i < nb_trace ; i++) {
3030 ts = (LttvTraceState *)self->parent.traces[i];
3031
3032 /* Find the eventtype id for the following events and register the
3033 associated by id hooks. */
3034
3035 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
3036 hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3037 hn = 0;
3038
3039 ret = lttv_trace_find_hook(ts->parent.t,
3040 LTT_EVENT_SYSCALL_ENTRY,
3041 LTT_FIELD_SYSCALL_ID, 0, 0,
3042 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3043 if(ret) hn--;
3044
3045 ret = lttv_trace_find_hook(ts->parent.t,
3046 LTT_EVENT_SYSCALL_EXIT,
3047 0, 0, 0,
3048 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3049 if(ret) hn--;
3050
3051 ret = lttv_trace_find_hook(ts->parent.t,
3052 LTT_EVENT_TRAP_ENTRY,
3053 LTT_FIELD_TRAP_ID, 0, 0,
3054 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3055 if(ret) hn--;
3056
3057 ret = lttv_trace_find_hook(ts->parent.t,
3058 LTT_EVENT_TRAP_EXIT,
3059 0, 0, 0,
3060 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3061 if(ret) hn--;
3062
3063 ret = lttv_trace_find_hook(ts->parent.t,
3064 LTT_EVENT_IRQ_ENTRY,
3065 LTT_FIELD_IRQ_ID, 0, 0,
3066 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3067 if(ret) hn--;
3068
3069 ret = lttv_trace_find_hook(ts->parent.t,
3070 LTT_EVENT_IRQ_EXIT,
3071 0, 0, 0,
3072 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3073 if(ret) hn--;
3074
3075 ret = lttv_trace_find_hook(ts->parent.t,
3076 LTT_EVENT_SOFT_IRQ_ENTRY,
3077 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
3078 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3079 if(ret) hn--;
3080
3081 ret = lttv_trace_find_hook(ts->parent.t,
3082 LTT_EVENT_SOFT_IRQ_EXIT,
3083 0, 0, 0,
3084 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3085 if(ret) hn--;
3086
3087 ret = lttv_trace_find_hook(ts->parent.t,
3088 LTT_EVENT_SCHED_SCHEDULE,
3089 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
3090 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3091 if(ret) hn--;
3092
3093 ret = lttv_trace_find_hook(ts->parent.t,
3094 LTT_EVENT_PROCESS_FORK,
3095 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, LTT_FIELD_CHILD_TGID,
3096 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3097 if(ret) hn--;
3098
3099 ret = lttv_trace_find_hook(ts->parent.t,
3100 LTT_EVENT_KTHREAD_CREATE,
3101 LTT_FIELD_PID, 0, 0,
3102 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
3103 hn++));
3104 if(ret) hn--;
3105
3106 ret = lttv_trace_find_hook(ts->parent.t,
3107 LTT_EVENT_PROCESS_EXIT,
3108 LTT_FIELD_PID, 0, 0,
3109 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3110 if(ret) hn--;
3111
3112 ret = lttv_trace_find_hook(ts->parent.t,
3113 LTT_EVENT_PROCESS_FREE,
3114 LTT_FIELD_PID, 0, 0,
3115 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3116 if(ret) hn--;
3117
3118 ret = lttv_trace_find_hook(ts->parent.t,
3119 LTT_EVENT_EXEC,
3120 LTT_FIELD_FILENAME, 0, 0,
3121 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3122 if(ret) hn--;
3123
3124 ret = lttv_trace_find_hook(ts->parent.t,
3125 LTT_EVENT_THREAD_BRAND,
3126 LTT_FIELD_NAME, 0, 0,
3127 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3128 if(ret) hn--;
3129
3130 /* statedump-related hooks */
3131 ret = lttv_trace_find_hook(ts->parent.t,
3132 LTT_EVENT_PROCESS_STATE,
3133 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3134 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3135 if(ret) hn--;
3136
3137 ret = lttv_trace_find_hook(ts->parent.t,
3138 LTT_EVENT_STATEDUMP_END,
3139 0, 0, 0,
3140 statedump_end, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3141 if(ret) hn--;
3142
3143 ret = lttv_trace_find_hook(ts->parent.t,
3144 LTT_EVENT_LIST_INTERRUPT,
3145 LTT_FIELD_ACTION, LTT_FIELD_NUM, 0,
3146 enum_interrupt, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3147 if(ret) hn--;
3148
3149 ret = lttv_trace_find_hook(ts->parent.t,
3150 LTT_EVENT_REQUEST_ISSUE,
3151 LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION,
3152 bdev_request_issue, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3153 if(ret) hn--;
3154
3155 ret = lttv_trace_find_hook(ts->parent.t,
3156 LTT_EVENT_REQUEST_COMPLETE,
3157 LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION,
3158 bdev_request_complete, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3159 if(ret) hn--;
3160
3161 ret = lttv_trace_find_hook(ts->parent.t,
3162 LTT_EVENT_FUNCTION_ENTRY,
3163 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
3164 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3165 if(ret) hn--;
3166
3167 ret = lttv_trace_find_hook(ts->parent.t,
3168 LTT_EVENT_FUNCTION_EXIT,
3169 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
3170 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3171 if(ret) hn--;
3172
3173 hooks = g_array_set_size(hooks, hn);
3174
3175 /* Add these hooks to each event_by_id hooks list */
3176
3177 nb_tracefile = ts->parent.tracefiles->len;
3178
3179 for(j = 0 ; j < nb_tracefile ; j++) {
3180 tfs =
3181 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3182 LttvTracefileContext*, j));
3183
3184 for(k = 0 ; k < hooks->len ; k++) {
3185 th = &g_array_index(hooks, LttvTraceHook, k);
3186 lttv_hooks_add(
3187 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3188 th->h,
3189 th,
3190 LTTV_PRIO_STATE);
3191 }
3192 }
3193 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3194 *(val.v_pointer) = hooks;
3195 }
3196 }
3197
3198 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3199 {
3200 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3201
3202 lttv_state_remove_event_hooks(tss);
3203
3204 return 0;
3205 }
3206
3207 void lttv_state_remove_event_hooks(LttvTracesetState *self)
3208 {
3209 LttvTraceset *traceset = self->parent.ts;
3210
3211 guint i, j, k, nb_trace, nb_tracefile;
3212
3213 LttvTraceState *ts;
3214
3215 LttvTracefileState *tfs;
3216
3217 GArray *hooks;
3218
3219 LttvTraceHook *th;
3220
3221 LttvAttributeValue val;
3222
3223 nb_trace = lttv_traceset_number(traceset);
3224 for(i = 0 ; i < nb_trace ; i++) {
3225 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3226
3227 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3228 hooks = *(val.v_pointer);
3229
3230 /* Remove these hooks from each event_by_id hooks list */
3231
3232 nb_tracefile = ts->parent.tracefiles->len;
3233
3234 for(j = 0 ; j < nb_tracefile ; j++) {
3235 tfs =
3236 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3237 LttvTracefileContext*, j));
3238
3239 for(k = 0 ; k < hooks->len ; k++) {
3240 th = &g_array_index(hooks, LttvTraceHook, k);
3241 lttv_hooks_remove_data(
3242 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3243 th->h,
3244 th);
3245 }
3246 }
3247 for(k = 0 ; k < hooks->len ; k++)
3248 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
3249 g_array_free(hooks, TRUE);
3250 }
3251 }
3252
3253 static gboolean state_save_event_hook(void *hook_data, void *call_data)
3254 {
3255 guint *event_count = (guint*)hook_data;
3256
3257 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3258 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3259 return FALSE;
3260 else
3261 *event_count = 0;
3262
3263 LttvTracefileState *self = (LttvTracefileState *)call_data;
3264
3265 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3266
3267 LttvAttribute *saved_states_tree, *saved_state_tree;
3268
3269 LttvAttributeValue value;
3270
3271 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3272 LTTV_STATE_SAVED_STATES);
3273 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3274 value = lttv_attribute_add(saved_states_tree,
3275 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3276 *(value.v_gobject) = (GObject *)saved_state_tree;
3277 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3278 *(value.v_time) = self->parent.timestamp;
3279 lttv_state_save(tcs, saved_state_tree);
3280 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3281 self->parent.timestamp.tv_nsec);
3282
3283 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3284
3285 return FALSE;
3286 }
3287
3288 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3289 {
3290 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3291
3292 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3293
3294 return FALSE;
3295 }
3296
3297 guint lttv_state_current_cpu(LttvTracefileState *tfs)
3298 {
3299 return tfs->cpu;
3300 }
3301
3302
3303
3304 #if 0
3305 static gboolean block_start(void *hook_data, void *call_data)
3306 {
3307 LttvTracefileState *self = (LttvTracefileState *)call_data;
3308
3309 LttvTracefileState *tfcs;
3310
3311 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3312
3313 LttEventPosition *ep;
3314
3315 guint i, nb_block, nb_event, nb_tracefile;
3316
3317 LttTracefile *tf;
3318
3319 LttvAttribute *saved_states_tree, *saved_state_tree;
3320
3321 LttvAttributeValue value;
3322
3323 ep = ltt_event_position_new();
3324
3325 nb_tracefile = tcs->parent.tracefiles->len;
3326
3327 /* Count the number of events added since the last block end in any
3328 tracefile. */
3329
3330 for(i = 0 ; i < nb_tracefile ; i++) {
3331 tfcs =
3332 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3333 LttvTracefileContext, i));
3334 ltt_event_position(tfcs->parent.e, ep);
3335 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3336 tcs->nb_event += nb_event - tfcs->saved_position;
3337 tfcs->saved_position = nb_event;
3338 }
3339 g_free(ep);
3340
3341 if(tcs->nb_event >= tcs->save_interval) {
3342 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3343 LTTV_STATE_SAVED_STATES);
3344 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3345 value = lttv_attribute_add(saved_states_tree,
3346 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3347 *(value.v_gobject) = (GObject *)saved_state_tree;
3348 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3349 *(value.v_time) = self->parent.timestamp;
3350 lttv_state_save(tcs, saved_state_tree);
3351 tcs->nb_event = 0;
3352 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3353 self->parent.timestamp.tv_nsec);
3354 }
3355 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3356 return FALSE;
3357 }
3358 #endif //0
3359
3360 #if 0
3361 static gboolean block_end(void *hook_data, void *call_data)
3362 {
3363 LttvTracefileState *self = (LttvTracefileState *)call_data;
3364
3365 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3366
3367 LttTracefile *tf;
3368
3369 LttEventPosition *ep;
3370
3371 guint nb_block, nb_event;
3372
3373 ep = ltt_event_position_new();
3374 ltt_event_position(self->parent.e, ep);
3375 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3376 tcs->nb_event += nb_event - self->saved_position + 1;
3377 self->saved_position = 0;
3378 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3379 g_free(ep);
3380
3381 return FALSE;
3382 }
3383 #endif //0
3384 #if 0
3385 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3386 {
3387 LttvTraceset *traceset = self->parent.ts;
3388
3389 guint i, j, nb_trace, nb_tracefile;
3390
3391 LttvTraceState *ts;
3392
3393 LttvTracefileState *tfs;
3394
3395 LttvTraceHook hook_start, hook_end;
3396
3397 nb_trace = lttv_traceset_number(traceset);
3398 for(i = 0 ; i < nb_trace ; i++) {
3399 ts = (LttvTraceState *)self->parent.traces[i];
3400
3401 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3402 NULL, NULL, block_start, &hook_start);
3403 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3404 NULL, NULL, block_end, &hook_end);
3405
3406 nb_tracefile = ts->parent.tracefiles->len;
3407
3408 for(j = 0 ; j < nb_tracefile ; j++) {
3409 tfs =
3410 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3411 LttvTracefileContext, j));
3412 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3413 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3414 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3415 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3416 }
3417 }
3418 }
3419 #endif //0
3420
3421 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3422 {
3423 LttvTraceset *traceset = self->parent.ts;
3424
3425 guint i, j, nb_trace, nb_tracefile;
3426
3427 LttvTraceState *ts;
3428
3429 LttvTracefileState *tfs;
3430
3431
3432 nb_trace = lttv_traceset_number(traceset);
3433 for(i = 0 ; i < nb_trace ; i++) {
3434
3435 ts = (LttvTraceState *)self->parent.traces[i];
3436 nb_tracefile = ts->parent.tracefiles->len;
3437
3438 if(ts->has_precomputed_states) continue;
3439
3440 guint *event_count = g_new(guint, 1);
3441 *event_count = 0;
3442
3443 for(j = 0 ; j < nb_tracefile ; j++) {
3444 tfs =
3445 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3446 LttvTracefileContext*, j));
3447 lttv_hooks_add(tfs->parent.event,
3448 state_save_event_hook,
3449 event_count,
3450 LTTV_PRIO_STATE);
3451
3452 }
3453 }
3454
3455 lttv_process_traceset_begin(&self->parent,
3456 NULL, NULL, NULL, NULL, NULL);
3457
3458 }
3459
3460 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3461 {
3462 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3463
3464 lttv_state_save_add_event_hooks(tss);
3465
3466 return 0;
3467 }
3468
3469
3470 #if 0
3471 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3472 {
3473 LttvTraceset *traceset = self->parent.ts;
3474
3475 guint i, j, nb_trace, nb_tracefile;
3476
3477 LttvTraceState *ts;
3478
3479 LttvTracefileState *tfs;
3480
3481 LttvTraceHook hook_start, hook_end;
3482
3483 nb_trace = lttv_traceset_number(traceset);
3484 for(i = 0 ; i < nb_trace ; i++) {
3485 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3486
3487 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3488 NULL, NULL, block_start, &hook_start);
3489
3490 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3491 NULL, NULL, block_end, &hook_end);
3492
3493 nb_tracefile = ts->parent.tracefiles->len;
3494
3495 for(j = 0 ; j < nb_tracefile ; j++) {
3496 tfs =
3497 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3498 LttvTracefileContext, j));
3499 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3500 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
3501 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3502 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
3503 }
3504 }
3505 }
3506 #endif //0
3507
3508 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3509 {
3510 LttvTraceset *traceset = self->parent.ts;
3511
3512 guint i, j, nb_trace, nb_tracefile;
3513
3514 LttvTraceState *ts;
3515
3516 LttvTracefileState *tfs;
3517
3518 LttvHooks *after_trace = lttv_hooks_new();
3519
3520 lttv_hooks_add(after_trace,
3521 state_save_after_trace_hook,
3522 NULL,
3523 LTTV_PRIO_STATE);
3524
3525
3526 lttv_process_traceset_end(&self->parent,
3527 NULL, after_trace, NULL, NULL, NULL);
3528
3529 lttv_hooks_destroy(after_trace);
3530
3531 nb_trace = lttv_traceset_number(traceset);
3532 for(i = 0 ; i < nb_trace ; i++) {
3533
3534 ts = (LttvTraceState *)self->parent.traces[i];
3535 nb_tracefile = ts->parent.tracefiles->len;
3536
3537 if(ts->has_precomputed_states) continue;
3538
3539 guint *event_count = NULL;
3540
3541 for(j = 0 ; j < nb_tracefile ; j++) {
3542 tfs =
3543 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3544 LttvTracefileContext*, j));
3545 event_count = lttv_hooks_remove(tfs->parent.event,
3546 state_save_event_hook);
3547 }
3548 if(event_count) g_free(event_count);
3549 }
3550 }
3551
3552 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3553 {
3554 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3555
3556 lttv_state_save_remove_event_hooks(tss);
3557
3558 return 0;
3559 }
3560
3561 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
3562 {
3563 LttvTraceset *traceset = self->parent.ts;
3564
3565 guint i, nb_trace;
3566
3567 int min_pos, mid_pos, max_pos;
3568
3569 guint call_rest = 0;
3570
3571 LttvTraceState *tcs;
3572
3573 LttvAttributeValue value;
3574
3575 LttvAttributeType type;
3576
3577 LttvAttributeName name;
3578
3579 gboolean is_named;
3580
3581 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3582
3583 //g_tree_destroy(self->parent.pqueue);
3584 //self->parent.pqueue = g_tree_new(compare_tracefile);
3585
3586 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3587
3588 nb_trace = lttv_traceset_number(traceset);
3589 for(i = 0 ; i < nb_trace ; i++) {
3590 tcs = (LttvTraceState *)self->parent.traces[i];
3591
3592 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3593 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3594 LTTV_STATE_SAVED_STATES);
3595 min_pos = -1;
3596
3597 if(saved_states_tree) {
3598 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3599 mid_pos = max_pos / 2;
3600 while(min_pos < max_pos) {
3601 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
3602 &is_named);
3603 g_assert(type == LTTV_GOBJECT);
3604 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3605 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3606 &value);
3607 g_assert(type == LTTV_TIME);
3608 if(ltt_time_compare(*(value.v_time), t) < 0) {
3609 min_pos = mid_pos;
3610 closest_tree = saved_state_tree;
3611 }
3612 else max_pos = mid_pos - 1;
3613
3614 mid_pos = (min_pos + max_pos + 1) / 2;
3615 }
3616 }
3617
3618 /* restore the closest earlier saved state */
3619 if(min_pos != -1) {
3620 lttv_state_restore(tcs, closest_tree);
3621 call_rest = 1;
3622 }
3623
3624 /* There is no saved state, yet we want to have it. Restart at T0 */
3625 else {
3626 restore_init_state(tcs);
3627 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
3628 }
3629 }
3630 /* We want to seek quickly without restoring/updating the state */
3631 else {
3632 restore_init_state(tcs);
3633 lttv_process_trace_seek_time(&(tcs->parent), t);
3634 }
3635 }
3636 if(!call_rest) g_info("NOT Calling restore");
3637 }
3638
3639
3640 static void
3641 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3642 {
3643 }
3644
3645
3646 static void
3647 traceset_state_finalize (LttvTracesetState *self)
3648 {
3649 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3650 finalize(G_OBJECT(self));
3651 }
3652
3653
3654 static void
3655 traceset_state_class_init (LttvTracesetContextClass *klass)
3656 {
3657 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3658
3659 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3660 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3661 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3662 klass->new_traceset_context = new_traceset_context;
3663 klass->new_trace_context = new_trace_context;
3664 klass->new_tracefile_context = new_tracefile_context;
3665 }
3666
3667
3668 GType
3669 lttv_traceset_state_get_type(void)
3670 {
3671 static GType type = 0;
3672 if (type == 0) {
3673 static const GTypeInfo info = {
3674 sizeof (LttvTracesetStateClass),
3675 NULL, /* base_init */
3676 NULL, /* base_finalize */
3677 (GClassInitFunc) traceset_state_class_init, /* class_init */
3678 NULL, /* class_finalize */
3679 NULL, /* class_data */
3680 sizeof (LttvTracesetState),
3681 0, /* n_preallocs */
3682 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3683 NULL /* value handling */
3684 };
3685
3686 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3687 &info, 0);
3688 }
3689 return type;
3690 }
3691
3692
3693 static void
3694 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3695 {
3696 }
3697
3698
3699 static void
3700 trace_state_finalize (LttvTraceState *self)
3701 {
3702 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3703 finalize(G_OBJECT(self));
3704 }
3705
3706
3707 static void
3708 trace_state_class_init (LttvTraceStateClass *klass)
3709 {
3710 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3711
3712 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3713 klass->state_save = state_save;
3714 klass->state_restore = state_restore;
3715 klass->state_saved_free = state_saved_free;
3716 }
3717
3718
3719 GType
3720 lttv_trace_state_get_type(void)
3721 {
3722 static GType type = 0;
3723 if (type == 0) {
3724 static const GTypeInfo info = {
3725 sizeof (LttvTraceStateClass),
3726 NULL, /* base_init */
3727 NULL, /* base_finalize */
3728 (GClassInitFunc) trace_state_class_init, /* class_init */
3729 NULL, /* class_finalize */
3730 NULL, /* class_data */
3731 sizeof (LttvTraceState),
3732 0, /* n_preallocs */
3733 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3734 NULL /* value handling */
3735 };
3736
3737 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3738 "LttvTraceStateType", &info, 0);
3739 }
3740 return type;
3741 }
3742
3743
3744 static void
3745 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3746 {
3747 }
3748
3749
3750 static void
3751 tracefile_state_finalize (LttvTracefileState *self)
3752 {
3753 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3754 finalize(G_OBJECT(self));
3755 }
3756
3757
3758 static void
3759 tracefile_state_class_init (LttvTracefileStateClass *klass)
3760 {
3761 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3762
3763 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3764 }
3765
3766
3767 GType
3768 lttv_tracefile_state_get_type(void)
3769 {
3770 static GType type = 0;
3771 if (type == 0) {
3772 static const GTypeInfo info = {
3773 sizeof (LttvTracefileStateClass),
3774 NULL, /* base_init */
3775 NULL, /* base_finalize */
3776 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3777 NULL, /* class_finalize */
3778 NULL, /* class_data */
3779 sizeof (LttvTracefileState),
3780 0, /* n_preallocs */
3781 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3782 NULL /* value handling */
3783 };
3784
3785 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3786 "LttvTracefileStateType", &info, 0);
3787 }
3788 return type;
3789 }
3790
3791
3792 static void module_init()
3793 {
3794 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
3795 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
3796 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3797 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3798 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3799 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3800 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3801 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3802 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3803 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3804 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3805 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3806 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3807 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3808 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3809 LTTV_STATE_RUN = g_quark_from_string("RUN");
3810 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
3811 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3812 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
3813 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3814 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3815 LTTV_STATE_PROCESS = g_quark_from_string("process");
3816 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
3817 LTTV_STATE_EVENT = g_quark_from_string("event");
3818 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
3819 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
3820 LTTV_STATE_TIME = g_quark_from_string("time");
3821 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
3822 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3823 LTTV_STATE_TRACE_STATE_USE_COUNT =
3824 g_quark_from_string("trace_state_use_count");
3825 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
3826 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
3827 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
3828
3829
3830 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
3831 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
3832 LTT_FACILITY_FS = g_quark_from_string("fs");
3833 LTT_FACILITY_LIST = g_quark_from_string("list");
3834 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
3835 LTT_FACILITY_BLOCK = g_quark_from_string("block");
3836
3837
3838 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3839 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3840 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3841 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3842 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3843 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
3844 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
3845 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
3846 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3847 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3848 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3849 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
3850 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
3851 LTT_EVENT_EXEC = g_quark_from_string("exec");
3852 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
3853 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
3854 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3855 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
3856 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
3857 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
3858 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
3859 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
3860
3861
3862 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3863 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3864 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
3865 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
3866 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3867 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3868 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
3869 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3870 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3871 LTT_FIELD_PID = g_quark_from_string("pid");
3872 LTT_FIELD_TGID = g_quark_from_string("tgid");
3873 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
3874 LTT_FIELD_FILENAME = g_quark_from_string("filename");
3875 LTT_FIELD_NAME = g_quark_from_string("name");
3876 LTT_FIELD_TYPE = g_quark_from_string("type");
3877 LTT_FIELD_MODE = g_quark_from_string("mode");
3878 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3879 LTT_FIELD_STATUS = g_quark_from_string("status");
3880 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3881 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
3882 LTT_FIELD_MAJOR = g_quark_from_string("major");
3883 LTT_FIELD_MINOR = g_quark_from_string("minor");
3884 LTT_FIELD_OPERATION = g_quark_from_string("direction");
3885 LTT_FIELD_ACTION = g_quark_from_string("action");
3886 LTT_FIELD_NUM = g_quark_from_string("num");
3887
3888 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3889 LTTV_CPU_IDLE = g_quark_from_string("idle");
3890 LTTV_CPU_BUSY = g_quark_from_string("busy");
3891 LTTV_CPU_IRQ = g_quark_from_string("irq");
3892 LTTV_CPU_TRAP = g_quark_from_string("trap");
3893
3894 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
3895 LTTV_IRQ_IDLE = g_quark_from_string("idle");
3896 LTTV_IRQ_BUSY = g_quark_from_string("busy");
3897
3898 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
3899 LTTV_BDEV_IDLE = g_quark_from_string("idle");
3900 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
3901 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
3902 }
3903
3904 static void module_destroy()
3905 {
3906 }
3907
3908
3909 LTTV_MODULE("state", "State computation", \
3910 "Update the system state, possibly saving it at intervals", \
3911 module_init, module_destroy)
3912
3913
3914
This page took 0.101947 seconds and 5 git commands to generate.