update for powerpc
[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 #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
37 GQuark
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
47 GQuark
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
68 GQuark
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
88 LttvExecutionMode
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
96 LttvExecutionSubmode
97 LTTV_STATE_SUBMODE_UNKNOWN,
98 LTTV_STATE_SUBMODE_NONE;
99
100 LttvProcessStatus
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
110 LttvProcessType
111 LTTV_STATE_USER_THREAD,
112 LTTV_STATE_KERNEL_THREAD;
113
114 static 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
127 static void create_max_time(LttvTraceState *tcs);
128
129 static void get_max_time(LttvTraceState *tcs);
130
131 static void free_max_time(LttvTraceState *tcs);
132
133 static void create_name_tables(LttvTraceState *tcs);
134
135 static void get_name_tables(LttvTraceState *tcs);
136
137 static void free_name_tables(LttvTraceState *tcs);
138
139 static void free_saved_state(LttvTraceState *tcs);
140
141 static void lttv_state_free_process_table(GHashTable *processes);
142
143
144 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
145 {
146 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
147 }
148
149
150 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
151 {
152 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
153 }
154
155
156 void 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
163 guint 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 */
172 gboolean 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
187 static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
188 {
189 g_tree_destroy((GTree*)value);
190 }
191
192 static 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
200 static void
201 restore_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
253 static 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
262 static void free_usertrace_key(gpointer data)
263 {
264 g_free(data);
265 }
266
267 static void
268 init(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
347 static void
348 fini(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
384 static LttvTracesetContext *
385 new_traceset_context(LttvTracesetContext *self)
386 {
387 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
388 }
389
390
391 static LttvTraceContext *
392 new_trace_context(LttvTracesetContext *self)
393 {
394 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
395 }
396
397
398 static LttvTracefileContext *
399 new_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
407 static 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
438 void 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
488 static 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
524 static 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
539 static 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
616 static 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
702 static 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
761 static 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
789 static void
790 create_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
802 static void
803 get_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
814 static void
815 free_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
826 typedef struct _LttvNameTables {
827 // FIXME GQuark *eventtype_names;
828 GQuark *syscall_names;
829 guint nb_syscalls;
830 GQuark *trap_names;
831 guint nb_traps;
832 GQuark *irq_names;
833 GQuark *soft_irq_names;
834 } LttvNameTables;
835
836
837 static void
838 create_name_tables(LttvTraceState *tcs)
839 {
840 int i, nb;
841
842 GQuark f_name, e_name;
843
844 LttvTraceHook h;
845
846 LttvTraceHookByFacility *thf;
847
848 LttEventType *et;
849
850 LttType *t;
851
852 GString *fe_name = g_string_new("");
853
854 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
855
856 LttvAttributeValue v;
857
858 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
859 LTTV_POINTER, &v);
860 g_assert(*(v.v_pointer) == NULL);
861 *(v.v_pointer) = name_tables;
862 #if 0 // Use iteration over the facilities_by_name and then list all event
863 // types of each facility
864 nb = ltt_trace_eventtype_number(tcs->parent.t);
865 name_tables->eventtype_names = g_new(GQuark, nb);
866 for(i = 0 ; i < nb ; i++) {
867 et = ltt_trace_eventtype_get(tcs->parent.t, i);
868 e_name = ltt_eventtype_name(et);
869 f_name = ltt_facility_name(ltt_eventtype_facility(et));
870 g_string_printf(fe_name, "%s.%s", f_name, e_name);
871 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
872 }
873 #endif //0
874 if(!lttv_trace_find_hook(tcs->parent.t,
875 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
876 LTT_FIELD_SYSCALL_ID, 0, 0,
877 NULL, NULL, &h)) {
878
879 thf = lttv_trace_hook_get_first(&h);
880
881 t = ltt_field_type(thf->f1);
882 nb = ltt_type_element_number(t);
883
884 lttv_trace_hook_destroy(&h);
885
886 name_tables->syscall_names = g_new(GQuark, nb);
887 name_tables->nb_syscalls = nb;
888
889 for(i = 0 ; i < nb ; i++) {
890 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
891 }
892
893 //name_tables->syscall_names = g_new(GQuark, 256);
894 //for(i = 0 ; i < 256 ; i++) {
895 // g_string_printf(fe_name, "syscall %d", i);
896 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
897 //}
898 } else {
899 name_tables->syscall_names = NULL;
900 name_tables->nb_syscalls = 0;
901 }
902
903 if(!lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
904 LTT_EVENT_TRAP_ENTRY,
905 LTT_FIELD_TRAP_ID, 0, 0,
906 NULL, NULL, &h)) {
907
908 thf = lttv_trace_hook_get_first(&h);
909
910 t = ltt_field_type(thf->f1);
911 //nb = ltt_type_element_number(t);
912
913 lttv_trace_hook_destroy(&h);
914
915 /*
916 name_tables->trap_names = g_new(GQuark, nb);
917 for(i = 0 ; i < nb ; i++) {
918 name_tables->trap_names[i] = g_quark_from_string(
919 ltt_enum_string_get(t, i));
920 }
921 */
922 name_tables->nb_traps = 256;
923 name_tables->trap_names = g_new(GQuark, 256);
924 for(i = 0 ; i < 256 ; i++) {
925 g_string_printf(fe_name, "trap %d", i);
926 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
927 }
928 } else {
929 name_tables->trap_names = NULL;
930 name_tables->nb_traps = 0;
931 }
932
933 if(!lttv_trace_find_hook(tcs->parent.t,
934 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
935 LTT_FIELD_IRQ_ID, 0, 0,
936 NULL, NULL, &h)) {
937
938 thf = lttv_trace_hook_get_first(&h);
939
940 t = ltt_field_type(thf->f1);
941 //nb = ltt_type_element_number(t);
942
943 lttv_trace_hook_destroy(&h);
944
945 /*
946 name_tables->irq_names = g_new(GQuark, nb);
947 for(i = 0 ; i < nb ; i++) {
948 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
949 }
950 */
951
952 name_tables->irq_names = g_new(GQuark, 256);
953 for(i = 0 ; i < 256 ; i++) {
954 g_string_printf(fe_name, "irq %d", i);
955 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
956 }
957 } else {
958 name_tables->irq_names = NULL;
959 }
960 /*
961 name_tables->soft_irq_names = g_new(GQuark, nb);
962 for(i = 0 ; i < nb ; i++) {
963 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
964 }
965 */
966
967 name_tables->soft_irq_names = g_new(GQuark, 256);
968 for(i = 0 ; i < 256 ; i++) {
969 g_string_printf(fe_name, "softirq %d", i);
970 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
971 }
972
973
974 g_string_free(fe_name, TRUE);
975 }
976
977
978 static void
979 get_name_tables(LttvTraceState *tcs)
980 {
981 LttvNameTables *name_tables;
982
983 LttvAttributeValue v;
984
985 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
986 LTTV_POINTER, &v);
987 g_assert(*(v.v_pointer) != NULL);
988 name_tables = (LttvNameTables *)*(v.v_pointer);
989 //tcs->eventtype_names = name_tables->eventtype_names;
990 tcs->syscall_names = name_tables->syscall_names;
991 tcs->nb_syscalls = name_tables->nb_syscalls;
992 tcs->trap_names = name_tables->trap_names;
993 tcs->nb_traps = name_tables->nb_traps;
994 tcs->irq_names = name_tables->irq_names;
995 tcs->soft_irq_names = name_tables->soft_irq_names;
996 }
997
998
999 static void
1000 free_name_tables(LttvTraceState *tcs)
1001 {
1002 LttvNameTables *name_tables;
1003
1004 LttvAttributeValue v;
1005
1006 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1007 LTTV_POINTER, &v);
1008 name_tables = (LttvNameTables *)*(v.v_pointer);
1009 *(v.v_pointer) = NULL;
1010
1011 // g_free(name_tables->eventtype_names);
1012 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1013 if(name_tables->trap_names) g_free(name_tables->trap_names);
1014 if(name_tables->irq_names) g_free(name_tables->irq_names);
1015 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1016 if(name_tables) g_free(name_tables);
1017 }
1018
1019 #ifdef HASH_TABLE_DEBUG
1020
1021 static void test_process(gpointer key, gpointer value, gpointer user_data)
1022 {
1023 LttvProcessState *process = (LttvProcessState *)value;
1024
1025 /* Test for process corruption */
1026 guint stack_len = process->execution_stack->len;
1027 }
1028
1029 static void hash_table_check(GHashTable *table)
1030 {
1031 g_hash_table_foreach(table, test_process, NULL);
1032 }
1033
1034
1035 #endif
1036
1037
1038 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1039 guint state_id)
1040 {
1041 LttvExecutionState *es;
1042
1043 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1044 guint cpu = tfs->cpu;
1045
1046 #ifdef HASH_TABLE_DEBUG
1047 hash_table_check(ts->processes);
1048 #endif
1049 LttvProcessState *process = ts->running_process[cpu];
1050
1051 guint depth = process->execution_stack->len;
1052
1053 process->execution_stack =
1054 g_array_set_size(process->execution_stack, depth + 1);
1055 /* Keep in sync */
1056 process->state =
1057 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1058
1059 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1060 es->t = t;
1061 es->n = state_id;
1062 es->entry = es->change = tfs->parent.timestamp;
1063 es->cum_cpu_time = ltt_time_zero;
1064 es->s = process->state->s;
1065 process->state = es;
1066 }
1067
1068 /* pop state
1069 * return 1 when empty, else 0 */
1070 int lttv_state_pop_state_cleanup(LttvProcessState *process,
1071 LttvTracefileState *tfs)
1072 {
1073 guint cpu = tfs->cpu;
1074 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1075
1076 guint depth = process->execution_stack->len;
1077
1078 if(depth == 1){
1079 return 1;
1080 }
1081
1082 process->execution_stack =
1083 g_array_set_size(process->execution_stack, depth - 1);
1084 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1085 depth - 2);
1086 process->state->change = tfs->parent.timestamp;
1087
1088 return 0;
1089 }
1090
1091 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1092 {
1093 guint cpu = tfs->cpu;
1094 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1095 LttvProcessState *process = ts->running_process[cpu];
1096
1097 guint depth = process->execution_stack->len;
1098
1099 if(process->state->t != t){
1100 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1101 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1102 g_info("process state has %s when pop_int is %s\n",
1103 g_quark_to_string(process->state->t),
1104 g_quark_to_string(t));
1105 g_info("{ %u, %u, %s, %s }\n",
1106 process->pid,
1107 process->ppid,
1108 g_quark_to_string(process->name),
1109 g_quark_to_string(process->state->s));
1110 return;
1111 }
1112
1113 if(depth == 1){
1114 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1115 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1116 return;
1117 }
1118
1119 process->execution_stack =
1120 g_array_set_size(process->execution_stack, depth - 1);
1121 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1122 depth - 2);
1123 process->state->change = tfs->parent.timestamp;
1124 }
1125
1126 struct search_result {
1127 const LttTime *time; /* Requested time */
1128 LttTime *best; /* Best result */
1129 };
1130
1131 static gint search_usertrace(gconstpointer a, gconstpointer b)
1132 {
1133 const LttTime *elem_time = (const LttTime*)a;
1134 /* Explicit non const cast */
1135 struct search_result *res = (struct search_result *)b;
1136
1137 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1138 /* The usertrace was created before the schedchange */
1139 /* Get larger keys */
1140 return 1;
1141 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1142 /* The usertrace was created after the schedchange time */
1143 /* Get smaller keys */
1144 if(res->best) {
1145 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1146 res->best = elem_time;
1147 }
1148 } else {
1149 res->best = elem_time;
1150 }
1151 return -1;
1152 }
1153 return 0;
1154 }
1155
1156 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1157 guint pid, const LttTime *timestamp)
1158 {
1159 LttvTracefileState *tfs = NULL;
1160 struct search_result res;
1161 /* Find the usertrace associated with a pid and time interval.
1162 * Search in the usertraces by PID (within a hash) and then, for each
1163 * corresponding element of the array, find the first one with creation
1164 * timestamp the lowest, but higher or equal to "timestamp". */
1165 res.time = timestamp;
1166 res.best = NULL;
1167 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1168 if(usertrace_tree) {
1169 g_tree_search(usertrace_tree, search_usertrace, &res);
1170 if(res.best)
1171 tfs = g_tree_lookup(usertrace_tree, res.best);
1172 }
1173
1174 return tfs;
1175 }
1176
1177
1178 LttvProcessState *
1179 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
1180 guint cpu, guint pid, GQuark name, const LttTime *timestamp)
1181 {
1182 LttvProcessState *process = g_new(LttvProcessState, 1);
1183
1184 LttvExecutionState *es;
1185
1186 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1187
1188 char buffer[128];
1189
1190 process->pid = pid;
1191 process->cpu = cpu;
1192 process->name = name;
1193 //process->last_cpu = tfs->cpu_name;
1194 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1195 process->type = LTTV_STATE_USER_THREAD;
1196 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1197 process->current_function = 0; //function 0x0 by default.
1198
1199 g_info("Process %u, core %p", process->pid, process);
1200 g_hash_table_insert(tcs->processes, process, process);
1201
1202 if(parent) {
1203 process->ppid = parent->pid;
1204 process->creation_time = *timestamp;
1205 }
1206
1207 /* No parent. This process exists but we are missing all information about
1208 its creation. The birth time is set to zero but we remember the time of
1209 insertion */
1210
1211 else {
1212 process->ppid = 0;
1213 process->creation_time = ltt_time_zero;
1214 }
1215
1216 process->insertion_time = *timestamp;
1217 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1218 process->creation_time.tv_nsec);
1219 process->pid_time = g_quark_from_string(buffer);
1220 process->cpu = cpu;
1221 //process->last_cpu = tfs->cpu_name;
1222 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1223 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1224 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1225 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1226 es = process->state = &g_array_index(process->execution_stack,
1227 LttvExecutionState, 0);
1228 es->t = LTTV_STATE_USER_MODE;
1229 es->n = LTTV_STATE_SUBMODE_NONE;
1230 es->entry = *timestamp;
1231 //g_assert(timestamp->tv_sec != 0);
1232 es->change = *timestamp;
1233 es->cum_cpu_time = ltt_time_zero;
1234 es->s = LTTV_STATE_RUN;
1235
1236 es = process->state = &g_array_index(process->execution_stack,
1237 LttvExecutionState, 1);
1238 es->t = LTTV_STATE_SYSCALL;
1239 es->n = LTTV_STATE_SUBMODE_NONE;
1240 es->entry = *timestamp;
1241 //g_assert(timestamp->tv_sec != 0);
1242 es->change = *timestamp;
1243 es->cum_cpu_time = ltt_time_zero;
1244 es->s = LTTV_STATE_WAIT_FORK;
1245
1246 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1247 process->user_stack = g_array_sized_new(FALSE, FALSE,
1248 sizeof(guint64), 0);
1249
1250 return process;
1251 }
1252
1253 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1254 guint pid)
1255 {
1256 LttvProcessState key;
1257 LttvProcessState *process;
1258
1259 key.pid = pid;
1260 key.cpu = cpu;
1261 process = g_hash_table_lookup(ts->processes, &key);
1262 return process;
1263 }
1264
1265 LttvProcessState *
1266 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1267 LttTime *timestamp)
1268 {
1269 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1270 LttvExecutionState *es;
1271
1272 /* Put ltt_time_zero creation time for unexisting processes */
1273 if(unlikely(process == NULL)) {
1274 process = lttv_state_create_process(ts,
1275 NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
1276 /* We are not sure is it's a kernel thread or normal thread, put the
1277 * bottom stack state to unknown */
1278 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1279 es->t = LTTV_STATE_MODE_UNKNOWN;
1280 }
1281 return process;
1282 }
1283
1284 /* FIXME : this function should be called when we receive an event telling that
1285 * release_task has been called in the kernel. In happens generally when
1286 * the parent waits for its child terminaison, but may also happen in special
1287 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1288 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1289 * of a killed thread ground, but isn't the leader.
1290 */
1291 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1292 {
1293 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1294 LttvProcessState key;
1295
1296 key.pid = process->pid;
1297 key.cpu = process->cpu;
1298 g_hash_table_remove(ts->processes, &key);
1299 g_array_free(process->execution_stack, TRUE);
1300 g_array_free(process->user_stack, TRUE);
1301 g_free(process);
1302 }
1303
1304
1305 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1306 {
1307 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1308 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
1309 g_free(value);
1310 }
1311
1312
1313 static void lttv_state_free_process_table(GHashTable *processes)
1314 {
1315 g_hash_table_foreach(processes, free_process_state, NULL);
1316 g_hash_table_destroy(processes);
1317 }
1318
1319
1320 static gboolean syscall_entry(void *hook_data, void *call_data)
1321 {
1322 LttvTracefileState *s = (LttvTracefileState *)call_data;
1323 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1324 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1325 LttField *f = thf->f1;
1326
1327 LttvExecutionSubmode submode;
1328
1329 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1330 guint syscall = ltt_event_get_unsigned(e, f);
1331
1332 if(syscall < nb_syscalls) {
1333 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1334 syscall];
1335 } else {
1336 /* Fixup an incomplete syscall table */
1337 GString *string = g_string_new("");
1338 g_string_printf(string, "syscall %u", syscall);
1339 submode = g_quark_from_string(string->str);
1340 g_string_free(string, TRUE);
1341 }
1342 push_state(s, LTTV_STATE_SYSCALL, submode);
1343 return FALSE;
1344 }
1345
1346
1347 static gboolean syscall_exit(void *hook_data, void *call_data)
1348 {
1349 LttvTracefileState *s = (LttvTracefileState *)call_data;
1350
1351 pop_state(s, LTTV_STATE_SYSCALL);
1352 return FALSE;
1353 }
1354
1355
1356 static gboolean trap_entry(void *hook_data, void *call_data)
1357 {
1358 LttvTracefileState *s = (LttvTracefileState *)call_data;
1359 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1360 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1361 LttField *f = thf->f1;
1362
1363 LttvExecutionSubmode submode;
1364
1365 guint nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
1366 guint trap = ltt_event_get_unsigned(e, f);
1367
1368 if(trap < nb_traps) {
1369 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
1370 } else {
1371 /* Fixup an incomplete trap table */
1372 GString *string = g_string_new("");
1373 g_string_printf(string, "trap %u", trap);
1374 submode = g_quark_from_string(string->str);
1375 g_string_free(string, TRUE);
1376 }
1377
1378 push_state(s, LTTV_STATE_TRAP, submode);
1379 return FALSE;
1380 }
1381
1382
1383 static gboolean trap_exit(void *hook_data, void *call_data)
1384 {
1385 LttvTracefileState *s = (LttvTracefileState *)call_data;
1386
1387 pop_state(s, LTTV_STATE_TRAP);
1388 return FALSE;
1389 }
1390
1391
1392 static gboolean irq_entry(void *hook_data, void *call_data)
1393 {
1394 LttvTracefileState *s = (LttvTracefileState *)call_data;
1395 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1396 guint8 fac_id = ltt_event_facility_id(e);
1397 guint8 ev_id = ltt_event_eventtype_id(e);
1398 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1399 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1400 g_assert(thf->f1 != NULL);
1401 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1402 LttField *f = thf->f1;
1403
1404 LttvExecutionSubmode submode;
1405
1406 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1407 ltt_event_get_unsigned(e, f)];
1408
1409 /* Do something with the info about being in user or system mode when int? */
1410 push_state(s, LTTV_STATE_IRQ, submode);
1411 return FALSE;
1412 }
1413
1414 static gboolean soft_irq_exit(void *hook_data, void *call_data)
1415 {
1416 LttvTracefileState *s = (LttvTracefileState *)call_data;
1417
1418 pop_state(s, LTTV_STATE_SOFT_IRQ);
1419 return FALSE;
1420 }
1421
1422
1423
1424 static gboolean irq_exit(void *hook_data, void *call_data)
1425 {
1426 LttvTracefileState *s = (LttvTracefileState *)call_data;
1427
1428 pop_state(s, LTTV_STATE_IRQ);
1429 return FALSE;
1430 }
1431
1432 static gboolean soft_irq_entry(void *hook_data, void *call_data)
1433 {
1434 LttvTracefileState *s = (LttvTracefileState *)call_data;
1435 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1436 guint8 fac_id = ltt_event_facility_id(e);
1437 guint8 ev_id = ltt_event_eventtype_id(e);
1438 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1439 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1440 g_assert(thf->f1 != NULL);
1441 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1442 LttField *f = thf->f1;
1443
1444 LttvExecutionSubmode submode;
1445
1446 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1447 ltt_event_get_unsigned(e, f)];
1448
1449 /* Do something with the info about being in user or system mode when int? */
1450 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1451 return FALSE;
1452 }
1453
1454 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
1455 {
1456 guint64 *new_func;
1457
1458 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1459 guint cpu = tfs->cpu;
1460 LttvProcessState *process = ts->running_process[cpu];
1461
1462 guint depth = process->user_stack->len;
1463
1464 process->user_stack =
1465 g_array_set_size(process->user_stack, depth + 1);
1466
1467 new_func = &g_array_index(process->user_stack, guint64, depth);
1468 *new_func = funcptr;
1469 process->current_function = funcptr;
1470 }
1471
1472 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
1473 {
1474 guint cpu = tfs->cpu;
1475 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1476 LttvProcessState *process = ts->running_process[cpu];
1477
1478 if(process->current_function != funcptr){
1479 g_info("Different functions (%lu.%09lu): ignore it\n",
1480 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1481 g_info("process state has %llu when pop_function is %llu\n",
1482 process->current_function, funcptr);
1483 g_info("{ %u, %u, %s, %s }\n",
1484 process->pid,
1485 process->ppid,
1486 g_quark_to_string(process->name),
1487 g_quark_to_string(process->state->s));
1488 return;
1489 }
1490 guint depth = process->user_stack->len;
1491
1492 if(depth == 0){
1493 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1494 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1495 return;
1496 }
1497
1498 process->user_stack =
1499 g_array_set_size(process->user_stack, depth - 1);
1500 process->current_function =
1501 g_array_index(process->user_stack, guint64, depth - 2);
1502 }
1503
1504
1505 static gboolean function_entry(void *hook_data, void *call_data)
1506 {
1507 LttvTracefileState *s = (LttvTracefileState *)call_data;
1508 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1509 guint8 fac_id = ltt_event_facility_id(e);
1510 guint8 ev_id = ltt_event_eventtype_id(e);
1511 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1512 g_assert(thf->f1 != NULL);
1513 LttField *f = thf->f1;
1514 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1515
1516 push_function(s, funcptr);
1517 return FALSE;
1518 }
1519
1520 static gboolean function_exit(void *hook_data, void *call_data)
1521 {
1522 LttvTracefileState *s = (LttvTracefileState *)call_data;
1523 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1524 guint8 fac_id = ltt_event_facility_id(e);
1525 guint8 ev_id = ltt_event_eventtype_id(e);
1526 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1527 g_assert(thf->f1 != NULL);
1528 LttField *f = thf->f1;
1529 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1530
1531 LttvExecutionSubmode submode;
1532
1533 pop_function(s, funcptr);
1534 return FALSE;
1535 }
1536
1537 static gboolean schedchange(void *hook_data, void *call_data)
1538 {
1539 LttvTracefileState *s = (LttvTracefileState *)call_data;
1540 guint cpu = s->cpu;
1541 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1542 LttvProcessState *process = ts->running_process[cpu];
1543 LttvProcessState *old_process = ts->running_process[cpu];
1544
1545 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1546 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1547 guint pid_in, pid_out;
1548 gint state_out;
1549
1550 pid_out = ltt_event_get_unsigned(e, thf->f1);
1551 pid_in = ltt_event_get_unsigned(e, thf->f2);
1552 state_out = ltt_event_get_int(e, thf->f3);
1553
1554 if(likely(process != NULL)) {
1555
1556 /* We could not know but it was not the idle process executing.
1557 This should only happen at the beginning, before the first schedule
1558 event, and when the initial information (current process for each CPU)
1559 is missing. It is not obvious how we could, after the fact, compensate
1560 the wrongly attributed statistics. */
1561
1562 //This test only makes sense once the state is known and if there is no
1563 //missing events. We need to silently ignore schedchange coming after a
1564 //process_free, or it causes glitches. (FIXME)
1565 //if(unlikely(process->pid != pid_out)) {
1566 // g_assert(process->pid == 0);
1567 //}
1568
1569 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1570 process->state->s = LTTV_STATE_ZOMBIE;
1571 process->state->change = s->parent.timestamp;
1572 } else {
1573 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1574 else process->state->s = LTTV_STATE_WAIT;
1575 process->state->change = s->parent.timestamp;
1576 }
1577
1578 if(state_out == 32)
1579 exit_process(s, process); /* EXIT_DEAD */
1580 /* see sched.h for states */
1581 }
1582 process = ts->running_process[cpu] =
1583 lttv_state_find_process_or_create(
1584 (LttvTraceState*)s->parent.t_context,
1585 cpu, pid_in,
1586 &s->parent.timestamp);
1587 process->state->s = LTTV_STATE_RUN;
1588 process->cpu = cpu;
1589 if(process->usertrace)
1590 process->usertrace->cpu = cpu;
1591 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1592 process->state->change = s->parent.timestamp;
1593 return FALSE;
1594 }
1595
1596 static gboolean process_fork(void *hook_data, void *call_data)
1597 {
1598 LttvTracefileState *s = (LttvTracefileState *)call_data;
1599 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1600 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1601 guint parent_pid;
1602 guint child_pid;
1603 LttvProcessState *zombie_process;
1604 guint cpu = s->cpu;
1605 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1606 LttvProcessState *process = ts->running_process[cpu];
1607 LttvProcessState *child_process;
1608
1609 /* Parent PID */
1610 parent_pid = ltt_event_get_unsigned(e, thf->f1);
1611
1612 /* Child PID */
1613 child_pid = ltt_event_get_unsigned(e, thf->f2);
1614
1615 /* Mathieu : it seems like the process might have been scheduled in before the
1616 * fork, and, in a rare case, might be the current process. This might happen
1617 * in a SMP case where we don't have enough precision on the clocks.
1618 *
1619 * Test reenabled after precision fixes on time. (Mathieu) */
1620 #if 0
1621 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1622
1623 if(unlikely(zombie_process != NULL)) {
1624 /* Reutilisation of PID. Only now we are sure that the old PID
1625 * has been released. FIXME : should know when release_task happens instead.
1626 */
1627 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1628 guint i;
1629 for(i=0; i< num_cpus; i++) {
1630 g_assert(zombie_process != ts->running_process[i]);
1631 }
1632
1633 exit_process(s, zombie_process);
1634 }
1635 #endif //0
1636 g_assert(process->pid != child_pid);
1637 // FIXME : Add this test in the "known state" section
1638 // g_assert(process->pid == parent_pid);
1639 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1640 if(child_process == NULL) {
1641 child_process = lttv_state_create_process(ts, process, cpu,
1642 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
1643 } else {
1644 /* The process has already been created : due to time imprecision between
1645 * multiple CPUs : it has been scheduled in before creation. Note that we
1646 * shouldn't have this kind of imprecision.
1647 *
1648 * Simply put a correct parent.
1649 */
1650 g_assert(0); /* This is a problematic case : the process has been created
1651 before the fork event */
1652 child_process->ppid = process->pid;
1653 }
1654 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1655 child_process->name = process->name;
1656
1657 return FALSE;
1658 }
1659
1660 /* We stamp a newly created process as kernel_thread */
1661 static gboolean process_kernel_thread(void *hook_data, void *call_data)
1662 {
1663 LttvTracefileState *s = (LttvTracefileState *)call_data;
1664 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1665 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1666 guint pid;
1667 guint cpu = s->cpu;
1668 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1669 LttvProcessState *process;
1670 LttvExecutionState *es;
1671
1672 /* PID */
1673 pid = ltt_event_get_unsigned(e, thf->f1);
1674
1675 process = lttv_state_find_process(ts, ANY_CPU, pid);
1676 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1677 es->t = LTTV_STATE_SYSCALL;
1678 process->type = LTTV_STATE_KERNEL_THREAD;
1679
1680 return FALSE;
1681 }
1682
1683 static gboolean process_exit(void *hook_data, void *call_data)
1684 {
1685 LttvTracefileState *s = (LttvTracefileState *)call_data;
1686 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1687 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1688 LttField *f;
1689 guint pid;
1690 guint cpu = s->cpu;
1691 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1692 LttvProcessState *process = ts->running_process[cpu];
1693
1694 pid = ltt_event_get_unsigned(e, thf->f1);
1695
1696 // FIXME : Add this test in the "known state" section
1697 // g_assert(process->pid == pid);
1698
1699 if(likely(process != NULL)) {
1700 process->state->s = LTTV_STATE_EXIT;
1701 }
1702 return FALSE;
1703 }
1704
1705 static gboolean process_free(void *hook_data, void *call_data)
1706 {
1707 LttvTracefileState *s = (LttvTracefileState *)call_data;
1708 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1709 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1710 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1711 guint release_pid;
1712 LttvProcessState *process;
1713
1714 /* PID of the process to release */
1715 release_pid = ltt_event_get_unsigned(e, thf->f1);
1716
1717 g_assert(release_pid != 0);
1718
1719 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1720
1721 if(likely(process != NULL)) {
1722 /* release_task is happening at kernel level : we can now safely release
1723 * the data structure of the process */
1724 //This test is fun, though, as it may happen that
1725 //at time t : CPU 0 : process_free
1726 //at time t+150ns : CPU 1 : schedule out
1727 //Clearly due to time imprecision, we disable it. (Mathieu)
1728 //If this weird case happen, we have no choice but to put the
1729 //Currently running process on the cpu to 0.
1730 //I re-enable it following time precision fixes. (Mathieu)
1731 //Well, in the case where an process is freed by a process on another CPU
1732 //and still scheduled, it happens that this is the schedchange that will
1733 //drop the last reference count. Do not free it here!
1734 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1735 guint i;
1736 for(i=0; i< num_cpus; i++) {
1737 //g_assert(process != ts->running_process[i]);
1738 if(process == ts->running_process[i]) {
1739 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1740 break;
1741 }
1742 }
1743 //if(i == num_cpus) /* process is not scheduled */
1744 //exit_process(s, process); // do nothing : wait for the schedchange to
1745 //delete the process.
1746 }
1747
1748 return FALSE;
1749 }
1750
1751
1752 static gboolean process_exec(void *hook_data, void *call_data)
1753 {
1754 LttvTracefileState *s = (LttvTracefileState *)call_data;
1755 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1756 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1757 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1758 //gchar *name;
1759 guint cpu = s->cpu;
1760 LttvProcessState *process = ts->running_process[cpu];
1761
1762 /* PID of the process to release */
1763 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1764 //name = ltt_event_get_string(e, thf->f1);
1765 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1766 gchar *name_begin =
1767 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1768 gchar *null_term_name = g_new(gchar, name_len+1);
1769 memcpy(null_term_name, name_begin, name_len);
1770 null_term_name[name_len] = '\0';
1771
1772 process->name = g_quark_from_string(null_term_name);
1773 g_free(null_term_name);
1774 return FALSE;
1775 }
1776
1777 static gboolean enum_process_state(void *hook_data, void *call_data)
1778 {
1779 LttvTracefileState *s = (LttvTracefileState *)call_data;
1780 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1781 //It's slow : optimise later by doing this before reading trace.
1782 LttEventType *et = ltt_event_eventtype(e);
1783 //
1784 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1785 guint parent_pid;
1786 guint pid;
1787 gchar * command;
1788 guint cpu = s->cpu;
1789 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1790 LttvProcessState *process = ts->running_process[cpu];
1791 LttvProcessState *parent_process;
1792 LttField *f4, *f5, *f6, *f7;
1793 GQuark type, mode, submode, status;
1794 LttvExecutionState *es;
1795
1796 /* PID */
1797 pid = ltt_event_get_unsigned(e, thf->f1);
1798
1799 /* Parent PID */
1800 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1801
1802 /* Command name */
1803 command = ltt_event_get_string(e, thf->f3);
1804
1805 /* type */
1806 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
1807 type = ltt_enum_string_get(ltt_field_type(f4),
1808 ltt_event_get_unsigned(e, f4));
1809
1810 /* mode */
1811 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1812 mode = ltt_enum_string_get(ltt_field_type(f5),
1813 ltt_event_get_unsigned(e, f5));
1814
1815 /* submode */
1816 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1817 submode = ltt_enum_string_get(ltt_field_type(f6),
1818 ltt_event_get_unsigned(e, f6));
1819
1820 /* status */
1821 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1822 status = ltt_enum_string_get(ltt_field_type(f7),
1823 ltt_event_get_unsigned(e, f7));
1824
1825 /* The process might exist if a process was forked while performing the sate dump. */
1826 process = lttv_state_find_process(ts, ANY_CPU, pid);
1827 if(process == NULL) {
1828 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1829 process = lttv_state_create_process(ts, parent_process, cpu,
1830 pid, g_quark_from_string(command),
1831 &s->parent.timestamp);
1832
1833 /* Keep the stack bottom : a running user mode */
1834 /* Disabled because of inconsistencies in the current statedump states. */
1835 if(type == LTTV_STATE_KERNEL_THREAD) {
1836 /* Only keep the bottom */
1837 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1838 es = process->state = &g_array_index(process->execution_stack,
1839 LttvExecutionState, 0);
1840 es->t = LTTV_STATE_SYSCALL;
1841 es->s = status;
1842 es->n = submode;
1843 } else {
1844 /* On top of it : */
1845 es = process->state = &g_array_index(process->execution_stack,
1846 LttvExecutionState, 1);
1847 es->t = LTTV_STATE_USER_MODE;
1848 es->s = status;
1849 es->n = submode;
1850 }
1851 #if 0
1852 /* UNKNOWN STATE */
1853 {
1854 es = process->state = &g_array_index(process->execution_stack,
1855 LttvExecutionState, 1);
1856 es->t = LTTV_STATE_MODE_UNKNOWN;
1857 es->s = LTTV_STATE_UNNAMED;
1858 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1859 }
1860 #endif //0
1861 } else {
1862 /* The process has already been created :
1863 * Probably was forked while dumping the process state or
1864 * was simply scheduled in prior to get the state dump event.
1865 * We know for sure if it is a user space thread.
1866 */
1867 process->ppid = parent_pid;
1868 process->name = g_quark_from_string(command);
1869 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1870 if(type != LTTV_STATE_KERNEL_THREAD)
1871 es->t = LTTV_STATE_USER_MODE;
1872 /* Don't mess around with the stack, it will eventually become
1873 * ok after the end of state dump. */
1874 }
1875
1876 return FALSE;
1877 }
1878
1879 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1880 {
1881 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1882
1883 lttv_state_add_event_hooks(tss);
1884
1885 return 0;
1886 }
1887
1888 void lttv_state_add_event_hooks(LttvTracesetState *self)
1889 {
1890 LttvTraceset *traceset = self->parent.ts;
1891
1892 guint i, j, k, l, nb_trace, nb_tracefile;
1893
1894 LttvTraceState *ts;
1895
1896 LttvTracefileState *tfs;
1897
1898 GArray *hooks;
1899
1900 LttvTraceHookByFacility *thf;
1901
1902 LttvTraceHook *hook;
1903
1904 LttvAttributeValue val;
1905
1906 gint ret;
1907 gint hn;
1908
1909 nb_trace = lttv_traceset_number(traceset);
1910 for(i = 0 ; i < nb_trace ; i++) {
1911 ts = (LttvTraceState *)self->parent.traces[i];
1912
1913 /* Find the eventtype id for the following events and register the
1914 associated by id hooks. */
1915
1916 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
1917 hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
1918 hn = 0;
1919
1920 ret = lttv_trace_find_hook(ts->parent.t,
1921 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1922 LTT_FIELD_SYSCALL_ID, 0, 0,
1923 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1924 if(ret) hn--;
1925
1926 ret = lttv_trace_find_hook(ts->parent.t,
1927 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1928 0, 0, 0,
1929 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1930 if(ret) hn--;
1931
1932 ret = lttv_trace_find_hook(ts->parent.t,
1933 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1934 LTT_FIELD_TRAP_ID, 0, 0,
1935 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1936 if(ret) hn--;
1937
1938 ret = lttv_trace_find_hook(ts->parent.t,
1939 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1940 0, 0, 0,
1941 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1942 if(ret) hn--;
1943
1944 ret = lttv_trace_find_hook(ts->parent.t,
1945 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1946 LTT_FIELD_IRQ_ID, 0, 0,
1947 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1948 if(ret) hn--;
1949
1950 ret = lttv_trace_find_hook(ts->parent.t,
1951 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1952 0, 0, 0,
1953 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1954 if(ret) hn--;
1955
1956 ret = lttv_trace_find_hook(ts->parent.t,
1957 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1958 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1959 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1960 if(ret) hn--;
1961
1962 ret = lttv_trace_find_hook(ts->parent.t,
1963 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1964 0, 0, 0,
1965 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1966 if(ret) hn--;
1967
1968 ret = lttv_trace_find_hook(ts->parent.t,
1969 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1970 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1971 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1972 if(ret) hn--;
1973
1974 ret = lttv_trace_find_hook(ts->parent.t,
1975 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1976 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1977 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1978 if(ret) hn--;
1979
1980 ret = lttv_trace_find_hook(ts->parent.t,
1981 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1982 LTT_FIELD_PID, 0, 0,
1983 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
1984 hn++));
1985 if(ret) hn--;
1986
1987 ret = lttv_trace_find_hook(ts->parent.t,
1988 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1989 LTT_FIELD_PID, 0, 0,
1990 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1991 if(ret) hn--;
1992
1993 ret = lttv_trace_find_hook(ts->parent.t,
1994 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1995 LTT_FIELD_PID, 0, 0,
1996 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1997 if(ret) hn--;
1998
1999 ret = lttv_trace_find_hook(ts->parent.t,
2000 LTT_FACILITY_FS, LTT_EVENT_EXEC,
2001 LTT_FIELD_FILENAME, 0, 0,
2002 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2003 if(ret) hn--;
2004
2005 /* statedump-related hooks */
2006 ret = lttv_trace_find_hook(ts->parent.t,
2007 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
2008 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
2009 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2010 if(ret) hn--;
2011
2012 ret = lttv_trace_find_hook(ts->parent.t,
2013 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2014 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2015 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2016 if(ret) hn--;
2017
2018 ret = lttv_trace_find_hook(ts->parent.t,
2019 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2020 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2021 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2022 if(ret) hn--;
2023
2024 hooks = g_array_set_size(hooks, hn);
2025
2026 /* Add these hooks to each event_by_id hooks list */
2027
2028 nb_tracefile = ts->parent.tracefiles->len;
2029
2030 for(j = 0 ; j < nb_tracefile ; j++) {
2031 tfs =
2032 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2033 LttvTracefileContext*, j));
2034
2035 for(k = 0 ; k < hooks->len ; k++) {
2036 hook = &g_array_index(hooks, LttvTraceHook, k);
2037 for(l=0;l<hook->fac_list->len;l++) {
2038 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2039 lttv_hooks_add(
2040 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2041 thf->h,
2042 thf,
2043 LTTV_PRIO_STATE);
2044 }
2045 }
2046 }
2047 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2048 *(val.v_pointer) = hooks;
2049 }
2050 }
2051
2052 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2053 {
2054 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2055
2056 lttv_state_remove_event_hooks(tss);
2057
2058 return 0;
2059 }
2060
2061 void lttv_state_remove_event_hooks(LttvTracesetState *self)
2062 {
2063 LttvTraceset *traceset = self->parent.ts;
2064
2065 guint i, j, k, l, nb_trace, nb_tracefile;
2066
2067 LttvTraceState *ts;
2068
2069 LttvTracefileState *tfs;
2070
2071 GArray *hooks;
2072
2073 LttvTraceHook *hook;
2074
2075 LttvTraceHookByFacility *thf;
2076
2077 LttvAttributeValue val;
2078
2079 nb_trace = lttv_traceset_number(traceset);
2080 for(i = 0 ; i < nb_trace ; i++) {
2081 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2082 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2083 hooks = *(val.v_pointer);
2084
2085 /* Remove these hooks from each event_by_id hooks list */
2086
2087 nb_tracefile = ts->parent.tracefiles->len;
2088
2089 for(j = 0 ; j < nb_tracefile ; j++) {
2090 tfs =
2091 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2092 LttvTracefileContext*, j));
2093
2094 for(k = 0 ; k < hooks->len ; k++) {
2095 hook = &g_array_index(hooks, LttvTraceHook, k);
2096 for(l=0;l<hook->fac_list->len;l++) {
2097 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2098
2099 lttv_hooks_remove_data(
2100 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2101 thf->h,
2102 thf);
2103 }
2104 }
2105 }
2106 for(k = 0 ; k < hooks->len ; k++)
2107 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2108 g_array_free(hooks, TRUE);
2109 }
2110 }
2111
2112 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2113 {
2114 guint *event_count = (guint*)hook_data;
2115
2116 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2117 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2118 return FALSE;
2119 else
2120 *event_count = 0;
2121
2122 LttvTracefileState *self = (LttvTracefileState *)call_data;
2123
2124 LttvTracefileState *tfcs;
2125
2126 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2127
2128 LttEventPosition *ep;
2129
2130 guint i;
2131
2132 LttTracefile *tf;
2133
2134 LttvAttribute *saved_states_tree, *saved_state_tree;
2135
2136 LttvAttributeValue value;
2137
2138 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2139 LTTV_STATE_SAVED_STATES);
2140 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2141 value = lttv_attribute_add(saved_states_tree,
2142 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2143 *(value.v_gobject) = (GObject *)saved_state_tree;
2144 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2145 *(value.v_time) = self->parent.timestamp;
2146 lttv_state_save(tcs, saved_state_tree);
2147 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2148 self->parent.timestamp.tv_nsec);
2149
2150 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2151
2152 return FALSE;
2153 }
2154
2155 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2156 {
2157 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2158
2159 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2160
2161 return FALSE;
2162 }
2163
2164 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2165 {
2166 return tfs->cpu;
2167 }
2168
2169
2170
2171 #if 0
2172 static gboolean block_start(void *hook_data, void *call_data)
2173 {
2174 LttvTracefileState *self = (LttvTracefileState *)call_data;
2175
2176 LttvTracefileState *tfcs;
2177
2178 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2179
2180 LttEventPosition *ep;
2181
2182 guint i, nb_block, nb_event, nb_tracefile;
2183
2184 LttTracefile *tf;
2185
2186 LttvAttribute *saved_states_tree, *saved_state_tree;
2187
2188 LttvAttributeValue value;
2189
2190 ep = ltt_event_position_new();
2191
2192 nb_tracefile = tcs->parent.tracefiles->len;
2193
2194 /* Count the number of events added since the last block end in any
2195 tracefile. */
2196
2197 for(i = 0 ; i < nb_tracefile ; i++) {
2198 tfcs =
2199 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2200 LttvTracefileContext, i));
2201 ltt_event_position(tfcs->parent.e, ep);
2202 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2203 tcs->nb_event += nb_event - tfcs->saved_position;
2204 tfcs->saved_position = nb_event;
2205 }
2206 g_free(ep);
2207
2208 if(tcs->nb_event >= tcs->save_interval) {
2209 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2210 LTTV_STATE_SAVED_STATES);
2211 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2212 value = lttv_attribute_add(saved_states_tree,
2213 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2214 *(value.v_gobject) = (GObject *)saved_state_tree;
2215 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2216 *(value.v_time) = self->parent.timestamp;
2217 lttv_state_save(tcs, saved_state_tree);
2218 tcs->nb_event = 0;
2219 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2220 self->parent.timestamp.tv_nsec);
2221 }
2222 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2223 return FALSE;
2224 }
2225 #endif //0
2226
2227 #if 0
2228 static gboolean block_end(void *hook_data, void *call_data)
2229 {
2230 LttvTracefileState *self = (LttvTracefileState *)call_data;
2231
2232 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2233
2234 LttTracefile *tf;
2235
2236 LttEventPosition *ep;
2237
2238 guint nb_block, nb_event;
2239
2240 ep = ltt_event_position_new();
2241 ltt_event_position(self->parent.e, ep);
2242 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2243 tcs->nb_event += nb_event - self->saved_position + 1;
2244 self->saved_position = 0;
2245 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2246 g_free(ep);
2247
2248 return FALSE;
2249 }
2250 #endif //0
2251 #if 0
2252 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2253 {
2254 LttvTraceset *traceset = self->parent.ts;
2255
2256 guint i, j, nb_trace, nb_tracefile;
2257
2258 LttvTraceState *ts;
2259
2260 LttvTracefileState *tfs;
2261
2262 LttvTraceHook hook_start, hook_end;
2263
2264 nb_trace = lttv_traceset_number(traceset);
2265 for(i = 0 ; i < nb_trace ; i++) {
2266 ts = (LttvTraceState *)self->parent.traces[i];
2267
2268 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2269 NULL, NULL, block_start, &hook_start);
2270 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2271 NULL, NULL, block_end, &hook_end);
2272
2273 nb_tracefile = ts->parent.tracefiles->len;
2274
2275 for(j = 0 ; j < nb_tracefile ; j++) {
2276 tfs =
2277 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2278 LttvTracefileContext, j));
2279 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2280 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2281 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2282 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2283 }
2284 }
2285 }
2286 #endif //0
2287
2288 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2289 {
2290 LttvTraceset *traceset = self->parent.ts;
2291
2292 guint i, j, nb_trace, nb_tracefile;
2293
2294 LttvTraceState *ts;
2295
2296 LttvTracefileState *tfs;
2297
2298
2299 nb_trace = lttv_traceset_number(traceset);
2300 for(i = 0 ; i < nb_trace ; i++) {
2301
2302 ts = (LttvTraceState *)self->parent.traces[i];
2303 nb_tracefile = ts->parent.tracefiles->len;
2304
2305 guint *event_count = g_new(guint, 1);
2306 *event_count = 0;
2307
2308 for(j = 0 ; j < nb_tracefile ; j++) {
2309 tfs =
2310 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2311 LttvTracefileContext*, j));
2312 lttv_hooks_add(tfs->parent.event,
2313 state_save_event_hook,
2314 event_count,
2315 LTTV_PRIO_STATE);
2316
2317 }
2318 }
2319
2320 lttv_process_traceset_begin(&self->parent,
2321 NULL, NULL, NULL, NULL, NULL);
2322
2323 }
2324
2325 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2326 {
2327 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2328
2329 lttv_state_save_add_event_hooks(tss);
2330
2331 return 0;
2332 }
2333
2334
2335 #if 0
2336 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2337 {
2338 LttvTraceset *traceset = self->parent.ts;
2339
2340 guint i, j, nb_trace, nb_tracefile;
2341
2342 LttvTraceState *ts;
2343
2344 LttvTracefileState *tfs;
2345
2346 LttvTraceHook hook_start, hook_end;
2347
2348 nb_trace = lttv_traceset_number(traceset);
2349 for(i = 0 ; i < nb_trace ; i++) {
2350 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2351
2352 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2353 NULL, NULL, block_start, &hook_start);
2354
2355 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2356 NULL, NULL, block_end, &hook_end);
2357
2358 nb_tracefile = ts->parent.tracefiles->len;
2359
2360 for(j = 0 ; j < nb_tracefile ; j++) {
2361 tfs =
2362 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2363 LttvTracefileContext, j));
2364 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2365 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2366 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2367 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2368 }
2369 }
2370 }
2371 #endif //0
2372
2373 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2374 {
2375 LttvTraceset *traceset = self->parent.ts;
2376
2377 guint i, j, nb_trace, nb_tracefile;
2378
2379 LttvTraceState *ts;
2380
2381 LttvTracefileState *tfs;
2382
2383 LttvHooks *after_trace = lttv_hooks_new();
2384
2385 lttv_hooks_add(after_trace,
2386 state_save_after_trace_hook,
2387 NULL,
2388 LTTV_PRIO_STATE);
2389
2390
2391 lttv_process_traceset_end(&self->parent,
2392 NULL, after_trace, NULL, NULL, NULL);
2393
2394 lttv_hooks_destroy(after_trace);
2395
2396 nb_trace = lttv_traceset_number(traceset);
2397 for(i = 0 ; i < nb_trace ; i++) {
2398
2399 ts = (LttvTraceState *)self->parent.traces[i];
2400 nb_tracefile = ts->parent.tracefiles->len;
2401
2402 guint *event_count = NULL;
2403
2404 for(j = 0 ; j < nb_tracefile ; j++) {
2405 tfs =
2406 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2407 LttvTracefileContext*, j));
2408 event_count = lttv_hooks_remove(tfs->parent.event,
2409 state_save_event_hook);
2410 }
2411 if(event_count) g_free(event_count);
2412 }
2413 }
2414
2415 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2416 {
2417 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2418
2419 lttv_state_save_remove_event_hooks(tss);
2420
2421 return 0;
2422 }
2423
2424 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2425 {
2426 LttvTraceset *traceset = self->parent.ts;
2427
2428 guint i, nb_trace;
2429
2430 int min_pos, mid_pos, max_pos;
2431
2432 guint call_rest = 0;
2433
2434 LttvTraceState *tcs;
2435
2436 LttvAttributeValue value;
2437
2438 LttvAttributeType type;
2439
2440 LttvAttributeName name;
2441
2442 gboolean is_named;
2443
2444 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2445
2446 //g_tree_destroy(self->parent.pqueue);
2447 //self->parent.pqueue = g_tree_new(compare_tracefile);
2448
2449 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2450
2451 nb_trace = lttv_traceset_number(traceset);
2452 for(i = 0 ; i < nb_trace ; i++) {
2453 tcs = (LttvTraceState *)self->parent.traces[i];
2454
2455 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2456 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2457 LTTV_STATE_SAVED_STATES);
2458 min_pos = -1;
2459
2460 if(saved_states_tree) {
2461 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2462 mid_pos = max_pos / 2;
2463 while(min_pos < max_pos) {
2464 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
2465 &is_named);
2466 g_assert(type == LTTV_GOBJECT);
2467 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2468 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2469 &value);
2470 g_assert(type == LTTV_TIME);
2471 if(ltt_time_compare(*(value.v_time), t) < 0) {
2472 min_pos = mid_pos;
2473 closest_tree = saved_state_tree;
2474 }
2475 else max_pos = mid_pos - 1;
2476
2477 mid_pos = (min_pos + max_pos + 1) / 2;
2478 }
2479 }
2480
2481 /* restore the closest earlier saved state */
2482 if(min_pos != -1) {
2483 lttv_state_restore(tcs, closest_tree);
2484 call_rest = 1;
2485 }
2486
2487 /* There is no saved state, yet we want to have it. Restart at T0 */
2488 else {
2489 restore_init_state(tcs);
2490 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2491 }
2492 }
2493 /* We want to seek quickly without restoring/updating the state */
2494 else {
2495 restore_init_state(tcs);
2496 lttv_process_trace_seek_time(&(tcs->parent), t);
2497 }
2498 }
2499 if(!call_rest) g_info("NOT Calling restore");
2500 }
2501
2502
2503 static void
2504 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2505 {
2506 }
2507
2508
2509 static void
2510 traceset_state_finalize (LttvTracesetState *self)
2511 {
2512 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2513 finalize(G_OBJECT(self));
2514 }
2515
2516
2517 static void
2518 traceset_state_class_init (LttvTracesetContextClass *klass)
2519 {
2520 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2521
2522 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2523 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2524 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2525 klass->new_traceset_context = new_traceset_context;
2526 klass->new_trace_context = new_trace_context;
2527 klass->new_tracefile_context = new_tracefile_context;
2528 }
2529
2530
2531 GType
2532 lttv_traceset_state_get_type(void)
2533 {
2534 static GType type = 0;
2535 if (type == 0) {
2536 static const GTypeInfo info = {
2537 sizeof (LttvTracesetStateClass),
2538 NULL, /* base_init */
2539 NULL, /* base_finalize */
2540 (GClassInitFunc) traceset_state_class_init, /* class_init */
2541 NULL, /* class_finalize */
2542 NULL, /* class_data */
2543 sizeof (LttvTracesetState),
2544 0, /* n_preallocs */
2545 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2546 NULL /* value handling */
2547 };
2548
2549 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2550 &info, 0);
2551 }
2552 return type;
2553 }
2554
2555
2556 static void
2557 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2558 {
2559 }
2560
2561
2562 static void
2563 trace_state_finalize (LttvTraceState *self)
2564 {
2565 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2566 finalize(G_OBJECT(self));
2567 }
2568
2569
2570 static void
2571 trace_state_class_init (LttvTraceStateClass *klass)
2572 {
2573 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2574
2575 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2576 klass->state_save = state_save;
2577 klass->state_restore = state_restore;
2578 klass->state_saved_free = state_saved_free;
2579 }
2580
2581
2582 GType
2583 lttv_trace_state_get_type(void)
2584 {
2585 static GType type = 0;
2586 if (type == 0) {
2587 static const GTypeInfo info = {
2588 sizeof (LttvTraceStateClass),
2589 NULL, /* base_init */
2590 NULL, /* base_finalize */
2591 (GClassInitFunc) trace_state_class_init, /* class_init */
2592 NULL, /* class_finalize */
2593 NULL, /* class_data */
2594 sizeof (LttvTraceState),
2595 0, /* n_preallocs */
2596 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2597 NULL /* value handling */
2598 };
2599
2600 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2601 "LttvTraceStateType", &info, 0);
2602 }
2603 return type;
2604 }
2605
2606
2607 static void
2608 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2609 {
2610 }
2611
2612
2613 static void
2614 tracefile_state_finalize (LttvTracefileState *self)
2615 {
2616 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2617 finalize(G_OBJECT(self));
2618 }
2619
2620
2621 static void
2622 tracefile_state_class_init (LttvTracefileStateClass *klass)
2623 {
2624 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2625
2626 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2627 }
2628
2629
2630 GType
2631 lttv_tracefile_state_get_type(void)
2632 {
2633 static GType type = 0;
2634 if (type == 0) {
2635 static const GTypeInfo info = {
2636 sizeof (LttvTracefileStateClass),
2637 NULL, /* base_init */
2638 NULL, /* base_finalize */
2639 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2640 NULL, /* class_finalize */
2641 NULL, /* class_data */
2642 sizeof (LttvTracefileState),
2643 0, /* n_preallocs */
2644 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2645 NULL /* value handling */
2646 };
2647
2648 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2649 "LttvTracefileStateType", &info, 0);
2650 }
2651 return type;
2652 }
2653
2654
2655 static void module_init()
2656 {
2657 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
2658 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2659 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2660 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2661 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2662 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2663 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2664 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2665 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2666 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2667 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2668 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2669 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2670 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2671 LTTV_STATE_RUN = g_quark_from_string("RUN");
2672 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2673 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
2674 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
2675 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2676 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2677 LTTV_STATE_PROCESS = g_quark_from_string("process");
2678 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2679 LTTV_STATE_EVENT = g_quark_from_string("event");
2680 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2681 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2682 LTTV_STATE_TIME = g_quark_from_string("time");
2683 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2684 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2685 LTTV_STATE_TRACE_STATE_USE_COUNT =
2686 g_quark_from_string("trace_state_use_count");
2687
2688
2689 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2690 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2691 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2692 LTT_FACILITY_FS = g_quark_from_string("fs");
2693 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2694 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
2695
2696
2697 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2698 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2699 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2700 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2701 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2702 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2703 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2704 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2705 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2706 LTT_EVENT_FORK = g_quark_from_string("fork");
2707 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
2708 LTT_EVENT_EXIT = g_quark_from_string("exit");
2709 LTT_EVENT_FREE = g_quark_from_string("free");
2710 LTT_EVENT_EXEC = g_quark_from_string("exec");
2711 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2712 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2713 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
2714
2715
2716 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2717 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2718 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2719 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2720 LTT_FIELD_OUT = g_quark_from_string("out");
2721 LTT_FIELD_IN = g_quark_from_string("in");
2722 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2723 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2724 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2725 LTT_FIELD_PID = g_quark_from_string("pid");
2726 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2727 LTT_FIELD_NAME = g_quark_from_string("name");
2728 LTT_FIELD_TYPE = g_quark_from_string("type");
2729 LTT_FIELD_MODE = g_quark_from_string("mode");
2730 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2731 LTT_FIELD_STATUS = g_quark_from_string("status");
2732 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2733 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
2734
2735 }
2736
2737 static void module_destroy()
2738 {
2739 }
2740
2741
2742 LTTV_MODULE("state", "State computation", \
2743 "Update the system state, possibly saving it at intervals", \
2744 module_init, module_destroy)
2745
2746
2747
This page took 0.092519 seconds and 4 git commands to generate.