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