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