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