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