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