usertrace update for powerpc
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
... / ...
CommitLineData
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <lttv/lttv.h>
24#include <lttv/module.h>
25#include <lttv/state.h>
26#include <ltt/facility.h>
27#include <ltt/trace.h>
28#include <ltt/event.h>
29#include <ltt/type.h>
30#include <stdio.h>
31#include <string.h>
32
33#define PREALLOCATED_EXECUTION_STACK 10
34
35/* Facilities Quarks */
36
37GQuark
38 LTT_FACILITY_KERNEL,
39 LTT_FACILITY_KERNEL_ARCH,
40 LTT_FACILITY_PROCESS,
41 LTT_FACILITY_FS,
42 LTT_FACILITY_STATEDUMP,
43 LTT_FACILITY_USER_GENERIC;
44
45/* Events Quarks */
46
47GQuark
48 LTT_EVENT_SYSCALL_ENTRY,
49 LTT_EVENT_SYSCALL_EXIT,
50 LTT_EVENT_TRAP_ENTRY,
51 LTT_EVENT_TRAP_EXIT,
52 LTT_EVENT_IRQ_ENTRY,
53 LTT_EVENT_IRQ_EXIT,
54 LTT_EVENT_SOFT_IRQ_ENTRY,
55 LTT_EVENT_SOFT_IRQ_EXIT,
56 LTT_EVENT_SCHEDCHANGE,
57 LTT_EVENT_FORK,
58 LTT_EVENT_KERNEL_THREAD,
59 LTT_EVENT_EXIT,
60 LTT_EVENT_FREE,
61 LTT_EVENT_EXEC,
62 LTT_EVENT_ENUM_PROCESS_STATE,
63 LTT_EVENT_FUNCTION_ENTRY,
64 LTT_EVENT_FUNCTION_EXIT;
65
66/* Fields Quarks */
67
68GQuark
69 LTT_FIELD_SYSCALL_ID,
70 LTT_FIELD_TRAP_ID,
71 LTT_FIELD_IRQ_ID,
72 LTT_FIELD_SOFT_IRQ_ID,
73 LTT_FIELD_OUT,
74 LTT_FIELD_IN,
75 LTT_FIELD_OUT_STATE,
76 LTT_FIELD_PARENT_PID,
77 LTT_FIELD_CHILD_PID,
78 LTT_FIELD_PID,
79 LTT_FIELD_FILENAME,
80 LTT_FIELD_NAME,
81 LTT_FIELD_TYPE,
82 LTT_FIELD_MODE,
83 LTT_FIELD_SUBMODE,
84 LTT_FIELD_STATUS,
85 LTT_FIELD_THIS_FN,
86 LTT_FIELD_CALL_SITE;
87
88LttvExecutionMode
89 LTTV_STATE_MODE_UNKNOWN,
90 LTTV_STATE_USER_MODE,
91 LTTV_STATE_SYSCALL,
92 LTTV_STATE_TRAP,
93 LTTV_STATE_IRQ,
94 LTTV_STATE_SOFT_IRQ;
95
96LttvExecutionSubmode
97 LTTV_STATE_SUBMODE_UNKNOWN,
98 LTTV_STATE_SUBMODE_NONE;
99
100LttvProcessStatus
101 LTTV_STATE_UNNAMED,
102 LTTV_STATE_WAIT_FORK,
103 LTTV_STATE_WAIT_CPU,
104 LTTV_STATE_EXIT,
105 LTTV_STATE_ZOMBIE,
106 LTTV_STATE_WAIT,
107 LTTV_STATE_RUN,
108 LTTV_STATE_DEAD;
109
110LttvProcessType
111 LTTV_STATE_USER_THREAD,
112 LTTV_STATE_KERNEL_THREAD;
113
114static GQuark
115 LTTV_STATE_TRACEFILES,
116 LTTV_STATE_PROCESSES,
117 LTTV_STATE_PROCESS,
118 LTTV_STATE_RUNNING_PROCESS,
119 LTTV_STATE_EVENT,
120 LTTV_STATE_SAVED_STATES,
121 LTTV_STATE_SAVED_STATES_TIME,
122 LTTV_STATE_TIME,
123 LTTV_STATE_HOOKS,
124 LTTV_STATE_NAME_TABLES,
125 LTTV_STATE_TRACE_STATE_USE_COUNT;
126
127static void create_max_time(LttvTraceState *tcs);
128
129static void get_max_time(LttvTraceState *tcs);
130
131static void free_max_time(LttvTraceState *tcs);
132
133static void create_name_tables(LttvTraceState *tcs);
134
135static void get_name_tables(LttvTraceState *tcs);
136
137static void free_name_tables(LttvTraceState *tcs);
138
139static void free_saved_state(LttvTraceState *tcs);
140
141static void lttv_state_free_process_table(GHashTable *processes);
142
143
144void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
145{
146 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
147}
148
149
150void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
151{
152 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
153}
154
155
156void lttv_state_state_saved_free(LttvTraceState *self,
157 LttvAttribute *container)
158{
159 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
160}
161
162
163guint process_hash(gconstpointer key)
164{
165 guint pid = ((const LttvProcessState *)key)->pid;
166 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
167}
168
169
170/* If the hash table hash function is well distributed,
171 * the process_equal should compare different pid */
172gboolean process_equal(gconstpointer a, gconstpointer b)
173{
174 const LttvProcessState *process_a, *process_b;
175 gboolean ret = TRUE;
176
177 process_a = (const LttvProcessState *)a;
178 process_b = (const LttvProcessState *)b;
179
180 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
181 else if(likely(process_a->pid == 0 &&
182 process_a->cpu != process_b->cpu)) ret = FALSE;
183
184 return ret;
185}
186
187static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
188{
189 g_tree_destroy((GTree*)value);
190}
191
192static void lttv_state_free_usertraces(GHashTable *usertraces)
193{
194 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
195 g_hash_table_destroy(usertraces);
196}
197
198
199
200static void
201restore_init_state(LttvTraceState *self)
202{
203 guint i, nb_cpus;
204
205 LttvTracefileState *tfcs;
206
207 /* Free the process tables */
208 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
209 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
210 self->processes = g_hash_table_new(process_hash, process_equal);
211 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
212 self->nb_event = 0;
213
214 /* Seek time to beginning */
215 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
216 // closest. It's the tracecontext job to seek the trace to the beginning
217 // anyway : the init state might be used at the middle of the trace as well...
218 //g_tree_destroy(self->parent.ts_context->pqueue);
219 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
220
221
222 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
223
224 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
225
226 /* Put the per cpu running_process to beginning state : process 0. */
227 for(i=0; i< nb_cpus; i++) {
228 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0,
229 LTTV_STATE_UNNAMED, &ltt_time_zero);
230 self->running_process[i]->state->s = LTTV_STATE_RUN;
231 self->running_process[i]->cpu = i;
232 }
233
234#if 0
235 nb_tracefile = self->parent.tracefiles->len;
236
237 for(i = 0 ; i < nb_tracefile ; i++) {
238 tfcs =
239 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
240 LttvTracefileContext*, i));
241 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
242// tfcs->saved_position = 0;
243 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
244 tfcs->process->state->s = LTTV_STATE_RUN;
245 tfcs->process->last_cpu = tfcs->cpu_name;
246 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
247 }
248#endif //0
249}
250
251//static LttTime time_zero = {0,0};
252
253static gint compare_usertraces(gconstpointer a, gconstpointer b,
254 gpointer user_data)
255{
256 const LttTime *t1 = (const LttTime *)a;
257 const LttTime *t2 = (const LttTime *)b;
258
259 return ltt_time_compare(*t1, *t2);
260}
261
262static void free_usertrace_key(gpointer data)
263{
264 g_free(data);
265}
266
267static void
268init(LttvTracesetState *self, LttvTraceset *ts)
269{
270 guint i, j, nb_trace, nb_tracefile;
271
272 LttvTraceContext *tc;
273
274 LttvTraceState *tcs;
275
276 LttvTracefileState *tfcs;
277
278 LttvAttributeValue v;
279
280 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
281 init((LttvTracesetContext *)self, ts);
282
283 nb_trace = lttv_traceset_number(ts);
284 for(i = 0 ; i < nb_trace ; i++) {
285 tc = self->parent.traces[i];
286 tcs = LTTV_TRACE_STATE(tc);
287 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
288 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
289 LTTV_UINT, &v);
290 (*v.v_uint)++;
291
292 if(*(v.v_uint) == 1) {
293 create_name_tables(tcs);
294 create_max_time(tcs);
295 }
296 get_name_tables(tcs);
297 get_max_time(tcs);
298
299 nb_tracefile = tc->tracefiles->len;
300 tcs->processes = NULL;
301 tcs->usertraces = NULL;
302 tcs->running_process = g_new(LttvProcessState*,
303 ltt_trace_get_num_cpu(tc->t));
304 restore_init_state(tcs);
305 for(j = 0 ; j < nb_tracefile ; j++) {
306 tfcs =
307 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
308 LttvTracefileContext*, j));
309 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
310 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
311#if 0
312 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
313 /* It's a Usertrace */
314 LttvProcessState *process;
315 LttTime timestamp =
316 ltt_interpolate_time_from_tsc(tfcs->parent.tf,
317 ltt_tracefile_creation(tfcs->parent.tf));
318 process = lttv_state_find_process_or_create(
319 tcs,
320 0, ltt_tracefile_tid(tfcs->parent.tf),
321 &timestamp);
322 process->usertrace = tfcs;
323 }
324 }
325#endif //0
326 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
327 /* It's a Usertrace */
328 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
329 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
330 (gconstpointer)tid);
331 if(!usertrace_tree) {
332 usertrace_tree = g_tree_new_full(compare_usertraces,
333 NULL, free_usertrace_key, NULL);
334 g_hash_table_insert(tcs->usertraces,
335 (gpointer)tid, usertrace_tree);
336 }
337 LttTime *timestamp = g_new(LttTime, 1);
338 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
339 ltt_tracefile_creation(tfcs->parent.tf));
340 g_tree_insert(usertrace_tree, timestamp, tfcs);
341 }
342 }
343
344 }
345}
346
347static void
348fini(LttvTracesetState *self)
349{
350 guint i, nb_trace;
351
352 LttvTraceState *tcs;
353
354 LttvTracefileState *tfcs;
355
356 LttvAttributeValue v;
357
358 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
359 for(i = 0 ; i < nb_trace ; i++) {
360 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
361 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
362 LTTV_UINT, &v);
363
364 g_assert(*(v.v_uint) != 0);
365 (*v.v_uint)--;
366
367 if(*(v.v_uint) == 0) {
368 free_name_tables(tcs);
369 free_max_time(tcs);
370 free_saved_state(tcs);
371 }
372 g_free(tcs->running_process);
373 tcs->running_process = NULL;
374 lttv_state_free_process_table(tcs->processes);
375 lttv_state_free_usertraces(tcs->usertraces);
376 tcs->processes = NULL;
377 tcs->usertraces = NULL;
378 }
379 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
380 fini((LttvTracesetContext *)self);
381}
382
383
384static LttvTracesetContext *
385new_traceset_context(LttvTracesetContext *self)
386{
387 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
388}
389
390
391static LttvTraceContext *
392new_trace_context(LttvTracesetContext *self)
393{
394 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
395}
396
397
398static LttvTracefileContext *
399new_tracefile_context(LttvTracesetContext *self)
400{
401 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
402}
403
404
405/* Write the process state of the trace */
406
407static void write_process_state(gpointer key, gpointer value,
408 gpointer user_data)
409{
410 LttvProcessState *process;
411
412 LttvExecutionState *es;
413
414 FILE *fp = (FILE *)user_data;
415
416 guint i;
417
418 process = (LttvProcessState *)value;
419 fprintf(fp,
420" <PROCESS CORE=%p PID=%u PPID=%u TYPE=\"%s\"CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
421 process, process->pid, process->ppid, g_quark_to_string(process->type),
422 process->creation_time.tv_sec,
423 process->creation_time.tv_nsec, g_quark_to_string(process->name),
424 process->cpu);
425
426 for(i = 0 ; i < process->execution_stack->len; i++) {
427 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
428 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
429 g_quark_to_string(es->t), g_quark_to_string(es->n),
430 es->entry.tv_sec, es->entry.tv_nsec);
431 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
432 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
433 }
434 fprintf(fp, " </PROCESS>\n");
435}
436
437
438void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
439{
440 guint i, nb_tracefile, nb_block, offset;
441 guint64 tsc;
442
443 LttvTracefileState *tfcs;
444
445 LttTracefile *tf;
446
447 LttEventPosition *ep;
448
449 guint nb_cpus;
450
451 ep = ltt_event_position_new();
452
453 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
454
455 g_hash_table_foreach(self->processes, write_process_state, fp);
456
457 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
458 for(i=0;i<nb_cpus;i++) {
459 fprintf(fp,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
460 i, self->running_process[i]->pid);
461 }
462
463 nb_tracefile = self->parent.tracefiles->len;
464
465 for(i = 0 ; i < nb_tracefile ; i++) {
466 tfcs =
467 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
468 LttvTracefileContext*, i));
469 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
470 tfcs->parent.timestamp.tv_sec,
471 tfcs->parent.timestamp.tv_nsec);
472 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
473 if(e == NULL) fprintf(fp,"/>\n");
474 else {
475 ltt_event_position(e, ep);
476 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
477 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
478 tsc);
479 }
480 }
481 g_free(ep);
482 fprintf(fp,"</PROCESS_STATE>");
483}
484
485
486/* Copy each process from an existing hash table to a new one */
487
488static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
489{
490 LttvProcessState *process, *new_process;
491
492 GHashTable *new_processes = (GHashTable *)user_data;
493
494 guint i;
495
496 process = (LttvProcessState *)value;
497 new_process = g_new(LttvProcessState, 1);
498 *new_process = *process;
499 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
500 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
501 new_process->execution_stack =
502 g_array_set_size(new_process->execution_stack,
503 process->execution_stack->len);
504 for(i = 0 ; i < process->execution_stack->len; i++) {
505 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
506 g_array_index(process->execution_stack, LttvExecutionState, i);
507 }
508 new_process->state = &g_array_index(new_process->execution_stack,
509 LttvExecutionState, new_process->execution_stack->len - 1);
510 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
511 sizeof(guint64), 0);
512 new_process->user_stack =
513 g_array_set_size(new_process->user_stack,
514 process->user_stack->len);
515 for(i = 0 ; i < process->user_stack->len; i++) {
516 g_array_index(new_process->user_stack, guint64, i) =
517 g_array_index(process->user_stack, guint64, i);
518 }
519 new_process->current_function = process->current_function;
520 g_hash_table_insert(new_processes, new_process, new_process);
521}
522
523
524static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
525{
526 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
527
528 g_hash_table_foreach(processes, copy_process_state, new_processes);
529 return new_processes;
530}
531
532
533/* The saved state for each trace contains a member "processes", which
534 stores a copy of the process table, and a member "tracefiles" with
535 one entry per tracefile. Each tracefile has a "process" member pointing
536 to the current process and a "position" member storing the tracefile
537 position (needed to seek to the current "next" event. */
538
539static void state_save(LttvTraceState *self, LttvAttribute *container)
540{
541 guint i, nb_tracefile, nb_cpus;
542
543 LttvTracefileState *tfcs;
544
545 LttvAttribute *tracefiles_tree, *tracefile_tree;
546
547 guint *running_process;
548
549 LttvAttributeType type;
550
551 LttvAttributeValue value;
552
553 LttvAttributeName name;
554
555 LttEventPosition *ep;
556
557 tracefiles_tree = lttv_attribute_find_subdir(container,
558 LTTV_STATE_TRACEFILES);
559
560 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
561 LTTV_POINTER);
562 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
563
564 /* Add the currently running processes array */
565 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
566 running_process = g_new(guint, nb_cpus);
567 for(i=0;i<nb_cpus;i++) {
568 running_process[i] = self->running_process[i]->pid;
569 }
570 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
571 LTTV_POINTER);
572 *(value.v_pointer) = running_process;
573
574 g_info("State save");
575
576 nb_tracefile = self->parent.tracefiles->len;
577
578 for(i = 0 ; i < nb_tracefile ; i++) {
579 tfcs =
580 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
581 LttvTracefileContext*, i));
582 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
583 value = lttv_attribute_add(tracefiles_tree, i,
584 LTTV_GOBJECT);
585 *(value.v_gobject) = (GObject *)tracefile_tree;
586#if 0
587 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
588 LTTV_UINT);
589 *(value.v_uint) = tfcs->process->pid;
590#endif //0
591 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
592 LTTV_POINTER);
593 /* Only save the position if the tfs has not infinite time. */
594 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
595 // && current_tfcs != tfcs) {
596 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
597 *(value.v_pointer) = NULL;
598 } else {
599 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
600 ep = ltt_event_position_new();
601 ltt_event_position(e, ep);
602 *(value.v_pointer) = ep;
603
604 guint nb_block, offset;
605 guint64 tsc;
606 LttTracefile *tf;
607 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
608 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
609 tsc,
610 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
611 }
612 }
613}
614
615
616static void state_restore(LttvTraceState *self, LttvAttribute *container)
617{
618 guint i, nb_tracefile, pid, nb_cpus;
619
620 LttvTracefileState *tfcs;
621
622 LttvAttribute *tracefiles_tree, *tracefile_tree;
623
624 guint *running_process;
625
626 LttvAttributeType type;
627
628 LttvAttributeValue value;
629
630 LttvAttributeName name;
631
632 gboolean is_named;
633
634 LttEventPosition *ep;
635
636 LttvTracesetContext *tsc = self->parent.ts_context;
637
638 tracefiles_tree = lttv_attribute_find_subdir(container,
639 LTTV_STATE_TRACEFILES);
640
641 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
642 &value);
643 g_assert(type == LTTV_POINTER);
644 lttv_state_free_process_table(self->processes);
645 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
646
647 /* Add the currently running processes array */
648 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
649 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
650 &value);
651 g_assert(type == LTTV_POINTER);
652 running_process = *(value.v_pointer);
653 for(i=0;i<nb_cpus;i++) {
654 pid = running_process[i];
655 self->running_process[i] = lttv_state_find_process(self, i, pid);
656 g_assert(self->running_process[i] != NULL);
657 }
658
659
660 nb_tracefile = self->parent.tracefiles->len;
661
662 //g_tree_destroy(tsc->pqueue);
663 //tsc->pqueue = g_tree_new(compare_tracefile);
664
665 for(i = 0 ; i < nb_tracefile ; i++) {
666 tfcs =
667 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
668 LttvTracefileContext*, i));
669 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
670 g_assert(type == LTTV_GOBJECT);
671 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
672#if 0
673 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
674 &value);
675 g_assert(type == LTTV_UINT);
676 pid = *(value.v_uint);
677 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
678#endif //0
679 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
680 &value);
681 g_assert(type == LTTV_POINTER);
682 //g_assert(*(value.v_pointer) != NULL);
683 ep = *(value.v_pointer);
684 g_assert(tfcs->parent.t_context != NULL);
685
686 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
687 g_tree_remove(tsc->pqueue, tfc);
688
689 if(ep != NULL) {
690 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
691 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
692 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
693 g_tree_insert(tsc->pqueue, tfc, tfc);
694 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
695 } else {
696 tfc->timestamp = ltt_time_infinite;
697 }
698 }
699}
700
701
702static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
703{
704 guint i, nb_tracefile, nb_cpus;
705
706 LttvTracefileState *tfcs;
707
708 LttvAttribute *tracefiles_tree, *tracefile_tree;
709
710 guint *running_process;
711
712 LttvAttributeType type;
713
714 LttvAttributeValue value;
715
716 LttvAttributeName name;
717
718 gboolean is_named;
719
720 LttEventPosition *ep;
721
722 tracefiles_tree = lttv_attribute_find_subdir(container,
723 LTTV_STATE_TRACEFILES);
724 g_object_ref(G_OBJECT(tracefiles_tree));
725 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
726
727 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
728 &value);
729 g_assert(type == LTTV_POINTER);
730 lttv_state_free_process_table(*(value.v_pointer));
731 *(value.v_pointer) = NULL;
732 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
733
734 /* Free running processes array */
735 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
736 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
737 &value);
738 g_assert(type == LTTV_POINTER);
739 running_process = *(value.v_pointer);
740 g_free(running_process);
741
742 nb_tracefile = self->parent.tracefiles->len;
743
744 for(i = 0 ; i < nb_tracefile ; i++) {
745 tfcs =
746 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
747 LttvTracefileContext*, i));
748 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
749 g_assert(type == LTTV_GOBJECT);
750 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
751
752 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
753 &value);
754 g_assert(type == LTTV_POINTER);
755 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
756 }
757 g_object_unref(G_OBJECT(tracefiles_tree));
758}
759
760
761static void free_saved_state(LttvTraceState *self)
762{
763 guint i, nb;
764
765 LttvAttributeType type;
766
767 LttvAttributeValue value;
768
769 LttvAttributeName name;
770
771 gboolean is_named;
772
773 LttvAttribute *saved_states;
774
775 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
776 LTTV_STATE_SAVED_STATES);
777
778 nb = lttv_attribute_get_number(saved_states);
779 for(i = 0 ; i < nb ; i++) {
780 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
781 g_assert(type == LTTV_GOBJECT);
782 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
783 }
784
785 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
786}
787
788
789static void
790create_max_time(LttvTraceState *tcs)
791{
792 LttvAttributeValue v;
793
794 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
795 LTTV_POINTER, &v);
796 g_assert(*(v.v_pointer) == NULL);
797 *(v.v_pointer) = g_new(LttTime,1);
798 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
799}
800
801
802static void
803get_max_time(LttvTraceState *tcs)
804{
805 LttvAttributeValue v;
806
807 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
808 LTTV_POINTER, &v);
809 g_assert(*(v.v_pointer) != NULL);
810 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
811}
812
813
814static void
815free_max_time(LttvTraceState *tcs)
816{
817 LttvAttributeValue v;
818
819 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
820 LTTV_POINTER, &v);
821 g_free(*(v.v_pointer));
822 *(v.v_pointer) = NULL;
823}
824
825
826typedef struct _LttvNameTables {
827 // FIXME GQuark *eventtype_names;
828 GQuark *syscall_names;
829 guint nb_syscalls;
830 GQuark *trap_names;
831 GQuark *irq_names;
832 GQuark *soft_irq_names;
833} LttvNameTables;
834
835
836static void
837create_name_tables(LttvTraceState *tcs)
838{
839 int i, nb;
840
841 GQuark f_name, e_name;
842
843 LttvTraceHook h;
844
845 LttvTraceHookByFacility *thf;
846
847 LttEventType *et;
848
849 LttType *t;
850
851 GString *fe_name = g_string_new("");
852
853 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
854
855 LttvAttributeValue v;
856
857 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
858 LTTV_POINTER, &v);
859 g_assert(*(v.v_pointer) == NULL);
860 *(v.v_pointer) = name_tables;
861#if 0 // Use iteration over the facilities_by_name and then list all event
862 // types of each facility
863 nb = ltt_trace_eventtype_number(tcs->parent.t);
864 name_tables->eventtype_names = g_new(GQuark, nb);
865 for(i = 0 ; i < nb ; i++) {
866 et = ltt_trace_eventtype_get(tcs->parent.t, i);
867 e_name = ltt_eventtype_name(et);
868 f_name = ltt_facility_name(ltt_eventtype_facility(et));
869 g_string_printf(fe_name, "%s.%s", f_name, e_name);
870 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
871 }
872#endif //0
873 if(!lttv_trace_find_hook(tcs->parent.t,
874 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
875 LTT_FIELD_SYSCALL_ID, 0, 0,
876 NULL, NULL, &h)) {
877
878 thf = lttv_trace_hook_get_first(&h);
879
880 t = ltt_field_type(thf->f1);
881 nb = ltt_type_element_number(t);
882
883 lttv_trace_hook_destroy(&h);
884
885 name_tables->syscall_names = g_new(GQuark, nb);
886 name_tables->nb_syscalls = nb;
887
888 for(i = 0 ; i < nb ; i++) {
889 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
890 }
891
892 //name_tables->syscall_names = g_new(GQuark, 256);
893 //for(i = 0 ; i < 256 ; i++) {
894 // g_string_printf(fe_name, "syscall %d", i);
895 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
896 //}
897 } else {
898 name_tables->syscall_names = NULL;
899 name_tables->nb_syscalls = 0;
900 }
901
902 if(!lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
903 LTT_EVENT_TRAP_ENTRY,
904 LTT_FIELD_TRAP_ID, 0, 0,
905 NULL, NULL, &h)) {
906
907 thf = lttv_trace_hook_get_first(&h);
908
909 t = ltt_field_type(thf->f1);
910 //nb = ltt_type_element_number(t);
911
912 lttv_trace_hook_destroy(&h);
913
914 /*
915 name_tables->trap_names = g_new(GQuark, nb);
916 for(i = 0 ; i < nb ; i++) {
917 name_tables->trap_names[i] = g_quark_from_string(
918 ltt_enum_string_get(t, i));
919 }
920 */
921
922 name_tables->trap_names = g_new(GQuark, 256);
923 for(i = 0 ; i < 256 ; i++) {
924 g_string_printf(fe_name, "trap %d", i);
925 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
926 }
927 } else {
928 name_tables->trap_names = NULL;
929 }
930
931 if(!lttv_trace_find_hook(tcs->parent.t,
932 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
933 LTT_FIELD_IRQ_ID, 0, 0,
934 NULL, NULL, &h)) {
935
936 thf = lttv_trace_hook_get_first(&h);
937
938 t = ltt_field_type(thf->f1);
939 //nb = ltt_type_element_number(t);
940
941 lttv_trace_hook_destroy(&h);
942
943 /*
944 name_tables->irq_names = g_new(GQuark, nb);
945 for(i = 0 ; i < nb ; i++) {
946 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
947 }
948 */
949
950 name_tables->irq_names = g_new(GQuark, 256);
951 for(i = 0 ; i < 256 ; i++) {
952 g_string_printf(fe_name, "irq %d", i);
953 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
954 }
955 } else {
956 name_tables->irq_names = NULL;
957 }
958 /*
959 name_tables->soft_irq_names = g_new(GQuark, nb);
960 for(i = 0 ; i < nb ; i++) {
961 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
962 }
963 */
964
965 name_tables->soft_irq_names = g_new(GQuark, 256);
966 for(i = 0 ; i < 256 ; i++) {
967 g_string_printf(fe_name, "softirq %d", i);
968 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
969 }
970
971
972 g_string_free(fe_name, TRUE);
973}
974
975
976static void
977get_name_tables(LttvTraceState *tcs)
978{
979 LttvNameTables *name_tables;
980
981 LttvAttributeValue v;
982
983 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
984 LTTV_POINTER, &v);
985 g_assert(*(v.v_pointer) != NULL);
986 name_tables = (LttvNameTables *)*(v.v_pointer);
987 //tcs->eventtype_names = name_tables->eventtype_names;
988 tcs->syscall_names = name_tables->syscall_names;
989 tcs->nb_syscalls = name_tables->nb_syscalls;
990 tcs->trap_names = name_tables->trap_names;
991 tcs->irq_names = name_tables->irq_names;
992 tcs->soft_irq_names = name_tables->soft_irq_names;
993}
994
995
996static void
997free_name_tables(LttvTraceState *tcs)
998{
999 LttvNameTables *name_tables;
1000
1001 LttvAttributeValue v;
1002
1003 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1004 LTTV_POINTER, &v);
1005 name_tables = (LttvNameTables *)*(v.v_pointer);
1006 *(v.v_pointer) = NULL;
1007
1008 // g_free(name_tables->eventtype_names);
1009 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1010 if(name_tables->trap_names) g_free(name_tables->trap_names);
1011 if(name_tables->irq_names) g_free(name_tables->irq_names);
1012 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1013 if(name_tables) g_free(name_tables);
1014}
1015
1016#ifdef HASH_TABLE_DEBUG
1017
1018static void test_process(gpointer key, gpointer value, gpointer user_data)
1019{
1020 LttvProcessState *process = (LttvProcessState *)value;
1021
1022 /* Test for process corruption */
1023 guint stack_len = process->execution_stack->len;
1024}
1025
1026static void hash_table_check(GHashTable *table)
1027{
1028 g_hash_table_foreach(table, test_process, NULL);
1029}
1030
1031
1032#endif
1033
1034
1035static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1036 guint state_id)
1037{
1038 LttvExecutionState *es;
1039
1040 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1041 guint cpu = tfs->cpu;
1042
1043#ifdef HASH_TABLE_DEBUG
1044 hash_table_check(ts->processes);
1045#endif
1046 LttvProcessState *process = ts->running_process[cpu];
1047
1048 guint depth = process->execution_stack->len;
1049
1050 process->execution_stack =
1051 g_array_set_size(process->execution_stack, depth + 1);
1052 /* Keep in sync */
1053 process->state =
1054 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1055
1056 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1057 es->t = t;
1058 es->n = state_id;
1059 es->entry = es->change = tfs->parent.timestamp;
1060 es->cum_cpu_time = ltt_time_zero;
1061 es->s = process->state->s;
1062 process->state = es;
1063}
1064
1065/* pop state
1066 * return 1 when empty, else 0 */
1067int lttv_state_pop_state_cleanup(LttvProcessState *process,
1068 LttvTracefileState *tfs)
1069{
1070 guint cpu = tfs->cpu;
1071 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1072
1073 guint depth = process->execution_stack->len;
1074
1075 if(depth == 1){
1076 return 1;
1077 }
1078
1079 process->execution_stack =
1080 g_array_set_size(process->execution_stack, depth - 1);
1081 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1082 depth - 2);
1083 process->state->change = tfs->parent.timestamp;
1084
1085 return 0;
1086}
1087
1088static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1089{
1090 guint cpu = tfs->cpu;
1091 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1092 LttvProcessState *process = ts->running_process[cpu];
1093
1094 guint depth = process->execution_stack->len;
1095
1096 if(process->state->t != t){
1097 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1098 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1099 g_info("process state has %s when pop_int is %s\n",
1100 g_quark_to_string(process->state->t),
1101 g_quark_to_string(t));
1102 g_info("{ %u, %u, %s, %s }\n",
1103 process->pid,
1104 process->ppid,
1105 g_quark_to_string(process->name),
1106 g_quark_to_string(process->state->s));
1107 return;
1108 }
1109
1110 if(depth == 1){
1111 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1112 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1113 return;
1114 }
1115
1116 process->execution_stack =
1117 g_array_set_size(process->execution_stack, depth - 1);
1118 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1119 depth - 2);
1120 process->state->change = tfs->parent.timestamp;
1121}
1122
1123struct search_result {
1124 const LttTime *time; /* Requested time */
1125 LttTime *best; /* Best result */
1126};
1127
1128static gint search_usertrace(gconstpointer a, gconstpointer b)
1129{
1130 const LttTime *elem_time = (const LttTime*)a;
1131 /* Explicit non const cast */
1132 struct search_result *res = (struct search_result *)b;
1133
1134 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1135 /* The usertrace was created before the schedchange */
1136 /* Get larger keys */
1137 return 1;
1138 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1139 /* The usertrace was created after the schedchange time */
1140 /* Get smaller keys */
1141 if(res->best) {
1142 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1143 res->best = elem_time;
1144 }
1145 } else {
1146 res->best = elem_time;
1147 }
1148 return -1;
1149 }
1150 return 0;
1151}
1152
1153static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1154 guint pid, const LttTime *timestamp)
1155{
1156 LttvTracefileState *tfs = NULL;
1157 struct search_result res;
1158 /* Find the usertrace associated with a pid and time interval.
1159 * Search in the usertraces by PID (within a hash) and then, for each
1160 * corresponding element of the array, find the first one with creation
1161 * timestamp the lowest, but higher or equal to "timestamp". */
1162 res.time = timestamp;
1163 res.best = NULL;
1164 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1165 if(usertrace_tree) {
1166 g_tree_search(usertrace_tree, search_usertrace, &res);
1167 if(res.best)
1168 tfs = g_tree_lookup(usertrace_tree, res.best);
1169 }
1170
1171 return tfs;
1172}
1173
1174
1175LttvProcessState *
1176lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
1177 guint cpu, guint pid, GQuark name, const LttTime *timestamp)
1178{
1179 LttvProcessState *process = g_new(LttvProcessState, 1);
1180
1181 LttvExecutionState *es;
1182
1183 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1184
1185 char buffer[128];
1186
1187 process->pid = pid;
1188 process->cpu = cpu;
1189 process->name = name;
1190 //process->last_cpu = tfs->cpu_name;
1191 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1192 process->type = LTTV_STATE_USER_THREAD;
1193 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1194 process->current_function = 0; //function 0x0 by default.
1195
1196 g_info("Process %u, core %p", process->pid, process);
1197 g_hash_table_insert(tcs->processes, process, process);
1198
1199 if(parent) {
1200 process->ppid = parent->pid;
1201 process->creation_time = *timestamp;
1202 }
1203
1204 /* No parent. This process exists but we are missing all information about
1205 its creation. The birth time is set to zero but we remember the time of
1206 insertion */
1207
1208 else {
1209 process->ppid = 0;
1210 process->creation_time = ltt_time_zero;
1211 }
1212
1213 process->insertion_time = *timestamp;
1214 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1215 process->creation_time.tv_nsec);
1216 process->pid_time = g_quark_from_string(buffer);
1217 process->cpu = cpu;
1218 //process->last_cpu = tfs->cpu_name;
1219 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1220 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1221 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1222 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1223 es = process->state = &g_array_index(process->execution_stack,
1224 LttvExecutionState, 0);
1225 es->t = LTTV_STATE_USER_MODE;
1226 es->n = LTTV_STATE_SUBMODE_NONE;
1227 es->entry = *timestamp;
1228 //g_assert(timestamp->tv_sec != 0);
1229 es->change = *timestamp;
1230 es->cum_cpu_time = ltt_time_zero;
1231 es->s = LTTV_STATE_RUN;
1232
1233 es = process->state = &g_array_index(process->execution_stack,
1234 LttvExecutionState, 1);
1235 es->t = LTTV_STATE_SYSCALL;
1236 es->n = LTTV_STATE_SUBMODE_NONE;
1237 es->entry = *timestamp;
1238 //g_assert(timestamp->tv_sec != 0);
1239 es->change = *timestamp;
1240 es->cum_cpu_time = ltt_time_zero;
1241 es->s = LTTV_STATE_WAIT_FORK;
1242
1243 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1244 process->user_stack = g_array_sized_new(FALSE, FALSE,
1245 sizeof(guint64), 0);
1246
1247 return process;
1248}
1249
1250LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1251 guint pid)
1252{
1253 LttvProcessState key;
1254 LttvProcessState *process;
1255
1256 key.pid = pid;
1257 key.cpu = cpu;
1258 process = g_hash_table_lookup(ts->processes, &key);
1259 return process;
1260}
1261
1262LttvProcessState *
1263lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1264 LttTime *timestamp)
1265{
1266 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1267 LttvExecutionState *es;
1268
1269 /* Put ltt_time_zero creation time for unexisting processes */
1270 if(unlikely(process == NULL)) {
1271 process = lttv_state_create_process(ts,
1272 NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
1273 /* We are not sure is it's a kernel thread or normal thread, put the
1274 * bottom stack state to unknown */
1275 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1276 es->t = LTTV_STATE_MODE_UNKNOWN;
1277 }
1278 return process;
1279}
1280
1281/* FIXME : this function should be called when we receive an event telling that
1282 * release_task has been called in the kernel. In happens generally when
1283 * the parent waits for its child terminaison, but may also happen in special
1284 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1285 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1286 * of a killed thread ground, but isn't the leader.
1287 */
1288static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1289{
1290 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1291 LttvProcessState key;
1292
1293 key.pid = process->pid;
1294 key.cpu = process->cpu;
1295 g_hash_table_remove(ts->processes, &key);
1296 g_array_free(process->execution_stack, TRUE);
1297 g_array_free(process->user_stack, TRUE);
1298 g_free(process);
1299}
1300
1301
1302static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1303{
1304 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1305 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
1306 g_free(value);
1307}
1308
1309
1310static void lttv_state_free_process_table(GHashTable *processes)
1311{
1312 g_hash_table_foreach(processes, free_process_state, NULL);
1313 g_hash_table_destroy(processes);
1314}
1315
1316
1317static gboolean syscall_entry(void *hook_data, void *call_data)
1318{
1319 LttvTracefileState *s = (LttvTracefileState *)call_data;
1320 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1321 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1322 LttField *f = thf->f1;
1323
1324 LttvExecutionSubmode submode;
1325
1326 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1327 guint syscall = ltt_event_get_unsigned(e, f);
1328
1329 if(syscall < nb_syscalls) {
1330 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1331 syscall];
1332 } else {
1333 /* Fixup an incomplete syscall table */
1334 GString *string = g_string_new("");
1335 g_string_printf(string, "syscall %u", syscall);
1336 submode = g_quark_from_string(string->str);
1337 g_string_free(string, TRUE);
1338 }
1339 push_state(s, LTTV_STATE_SYSCALL, submode);
1340 return FALSE;
1341}
1342
1343
1344static gboolean syscall_exit(void *hook_data, void *call_data)
1345{
1346 LttvTracefileState *s = (LttvTracefileState *)call_data;
1347
1348 pop_state(s, LTTV_STATE_SYSCALL);
1349 return FALSE;
1350}
1351
1352
1353static gboolean trap_entry(void *hook_data, void *call_data)
1354{
1355 LttvTracefileState *s = (LttvTracefileState *)call_data;
1356 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1357 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1358 LttField *f = thf->f1;
1359
1360 LttvExecutionSubmode submode;
1361
1362 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1363 ltt_event_get_unsigned(e, f)];
1364 push_state(s, LTTV_STATE_TRAP, submode);
1365 return FALSE;
1366}
1367
1368
1369static gboolean trap_exit(void *hook_data, void *call_data)
1370{
1371 LttvTracefileState *s = (LttvTracefileState *)call_data;
1372
1373 pop_state(s, LTTV_STATE_TRAP);
1374 return FALSE;
1375}
1376
1377
1378static gboolean irq_entry(void *hook_data, void *call_data)
1379{
1380 LttvTracefileState *s = (LttvTracefileState *)call_data;
1381 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1382 guint8 fac_id = ltt_event_facility_id(e);
1383 guint8 ev_id = ltt_event_eventtype_id(e);
1384 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1385 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1386 g_assert(thf->f1 != NULL);
1387 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1388 LttField *f = thf->f1;
1389
1390 LttvExecutionSubmode submode;
1391
1392 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1393 ltt_event_get_unsigned(e, f)];
1394
1395 /* Do something with the info about being in user or system mode when int? */
1396 push_state(s, LTTV_STATE_IRQ, submode);
1397 return FALSE;
1398}
1399
1400static gboolean soft_irq_exit(void *hook_data, void *call_data)
1401{
1402 LttvTracefileState *s = (LttvTracefileState *)call_data;
1403
1404 pop_state(s, LTTV_STATE_SOFT_IRQ);
1405 return FALSE;
1406}
1407
1408
1409
1410static gboolean irq_exit(void *hook_data, void *call_data)
1411{
1412 LttvTracefileState *s = (LttvTracefileState *)call_data;
1413
1414 pop_state(s, LTTV_STATE_IRQ);
1415 return FALSE;
1416}
1417
1418static gboolean soft_irq_entry(void *hook_data, void *call_data)
1419{
1420 LttvTracefileState *s = (LttvTracefileState *)call_data;
1421 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1422 guint8 fac_id = ltt_event_facility_id(e);
1423 guint8 ev_id = ltt_event_eventtype_id(e);
1424 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1425 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1426 g_assert(thf->f1 != NULL);
1427 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1428 LttField *f = thf->f1;
1429
1430 LttvExecutionSubmode submode;
1431
1432 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1433 ltt_event_get_unsigned(e, f)];
1434
1435 /* Do something with the info about being in user or system mode when int? */
1436 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1437 return FALSE;
1438}
1439
1440static void push_function(LttvTracefileState *tfs, guint64 funcptr)
1441{
1442 guint64 *new_func;
1443
1444 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1445 guint cpu = tfs->cpu;
1446 LttvProcessState *process = ts->running_process[cpu];
1447
1448 guint depth = process->user_stack->len;
1449
1450 process->user_stack =
1451 g_array_set_size(process->user_stack, depth + 1);
1452
1453 new_func = &g_array_index(process->user_stack, guint64, depth);
1454 *new_func = funcptr;
1455 process->current_function = funcptr;
1456}
1457
1458static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
1459{
1460 guint cpu = tfs->cpu;
1461 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1462 LttvProcessState *process = ts->running_process[cpu];
1463
1464 if(process->current_function != funcptr){
1465 g_info("Different functions (%lu.%09lu): ignore it\n",
1466 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1467 g_info("process state has %llu when pop_function is %llu\n",
1468 process->current_function, funcptr);
1469 g_info("{ %u, %u, %s, %s }\n",
1470 process->pid,
1471 process->ppid,
1472 g_quark_to_string(process->name),
1473 g_quark_to_string(process->state->s));
1474 return;
1475 }
1476 guint depth = process->user_stack->len;
1477
1478 if(depth == 0){
1479 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1480 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1481 return;
1482 }
1483
1484 process->user_stack =
1485 g_array_set_size(process->user_stack, depth - 1);
1486 process->current_function =
1487 g_array_index(process->user_stack, guint64, depth - 2);
1488}
1489
1490
1491static gboolean function_entry(void *hook_data, void *call_data)
1492{
1493 LttvTracefileState *s = (LttvTracefileState *)call_data;
1494 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1495 guint8 fac_id = ltt_event_facility_id(e);
1496 guint8 ev_id = ltt_event_eventtype_id(e);
1497 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1498 g_assert(thf->f1 != NULL);
1499 LttField *f = thf->f1;
1500 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1501
1502 push_function(s, funcptr);
1503 return FALSE;
1504}
1505
1506static gboolean function_exit(void *hook_data, void *call_data)
1507{
1508 LttvTracefileState *s = (LttvTracefileState *)call_data;
1509 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1510 guint8 fac_id = ltt_event_facility_id(e);
1511 guint8 ev_id = ltt_event_eventtype_id(e);
1512 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1513 g_assert(thf->f1 != NULL);
1514 LttField *f = thf->f1;
1515 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1516
1517 LttvExecutionSubmode submode;
1518
1519 pop_function(s, funcptr);
1520 return FALSE;
1521}
1522
1523static gboolean schedchange(void *hook_data, void *call_data)
1524{
1525 LttvTracefileState *s = (LttvTracefileState *)call_data;
1526 guint cpu = s->cpu;
1527 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1528 LttvProcessState *process = ts->running_process[cpu];
1529 LttvProcessState *old_process = ts->running_process[cpu];
1530
1531 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1532 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1533 guint pid_in, pid_out;
1534 gint state_out;
1535
1536 pid_out = ltt_event_get_unsigned(e, thf->f1);
1537 pid_in = ltt_event_get_unsigned(e, thf->f2);
1538 state_out = ltt_event_get_int(e, thf->f3);
1539
1540 if(likely(process != NULL)) {
1541
1542 /* We could not know but it was not the idle process executing.
1543 This should only happen at the beginning, before the first schedule
1544 event, and when the initial information (current process for each CPU)
1545 is missing. It is not obvious how we could, after the fact, compensate
1546 the wrongly attributed statistics. */
1547
1548 //This test only makes sense once the state is known and if there is no
1549 //missing events. We need to silently ignore schedchange coming after a
1550 //process_free, or it causes glitches. (FIXME)
1551 //if(unlikely(process->pid != pid_out)) {
1552 // g_assert(process->pid == 0);
1553 //}
1554
1555 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1556 process->state->s = LTTV_STATE_ZOMBIE;
1557 process->state->change = s->parent.timestamp;
1558 } else {
1559 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1560 else process->state->s = LTTV_STATE_WAIT;
1561 process->state->change = s->parent.timestamp;
1562 }
1563
1564 if(state_out == 32)
1565 exit_process(s, process); /* EXIT_DEAD */
1566 /* see sched.h for states */
1567 }
1568 process = ts->running_process[cpu] =
1569 lttv_state_find_process_or_create(
1570 (LttvTraceState*)s->parent.t_context,
1571 cpu, pid_in,
1572 &s->parent.timestamp);
1573 process->state->s = LTTV_STATE_RUN;
1574 process->cpu = cpu;
1575 if(process->usertrace)
1576 process->usertrace->cpu = cpu;
1577 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1578 process->state->change = s->parent.timestamp;
1579 return FALSE;
1580}
1581
1582static gboolean process_fork(void *hook_data, void *call_data)
1583{
1584 LttvTracefileState *s = (LttvTracefileState *)call_data;
1585 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1586 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1587 guint parent_pid;
1588 guint child_pid;
1589 LttvProcessState *zombie_process;
1590 guint cpu = s->cpu;
1591 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1592 LttvProcessState *process = ts->running_process[cpu];
1593 LttvProcessState *child_process;
1594
1595 /* Parent PID */
1596 parent_pid = ltt_event_get_unsigned(e, thf->f1);
1597
1598 /* Child PID */
1599 child_pid = ltt_event_get_unsigned(e, thf->f2);
1600
1601 /* Mathieu : it seems like the process might have been scheduled in before the
1602 * fork, and, in a rare case, might be the current process. This might happen
1603 * in a SMP case where we don't have enough precision on the clocks.
1604 *
1605 * Test reenabled after precision fixes on time. (Mathieu) */
1606#if 0
1607 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1608
1609 if(unlikely(zombie_process != NULL)) {
1610 /* Reutilisation of PID. Only now we are sure that the old PID
1611 * has been released. FIXME : should know when release_task happens instead.
1612 */
1613 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1614 guint i;
1615 for(i=0; i< num_cpus; i++) {
1616 g_assert(zombie_process != ts->running_process[i]);
1617 }
1618
1619 exit_process(s, zombie_process);
1620 }
1621#endif //0
1622 g_assert(process->pid != child_pid);
1623 // FIXME : Add this test in the "known state" section
1624 // g_assert(process->pid == parent_pid);
1625 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1626 if(child_process == NULL) {
1627 child_process = lttv_state_create_process(ts, process, cpu,
1628 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
1629 } else {
1630 /* The process has already been created : due to time imprecision between
1631 * multiple CPUs : it has been scheduled in before creation. Note that we
1632 * shouldn't have this kind of imprecision.
1633 *
1634 * Simply put a correct parent.
1635 */
1636 g_assert(0); /* This is a problematic case : the process has been created
1637 before the fork event */
1638 child_process->ppid = process->pid;
1639 }
1640 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1641 child_process->name = process->name;
1642
1643 return FALSE;
1644}
1645
1646/* We stamp a newly created process as kernel_thread */
1647static gboolean process_kernel_thread(void *hook_data, void *call_data)
1648{
1649 LttvTracefileState *s = (LttvTracefileState *)call_data;
1650 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1651 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1652 guint pid;
1653 guint cpu = s->cpu;
1654 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1655 LttvProcessState *process;
1656 LttvExecutionState *es;
1657
1658 /* PID */
1659 pid = ltt_event_get_unsigned(e, thf->f1);
1660
1661 process = lttv_state_find_process(ts, ANY_CPU, pid);
1662 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1663 es->t = LTTV_STATE_SYSCALL;
1664 process->type = LTTV_STATE_KERNEL_THREAD;
1665
1666 return FALSE;
1667}
1668
1669static gboolean process_exit(void *hook_data, void *call_data)
1670{
1671 LttvTracefileState *s = (LttvTracefileState *)call_data;
1672 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1673 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1674 LttField *f;
1675 guint pid;
1676 guint cpu = s->cpu;
1677 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1678 LttvProcessState *process = ts->running_process[cpu];
1679
1680 pid = ltt_event_get_unsigned(e, thf->f1);
1681
1682 // FIXME : Add this test in the "known state" section
1683 // g_assert(process->pid == pid);
1684
1685 if(likely(process != NULL)) {
1686 process->state->s = LTTV_STATE_EXIT;
1687 }
1688 return FALSE;
1689}
1690
1691static gboolean process_free(void *hook_data, void *call_data)
1692{
1693 LttvTracefileState *s = (LttvTracefileState *)call_data;
1694 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1695 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1696 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1697 guint release_pid;
1698 LttvProcessState *process;
1699
1700 /* PID of the process to release */
1701 release_pid = ltt_event_get_unsigned(e, thf->f1);
1702
1703 g_assert(release_pid != 0);
1704
1705 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1706
1707 if(likely(process != NULL)) {
1708 /* release_task is happening at kernel level : we can now safely release
1709 * the data structure of the process */
1710 //This test is fun, though, as it may happen that
1711 //at time t : CPU 0 : process_free
1712 //at time t+150ns : CPU 1 : schedule out
1713 //Clearly due to time imprecision, we disable it. (Mathieu)
1714 //If this weird case happen, we have no choice but to put the
1715 //Currently running process on the cpu to 0.
1716 //I re-enable it following time precision fixes. (Mathieu)
1717 //Well, in the case where an process is freed by a process on another CPU
1718 //and still scheduled, it happens that this is the schedchange that will
1719 //drop the last reference count. Do not free it here!
1720 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1721 guint i;
1722 for(i=0; i< num_cpus; i++) {
1723 //g_assert(process != ts->running_process[i]);
1724 if(process == ts->running_process[i]) {
1725 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1726 break;
1727 }
1728 }
1729 //if(i == num_cpus) /* process is not scheduled */
1730 //exit_process(s, process); // do nothing : wait for the schedchange to
1731 //delete the process.
1732 }
1733
1734 return FALSE;
1735}
1736
1737
1738static gboolean process_exec(void *hook_data, void *call_data)
1739{
1740 LttvTracefileState *s = (LttvTracefileState *)call_data;
1741 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1742 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1743 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1744 //gchar *name;
1745 guint cpu = s->cpu;
1746 LttvProcessState *process = ts->running_process[cpu];
1747
1748 /* PID of the process to release */
1749 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1750 //name = ltt_event_get_string(e, thf->f1);
1751 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1752 gchar *name_begin =
1753 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1754 gchar *null_term_name = g_new(gchar, name_len+1);
1755 memcpy(null_term_name, name_begin, name_len);
1756 null_term_name[name_len] = '\0';
1757
1758 process->name = g_quark_from_string(null_term_name);
1759 g_free(null_term_name);
1760 return FALSE;
1761}
1762
1763static gboolean enum_process_state(void *hook_data, void *call_data)
1764{
1765 LttvTracefileState *s = (LttvTracefileState *)call_data;
1766 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1767 //It's slow : optimise later by doing this before reading trace.
1768 LttEventType *et = ltt_event_eventtype(e);
1769 //
1770 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1771 guint parent_pid;
1772 guint pid;
1773 gchar * command;
1774 guint cpu = s->cpu;
1775 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1776 LttvProcessState *process = ts->running_process[cpu];
1777 LttvProcessState *parent_process;
1778 LttField *f4, *f5, *f6, *f7;
1779 GQuark type, mode, submode, status;
1780 LttvExecutionState *es;
1781
1782 /* PID */
1783 pid = ltt_event_get_unsigned(e, thf->f1);
1784
1785 /* Parent PID */
1786 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1787
1788 /* Command name */
1789 command = ltt_event_get_string(e, thf->f3);
1790
1791 /* type */
1792 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
1793 type = ltt_enum_string_get(ltt_field_type(f4),
1794 ltt_event_get_unsigned(e, f4));
1795
1796 /* mode */
1797 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1798 mode = ltt_enum_string_get(ltt_field_type(f5),
1799 ltt_event_get_unsigned(e, f5));
1800
1801 /* submode */
1802 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1803 submode = ltt_enum_string_get(ltt_field_type(f6),
1804 ltt_event_get_unsigned(e, f6));
1805
1806 /* status */
1807 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1808 status = ltt_enum_string_get(ltt_field_type(f7),
1809 ltt_event_get_unsigned(e, f7));
1810
1811 /* The process might exist if a process was forked while performing the sate dump. */
1812 process = lttv_state_find_process(ts, ANY_CPU, pid);
1813 if(process == NULL) {
1814 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1815 process = lttv_state_create_process(ts, parent_process, cpu,
1816 pid, g_quark_from_string(command),
1817 &s->parent.timestamp);
1818
1819 /* Keep the stack bottom : a running user mode */
1820 /* Disabled because of inconsistencies in the current statedump states. */
1821 if(type == LTTV_STATE_KERNEL_THREAD) {
1822 /* Only keep the bottom */
1823 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1824 es = process->state = &g_array_index(process->execution_stack,
1825 LttvExecutionState, 0);
1826 es->t = LTTV_STATE_SYSCALL;
1827 es->s = status;
1828 es->n = submode;
1829 } else {
1830 /* On top of it : */
1831 es = process->state = &g_array_index(process->execution_stack,
1832 LttvExecutionState, 1);
1833 es->t = LTTV_STATE_USER_MODE;
1834 es->s = status;
1835 es->n = submode;
1836 }
1837#if 0
1838 /* UNKNOWN STATE */
1839 {
1840 es = process->state = &g_array_index(process->execution_stack,
1841 LttvExecutionState, 1);
1842 es->t = LTTV_STATE_MODE_UNKNOWN;
1843 es->s = LTTV_STATE_UNNAMED;
1844 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1845 }
1846#endif //0
1847 } else {
1848 /* The process has already been created :
1849 * Probably was forked while dumping the process state or
1850 * was simply scheduled in prior to get the state dump event.
1851 * We know for sure if it is a user space thread.
1852 */
1853 process->ppid = parent_pid;
1854 process->name = g_quark_from_string(command);
1855 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1856 if(type != LTTV_STATE_KERNEL_THREAD)
1857 es->t = LTTV_STATE_USER_MODE;
1858 /* Don't mess around with the stack, it will eventually become
1859 * ok after the end of state dump. */
1860 }
1861
1862 return FALSE;
1863}
1864
1865gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1866{
1867 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1868
1869 lttv_state_add_event_hooks(tss);
1870
1871 return 0;
1872}
1873
1874void lttv_state_add_event_hooks(LttvTracesetState *self)
1875{
1876 LttvTraceset *traceset = self->parent.ts;
1877
1878 guint i, j, k, l, nb_trace, nb_tracefile;
1879
1880 LttvTraceState *ts;
1881
1882 LttvTracefileState *tfs;
1883
1884 GArray *hooks;
1885
1886 LttvTraceHookByFacility *thf;
1887
1888 LttvTraceHook *hook;
1889
1890 LttvAttributeValue val;
1891
1892 gint ret;
1893 gint hn;
1894
1895 nb_trace = lttv_traceset_number(traceset);
1896 for(i = 0 ; i < nb_trace ; i++) {
1897 ts = (LttvTraceState *)self->parent.traces[i];
1898
1899 /* Find the eventtype id for the following events and register the
1900 associated by id hooks. */
1901
1902 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
1903 hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
1904 hn = 0;
1905
1906 ret = lttv_trace_find_hook(ts->parent.t,
1907 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1908 LTT_FIELD_SYSCALL_ID, 0, 0,
1909 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1910 if(ret) hn--;
1911
1912 ret = lttv_trace_find_hook(ts->parent.t,
1913 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1914 0, 0, 0,
1915 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1916 if(ret) hn--;
1917
1918 ret = lttv_trace_find_hook(ts->parent.t,
1919 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1920 LTT_FIELD_TRAP_ID, 0, 0,
1921 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1922 if(ret) hn--;
1923
1924 ret = lttv_trace_find_hook(ts->parent.t,
1925 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1926 0, 0, 0,
1927 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1928 if(ret) hn--;
1929
1930 ret = lttv_trace_find_hook(ts->parent.t,
1931 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1932 LTT_FIELD_IRQ_ID, 0, 0,
1933 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1934 if(ret) hn--;
1935
1936 ret = lttv_trace_find_hook(ts->parent.t,
1937 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1938 0, 0, 0,
1939 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1940 if(ret) hn--;
1941
1942 ret = lttv_trace_find_hook(ts->parent.t,
1943 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1944 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1945 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1946 if(ret) hn--;
1947
1948 ret = lttv_trace_find_hook(ts->parent.t,
1949 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1950 0, 0, 0,
1951 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1952 if(ret) hn--;
1953
1954 ret = lttv_trace_find_hook(ts->parent.t,
1955 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1956 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1957 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1958 if(ret) hn--;
1959
1960 ret = lttv_trace_find_hook(ts->parent.t,
1961 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1962 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1963 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1964 if(ret) hn--;
1965
1966 ret = lttv_trace_find_hook(ts->parent.t,
1967 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1968 LTT_FIELD_PID, 0, 0,
1969 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
1970 hn++));
1971 if(ret) hn--;
1972
1973 ret = lttv_trace_find_hook(ts->parent.t,
1974 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1975 LTT_FIELD_PID, 0, 0,
1976 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1977 if(ret) hn--;
1978
1979 ret = lttv_trace_find_hook(ts->parent.t,
1980 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1981 LTT_FIELD_PID, 0, 0,
1982 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1983 if(ret) hn--;
1984
1985 ret = lttv_trace_find_hook(ts->parent.t,
1986 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1987 LTT_FIELD_FILENAME, 0, 0,
1988 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1989 if(ret) hn--;
1990
1991 /* statedump-related hooks */
1992 ret = lttv_trace_find_hook(ts->parent.t,
1993 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1994 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1995 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1996 if(ret) hn--;
1997
1998 ret = lttv_trace_find_hook(ts->parent.t,
1999 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2000 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2001 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2002 if(ret) hn--;
2003
2004 ret = lttv_trace_find_hook(ts->parent.t,
2005 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2006 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2007 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2008 if(ret) hn--;
2009
2010 hooks = g_array_set_size(hooks, hn);
2011
2012 /* Add these hooks to each event_by_id hooks list */
2013
2014 nb_tracefile = ts->parent.tracefiles->len;
2015
2016 for(j = 0 ; j < nb_tracefile ; j++) {
2017 tfs =
2018 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2019 LttvTracefileContext*, j));
2020
2021 for(k = 0 ; k < hooks->len ; k++) {
2022 hook = &g_array_index(hooks, LttvTraceHook, k);
2023 for(l=0;l<hook->fac_list->len;l++) {
2024 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2025 lttv_hooks_add(
2026 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2027 thf->h,
2028 thf,
2029 LTTV_PRIO_STATE);
2030 }
2031 }
2032 }
2033 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2034 *(val.v_pointer) = hooks;
2035 }
2036}
2037
2038gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2039{
2040 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2041
2042 lttv_state_remove_event_hooks(tss);
2043
2044 return 0;
2045}
2046
2047void lttv_state_remove_event_hooks(LttvTracesetState *self)
2048{
2049 LttvTraceset *traceset = self->parent.ts;
2050
2051 guint i, j, k, l, nb_trace, nb_tracefile;
2052
2053 LttvTraceState *ts;
2054
2055 LttvTracefileState *tfs;
2056
2057 GArray *hooks;
2058
2059 LttvTraceHook *hook;
2060
2061 LttvTraceHookByFacility *thf;
2062
2063 LttvAttributeValue val;
2064
2065 nb_trace = lttv_traceset_number(traceset);
2066 for(i = 0 ; i < nb_trace ; i++) {
2067 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2068 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2069 hooks = *(val.v_pointer);
2070
2071 /* Remove these hooks from each event_by_id hooks list */
2072
2073 nb_tracefile = ts->parent.tracefiles->len;
2074
2075 for(j = 0 ; j < nb_tracefile ; j++) {
2076 tfs =
2077 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2078 LttvTracefileContext*, j));
2079
2080 for(k = 0 ; k < hooks->len ; k++) {
2081 hook = &g_array_index(hooks, LttvTraceHook, k);
2082 for(l=0;l<hook->fac_list->len;l++) {
2083 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2084
2085 lttv_hooks_remove_data(
2086 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2087 thf->h,
2088 thf);
2089 }
2090 }
2091 }
2092 for(k = 0 ; k < hooks->len ; k++)
2093 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2094 g_array_free(hooks, TRUE);
2095 }
2096}
2097
2098static gboolean state_save_event_hook(void *hook_data, void *call_data)
2099{
2100 guint *event_count = (guint*)hook_data;
2101
2102 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2103 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2104 return FALSE;
2105 else
2106 *event_count = 0;
2107
2108 LttvTracefileState *self = (LttvTracefileState *)call_data;
2109
2110 LttvTracefileState *tfcs;
2111
2112 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2113
2114 LttEventPosition *ep;
2115
2116 guint i;
2117
2118 LttTracefile *tf;
2119
2120 LttvAttribute *saved_states_tree, *saved_state_tree;
2121
2122 LttvAttributeValue value;
2123
2124 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2125 LTTV_STATE_SAVED_STATES);
2126 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2127 value = lttv_attribute_add(saved_states_tree,
2128 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2129 *(value.v_gobject) = (GObject *)saved_state_tree;
2130 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2131 *(value.v_time) = self->parent.timestamp;
2132 lttv_state_save(tcs, saved_state_tree);
2133 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2134 self->parent.timestamp.tv_nsec);
2135
2136 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2137
2138 return FALSE;
2139}
2140
2141static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2142{
2143 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2144
2145 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2146
2147 return FALSE;
2148}
2149
2150guint lttv_state_current_cpu(LttvTracefileState *tfs)
2151{
2152 return tfs->cpu;
2153}
2154
2155
2156
2157#if 0
2158static gboolean block_start(void *hook_data, void *call_data)
2159{
2160 LttvTracefileState *self = (LttvTracefileState *)call_data;
2161
2162 LttvTracefileState *tfcs;
2163
2164 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2165
2166 LttEventPosition *ep;
2167
2168 guint i, nb_block, nb_event, nb_tracefile;
2169
2170 LttTracefile *tf;
2171
2172 LttvAttribute *saved_states_tree, *saved_state_tree;
2173
2174 LttvAttributeValue value;
2175
2176 ep = ltt_event_position_new();
2177
2178 nb_tracefile = tcs->parent.tracefiles->len;
2179
2180 /* Count the number of events added since the last block end in any
2181 tracefile. */
2182
2183 for(i = 0 ; i < nb_tracefile ; i++) {
2184 tfcs =
2185 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2186 LttvTracefileContext, i));
2187 ltt_event_position(tfcs->parent.e, ep);
2188 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2189 tcs->nb_event += nb_event - tfcs->saved_position;
2190 tfcs->saved_position = nb_event;
2191 }
2192 g_free(ep);
2193
2194 if(tcs->nb_event >= tcs->save_interval) {
2195 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2196 LTTV_STATE_SAVED_STATES);
2197 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2198 value = lttv_attribute_add(saved_states_tree,
2199 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2200 *(value.v_gobject) = (GObject *)saved_state_tree;
2201 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2202 *(value.v_time) = self->parent.timestamp;
2203 lttv_state_save(tcs, saved_state_tree);
2204 tcs->nb_event = 0;
2205 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2206 self->parent.timestamp.tv_nsec);
2207 }
2208 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2209 return FALSE;
2210}
2211#endif //0
2212
2213#if 0
2214static gboolean block_end(void *hook_data, void *call_data)
2215{
2216 LttvTracefileState *self = (LttvTracefileState *)call_data;
2217
2218 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2219
2220 LttTracefile *tf;
2221
2222 LttEventPosition *ep;
2223
2224 guint nb_block, nb_event;
2225
2226 ep = ltt_event_position_new();
2227 ltt_event_position(self->parent.e, ep);
2228 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2229 tcs->nb_event += nb_event - self->saved_position + 1;
2230 self->saved_position = 0;
2231 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2232 g_free(ep);
2233
2234 return FALSE;
2235}
2236#endif //0
2237#if 0
2238void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2239{
2240 LttvTraceset *traceset = self->parent.ts;
2241
2242 guint i, j, nb_trace, nb_tracefile;
2243
2244 LttvTraceState *ts;
2245
2246 LttvTracefileState *tfs;
2247
2248 LttvTraceHook hook_start, hook_end;
2249
2250 nb_trace = lttv_traceset_number(traceset);
2251 for(i = 0 ; i < nb_trace ; i++) {
2252 ts = (LttvTraceState *)self->parent.traces[i];
2253
2254 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2255 NULL, NULL, block_start, &hook_start);
2256 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2257 NULL, NULL, block_end, &hook_end);
2258
2259 nb_tracefile = ts->parent.tracefiles->len;
2260
2261 for(j = 0 ; j < nb_tracefile ; j++) {
2262 tfs =
2263 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2264 LttvTracefileContext, j));
2265 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2266 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2267 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2268 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2269 }
2270 }
2271}
2272#endif //0
2273
2274void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2275{
2276 LttvTraceset *traceset = self->parent.ts;
2277
2278 guint i, j, nb_trace, nb_tracefile;
2279
2280 LttvTraceState *ts;
2281
2282 LttvTracefileState *tfs;
2283
2284
2285 nb_trace = lttv_traceset_number(traceset);
2286 for(i = 0 ; i < nb_trace ; i++) {
2287
2288 ts = (LttvTraceState *)self->parent.traces[i];
2289 nb_tracefile = ts->parent.tracefiles->len;
2290
2291 guint *event_count = g_new(guint, 1);
2292 *event_count = 0;
2293
2294 for(j = 0 ; j < nb_tracefile ; j++) {
2295 tfs =
2296 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2297 LttvTracefileContext*, j));
2298 lttv_hooks_add(tfs->parent.event,
2299 state_save_event_hook,
2300 event_count,
2301 LTTV_PRIO_STATE);
2302
2303 }
2304 }
2305
2306 lttv_process_traceset_begin(&self->parent,
2307 NULL, NULL, NULL, NULL, NULL);
2308
2309}
2310
2311gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2312{
2313 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2314
2315 lttv_state_save_add_event_hooks(tss);
2316
2317 return 0;
2318}
2319
2320
2321#if 0
2322void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2323{
2324 LttvTraceset *traceset = self->parent.ts;
2325
2326 guint i, j, nb_trace, nb_tracefile;
2327
2328 LttvTraceState *ts;
2329
2330 LttvTracefileState *tfs;
2331
2332 LttvTraceHook hook_start, hook_end;
2333
2334 nb_trace = lttv_traceset_number(traceset);
2335 for(i = 0 ; i < nb_trace ; i++) {
2336 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2337
2338 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2339 NULL, NULL, block_start, &hook_start);
2340
2341 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2342 NULL, NULL, block_end, &hook_end);
2343
2344 nb_tracefile = ts->parent.tracefiles->len;
2345
2346 for(j = 0 ; j < nb_tracefile ; j++) {
2347 tfs =
2348 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2349 LttvTracefileContext, j));
2350 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2351 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2352 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2353 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2354 }
2355 }
2356}
2357#endif //0
2358
2359void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2360{
2361 LttvTraceset *traceset = self->parent.ts;
2362
2363 guint i, j, nb_trace, nb_tracefile;
2364
2365 LttvTraceState *ts;
2366
2367 LttvTracefileState *tfs;
2368
2369 LttvHooks *after_trace = lttv_hooks_new();
2370
2371 lttv_hooks_add(after_trace,
2372 state_save_after_trace_hook,
2373 NULL,
2374 LTTV_PRIO_STATE);
2375
2376
2377 lttv_process_traceset_end(&self->parent,
2378 NULL, after_trace, NULL, NULL, NULL);
2379
2380 lttv_hooks_destroy(after_trace);
2381
2382 nb_trace = lttv_traceset_number(traceset);
2383 for(i = 0 ; i < nb_trace ; i++) {
2384
2385 ts = (LttvTraceState *)self->parent.traces[i];
2386 nb_tracefile = ts->parent.tracefiles->len;
2387
2388 guint *event_count = NULL;
2389
2390 for(j = 0 ; j < nb_tracefile ; j++) {
2391 tfs =
2392 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2393 LttvTracefileContext*, j));
2394 event_count = lttv_hooks_remove(tfs->parent.event,
2395 state_save_event_hook);
2396 }
2397 if(event_count) g_free(event_count);
2398 }
2399}
2400
2401gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2402{
2403 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2404
2405 lttv_state_save_remove_event_hooks(tss);
2406
2407 return 0;
2408}
2409
2410void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2411{
2412 LttvTraceset *traceset = self->parent.ts;
2413
2414 guint i, nb_trace;
2415
2416 int min_pos, mid_pos, max_pos;
2417
2418 guint call_rest = 0;
2419
2420 LttvTraceState *tcs;
2421
2422 LttvAttributeValue value;
2423
2424 LttvAttributeType type;
2425
2426 LttvAttributeName name;
2427
2428 gboolean is_named;
2429
2430 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2431
2432 //g_tree_destroy(self->parent.pqueue);
2433 //self->parent.pqueue = g_tree_new(compare_tracefile);
2434
2435 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2436
2437 nb_trace = lttv_traceset_number(traceset);
2438 for(i = 0 ; i < nb_trace ; i++) {
2439 tcs = (LttvTraceState *)self->parent.traces[i];
2440
2441 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2442 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2443 LTTV_STATE_SAVED_STATES);
2444 min_pos = -1;
2445
2446 if(saved_states_tree) {
2447 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2448 mid_pos = max_pos / 2;
2449 while(min_pos < max_pos) {
2450 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
2451 &is_named);
2452 g_assert(type == LTTV_GOBJECT);
2453 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2454 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2455 &value);
2456 g_assert(type == LTTV_TIME);
2457 if(ltt_time_compare(*(value.v_time), t) < 0) {
2458 min_pos = mid_pos;
2459 closest_tree = saved_state_tree;
2460 }
2461 else max_pos = mid_pos - 1;
2462
2463 mid_pos = (min_pos + max_pos + 1) / 2;
2464 }
2465 }
2466
2467 /* restore the closest earlier saved state */
2468 if(min_pos != -1) {
2469 lttv_state_restore(tcs, closest_tree);
2470 call_rest = 1;
2471 }
2472
2473 /* There is no saved state, yet we want to have it. Restart at T0 */
2474 else {
2475 restore_init_state(tcs);
2476 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2477 }
2478 }
2479 /* We want to seek quickly without restoring/updating the state */
2480 else {
2481 restore_init_state(tcs);
2482 lttv_process_trace_seek_time(&(tcs->parent), t);
2483 }
2484 }
2485 if(!call_rest) g_info("NOT Calling restore");
2486}
2487
2488
2489static void
2490traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2491{
2492}
2493
2494
2495static void
2496traceset_state_finalize (LttvTracesetState *self)
2497{
2498 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2499 finalize(G_OBJECT(self));
2500}
2501
2502
2503static void
2504traceset_state_class_init (LttvTracesetContextClass *klass)
2505{
2506 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2507
2508 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2509 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2510 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2511 klass->new_traceset_context = new_traceset_context;
2512 klass->new_trace_context = new_trace_context;
2513 klass->new_tracefile_context = new_tracefile_context;
2514}
2515
2516
2517GType
2518lttv_traceset_state_get_type(void)
2519{
2520 static GType type = 0;
2521 if (type == 0) {
2522 static const GTypeInfo info = {
2523 sizeof (LttvTracesetStateClass),
2524 NULL, /* base_init */
2525 NULL, /* base_finalize */
2526 (GClassInitFunc) traceset_state_class_init, /* class_init */
2527 NULL, /* class_finalize */
2528 NULL, /* class_data */
2529 sizeof (LttvTracesetState),
2530 0, /* n_preallocs */
2531 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2532 NULL /* value handling */
2533 };
2534
2535 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2536 &info, 0);
2537 }
2538 return type;
2539}
2540
2541
2542static void
2543trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2544{
2545}
2546
2547
2548static void
2549trace_state_finalize (LttvTraceState *self)
2550{
2551 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2552 finalize(G_OBJECT(self));
2553}
2554
2555
2556static void
2557trace_state_class_init (LttvTraceStateClass *klass)
2558{
2559 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2560
2561 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2562 klass->state_save = state_save;
2563 klass->state_restore = state_restore;
2564 klass->state_saved_free = state_saved_free;
2565}
2566
2567
2568GType
2569lttv_trace_state_get_type(void)
2570{
2571 static GType type = 0;
2572 if (type == 0) {
2573 static const GTypeInfo info = {
2574 sizeof (LttvTraceStateClass),
2575 NULL, /* base_init */
2576 NULL, /* base_finalize */
2577 (GClassInitFunc) trace_state_class_init, /* class_init */
2578 NULL, /* class_finalize */
2579 NULL, /* class_data */
2580 sizeof (LttvTraceState),
2581 0, /* n_preallocs */
2582 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2583 NULL /* value handling */
2584 };
2585
2586 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2587 "LttvTraceStateType", &info, 0);
2588 }
2589 return type;
2590}
2591
2592
2593static void
2594tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2595{
2596}
2597
2598
2599static void
2600tracefile_state_finalize (LttvTracefileState *self)
2601{
2602 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2603 finalize(G_OBJECT(self));
2604}
2605
2606
2607static void
2608tracefile_state_class_init (LttvTracefileStateClass *klass)
2609{
2610 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2611
2612 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2613}
2614
2615
2616GType
2617lttv_tracefile_state_get_type(void)
2618{
2619 static GType type = 0;
2620 if (type == 0) {
2621 static const GTypeInfo info = {
2622 sizeof (LttvTracefileStateClass),
2623 NULL, /* base_init */
2624 NULL, /* base_finalize */
2625 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2626 NULL, /* class_finalize */
2627 NULL, /* class_data */
2628 sizeof (LttvTracefileState),
2629 0, /* n_preallocs */
2630 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2631 NULL /* value handling */
2632 };
2633
2634 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2635 "LttvTracefileStateType", &info, 0);
2636 }
2637 return type;
2638}
2639
2640
2641static void module_init()
2642{
2643 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
2644 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2645 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2646 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2647 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2648 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2649 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2650 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2651 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2652 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2653 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2654 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2655 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2656 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2657 LTTV_STATE_RUN = g_quark_from_string("RUN");
2658 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2659 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
2660 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
2661 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2662 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2663 LTTV_STATE_PROCESS = g_quark_from_string("process");
2664 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2665 LTTV_STATE_EVENT = g_quark_from_string("event");
2666 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2667 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2668 LTTV_STATE_TIME = g_quark_from_string("time");
2669 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2670 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2671 LTTV_STATE_TRACE_STATE_USE_COUNT =
2672 g_quark_from_string("trace_state_use_count");
2673
2674
2675 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2676 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2677 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2678 LTT_FACILITY_FS = g_quark_from_string("fs");
2679 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2680 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
2681
2682
2683 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2684 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2685 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2686 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2687 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2688 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2689 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2690 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2691 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2692 LTT_EVENT_FORK = g_quark_from_string("fork");
2693 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
2694 LTT_EVENT_EXIT = g_quark_from_string("exit");
2695 LTT_EVENT_FREE = g_quark_from_string("free");
2696 LTT_EVENT_EXEC = g_quark_from_string("exec");
2697 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2698 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2699 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
2700
2701
2702 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2703 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2704 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2705 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2706 LTT_FIELD_OUT = g_quark_from_string("out");
2707 LTT_FIELD_IN = g_quark_from_string("in");
2708 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2709 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2710 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2711 LTT_FIELD_PID = g_quark_from_string("pid");
2712 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2713 LTT_FIELD_NAME = g_quark_from_string("name");
2714 LTT_FIELD_TYPE = g_quark_from_string("type");
2715 LTT_FIELD_MODE = g_quark_from_string("mode");
2716 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2717 LTT_FIELD_STATUS = g_quark_from_string("status");
2718 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2719 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
2720
2721}
2722
2723static void module_destroy()
2724{
2725}
2726
2727
2728LTTV_MODULE("state", "State computation", \
2729 "Update the system state, possibly saving it at intervals", \
2730 module_init, module_destroy)
2731
2732
2733
This page took 0.029846 seconds and 4 git commands to generate.