update compat
[lttv.git] / tags / LinuxTraceToolkitViewer-0.10.0-pre-115102007 / lttv / lttv / state.c
CommitLineData
0bc7c2cd 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19#define _GNU_SOURCE
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <glib.h>
25#include <lttv/lttv.h>
26#include <lttv/module.h>
27#include <lttv/state.h>
28#include <ltt/trace.h>
29#include <ltt/event.h>
30#include <ltt/ltt.h>
31#include <ltt/marker-desc.h>
32#include <stdio.h>
33#include <string.h>
34
35/* Comment :
36 * Mathieu Desnoyers
37 * usertrace is there only to be able to update the current CPU of the
38 * usertraces when there is a schedchange. it is a way to link the ProcessState
39 * to the associated usertrace. Link only created upon thread creation.
40 *
41 * The cpu id is necessary : it gives us back the current ProcessState when we
42 * are considering data from the usertrace.
43 */
44
45#define PREALLOCATED_EXECUTION_STACK 10
46
47/* Facilities Quarks */
48
49GQuark
50 LTT_FACILITY_KERNEL,
51 LTT_FACILITY_KERNEL_ARCH,
52 LTT_FACILITY_LIST,
53 LTT_FACILITY_FS,
54 LTT_FACILITY_USER_GENERIC,
55 LTT_FACILITY_BLOCK;
56
57/* Events Quarks */
58
59GQuark
60 LTT_EVENT_SYSCALL_ENTRY,
61 LTT_EVENT_SYSCALL_EXIT,
62 LTT_EVENT_TRAP_ENTRY,
63 LTT_EVENT_TRAP_EXIT,
64 LTT_EVENT_IRQ_ENTRY,
65 LTT_EVENT_IRQ_EXIT,
66 LTT_EVENT_SOFT_IRQ_ENTRY,
67 LTT_EVENT_SOFT_IRQ_EXIT,
68 LTT_EVENT_SCHED_SCHEDULE,
69 LTT_EVENT_PROCESS_FORK,
70 LTT_EVENT_KTHREAD_CREATE,
71 LTT_EVENT_PROCESS_EXIT,
72 LTT_EVENT_PROCESS_FREE,
73 LTT_EVENT_EXEC,
74 LTT_EVENT_PROCESS_STATE,
75 LTT_EVENT_STATEDUMP_END,
76 LTT_EVENT_FUNCTION_ENTRY,
77 LTT_EVENT_FUNCTION_EXIT,
78 LTT_EVENT_THREAD_BRAND,
79 LTT_EVENT_REQUEST_ISSUE,
80 LTT_EVENT_REQUEST_COMPLETE,
81 LTT_EVENT_LIST_INTERRUPT;
82
83/* Fields Quarks */
84
85GQuark
86 LTT_FIELD_SYSCALL_ID,
87 LTT_FIELD_TRAP_ID,
88 LTT_FIELD_IRQ_ID,
89 LTT_FIELD_SOFT_IRQ_ID,
90 LTT_FIELD_PREV_PID,
91 LTT_FIELD_NEXT_PID,
92 LTT_FIELD_PREV_STATE,
93 LTT_FIELD_PARENT_PID,
94 LTT_FIELD_CHILD_PID,
95 LTT_FIELD_PID,
96 LTT_FIELD_TGID,
97 LTT_FIELD_CHILD_TGID,
98 LTT_FIELD_FILENAME,
99 LTT_FIELD_NAME,
100 LTT_FIELD_TYPE,
101 LTT_FIELD_MODE,
102 LTT_FIELD_SUBMODE,
103 LTT_FIELD_STATUS,
104 LTT_FIELD_THIS_FN,
105 LTT_FIELD_CALL_SITE,
106 LTT_FIELD_MINOR,
107 LTT_FIELD_MAJOR,
108 LTT_FIELD_OPERATION,
109 LTT_FIELD_ACTION;
110
111LttvExecutionMode
112 LTTV_STATE_MODE_UNKNOWN,
113 LTTV_STATE_USER_MODE,
114 LTTV_STATE_SYSCALL,
115 LTTV_STATE_TRAP,
116 LTTV_STATE_IRQ,
117 LTTV_STATE_SOFT_IRQ;
118
119LttvExecutionSubmode
120 LTTV_STATE_SUBMODE_UNKNOWN,
121 LTTV_STATE_SUBMODE_NONE;
122
123LttvProcessStatus
124 LTTV_STATE_UNNAMED,
125 LTTV_STATE_WAIT_FORK,
126 LTTV_STATE_WAIT_CPU,
127 LTTV_STATE_EXIT,
128 LTTV_STATE_ZOMBIE,
129 LTTV_STATE_WAIT,
130 LTTV_STATE_RUN,
131 LTTV_STATE_DEAD;
132
133GQuark
134 LTTV_STATE_UNBRANDED;
135
136LttvProcessType
137 LTTV_STATE_USER_THREAD,
138 LTTV_STATE_KERNEL_THREAD;
139
140LttvCPUMode
141 LTTV_CPU_UNKNOWN,
142 LTTV_CPU_IDLE,
143 LTTV_CPU_BUSY,
144 LTTV_CPU_IRQ,
145 LTTV_CPU_TRAP;
146
147LttvIRQMode
148 LTTV_IRQ_UNKNOWN,
149 LTTV_IRQ_IDLE,
150 LTTV_IRQ_BUSY;
151
152LttvBdevMode
153 LTTV_BDEV_UNKNOWN,
154 LTTV_BDEV_IDLE,
155 LTTV_BDEV_BUSY_READING,
156 LTTV_BDEV_BUSY_WRITING;
157
158static GQuark
159 LTTV_STATE_TRACEFILES,
160 LTTV_STATE_PROCESSES,
161 LTTV_STATE_PROCESS,
162 LTTV_STATE_RUNNING_PROCESS,
163 LTTV_STATE_EVENT,
164 LTTV_STATE_SAVED_STATES,
165 LTTV_STATE_SAVED_STATES_TIME,
166 LTTV_STATE_TIME,
167 LTTV_STATE_HOOKS,
168 LTTV_STATE_NAME_TABLES,
169 LTTV_STATE_TRACE_STATE_USE_COUNT,
170 LTTV_STATE_RESOURCE_CPUS,
171 LTTV_STATE_RESOURCE_IRQS,
172 LTTV_STATE_RESOURCE_BLKDEVS;
173
174static void create_max_time(LttvTraceState *tcs);
175
176static void get_max_time(LttvTraceState *tcs);
177
178static void free_max_time(LttvTraceState *tcs);
179
180static void create_name_tables(LttvTraceState *tcs);
181
182static void get_name_tables(LttvTraceState *tcs);
183
184static void free_name_tables(LttvTraceState *tcs);
185
186static void free_saved_state(LttvTraceState *tcs);
187
188static void lttv_state_free_process_table(GHashTable *processes);
189
190static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
191 GPtrArray *quarktable);
192
193/* Resource function prototypes */
194static LttvBdevState *get_hashed_bdevstate(LttvTraceState *ts, guint16 devcode);
195static LttvBdevState *bdevstate_new(void);
196static void bdevstate_free(LttvBdevState *);
197static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data);
198static LttvBdevState *bdevstate_copy(LttvBdevState *bds);
199
200
201void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
202{
203 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
204}
205
206
207void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
208{
209 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
210}
211
212
213void 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
220guint 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 */
229gboolean 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
244static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
245{
246 g_tree_destroy((GTree*)value);
247}
248
249static 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
257static void
258restore_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
339static 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
348static void free_usertrace_key(gpointer data)
349{
350 g_free(data);
351}
352
353#define MAX_STRING_LEN 4096
354
355static void
356state_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
418end:
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
430static void
431init(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
518static void
519fini(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
555static LttvTracesetContext *
556new_traceset_context(LttvTracesetContext *self)
557{
558 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
559}
560
561
562static LttvTraceContext *
563new_trace_context(LttvTracesetContext *self)
564{
565 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
566}
567
568
569static LttvTracefileContext *
570new_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
578static 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
629void 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
677static 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
774void 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 */
836static 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);
928end_loop:
929 return;
930}
931
932
933/* Called because a HDR_PROCESS_STATE was found */
934/* Append a saved state to the trace states */
935void 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);
987end_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 */
1044void 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);
1078end_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
1089static 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
1125static 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
1133static 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
1152static 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
1163static 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
1181static 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
1194static 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
1212static 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
1221static void bdevstate_free(LttvBdevState *bds)
1222{
1223 g_array_free(bds->mode_stack, FALSE);
1224 g_free(bds);
1225}
1226
1227static void bdevstate_free_cb(gpointer key, gpointer value, gpointer user_data)
1228{
1229 LttvBdevState *bds = (LttvBdevState *) value;
1230
1231 bdevstate_free(bds);
1232}
1233
1234static 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
1244static 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
1255static 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
1269static 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
1281static 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
1374static 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
1480static 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
1537static 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
1565static void
1566create_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
1578static void
1579get_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
1590static void
1591free_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
1602typedef 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
1615static void
1616create_name_tables(LttvTraceState *tcs)
1617{
1618 int i;
1619
1620 GString *fe_name = g_string_new("");
1621
1622 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1623
1624 LttvAttributeValue v;
1625
1626 GArray *hooks;
1627
1628 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1629 LTTV_POINTER, &v);
1630 g_assert(*(v.v_pointer) == NULL);
1631 *(v.v_pointer) = name_tables;
1632
1633 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1);
1634
1635 if(!lttv_trace_find_hook(tcs->parent.t,
1636 LTT_FACILITY_KERNEL_ARCH,
1637 LTT_EVENT_SYSCALL_ENTRY,
1638 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
1639 NULL, NULL, &hooks)) {
1640
1641// th = lttv_trace_hook_get_first(&th);
1642//
1643// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1644// nb = ltt_type_element_number(t);
1645//
1646// name_tables->syscall_names = g_new(GQuark, nb);
1647// name_tables->nb_syscalls = nb;
1648//
1649// for(i = 0 ; i < nb ; i++) {
1650// name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1651// if(!name_tables->syscall_names[i]) {
1652// GString *string = g_string_new("");
1653// g_string_printf(string, "syscall %u", i);
1654// name_tables->syscall_names[i] = g_quark_from_string(string->str);
1655// g_string_free(string, TRUE);
1656// }
1657// }
1658
1659 name_tables->nb_syscalls = 256;
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 lttv_trace_hook_remove_all(&hooks);
1670
1671 if(!lttv_trace_find_hook(tcs->parent.t,
1672 LTT_FACILITY_KERNEL_ARCH,
1673 LTT_EVENT_TRAP_ENTRY,
1674 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
1675 NULL, NULL, &hooks)) {
1676
1677// th = lttv_trace_hook_get_first(&th);
1678//
1679// t = ltt_field_type(lttv_trace_get_hook_field(th, 0));
1680// //nb = ltt_type_element_number(t);
1681//
1682// name_tables->trap_names = g_new(GQuark, nb);
1683// for(i = 0 ; i < nb ; i++) {
1684// name_tables->trap_names[i] = g_quark_from_string(
1685// ltt_enum_string_get(t, i));
1686// }
1687
1688 name_tables->nb_traps = 256;
1689 name_tables->trap_names = g_new(GQuark, 256);
1690 for(i = 0 ; i < 256 ; i++) {
1691 g_string_printf(fe_name, "trap %d", i);
1692 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1693 }
1694 } else {
1695 name_tables->trap_names = NULL;
1696 name_tables->nb_traps = 0;
1697 }
1698 lttv_trace_hook_remove_all(&hooks);
1699
1700 if(!lttv_trace_find_hook(tcs->parent.t,
1701 LTT_FACILITY_KERNEL,
1702 LTT_EVENT_IRQ_ENTRY,
1703 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
1704 NULL, NULL, &hooks)) {
1705
1706 /*
1707 name_tables->irq_names = g_new(GQuark, nb);
1708 for(i = 0 ; i < nb ; i++) {
1709 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1710 }
1711 */
1712
1713 name_tables->nb_irqs = 256;
1714 name_tables->irq_names = g_new(GQuark, 256);
1715 for(i = 0 ; i < 256 ; i++) {
1716 g_string_printf(fe_name, "irq %d", i);
1717 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1718 }
1719 } else {
1720 name_tables->nb_irqs = 0;
1721 name_tables->irq_names = NULL;
1722 }
1723 lttv_trace_hook_remove_all(&hooks);
1724 /*
1725 name_tables->soft_irq_names = g_new(GQuark, nb);
1726 for(i = 0 ; i < nb ; i++) {
1727 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1728 }
1729 */
1730
1731 name_tables->nb_softirqs = 256;
1732 name_tables->soft_irq_names = g_new(GQuark, 256);
1733 for(i = 0 ; i < 256 ; i++) {
1734 g_string_printf(fe_name, "softirq %d", i);
1735 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1736 }
1737 g_array_free(hooks, TRUE);
1738
1739 g_string_free(fe_name, TRUE);
1740}
1741
1742
1743static void
1744get_name_tables(LttvTraceState *tcs)
1745{
1746 LttvNameTables *name_tables;
1747
1748 LttvAttributeValue v;
1749
1750 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1751 LTTV_POINTER, &v);
1752 g_assert(*(v.v_pointer) != NULL);
1753 name_tables = (LttvNameTables *)*(v.v_pointer);
1754 //tcs->eventtype_names = name_tables->eventtype_names;
1755 tcs->syscall_names = name_tables->syscall_names;
1756 tcs->nb_syscalls = name_tables->nb_syscalls;
1757 tcs->trap_names = name_tables->trap_names;
1758 tcs->nb_traps = name_tables->nb_traps;
1759 tcs->irq_names = name_tables->irq_names;
1760 tcs->soft_irq_names = name_tables->soft_irq_names;
1761 tcs->nb_irqs = name_tables->nb_irqs;
1762 tcs->nb_softirqs = name_tables->nb_softirqs;
1763}
1764
1765
1766static void
1767free_name_tables(LttvTraceState *tcs)
1768{
1769 LttvNameTables *name_tables;
1770
1771 LttvAttributeValue v;
1772
1773 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1774 LTTV_POINTER, &v);
1775 name_tables = (LttvNameTables *)*(v.v_pointer);
1776 *(v.v_pointer) = NULL;
1777
1778 // g_free(name_tables->eventtype_names);
1779 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1780 if(name_tables->trap_names) g_free(name_tables->trap_names);
1781 if(name_tables->irq_names) g_free(name_tables->irq_names);
1782 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1783 if(name_tables) g_free(name_tables);
1784}
1785
1786#ifdef HASH_TABLE_DEBUG
1787
1788static void test_process(gpointer key, gpointer value, gpointer user_data)
1789{
1790 LttvProcessState *process = (LttvProcessState *)value;
1791
1792 /* Test for process corruption */
1793 guint stack_len = process->execution_stack->len;
1794}
1795
1796static void hash_table_check(GHashTable *table)
1797{
1798 g_hash_table_foreach(table, test_process, NULL);
1799}
1800
1801
1802#endif
1803
1804/* clears the stack and sets the state passed as argument */
1805static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1806{
1807 g_array_set_size(cpust->mode_stack, 1);
1808 ((GQuark *)cpust->mode_stack->data)[0] = state;
1809}
1810
1811static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1812{
1813 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1814 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1815}
1816
1817static void cpu_pop_mode(LttvCPUState *cpust)
1818{
1819 if(cpust->mode_stack->len <= 1)
1820 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1821 else
1822 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1823}
1824
1825/* clears the stack and sets the state passed as argument */
1826static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
1827{
1828 g_array_set_size(bdevst->mode_stack, 1);
1829 ((GQuark *)bdevst->mode_stack->data)[0] = state;
1830}
1831
1832static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
1833{
1834 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
1835 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
1836}
1837
1838static void bdev_pop_mode(LttvBdevState *bdevst)
1839{
1840 if(bdevst->mode_stack->len <= 1)
1841 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
1842 else
1843 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
1844}
1845
1846static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
1847{
1848 g_array_set_size(irqst->mode_stack, 1);
1849 ((GQuark *)irqst->mode_stack->data)[0] = state;
1850}
1851
1852static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
1853{
1854 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
1855 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
1856}
1857
1858static void irq_pop_mode(LttvIRQState *irqst)
1859{
1860 if(irqst->mode_stack->len <= 1)
1861 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
1862 else
1863 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
1864}
1865
1866static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1867 guint state_id)
1868{
1869 LttvExecutionState *es;
1870
1871 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1872 guint cpu = tfs->cpu;
1873
1874#ifdef HASH_TABLE_DEBUG
1875 hash_table_check(ts->processes);
1876#endif
1877 LttvProcessState *process = ts->running_process[cpu];
1878
1879 guint depth = process->execution_stack->len;
1880
1881 process->execution_stack =
1882 g_array_set_size(process->execution_stack, depth + 1);
1883 /* Keep in sync */
1884 process->state =
1885 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1886
1887 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1888 es->t = t;
1889 es->n = state_id;
1890 es->entry = es->change = tfs->parent.timestamp;
1891 es->cum_cpu_time = ltt_time_zero;
1892 es->s = process->state->s;
1893 process->state = es;
1894}
1895
1896/* pop state
1897 * return 1 when empty, else 0 */
1898int lttv_state_pop_state_cleanup(LttvProcessState *process,
1899 LttvTracefileState *tfs)
1900{
1901 guint depth = process->execution_stack->len;
1902
1903 if(depth == 1){
1904 return 1;
1905 }
1906
1907 process->execution_stack =
1908 g_array_set_size(process->execution_stack, depth - 1);
1909 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1910 depth - 2);
1911 process->state->change = tfs->parent.timestamp;
1912
1913 return 0;
1914}
1915
1916static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1917{
1918 guint cpu = tfs->cpu;
1919 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1920 LttvProcessState *process = ts->running_process[cpu];
1921
1922 guint depth = process->execution_stack->len;
1923
1924 if(process->state->t != t){
1925 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1926 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1927 g_info("process state has %s when pop_int is %s\n",
1928 g_quark_to_string(process->state->t),
1929 g_quark_to_string(t));
1930 g_info("{ %u, %u, %s, %s, %s }\n",
1931 process->pid,
1932 process->ppid,
1933 g_quark_to_string(process->name),
1934 g_quark_to_string(process->brand),
1935 g_quark_to_string(process->state->s));
1936 return;
1937 }
1938
1939 if(depth == 1){
1940 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1941 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1942 return;
1943 }
1944
1945 process->execution_stack =
1946 g_array_set_size(process->execution_stack, depth - 1);
1947 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1948 depth - 2);
1949 process->state->change = tfs->parent.timestamp;
1950}
1951
1952struct search_result {
1953 const LttTime *time; /* Requested time */
1954 LttTime *best; /* Best result */
1955};
1956
1957static gint search_usertrace(gconstpointer a, gconstpointer b)
1958{
1959 const LttTime *elem_time = (const LttTime*)a;
1960 /* Explicit non const cast */
1961 struct search_result *res = (struct search_result *)b;
1962
1963 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1964 /* The usertrace was created before the schedchange */
1965 /* Get larger keys */
1966 return 1;
1967 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1968 /* The usertrace was created after the schedchange time */
1969 /* Get smaller keys */
1970 if(res->best) {
1971 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1972 res->best = (LttTime *)elem_time;
1973 }
1974 } else {
1975 res->best = (LttTime *)elem_time;
1976 }
1977 return -1;
1978 }
1979 return 0;
1980}
1981
1982static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1983 guint pid, const LttTime *timestamp)
1984{
1985 LttvTracefileState *tfs = NULL;
1986 struct search_result res;
1987 /* Find the usertrace associated with a pid and time interval.
1988 * Search in the usertraces by PID (within a hash) and then, for each
1989 * corresponding element of the array, find the first one with creation
1990 * timestamp the lowest, but higher or equal to "timestamp". */
1991 res.time = timestamp;
1992 res.best = NULL;
1993 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1994 if(usertrace_tree) {
1995 g_tree_search(usertrace_tree, search_usertrace, &res);
1996 if(res.best)
1997 tfs = g_tree_lookup(usertrace_tree, res.best);
1998 }
1999
2000 return tfs;
2001}
2002
2003
2004LttvProcessState *
2005lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
2006 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
2007{
2008 LttvProcessState *process = g_new(LttvProcessState, 1);
2009
2010 LttvExecutionState *es;
2011
2012 char buffer[128];
2013
2014 process->pid = pid;
2015 process->tgid = tgid;
2016 process->cpu = cpu;
2017 process->name = name;
2018 process->brand = LTTV_STATE_UNBRANDED;
2019 //process->last_cpu = tfs->cpu_name;
2020 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2021 process->type = LTTV_STATE_USER_THREAD;
2022 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
2023 process->current_function = 0; //function 0x0 by default.
2024
2025 g_info("Process %u, core %p", process->pid, process);
2026 g_hash_table_insert(tcs->processes, process, process);
2027
2028 if(parent) {
2029 process->ppid = parent->pid;
2030 process->creation_time = *timestamp;
2031 }
2032
2033 /* No parent. This process exists but we are missing all information about
2034 its creation. The birth time is set to zero but we remember the time of
2035 insertion */
2036
2037 else {
2038 process->ppid = 0;
2039 process->creation_time = ltt_time_zero;
2040 }
2041
2042 process->insertion_time = *timestamp;
2043 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
2044 process->creation_time.tv_nsec);
2045 process->pid_time = g_quark_from_string(buffer);
2046 process->cpu = cpu;
2047 //process->last_cpu = tfs->cpu_name;
2048 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
2049 process->execution_stack = g_array_sized_new(FALSE, FALSE,
2050 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
2051 process->execution_stack = g_array_set_size(process->execution_stack, 2);
2052 es = process->state = &g_array_index(process->execution_stack,
2053 LttvExecutionState, 0);
2054 es->t = LTTV_STATE_USER_MODE;
2055 es->n = LTTV_STATE_SUBMODE_NONE;
2056 es->entry = *timestamp;
2057 //g_assert(timestamp->tv_sec != 0);
2058 es->change = *timestamp;
2059 es->cum_cpu_time = ltt_time_zero;
2060 es->s = LTTV_STATE_RUN;
2061
2062 es = process->state = &g_array_index(process->execution_stack,
2063 LttvExecutionState, 1);
2064 es->t = LTTV_STATE_SYSCALL;
2065 es->n = LTTV_STATE_SUBMODE_NONE;
2066 es->entry = *timestamp;
2067 //g_assert(timestamp->tv_sec != 0);
2068 es->change = *timestamp;
2069 es->cum_cpu_time = ltt_time_zero;
2070 es->s = LTTV_STATE_WAIT_FORK;
2071
2072 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2073 process->user_stack = g_array_sized_new(FALSE, FALSE,
2074 sizeof(guint64), 0);
2075
2076 return process;
2077}
2078
2079LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
2080 guint pid)
2081{
2082 LttvProcessState key;
2083 LttvProcessState *process;
2084
2085 key.pid = pid;
2086 key.cpu = cpu;
2087 process = g_hash_table_lookup(ts->processes, &key);
2088 return process;
2089}
2090
2091LttvProcessState *
2092lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
2093 const LttTime *timestamp)
2094{
2095 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
2096 LttvExecutionState *es;
2097
2098 /* Put ltt_time_zero creation time for unexisting processes */
2099 if(unlikely(process == NULL)) {
2100 process = lttv_state_create_process(ts,
2101 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
2102 /* We are not sure is it's a kernel thread or normal thread, put the
2103 * bottom stack state to unknown */
2104 process->execution_stack =
2105 g_array_set_size(process->execution_stack, 1);
2106 process->state = es =
2107 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2108 es->t = LTTV_STATE_MODE_UNKNOWN;
2109 es->s = LTTV_STATE_UNNAMED;
2110 }
2111 return process;
2112}
2113
2114/* FIXME : this function should be called when we receive an event telling that
2115 * release_task has been called in the kernel. In happens generally when
2116 * the parent waits for its child terminaison, but may also happen in special
2117 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2118 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2119 * of a killed thread ground, but isn't the leader.
2120 */
2121static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
2122{
2123 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2124 LttvProcessState key;
2125
2126 key.pid = process->pid;
2127 key.cpu = process->cpu;
2128 g_hash_table_remove(ts->processes, &key);
2129 g_array_free(process->execution_stack, TRUE);
2130 g_array_free(process->user_stack, TRUE);
2131 g_free(process);
2132}
2133
2134
2135static void free_process_state(gpointer key, gpointer value,gpointer user_data)
2136{
2137 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
2138 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
2139 g_free(value);
2140}
2141
2142
2143static void lttv_state_free_process_table(GHashTable *processes)
2144{
2145 g_hash_table_foreach(processes, free_process_state, NULL);
2146 g_hash_table_destroy(processes);
2147}
2148
2149
2150static gboolean syscall_entry(void *hook_data, void *call_data)
2151{
2152 LttvTracefileState *s = (LttvTracefileState *)call_data;
2153 guint cpu = s->cpu;
2154 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2155 LttvProcessState *process = ts->running_process[cpu];
2156 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2157 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2158 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2159
2160 LttvExecutionSubmode submode;
2161
2162 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2163 guint syscall = ltt_event_get_unsigned(e, f);
2164
2165 if(syscall < nb_syscalls) {
2166 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2167 syscall];
2168 } else {
2169 /* Fixup an incomplete syscall table */
2170 GString *string = g_string_new("");
2171 g_string_printf(string, "syscall %u", syscall);
2172 submode = g_quark_from_string(string->str);
2173 g_string_free(string, TRUE);
2174 }
2175 /* There can be no system call from PID 0 : unknown state */
2176 if(process->pid != 0)
2177 push_state(s, LTTV_STATE_SYSCALL, submode);
2178 return FALSE;
2179}
2180
2181
2182static gboolean syscall_exit(void *hook_data, void *call_data)
2183{
2184 LttvTracefileState *s = (LttvTracefileState *)call_data;
2185 guint cpu = s->cpu;
2186 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2187 LttvProcessState *process = ts->running_process[cpu];
2188
2189 /* There can be no system call from PID 0 : unknown state */
2190 if(process->pid != 0)
2191 pop_state(s, LTTV_STATE_SYSCALL);
2192 return FALSE;
2193}
2194
2195
2196static gboolean trap_entry(void *hook_data, void *call_data)
2197{
2198 LttvTracefileState *s = (LttvTracefileState *)call_data;
2199 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2200 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2201 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2202
2203 LttvExecutionSubmode submode;
2204
2205 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2206 guint64 trap = ltt_event_get_long_unsigned(e, f);
2207
2208 if(trap < nb_traps) {
2209 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2210 } else {
2211 /* Fixup an incomplete trap table */
2212 GString *string = g_string_new("");
2213 g_string_printf(string, "trap %llu", trap);
2214 submode = g_quark_from_string(string->str);
2215 g_string_free(string, TRUE);
2216 }
2217
2218 push_state(s, LTTV_STATE_TRAP, submode);
2219
2220 /* update cpu status */
2221 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2222
2223 return FALSE;
2224}
2225
2226static gboolean trap_exit(void *hook_data, void *call_data)
2227{
2228 LttvTracefileState *s = (LttvTracefileState *)call_data;
2229
2230 pop_state(s, LTTV_STATE_TRAP);
2231
2232 /* update cpu status */
2233 cpu_pop_mode(s->cpu_state);
2234
2235 return FALSE;
2236}
2237
2238static gboolean irq_entry(void *hook_data, void *call_data)
2239{
2240 LttvTracefileState *s = (LttvTracefileState *)call_data;
2241 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2242 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2243 //guint8 ev_id = ltt_event_eventtype_id(e);
2244 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2245 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2246
2247 LttvExecutionSubmode submode;
2248 guint64 irq = ltt_event_get_long_unsigned(e, f);
2249 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
2250
2251 if(irq < nb_irqs) {
2252 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2253 } else {
2254 /* Fixup an incomplete irq table */
2255 GString *string = g_string_new("");
2256 g_string_printf(string, "irq %llu", irq);
2257 submode = g_quark_from_string(string->str);
2258 g_string_free(string, TRUE);
2259 }
2260
2261 /* Do something with the info about being in user or system mode when int? */
2262 push_state(s, LTTV_STATE_IRQ, submode);
2263
2264 /* update cpu status */
2265 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2266
2267 /* update irq status */
2268 s->cpu_state->last_irq = irq;
2269 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2270
2271 return FALSE;
2272}
2273
2274static gboolean soft_irq_exit(void *hook_data, void *call_data)
2275{
2276 LttvTracefileState *s = (LttvTracefileState *)call_data;
2277
2278 pop_state(s, LTTV_STATE_SOFT_IRQ);
2279 return FALSE;
2280}
2281
2282
2283
2284static gboolean irq_exit(void *hook_data, void *call_data)
2285{
2286 LttvTracefileState *s = (LttvTracefileState *)call_data;
2287 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2288
2289 pop_state(s, LTTV_STATE_IRQ);
2290
2291 /* update cpu status */
2292 cpu_pop_mode(s->cpu_state);
2293
2294 /* update irq status */
2295 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2296
2297 return FALSE;
2298}
2299
2300static gboolean soft_irq_entry(void *hook_data, void *call_data)
2301{
2302 LttvTracefileState *s = (LttvTracefileState *)call_data;
2303 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2304 //guint8 ev_id = ltt_event_eventtype_id(e);
2305 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2306 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2307
2308 LttvExecutionSubmode submode;
2309 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2310 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
2311
2312 if(softirq < nb_softirqs) {
2313 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2314 } else {
2315 /* Fixup an incomplete irq table */
2316 GString *string = g_string_new("");
2317 g_string_printf(string, "softirq %llu", softirq);
2318 submode = g_quark_from_string(string->str);
2319 g_string_free(string, TRUE);
2320 }
2321
2322 /* Do something with the info about being in user or system mode when int? */
2323 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2324 return FALSE;
2325}
2326
2327static gboolean enum_interrupt(void *hook_data, void *call_data)
2328{
2329 LttvTracefileState *s = (LttvTracefileState *)call_data;
2330 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2331 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2332 //guint8 ev_id = ltt_event_eventtype_id(e);
2333 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2334
2335 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2336 lttv_trace_get_hook_field(th, 0)));
2337 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
2338
2339 ts->irq_names[irq] = action;
2340
2341 return FALSE;
2342}
2343
2344
2345static gboolean bdev_request_issue(void *hook_data, void *call_data)
2346{
2347 LttvTracefileState *s = (LttvTracefileState *)call_data;
2348 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2349 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2350 //guint8 ev_id = ltt_event_eventtype_id(e);
2351 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2352
2353 guint major = ltt_event_get_long_unsigned(e,
2354 lttv_trace_get_hook_field(th, 0));
2355 guint minor = ltt_event_get_long_unsigned(e,
2356 lttv_trace_get_hook_field(th, 1));
2357 guint oper = ltt_event_get_long_unsigned(e,
2358 lttv_trace_get_hook_field(th, 2));
2359 guint16 devcode = MKDEV(major,minor);
2360
2361 /* have we seen this block device before? */
2362 gpointer bdev = get_hashed_bdevstate(ts, devcode);
2363
2364 if(oper == 0)
2365 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2366 else
2367 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2368
2369 return FALSE;
2370}
2371
2372static gboolean bdev_request_complete(void *hook_data, void *call_data)
2373{
2374 LttvTracefileState *s = (LttvTracefileState *)call_data;
2375 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2376 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2377 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2378
2379 guint major = ltt_event_get_long_unsigned(e,
2380 lttv_trace_get_hook_field(th, 0));
2381 guint minor = ltt_event_get_long_unsigned(e,
2382 lttv_trace_get_hook_field(th, 1));
2383 //guint oper = ltt_event_get_long_unsigned(e,
2384 // lttv_trace_get_hook_field(th, 2));
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
2396static 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
2414static 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
2448static 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 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2455 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2456
2457 push_function(s, funcptr);
2458 return FALSE;
2459}
2460
2461static gboolean function_exit(void *hook_data, void *call_data)
2462{
2463 LttvTracefileState *s = (LttvTracefileState *)call_data;
2464 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2465 //guint8 ev_id = ltt_event_eventtype_id(e);
2466 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2467 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
2468 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2469
2470 pop_function(s, funcptr);
2471 return FALSE;
2472}
2473
2474static gboolean schedchange(void *hook_data, void *call_data)
2475{
2476 LttvTracefileState *s = (LttvTracefileState *)call_data;
2477 guint cpu = s->cpu;
2478 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2479 LttvProcessState *process = ts->running_process[cpu];
2480 //LttvProcessState *old_process = ts->running_process[cpu];
2481
2482 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2483 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2484 guint pid_in, pid_out;
2485 gint64 state_out;
2486
2487 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2488 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2489 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
2490
2491 if(likely(process != NULL)) {
2492
2493 /* We could not know but it was not the idle process executing.
2494 This should only happen at the beginning, before the first schedule
2495 event, and when the initial information (current process for each CPU)
2496 is missing. It is not obvious how we could, after the fact, compensate
2497 the wrongly attributed statistics. */
2498
2499 //This test only makes sense once the state is known and if there is no
2500 //missing events. We need to silently ignore schedchange coming after a
2501 //process_free, or it causes glitches. (FIXME)
2502 //if(unlikely(process->pid != pid_out)) {
2503 // g_assert(process->pid == 0);
2504 //}
2505 if(process->pid == 0
2506 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2507 if(pid_out == 0) {
2508 /* Scheduling out of pid 0 at beginning of the trace :
2509 * we know for sure it is in syscall mode at this point. */
2510 g_assert(process->execution_stack->len == 1);
2511 process->state->t = LTTV_STATE_SYSCALL;
2512 process->state->s = LTTV_STATE_WAIT;
2513 process->state->change = s->parent.timestamp;
2514 process->state->entry = s->parent.timestamp;
2515 }
2516 } else {
2517 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2518 process->state->s = LTTV_STATE_ZOMBIE;
2519 process->state->change = s->parent.timestamp;
2520 } else {
2521 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2522 else process->state->s = LTTV_STATE_WAIT;
2523 process->state->change = s->parent.timestamp;
2524 }
2525
2526 if(state_out == 32 || state_out == 128)
2527 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
2528 /* see sched.h for states */
2529 }
2530 }
2531 process = ts->running_process[cpu] =
2532 lttv_state_find_process_or_create(
2533 (LttvTraceState*)s->parent.t_context,
2534 cpu, pid_in,
2535 &s->parent.timestamp);
2536 process->state->s = LTTV_STATE_RUN;
2537 process->cpu = cpu;
2538 if(process->usertrace)
2539 process->usertrace->cpu = cpu;
2540 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2541 process->state->change = s->parent.timestamp;
2542
2543 /* update cpu status */
2544 if(pid_in == 0)
2545 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
2546 else
2547 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
2548
2549 return FALSE;
2550}
2551
2552static gboolean process_fork(void *hook_data, void *call_data)
2553{
2554 LttvTracefileState *s = (LttvTracefileState *)call_data;
2555 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2556 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2557 guint parent_pid;
2558 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2559 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2560 //LttvProcessState *zombie_process;
2561 guint cpu = s->cpu;
2562 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2563 LttvProcessState *process = ts->running_process[cpu];
2564 LttvProcessState *child_process;
2565 struct marker_field *f;
2566
2567 /* Parent PID */
2568 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2569
2570 /* Child PID */
2571 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2572 s->parent.target_pid = child_pid;
2573
2574 /* Child TGID */
2575 f = lttv_trace_get_hook_field(th, 2);
2576 if (likely(f))
2577 child_tgid = ltt_event_get_unsigned(e, f);
2578 else
2579 child_tgid = 0;
2580
2581 /* Mathieu : it seems like the process might have been scheduled in before the
2582 * fork, and, in a rare case, might be the current process. This might happen
2583 * in a SMP case where we don't have enough precision on the clocks.
2584 *
2585 * Test reenabled after precision fixes on time. (Mathieu) */
2586#if 0
2587 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2588
2589 if(unlikely(zombie_process != NULL)) {
2590 /* Reutilisation of PID. Only now we are sure that the old PID
2591 * has been released. FIXME : should know when release_task happens instead.
2592 */
2593 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2594 guint i;
2595 for(i=0; i< num_cpus; i++) {
2596 g_assert(zombie_process != ts->running_process[i]);
2597 }
2598
2599 exit_process(s, zombie_process);
2600 }
2601#endif //0
2602 g_assert(process->pid != child_pid);
2603 // FIXME : Add this test in the "known state" section
2604 // g_assert(process->pid == parent_pid);
2605 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2606 if(child_process == NULL) {
2607 child_process = lttv_state_create_process(ts, process, cpu,
2608 child_pid, child_tgid,
2609 LTTV_STATE_UNNAMED, &s->parent.timestamp);
2610 } else {
2611 /* The process has already been created : due to time imprecision between
2612 * multiple CPUs : it has been scheduled in before creation. Note that we
2613 * shouldn't have this kind of imprecision.
2614 *
2615 * Simply put a correct parent.
2616 */
2617 g_assert(0); /* This is a problematic case : the process has been created
2618 before the fork event */
2619 child_process->ppid = process->pid;
2620 child_process->tgid = child_tgid;
2621 }
2622 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2623 child_process->name = process->name;
2624 child_process->brand = process->brand;
2625
2626 return FALSE;
2627}
2628
2629/* We stamp a newly created process as kernel_thread.
2630 * The thread should not be running yet. */
2631static gboolean process_kernel_thread(void *hook_data, void *call_data)
2632{
2633 LttvTracefileState *s = (LttvTracefileState *)call_data;
2634 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2635 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2636 guint pid;
2637 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2638 LttvProcessState *process;
2639 LttvExecutionState *es;
2640
2641 /* PID */
2642 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2643 s->parent.target_pid = pid;
2644
2645 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2646 &ltt_time_zero);
2647 process->execution_stack =
2648 g_array_set_size(process->execution_stack, 1);
2649 es = process->state =
2650 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2651 es->t = LTTV_STATE_SYSCALL;
2652 process->type = LTTV_STATE_KERNEL_THREAD;
2653
2654 return FALSE;
2655}
2656
2657static gboolean process_exit(void *hook_data, void *call_data)
2658{
2659 LttvTracefileState *s = (LttvTracefileState *)call_data;
2660 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2661 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2662 guint pid;
2663 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2664 LttvProcessState *process; // = ts->running_process[cpu];
2665
2666 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2667 s->parent.target_pid = pid;
2668
2669 // FIXME : Add this test in the "known state" section
2670 // g_assert(process->pid == pid);
2671
2672 process = lttv_state_find_process(ts, ANY_CPU, pid);
2673 if(likely(process != NULL)) {
2674 process->state->s = LTTV_STATE_EXIT;
2675 }
2676 return FALSE;
2677}
2678
2679static gboolean process_free(void *hook_data, void *call_data)
2680{
2681 LttvTracefileState *s = (LttvTracefileState *)call_data;
2682 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2683 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2684 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2685 guint release_pid;
2686 LttvProcessState *process;
2687
2688 /* PID of the process to release */
2689 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2690 s->parent.target_pid = release_pid;
2691
2692 g_assert(release_pid != 0);
2693
2694 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2695
2696 if(likely(process != NULL)) {
2697 /* release_task is happening at kernel level : we can now safely release
2698 * the data structure of the process */
2699 //This test is fun, though, as it may happen that
2700 //at time t : CPU 0 : process_free
2701 //at time t+150ns : CPU 1 : schedule out
2702 //Clearly due to time imprecision, we disable it. (Mathieu)
2703 //If this weird case happen, we have no choice but to put the
2704 //Currently running process on the cpu to 0.
2705 //I re-enable it following time precision fixes. (Mathieu)
2706 //Well, in the case where an process is freed by a process on another CPU
2707 //and still scheduled, it happens that this is the schedchange that will
2708 //drop the last reference count. Do not free it here!
2709 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2710 guint i;
2711 for(i=0; i< num_cpus; i++) {
2712 //g_assert(process != ts->running_process[i]);
2713 if(process == ts->running_process[i]) {
2714 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2715 break;
2716 }
2717 }
2718 if(i == num_cpus) /* process is not scheduled */
2719 exit_process(s, process);
2720 }
2721
2722 return FALSE;
2723}
2724
2725
2726static gboolean process_exec(void *hook_data, void *call_data)
2727{
2728 LttvTracefileState *s = (LttvTracefileState *)call_data;
2729 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2730 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2731 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2732 //gchar *name;
2733 guint cpu = s->cpu;
2734 LttvProcessState *process = ts->running_process[cpu];
2735
2736#if 0//how to use a sequence that must be transformed in a string
2737 /* PID of the process to release */
2738 guint64 name_len = ltt_event_field_element_number(e,
2739 lttv_trace_get_hook_field(th, 0));
2740 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2741 LttField *child = ltt_event_field_element_select(e,
2742 lttv_trace_get_hook_field(th, 0), 0);
2743 gchar *name_begin =
2744 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
2745 gchar *null_term_name = g_new(gchar, name_len+1);
2746 memcpy(null_term_name, name_begin, name_len);
2747 null_term_name[name_len] = '\0';
2748 process->name = g_quark_from_string(null_term_name);
2749#endif //0
2750
2751 process->name = g_quark_from_string(ltt_event_get_string(e,
2752 lttv_trace_get_hook_field(th, 0)));
2753 process->brand = LTTV_STATE_UNBRANDED;
2754 //g_free(null_term_name);
2755 return FALSE;
2756}
2757
2758static gboolean thread_brand(void *hook_data, void *call_data)
2759{
2760 LttvTracefileState *s = (LttvTracefileState *)call_data;
2761 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2762 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2763 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2764 gchar *name;
2765 guint cpu = s->cpu;
2766 LttvProcessState *process = ts->running_process[cpu];
2767
2768 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2769 process->brand = g_quark_from_string(name);
2770
2771 return FALSE;
2772}
2773
2774static void fix_process(gpointer key, gpointer value,
2775 gpointer user_data)
2776{
2777 LttvProcessState *process;
2778 LttvExecutionState *es;
2779 process = (LttvProcessState *)value;
2780 LttTime *timestamp = (LttTime*)user_data;
2781
2782 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2783 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2784 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2785 es->t = LTTV_STATE_SYSCALL;
2786 es->n = LTTV_STATE_SUBMODE_NONE;
2787 es->entry = *timestamp;
2788 es->change = *timestamp;
2789 es->cum_cpu_time = ltt_time_zero;
2790 if(es->s == LTTV_STATE_UNNAMED)
2791 es->s = LTTV_STATE_WAIT;
2792 }
2793 } else {
2794 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2795 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2796 es->t = LTTV_STATE_USER_MODE;
2797 es->n = LTTV_STATE_SUBMODE_NONE;
2798 es->entry = *timestamp;
2799 //g_assert(timestamp->tv_sec != 0);
2800 es->change = *timestamp;
2801 es->cum_cpu_time = ltt_time_zero;
2802 if(es->s == LTTV_STATE_UNNAMED)
2803 es->s = LTTV_STATE_RUN;
2804
2805 if(process->execution_stack->len == 1) {
2806 /* Still in bottom unknown mode, means never did a system call
2807 * May be either in user mode, syscall mode, running or waiting.*/
2808 /* FIXME : we may be tagging syscall mode when being user mode */
2809 process->execution_stack =
2810 g_array_set_size(process->execution_stack, 2);
2811 es = process->state = &g_array_index(process->execution_stack,
2812 LttvExecutionState, 1);
2813 es->t = LTTV_STATE_SYSCALL;
2814 es->n = LTTV_STATE_SUBMODE_NONE;
2815 es->entry = *timestamp;
2816 //g_assert(timestamp->tv_sec != 0);
2817 es->change = *timestamp;
2818 es->cum_cpu_time = ltt_time_zero;
2819 if(es->s == LTTV_STATE_WAIT_FORK)
2820 es->s = LTTV_STATE_WAIT;
2821 }
2822 }
2823 }
2824}
2825
2826static gboolean statedump_end(void *hook_data, void *call_data)
2827{
2828 LttvTracefileState *s = (LttvTracefileState *)call_data;
2829 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2830 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2831 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2832 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
2833
2834 /* For all processes */
2835 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2836 /* else, if stack[0] is unknown, set to user mode, running */
2837
2838 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
2839
2840 return FALSE;
2841}
2842
2843static gboolean enum_process_state(void *hook_data, void *call_data)
2844{
2845 LttvTracefileState *s = (LttvTracefileState *)call_data;
2846 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2847 //It's slow : optimise later by doing this before reading trace.
2848 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2849 guint parent_pid;
2850 guint pid;
2851 guint tgid;
2852 gchar * command;
2853 guint cpu = s->cpu;
2854 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2855 LttvProcessState *process = ts->running_process[cpu];
2856 LttvProcessState *parent_process;
2857 struct marker_field *f;
2858 GQuark type, mode, submode, status;
2859 LttvExecutionState *es;
2860 guint i, nb_cpus;
2861
2862 /* PID */
2863 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2864 s->parent.target_pid = pid;
2865
2866 /* Parent PID */
2867 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2868
2869 /* Command name */
2870 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
2871
2872 /* type */
2873 f = lttv_trace_get_hook_field(th, 3);
2874 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
2875
2876 /* mode */
2877 f = lttv_trace_get_hook_field(th, 4);
2878 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
2879
2880 /* submode */
2881 f = lttv_trace_get_hook_field(th, 5);
2882 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
2883
2884 /* status */
2885 f = lttv_trace_get_hook_field(th, 6);
2886 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
2887
2888 /* TGID */
2889 f = lttv_trace_get_hook_field(th, 7);
2890 if(f)
2891 tgid = ltt_event_get_unsigned(e, f);
2892 else
2893 tgid = 0;
2894
2895 if(pid == 0) {
2896 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2897 for(i=0; i<nb_cpus; i++) {
2898 process = lttv_state_find_process(ts, i, pid);
2899 g_assert(process != NULL);
2900
2901 process->ppid = parent_pid;
2902 process->tgid = tgid;
2903 process->name = g_quark_from_string(command);
2904 es =
2905 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2906 process->type = LTTV_STATE_KERNEL_THREAD;
2907 }
2908
2909 } else {
2910 /* The process might exist if a process was forked while performing the
2911 * state dump. */
2912 process = lttv_state_find_process(ts, ANY_CPU, pid);
2913 if(process == NULL) {
2914 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2915 process = lttv_state_create_process(ts, parent_process, cpu,
2916 pid, tgid, g_quark_from_string(command),
2917 &s->parent.timestamp);
2918
2919 /* Keep the stack bottom : a running user mode */
2920 /* Disabled because of inconsistencies in the current statedump states. */
2921 if(type == LTTV_STATE_KERNEL_THREAD) {
2922 /* Only keep the bottom
2923 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2924 /* Will cause expected trap when in fact being syscall (even after end of
2925 * statedump event)
2926 * Will cause expected interrupt when being syscall. (only before end of
2927 * statedump event) */
2928 // This will cause a "popping last state on stack, ignoring it."
2929 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2930 es = process->state = &g_array_index(process->execution_stack,
2931 LttvExecutionState, 0);
2932 process->type = LTTV_STATE_KERNEL_THREAD;
2933 es->t = LTTV_STATE_MODE_UNKNOWN;
2934 es->s = LTTV_STATE_UNNAMED;
2935 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2936 #if 0
2937 es->t = LTTV_STATE_SYSCALL;
2938 es->s = status;
2939 es->n = submode;
2940 #endif //0
2941 } else {
2942 /* User space process :
2943 * bottom : user mode
2944 * either currently running or scheduled out.
2945 * can be scheduled out because interrupted in (user mode or in syscall)
2946 * or because of an explicit call to the scheduler in syscall. Note that
2947 * the scheduler call comes after the irq_exit, so never in interrupt
2948 * context. */
2949 // temp workaround : set size to 1 : only have user mode bottom of stack.
2950 // will cause g_info message of expected syscall mode when in fact being
2951 // in user mode. Can also cause expected trap when in fact being user
2952 // mode in the event of a page fault reenabling interrupts in the handler.
2953 // Expected syscall and trap can also happen after the end of statedump
2954 // This will cause a "popping last state on stack, ignoring it."
2955 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2956 es = process->state = &g_array_index(process->execution_stack,
2957 LttvExecutionState, 0);
2958 es->t = LTTV_STATE_MODE_UNKNOWN;
2959 es->s = LTTV_STATE_UNNAMED;
2960 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2961 #if 0
2962 es->t = LTTV_STATE_USER_MODE;
2963 es->s = status;
2964 es->n = submode;
2965 #endif //0
2966 }
2967 #if 0
2968 /* UNKNOWN STATE */
2969 {
2970 es = process->state = &g_array_index(process->execution_stack,
2971 LttvExecutionState, 1);
2972 es->t = LTTV_STATE_MODE_UNKNOWN;
2973 es->s = LTTV_STATE_UNNAMED;
2974 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2975 }
2976 #endif //0
2977 } else {
2978 /* The process has already been created :
2979 * Probably was forked while dumping the process state or
2980 * was simply scheduled in prior to get the state dump event.
2981 */
2982 process->ppid = parent_pid;
2983 process->tgid = tgid;
2984 process->name = g_quark_from_string(command);
2985 process->type = type;
2986 es =
2987 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2988#if 0
2989 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2990 if(type == LTTV_STATE_KERNEL_THREAD)
2991 es->t = LTTV_STATE_SYSCALL;
2992 else
2993 es->t = LTTV_STATE_USER_MODE;
2994 }
2995#endif //0
2996 /* Don't mess around with the stack, it will eventually become
2997 * ok after the end of state dump. */
2998 }
2999 }
3000
3001 return FALSE;
3002}
3003
3004gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3005{
3006 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3007
3008 lttv_state_add_event_hooks(tss);
3009
3010 return 0;
3011}
3012
3013void lttv_state_add_event_hooks(LttvTracesetState *self)
3014{
3015 LttvTraceset *traceset = self->parent.ts;
3016
3017 guint i, j, k, nb_trace, nb_tracefile;
3018
3019 LttvTraceState *ts;
3020
3021 LttvTracefileState *tfs;
3022
3023 GArray *hooks;
3024
3025 LttvTraceHook *th;
3026
3027 LttvAttributeValue val;
3028
3029 nb_trace = lttv_traceset_number(traceset);
3030 for(i = 0 ; i < nb_trace ; i++) {
3031 ts = (LttvTraceState *)self->parent.traces[i];
3032
3033 /* Find the eventtype id for the following events and register the
3034 associated by id hooks. */
3035
3036 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
3037 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3038 //hn = 0;
3039
3040 lttv_trace_find_hook(ts->parent.t,
3041 LTT_FACILITY_KERNEL_ARCH,
3042 LTT_EVENT_SYSCALL_ENTRY,
3043 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3044 syscall_entry, NULL, &hooks);
3045
3046 lttv_trace_find_hook(ts->parent.t,
3047 LTT_FACILITY_KERNEL_ARCH,
3048 LTT_EVENT_SYSCALL_EXIT,
3049 NULL,
3050 syscall_exit, NULL, &hooks);
3051
3052 lttv_trace_find_hook(ts->parent.t,
3053 LTT_FACILITY_KERNEL_ARCH,
3054 LTT_EVENT_TRAP_ENTRY,
3055 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3056 trap_entry, NULL, &hooks);
3057
3058 lttv_trace_find_hook(ts->parent.t,
3059 LTT_FACILITY_KERNEL_ARCH,
3060 LTT_EVENT_TRAP_EXIT,
3061 NULL,
3062 trap_exit, NULL, &hooks);
3063
3064 lttv_trace_find_hook(ts->parent.t,
3065 LTT_FACILITY_KERNEL,
3066 LTT_EVENT_IRQ_ENTRY,
3067 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3068 irq_entry, NULL, &hooks);
3069
3070 lttv_trace_find_hook(ts->parent.t,
3071 LTT_FACILITY_KERNEL,
3072 LTT_EVENT_IRQ_EXIT,
3073 NULL,
3074 irq_exit, NULL, &hooks);
3075
3076 lttv_trace_find_hook(ts->parent.t,
3077 LTT_FACILITY_KERNEL,
3078 LTT_EVENT_SOFT_IRQ_ENTRY,
3079 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3080 soft_irq_entry, NULL, &hooks);
3081
3082 lttv_trace_find_hook(ts->parent.t,
3083 LTT_FACILITY_KERNEL,
3084 LTT_EVENT_SOFT_IRQ_EXIT,
3085 NULL,
3086 soft_irq_exit, NULL, &hooks);
3087
3088 lttv_trace_find_hook(ts->parent.t,
3089 LTT_FACILITY_KERNEL,
3090 LTT_EVENT_SCHED_SCHEDULE,
3091 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3092 LTT_FIELD_PREV_STATE),
3093 schedchange, NULL, &hooks);
3094
3095 lttv_trace_find_hook(ts->parent.t,
3096 LTT_FACILITY_KERNEL,
3097 LTT_EVENT_PROCESS_FORK,
3098 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3099 LTT_FIELD_CHILD_TGID),
3100 process_fork, NULL, &hooks);
3101
3102 lttv_trace_find_hook(ts->parent.t,
3103 LTT_FACILITY_KERNEL_ARCH,
3104 LTT_EVENT_KTHREAD_CREATE,
3105 FIELD_ARRAY(LTT_FIELD_PID),
3106 process_kernel_thread, NULL, &hooks);
3107
3108 lttv_trace_find_hook(ts->parent.t,
3109 LTT_FACILITY_KERNEL,
3110 LTT_EVENT_PROCESS_EXIT,
3111 FIELD_ARRAY(LTT_FIELD_PID),
3112 process_exit, NULL, &hooks);
3113
3114 lttv_trace_find_hook(ts->parent.t,
3115 LTT_FACILITY_KERNEL,
3116 LTT_EVENT_PROCESS_FREE,
3117 FIELD_ARRAY(LTT_FIELD_PID),
3118 process_free, NULL, &hooks);
3119
3120 lttv_trace_find_hook(ts->parent.t,
3121 LTT_FACILITY_FS,
3122 LTT_EVENT_EXEC,
3123 FIELD_ARRAY(LTT_FIELD_FILENAME),
3124 process_exec, NULL, &hooks);
3125
3126 lttv_trace_find_hook(ts->parent.t,
3127 LTT_FACILITY_USER_GENERIC,
3128 LTT_EVENT_THREAD_BRAND,
3129 FIELD_ARRAY(LTT_FIELD_NAME),
3130 thread_brand, NULL, &hooks);
3131
3132 /* statedump-related hooks */
3133 lttv_trace_find_hook(ts->parent.t,
3134 LTT_FACILITY_LIST,
3135 LTT_EVENT_PROCESS_STATE,
3136 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3137 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3138 LTT_FIELD_STATUS, LTT_FIELD_TGID),
3139 enum_process_state, NULL, &hooks);
3140
3141 lttv_trace_find_hook(ts->parent.t,
3142 LTT_FACILITY_LIST,
3143 LTT_EVENT_STATEDUMP_END,
3144 NULL,
3145 statedump_end, NULL, &hooks);
3146
3147 lttv_trace_find_hook(ts->parent.t,
3148 LTT_FACILITY_LIST,
3149 LTT_EVENT_LIST_INTERRUPT,
3150 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
3151 enum_interrupt, NULL, &hooks);
3152
3153 lttv_trace_find_hook(ts->parent.t,
3154 LTT_FACILITY_BLOCK,
3155 LTT_EVENT_REQUEST_ISSUE,
3156 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3157 bdev_request_issue, NULL, &hooks);
3158
3159 lttv_trace_find_hook(ts->parent.t,
3160 LTT_FACILITY_BLOCK,
3161 LTT_EVENT_REQUEST_COMPLETE,
3162 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3163 bdev_request_complete, NULL, &hooks);
3164
3165 lttv_trace_find_hook(ts->parent.t,
3166 LTT_FACILITY_USER_GENERIC,
3167 LTT_EVENT_FUNCTION_ENTRY,
3168 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3169 function_entry, NULL, &hooks);
3170
3171 lttv_trace_find_hook(ts->parent.t,
3172 LTT_FACILITY_USER_GENERIC,
3173 LTT_EVENT_FUNCTION_EXIT,
3174 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3175 function_exit, NULL, &hooks);
3176
3177 /* Add these hooks to each event_by_id hooks list */
3178
3179 nb_tracefile = ts->parent.tracefiles->len;
3180
3181 for(j = 0 ; j < nb_tracefile ; j++) {
3182 tfs =
3183 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3184 LttvTracefileContext*, j));
3185
3186 for(k = 0 ; k < hooks->len ; k++) {
3187 th = &g_array_index(hooks, LttvTraceHook, k);
3188 lttv_hooks_add(
3189 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3190 th->h,
3191 th,
3192 LTTV_PRIO_STATE);
3193 }
3194 }
3195 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3196 *(val.v_pointer) = hooks;
3197 }
3198}
3199
3200gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3201{
3202 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3203
3204 lttv_state_remove_event_hooks(tss);
3205
3206 return 0;
3207}
3208
3209void lttv_state_remove_event_hooks(LttvTracesetState *self)
3210{
3211 LttvTraceset *traceset = self->parent.ts;
3212
3213 guint i, j, k, nb_trace, nb_tracefile;
3214
3215 LttvTraceState *ts;
3216
3217 LttvTracefileState *tfs;
3218
3219 GArray *hooks;
3220
3221 LttvTraceHook *th;
3222
3223 LttvAttributeValue val;
3224
3225 nb_trace = lttv_traceset_number(traceset);
3226 for(i = 0 ; i < nb_trace ; i++) {
3227 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3228
3229 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
3230 hooks = *(val.v_pointer);
3231
3232 /* Remove these hooks from each event_by_id hooks list */
3233
3234 nb_tracefile = ts->parent.tracefiles->len;
3235
3236 for(j = 0 ; j < nb_tracefile ; j++) {
3237 tfs =
3238 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3239 LttvTracefileContext*, j));
3240
3241 for(k = 0 ; k < hooks->len ; k++) {
3242 th = &g_array_index(hooks, LttvTraceHook, k);
3243 lttv_hooks_remove_data(
3244 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3245 th->h,
3246 th);
3247 }
3248 }
3249 lttv_trace_hook_remove_all(&hooks);
3250 g_array_free(hooks, TRUE);
3251 }
3252}
3253
3254static gboolean state_save_event_hook(void *hook_data, void *call_data)
3255{
3256 guint *event_count = (guint*)hook_data;
3257
3258 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3259 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3260 return FALSE;
3261 else
3262 *event_count = 0;
3263
3264 LttvTracefileState *self = (LttvTracefileState *)call_data;
3265
3266 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3267
3268 LttvAttribute *saved_states_tree, *saved_state_tree;
3269
3270 LttvAttributeValue value;
3271
3272 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3273 LTTV_STATE_SAVED_STATES);
3274 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3275 value = lttv_attribute_add(saved_states_tree,
3276 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3277 *(value.v_gobject) = (GObject *)saved_state_tree;
3278 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3279 *(value.v_time) = self->parent.timestamp;
3280 lttv_state_save(tcs, saved_state_tree);
3281 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3282 self->parent.timestamp.tv_nsec);
3283
3284 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3285
3286 return FALSE;
3287}
3288
3289static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3290{
3291 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3292
3293 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3294
3295 return FALSE;
3296}
3297
3298guint lttv_state_current_cpu(LttvTracefileState *tfs)
3299{
3300 return tfs->cpu;
3301}
3302
3303
3304
3305#if 0
3306static gboolean block_start(void *hook_data, void *call_data)
3307{
3308 LttvTracefileState *self = (LttvTracefileState *)call_data;
3309
3310 LttvTracefileState *tfcs;
3311
3312 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3313
3314 LttEventPosition *ep;
3315
3316 guint i, nb_block, nb_event, nb_tracefile;
3317
3318 LttTracefile *tf;
3319
3320 LttvAttribute *saved_states_tree, *saved_state_tree;
3321
3322 LttvAttributeValue value;
3323
3324 ep = ltt_event_position_new();
3325
3326 nb_tracefile = tcs->parent.tracefiles->len;
3327
3328 /* Count the number of events added since the last block end in any
3329 tracefile. */
3330
3331 for(i = 0 ; i < nb_tracefile ; i++) {
3332 tfcs =
3333 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3334 LttvTracefileContext, i));
3335 ltt_event_position(tfcs->parent.e, ep);
3336 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3337 tcs->nb_event += nb_event - tfcs->saved_position;
3338 tfcs->saved_position = nb_event;
3339 }
3340 g_free(ep);
3341
3342 if(tcs->nb_event >= tcs->save_interval) {
3343 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3344 LTTV_STATE_SAVED_STATES);
3345 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3346 value = lttv_attribute_add(saved_states_tree,
3347 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3348 *(value.v_gobject) = (GObject *)saved_state_tree;
3349 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3350 *(value.v_time) = self->parent.timestamp;
3351 lttv_state_save(tcs, saved_state_tree);
3352 tcs->nb_event = 0;
3353 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3354 self->parent.timestamp.tv_nsec);
3355 }
3356 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3357 return FALSE;
3358}
3359#endif //0
3360
3361#if 0
3362static gboolean block_end(void *hook_data, void *call_data)
3363{
3364 LttvTracefileState *self = (LttvTracefileState *)call_data;
3365
3366 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3367
3368 LttTracefile *tf;
3369
3370 LttEventPosition *ep;
3371
3372 guint nb_block, nb_event;
3373
3374 ep = ltt_event_position_new();
3375 ltt_event_position(self->parent.e, ep);
3376 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3377 tcs->nb_event += nb_event - self->saved_position + 1;
3378 self->saved_position = 0;
3379 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3380 g_free(ep);
3381
3382 return FALSE;
3383}
3384#endif //0
3385#if 0
3386void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3387{
3388 LttvTraceset *traceset = self->parent.ts;
3389
3390 guint i, j, nb_trace, nb_tracefile;
3391
3392 LttvTraceState *ts;
3393
3394 LttvTracefileState *tfs;
3395
3396 LttvTraceHook hook_start, hook_end;
3397
3398 nb_trace = lttv_traceset_number(traceset);
3399 for(i = 0 ; i < nb_trace ; i++) {
3400 ts = (LttvTraceState *)self->parent.traces[i];
3401
3402 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3403 NULL, NULL, block_start, &hook_start);
3404 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3405 NULL, NULL, block_end, &hook_end);
3406
3407 nb_tracefile = ts->parent.tracefiles->len;
3408
3409 for(j = 0 ; j < nb_tracefile ; j++) {
3410 tfs =
3411 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3412 LttvTracefileContext, j));
3413 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3414 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3415 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3416 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3417 }
3418 }
3419}
3420#endif //0
3421
3422void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3423{
3424 LttvTraceset *traceset = self->parent.ts;
3425
3426 guint i, j, nb_trace, nb_tracefile;
3427
3428 LttvTraceState *ts;
3429
3430 LttvTracefileState *tfs;
3431
3432
3433 nb_trace = lttv_traceset_number(traceset);
3434 for(i = 0 ; i < nb_trace ; i++) {
3435
3436 ts = (LttvTraceState *)self->parent.traces[i];
3437 nb_tracefile = ts->parent.tracefiles->len;
3438
3439 if(ts->has_precomputed_states) continue;
3440
3441 guint *event_count = g_new(guint, 1);
3442 *event_count = 0;
3443
3444 for(j = 0 ; j < nb_tracefile ; j++) {
3445 tfs =
3446 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3447 LttvTracefileContext*, j));
3448 lttv_hooks_add(tfs->parent.event,
3449 state_save_event_hook,
3450 event_count,
3451 LTTV_PRIO_STATE);
3452
3453 }
3454 }
3455
3456 lttv_process_traceset_begin(&self->parent,
3457 NULL, NULL, NULL, NULL, NULL);
3458
3459}
3460
3461gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3462{
3463 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3464
3465 lttv_state_save_add_event_hooks(tss);
3466
3467 return 0;
3468}
3469
3470
3471#if 0
3472void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3473{
3474 LttvTraceset *traceset = self->parent.ts;
3475
3476 guint i, j, nb_trace, nb_tracefile;
3477
3478 LttvTraceState *ts;
3479
3480 LttvTracefileState *tfs;
3481
3482 LttvTraceHook hook_start, hook_end;
3483
3484 nb_trace = lttv_traceset_number(traceset);
3485 for(i = 0 ; i < nb_trace ; i++) {
3486 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3487
3488 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3489 NULL, NULL, block_start, &hook_start);
3490
3491 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3492 NULL, NULL, block_end, &hook_end);
3493
3494 nb_tracefile = ts->parent.tracefiles->len;
3495
3496 for(j = 0 ; j < nb_tracefile ; j++) {
3497 tfs =
3498 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3499 LttvTracefileContext, j));
3500 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3501 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
3502 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3503 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
3504 }
3505 }
3506}
3507#endif //0
3508
3509void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3510{
3511 LttvTraceset *traceset = self->parent.ts;
3512
3513 guint i, j, nb_trace, nb_tracefile;
3514
3515 LttvTraceState *ts;
3516
3517 LttvTracefileState *tfs;
3518
3519 LttvHooks *after_trace = lttv_hooks_new();
3520
3521 lttv_hooks_add(after_trace,
3522 state_save_after_trace_hook,
3523 NULL,
3524 LTTV_PRIO_STATE);
3525
3526
3527 lttv_process_traceset_end(&self->parent,
3528 NULL, after_trace, NULL, NULL, NULL);
3529
3530 lttv_hooks_destroy(after_trace);
3531
3532 nb_trace = lttv_traceset_number(traceset);
3533 for(i = 0 ; i < nb_trace ; i++) {
3534
3535 ts = (LttvTraceState *)self->parent.traces[i];
3536 nb_tracefile = ts->parent.tracefiles->len;
3537
3538 if(ts->has_precomputed_states) continue;
3539
3540 guint *event_count = NULL;
3541
3542 for(j = 0 ; j < nb_tracefile ; j++) {
3543 tfs =
3544 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3545 LttvTracefileContext*, j));
3546 event_count = lttv_hooks_remove(tfs->parent.event,
3547 state_save_event_hook);
3548 }
3549 if(event_count) g_free(event_count);
3550 }
3551}
3552
3553gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3554{
3555 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3556
3557 lttv_state_save_remove_event_hooks(tss);
3558
3559 return 0;
3560}
3561
3562void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
3563{
3564 LttvTraceset *traceset = self->parent.ts;
3565
3566 guint i, nb_trace;
3567
3568 int min_pos, mid_pos, max_pos;
3569
3570 guint call_rest = 0;
3571
3572 LttvTraceState *tcs;
3573
3574 LttvAttributeValue value;
3575
3576 LttvAttributeType type;
3577
3578 LttvAttributeName name;
3579
3580 gboolean is_named;
3581
3582 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3583
3584 //g_tree_destroy(self->parent.pqueue);
3585 //self->parent.pqueue = g_tree_new(compare_tracefile);
3586
3587 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3588
3589 nb_trace = lttv_traceset_number(traceset);
3590 for(i = 0 ; i < nb_trace ; i++) {
3591 tcs = (LttvTraceState *)self->parent.traces[i];
3592
3593 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3594 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3595 LTTV_STATE_SAVED_STATES);
3596 min_pos = -1;
3597
3598 if(saved_states_tree) {
3599 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3600 mid_pos = max_pos / 2;
3601 while(min_pos < max_pos) {
3602 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
3603 &is_named);
3604 g_assert(type == LTTV_GOBJECT);
3605 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3606 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3607 &value);
3608 g_assert(type == LTTV_TIME);
3609 if(ltt_time_compare(*(value.v_time), t) < 0) {
3610 min_pos = mid_pos;
3611 closest_tree = saved_state_tree;
3612 }
3613 else max_pos = mid_pos - 1;
3614
3615 mid_pos = (min_pos + max_pos + 1) / 2;
3616 }
3617 }
3618
3619 /* restore the closest earlier saved state */
3620 if(min_pos != -1) {
3621 lttv_state_restore(tcs, closest_tree);
3622 call_rest = 1;
3623 }
3624
3625 /* There is no saved state, yet we want to have it. Restart at T0 */
3626 else {
3627 restore_init_state(tcs);
3628 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
3629 }
3630 }
3631 /* We want to seek quickly without restoring/updating the state */
3632 else {
3633 restore_init_state(tcs);
3634 lttv_process_trace_seek_time(&(tcs->parent), t);
3635 }
3636 }
3637 if(!call_rest) g_info("NOT Calling restore");
3638}
3639
3640
3641static void
3642traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3643{
3644}
3645
3646
3647static void
3648traceset_state_finalize (LttvTracesetState *self)
3649{
3650 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3651 finalize(G_OBJECT(self));
3652}
3653
3654
3655static void
3656traceset_state_class_init (LttvTracesetContextClass *klass)
3657{
3658 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3659
3660 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3661 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3662 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3663 klass->new_traceset_context = new_traceset_context;
3664 klass->new_trace_context = new_trace_context;
3665 klass->new_tracefile_context = new_tracefile_context;
3666}
3667
3668
3669GType
3670lttv_traceset_state_get_type(void)
3671{
3672 static GType type = 0;
3673 if (type == 0) {
3674 static const GTypeInfo info = {
3675 sizeof (LttvTracesetStateClass),
3676 NULL, /* base_init */
3677 NULL, /* base_finalize */
3678 (GClassInitFunc) traceset_state_class_init, /* class_init */
3679 NULL, /* class_finalize */
3680 NULL, /* class_data */
3681 sizeof (LttvTracesetState),
3682 0, /* n_preallocs */
3683 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3684 NULL /* value handling */
3685 };
3686
3687 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3688 &info, 0);
3689 }
3690 return type;
3691}
3692
3693
3694static void
3695trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3696{
3697}
3698
3699
3700static void
3701trace_state_finalize (LttvTraceState *self)
3702{
3703 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3704 finalize(G_OBJECT(self));
3705}
3706
3707
3708static void
3709trace_state_class_init (LttvTraceStateClass *klass)
3710{
3711 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3712
3713 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3714 klass->state_save = state_save;
3715 klass->state_restore = state_restore;
3716 klass->state_saved_free = state_saved_free;
3717}
3718
3719
3720GType
3721lttv_trace_state_get_type(void)
3722{
3723 static GType type = 0;
3724 if (type == 0) {
3725 static const GTypeInfo info = {
3726 sizeof (LttvTraceStateClass),
3727 NULL, /* base_init */
3728 NULL, /* base_finalize */
3729 (GClassInitFunc) trace_state_class_init, /* class_init */
3730 NULL, /* class_finalize */
3731 NULL, /* class_data */
3732 sizeof (LttvTraceState),
3733 0, /* n_preallocs */
3734 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3735 NULL /* value handling */
3736 };
3737
3738 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3739 "LttvTraceStateType", &info, 0);
3740 }
3741 return type;
3742}
3743
3744
3745static void
3746tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3747{
3748}
3749
3750
3751static void
3752tracefile_state_finalize (LttvTracefileState *self)
3753{
3754 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3755 finalize(G_OBJECT(self));
3756}
3757
3758
3759static void
3760tracefile_state_class_init (LttvTracefileStateClass *klass)
3761{
3762 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3763
3764 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3765}
3766
3767
3768GType
3769lttv_tracefile_state_get_type(void)
3770{
3771 static GType type = 0;
3772 if (type == 0) {
3773 static const GTypeInfo info = {
3774 sizeof (LttvTracefileStateClass),
3775 NULL, /* base_init */
3776 NULL, /* base_finalize */
3777 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3778 NULL, /* class_finalize */
3779 NULL, /* class_data */
3780 sizeof (LttvTracefileState),
3781 0, /* n_preallocs */
3782 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3783 NULL /* value handling */
3784 };
3785
3786 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3787 "LttvTracefileStateType", &info, 0);
3788 }
3789 return type;
3790}
3791
3792
3793static void module_init()
3794{
3795 LTTV_STATE_UNNAMED = g_quark_from_string("");
3796 LTTV_STATE_UNBRANDED = g_quark_from_string("");
3797 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3798 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3799 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3800 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3801 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3802 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3803 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3804 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3805 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3806 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3807 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3808 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3809 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3810 LTTV_STATE_RUN = g_quark_from_string("RUN");
3811 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
3812 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3813 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
3814 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3815 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3816 LTTV_STATE_PROCESS = g_quark_from_string("process");
3817 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
3818 LTTV_STATE_EVENT = g_quark_from_string("event");
3819 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
3820 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
3821 LTTV_STATE_TIME = g_quark_from_string("time");
3822 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
3823 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3824 LTTV_STATE_TRACE_STATE_USE_COUNT =
3825 g_quark_from_string("trace_state_use_count");
3826 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
3827 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
3828 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
3829
3830
3831 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
3832 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
3833 LTT_FACILITY_FS = g_quark_from_string("fs");
3834 LTT_FACILITY_LIST = g_quark_from_string("list");
3835 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
3836 LTT_FACILITY_BLOCK = g_quark_from_string("block");
3837
3838
3839 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3840 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3841 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3842 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3843 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3844 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
3845 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
3846 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
3847 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3848 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3849 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3850 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
3851 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
3852 LTT_EVENT_EXEC = g_quark_from_string("exec");
3853 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
3854 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
3855 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3856 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
3857 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
3858 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
3859 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
3860 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
3861
3862
3863 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3864 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3865 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
3866 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
3867 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3868 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3869 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
3870 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3871 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3872 LTT_FIELD_PID = g_quark_from_string("pid");
3873 LTT_FIELD_TGID = g_quark_from_string("tgid");
3874 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
3875 LTT_FIELD_FILENAME = g_quark_from_string("filename");
3876 LTT_FIELD_NAME = g_quark_from_string("name");
3877 LTT_FIELD_TYPE = g_quark_from_string("type");
3878 LTT_FIELD_MODE = g_quark_from_string("mode");
3879 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3880 LTT_FIELD_STATUS = g_quark_from_string("status");
3881 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3882 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
3883 LTT_FIELD_MAJOR = g_quark_from_string("major");
3884 LTT_FIELD_MINOR = g_quark_from_string("minor");
3885 LTT_FIELD_OPERATION = g_quark_from_string("direction");
3886 LTT_FIELD_ACTION = g_quark_from_string("action");
3887
3888 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3889 LTTV_CPU_IDLE = g_quark_from_string("idle");
3890 LTTV_CPU_BUSY = g_quark_from_string("busy");
3891 LTTV_CPU_IRQ = g_quark_from_string("irq");
3892 LTTV_CPU_TRAP = g_quark_from_string("trap");
3893
3894 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
3895 LTTV_IRQ_IDLE = g_quark_from_string("idle");
3896 LTTV_IRQ_BUSY = g_quark_from_string("busy");
3897
3898 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
3899 LTTV_BDEV_IDLE = g_quark_from_string("idle");
3900 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
3901 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
3902}
3903
3904static void module_destroy()
3905{
3906}
3907
3908
3909LTTV_MODULE("state", "State computation", \
3910 "Update the system state, possibly saving it at intervals", \
3911 module_init, module_destroy)
3912
3913
3914
This page took 0.184861 seconds and 4 git commands to generate.