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