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