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