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