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