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