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