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