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