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