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