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