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