state.c function bugfix
[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 = funcptr;
1420 }
1421
1422 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
1423 {
1424 guint cpu = tfs->cpu;
1425 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1426 LttvProcessState *process = ts->running_process[cpu];
1427
1428 if(process->current_function != funcptr){
1429 g_info("Different functions (%lu.%09lu): ignore it\n",
1430 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1431 g_info("process state has %llu when pop_function is %llu\n",
1432 process->current_function, funcptr);
1433 g_info("{ %u, %u, %s, %s }\n",
1434 process->pid,
1435 process->ppid,
1436 g_quark_to_string(process->name),
1437 g_quark_to_string(process->state->s));
1438 return;
1439 }
1440 guint depth = process->user_stack->len;
1441
1442 if(depth == 0){
1443 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1444 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1445 return;
1446 }
1447
1448 process->user_stack =
1449 g_array_set_size(process->user_stack, depth - 1);
1450 process->current_function =
1451 g_array_index(process->user_stack, guint64, depth - 2);
1452 }
1453
1454
1455 static gboolean function_entry(void *hook_data, void *call_data)
1456 {
1457 LttvTracefileState *s = (LttvTracefileState *)call_data;
1458 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1459 guint8 fac_id = ltt_event_facility_id(e);
1460 guint8 ev_id = ltt_event_eventtype_id(e);
1461 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1462 g_assert(thf->f1 != NULL);
1463 LttField *f = thf->f1;
1464 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1465
1466 push_function(s, funcptr);
1467 return FALSE;
1468 }
1469
1470 static gboolean function_exit(void *hook_data, void *call_data)
1471 {
1472 LttvTracefileState *s = (LttvTracefileState *)call_data;
1473 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1474 guint8 fac_id = ltt_event_facility_id(e);
1475 guint8 ev_id = ltt_event_eventtype_id(e);
1476 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1477 g_assert(thf->f1 != NULL);
1478 LttField *f = thf->f1;
1479 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1480
1481 LttvExecutionSubmode submode;
1482
1483 pop_function(s, funcptr);
1484 return FALSE;
1485 }
1486
1487 static gboolean schedchange(void *hook_data, void *call_data)
1488 {
1489 LttvTracefileState *s = (LttvTracefileState *)call_data;
1490 guint cpu = s->cpu;
1491 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1492 LttvProcessState *process = ts->running_process[cpu];
1493 LttvProcessState *old_process = ts->running_process[cpu];
1494
1495 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1496 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1497 guint pid_in, pid_out;
1498 gint state_out;
1499
1500 pid_out = ltt_event_get_unsigned(e, thf->f1);
1501 pid_in = ltt_event_get_unsigned(e, thf->f2);
1502 state_out = ltt_event_get_int(e, thf->f3);
1503
1504 if(likely(process != NULL)) {
1505
1506 /* We could not know but it was not the idle process executing.
1507 This should only happen at the beginning, before the first schedule
1508 event, and when the initial information (current process for each CPU)
1509 is missing. It is not obvious how we could, after the fact, compensate
1510 the wrongly attributed statistics. */
1511
1512 //This test only makes sense once the state is known and if there is no
1513 //missing events. We need to silently ignore schedchange coming after a
1514 //process_free, or it causes glitches. (FIXME)
1515 //if(unlikely(process->pid != pid_out)) {
1516 // g_assert(process->pid == 0);
1517 //}
1518
1519 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1520 process->state->s = LTTV_STATE_ZOMBIE;
1521 process->state->change = s->parent.timestamp;
1522 } else {
1523 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1524 else process->state->s = LTTV_STATE_WAIT;
1525 process->state->change = s->parent.timestamp;
1526 }
1527
1528 if(state_out == 32)
1529 exit_process(s, process); /* EXIT_DEAD */
1530 /* see sched.h for states */
1531 }
1532 process = ts->running_process[cpu] =
1533 lttv_state_find_process_or_create(
1534 (LttvTraceState*)s->parent.t_context,
1535 cpu, pid_in,
1536 &s->parent.timestamp);
1537 process->state->s = LTTV_STATE_RUN;
1538 process->cpu = cpu;
1539 if(process->usertrace)
1540 process->usertrace->cpu = cpu;
1541 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1542 process->state->change = s->parent.timestamp;
1543 return FALSE;
1544 }
1545
1546 static gboolean process_fork(void *hook_data, void *call_data)
1547 {
1548 LttvTracefileState *s = (LttvTracefileState *)call_data;
1549 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1550 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1551 guint parent_pid;
1552 guint child_pid;
1553 LttvProcessState *zombie_process;
1554 guint cpu = s->cpu;
1555 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1556 LttvProcessState *process = ts->running_process[cpu];
1557 LttvProcessState *child_process;
1558
1559 /* Parent PID */
1560 parent_pid = ltt_event_get_unsigned(e, thf->f1);
1561
1562 /* Child PID */
1563 child_pid = ltt_event_get_unsigned(e, thf->f2);
1564
1565 /* Mathieu : it seems like the process might have been scheduled in before the
1566 * fork, and, in a rare case, might be the current process. This might happen
1567 * in a SMP case where we don't have enough precision on the clocks.
1568 *
1569 * Test reenabled after precision fixes on time. (Mathieu) */
1570 #if 0
1571 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1572
1573 if(unlikely(zombie_process != NULL)) {
1574 /* Reutilisation of PID. Only now we are sure that the old PID
1575 * has been released. FIXME : should know when release_task happens instead.
1576 */
1577 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1578 guint i;
1579 for(i=0; i< num_cpus; i++) {
1580 g_assert(zombie_process != ts->running_process[i]);
1581 }
1582
1583 exit_process(s, zombie_process);
1584 }
1585 #endif //0
1586 g_assert(process->pid != child_pid);
1587 // FIXME : Add this test in the "known state" section
1588 // g_assert(process->pid == parent_pid);
1589 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1590 if(child_process == NULL) {
1591 child_process = lttv_state_create_process(ts, process, cpu,
1592 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
1593 } else {
1594 /* The process has already been created : due to time imprecision between
1595 * multiple CPUs : it has been scheduled in before creation. Note that we
1596 * shouldn't have this kind of imprecision.
1597 *
1598 * Simply put a correct parent.
1599 */
1600 g_assert(0); /* This is a problematic case : the process has been created
1601 before the fork event */
1602 child_process->ppid = process->pid;
1603 }
1604 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1605 child_process->name = process->name;
1606
1607 return FALSE;
1608 }
1609
1610 /* We stamp a newly created process as kernel_thread */
1611 static gboolean process_kernel_thread(void *hook_data, void *call_data)
1612 {
1613 LttvTracefileState *s = (LttvTracefileState *)call_data;
1614 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1615 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1616 guint pid;
1617 guint cpu = s->cpu;
1618 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1619 LttvProcessState *process;
1620 LttvExecutionState *es;
1621
1622 /* PID */
1623 pid = ltt_event_get_unsigned(e, thf->f1);
1624
1625 process = lttv_state_find_process(ts, ANY_CPU, pid);
1626 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1627 es->t = LTTV_STATE_SYSCALL;
1628 process->kernel_thread = 1;
1629
1630 return FALSE;
1631 }
1632
1633 static gboolean process_exit(void *hook_data, void *call_data)
1634 {
1635 LttvTracefileState *s = (LttvTracefileState *)call_data;
1636 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1637 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1638 LttField *f;
1639 guint pid;
1640 guint cpu = s->cpu;
1641 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1642 LttvProcessState *process = ts->running_process[cpu];
1643
1644 pid = ltt_event_get_unsigned(e, thf->f1);
1645
1646 // FIXME : Add this test in the "known state" section
1647 // g_assert(process->pid == pid);
1648
1649 if(likely(process != NULL)) {
1650 process->state->s = LTTV_STATE_EXIT;
1651 }
1652 return FALSE;
1653 }
1654
1655 static gboolean process_free(void *hook_data, void *call_data)
1656 {
1657 LttvTracefileState *s = (LttvTracefileState *)call_data;
1658 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1659 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1660 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1661 guint release_pid;
1662 LttvProcessState *process;
1663
1664 /* PID of the process to release */
1665 release_pid = ltt_event_get_unsigned(e, thf->f1);
1666
1667 g_assert(release_pid != 0);
1668
1669 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1670
1671 if(likely(process != NULL)) {
1672 /* release_task is happening at kernel level : we can now safely release
1673 * the data structure of the process */
1674 //This test is fun, though, as it may happen that
1675 //at time t : CPU 0 : process_free
1676 //at time t+150ns : CPU 1 : schedule out
1677 //Clearly due to time imprecision, we disable it. (Mathieu)
1678 //If this weird case happen, we have no choice but to put the
1679 //Currently running process on the cpu to 0.
1680 //I re-enable it following time precision fixes. (Mathieu)
1681 //Well, in the case where an process is freed by a process on another CPU
1682 //and still scheduled, it happens that this is the schedchange that will
1683 //drop the last reference count. Do not free it here!
1684 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1685 guint i;
1686 for(i=0; i< num_cpus; i++) {
1687 //g_assert(process != ts->running_process[i]);
1688 if(process == ts->running_process[i]) {
1689 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1690 break;
1691 }
1692 }
1693 //if(i == num_cpus) /* process is not scheduled */
1694 //exit_process(s, process); // do nothing : wait for the schedchange to
1695 //delete the process.
1696 }
1697
1698 return FALSE;
1699 }
1700
1701
1702 static gboolean process_exec(void *hook_data, void *call_data)
1703 {
1704 LttvTracefileState *s = (LttvTracefileState *)call_data;
1705 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1706 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1707 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1708 //gchar *name;
1709 guint cpu = s->cpu;
1710 LttvProcessState *process = ts->running_process[cpu];
1711
1712 /* PID of the process to release */
1713 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1714 //name = ltt_event_get_string(e, thf->f1);
1715 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1716 gchar *name_begin =
1717 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1718 gchar *null_term_name = g_new(gchar, name_len+1);
1719 memcpy(null_term_name, name_begin, name_len);
1720 null_term_name[name_len] = '\0';
1721
1722 process->name = g_quark_from_string(null_term_name);
1723 g_free(null_term_name);
1724 return FALSE;
1725 }
1726
1727 static gboolean enum_process_state(void *hook_data, void *call_data)
1728 {
1729 LttvTracefileState *s = (LttvTracefileState *)call_data;
1730 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1731 //It's slow : optimise later by doing this before reading trace.
1732 LttEventType *et = ltt_event_eventtype(e);
1733 //
1734 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1735 guint parent_pid;
1736 guint pid;
1737 gchar * command;
1738 guint cpu = s->cpu;
1739 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1740 LttvProcessState *process = ts->running_process[cpu];
1741 LttvProcessState *parent_process;
1742 LttField *f4, *f5, *f6;
1743 GQuark mode, submode, status;
1744
1745 /* PID */
1746 pid = ltt_event_get_unsigned(e, thf->f1);
1747
1748 /* Parent PID */
1749 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1750
1751 /* Command name */
1752 command = ltt_event_get_string(e, thf->f3);
1753
1754 /* mode */
1755 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1756 mode = ltt_enum_string_get(ltt_field_type(f4),
1757 ltt_event_get_unsigned(e, f4));
1758
1759 /* submode */
1760 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1761 submode = ltt_enum_string_get(ltt_field_type(f5),
1762 ltt_event_get_unsigned(e, f5));
1763
1764 /* status */
1765 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1766 status = ltt_enum_string_get(ltt_field_type(f6),
1767 ltt_event_get_unsigned(e, f6));
1768
1769 /* The process might exist if a process was forked while performing the sate dump. */
1770 process = lttv_state_find_process(ts, ANY_CPU, pid);
1771 if(process == NULL) {
1772 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1773 process = lttv_state_create_process(ts, parent_process, cpu,
1774 pid, g_quark_from_string(command),
1775 &s->parent.timestamp);
1776
1777 /* Keep the stack bottom : a running user mode */
1778 #if 0
1779 /* Disabled because of inconsistencies in the current statedump states. */
1780 if(mode == LTTV_STATE_USER_MODE) {
1781 /* Only keep the bottom */
1782 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1783 } else {
1784 /* On top of it : */
1785 LttvExecutionState *es;
1786 es = process->state = &g_array_index(process->execution_stack,
1787 LttvExecutionState, 1);
1788 es->t = mode;
1789 es->s = status;
1790 es->n = submode;
1791 }
1792 #endif //0
1793
1794 /* UNKNOWN STATE */
1795 {
1796 LttvExecutionState *es;
1797 es = process->state = &g_array_index(process->execution_stack,
1798 LttvExecutionState, 1);
1799 es->t = LTTV_STATE_MODE_UNKNOWN;
1800 es->s = LTTV_STATE_UNNAMED;
1801 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1802 }
1803 } else {
1804 /* The process has already been created :
1805 * Probably was forked while dumping the process state or
1806 * was simply scheduled in prior to get the state dump event.
1807 */
1808 process->ppid = parent_pid;
1809 process->name = g_quark_from_string(command);
1810 /* Don't mess around with the stack, it will eventually become
1811 * ok after the end of state dump. */
1812 }
1813
1814 return FALSE;
1815 }
1816
1817 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1818 {
1819 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1820
1821 lttv_state_add_event_hooks(tss);
1822
1823 return 0;
1824 }
1825
1826 void lttv_state_add_event_hooks(LttvTracesetState *self)
1827 {
1828 LttvTraceset *traceset = self->parent.ts;
1829
1830 guint i, j, k, l, nb_trace, nb_tracefile;
1831
1832 LttvTraceState *ts;
1833
1834 LttvTracefileState *tfs;
1835
1836 GArray *hooks;
1837
1838 LttvTraceHookByFacility *thf;
1839
1840 LttvTraceHook *hook;
1841
1842 LttvAttributeValue val;
1843
1844 gint ret;
1845 gint hn;
1846
1847 nb_trace = lttv_traceset_number(traceset);
1848 for(i = 0 ; i < nb_trace ; i++) {
1849 ts = (LttvTraceState *)self->parent.traces[i];
1850
1851 /* Find the eventtype id for the following events and register the
1852 associated by id hooks. */
1853
1854 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
1855 hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
1856 hn = 0;
1857
1858 ret = lttv_trace_find_hook(ts->parent.t,
1859 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1860 LTT_FIELD_SYSCALL_ID, 0, 0,
1861 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1862 if(ret) hn--;
1863
1864 ret = lttv_trace_find_hook(ts->parent.t,
1865 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1866 0, 0, 0,
1867 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1868 if(ret) hn--;
1869
1870 ret = lttv_trace_find_hook(ts->parent.t,
1871 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1872 LTT_FIELD_TRAP_ID, 0, 0,
1873 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1874 if(ret) hn--;
1875
1876 ret = lttv_trace_find_hook(ts->parent.t,
1877 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1878 0, 0, 0,
1879 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1880 if(ret) hn--;
1881
1882 ret = lttv_trace_find_hook(ts->parent.t,
1883 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1884 LTT_FIELD_IRQ_ID, 0, 0,
1885 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1886 if(ret) hn--;
1887
1888 ret = lttv_trace_find_hook(ts->parent.t,
1889 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1890 0, 0, 0,
1891 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1892 if(ret) hn--;
1893
1894 ret = lttv_trace_find_hook(ts->parent.t,
1895 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1896 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1897 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1898 if(ret) hn--;
1899
1900 ret = lttv_trace_find_hook(ts->parent.t,
1901 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1902 0, 0, 0,
1903 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1904 if(ret) hn--;
1905
1906 ret = lttv_trace_find_hook(ts->parent.t,
1907 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1908 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1909 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1910 if(ret) hn--;
1911
1912 ret = lttv_trace_find_hook(ts->parent.t,
1913 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1914 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1915 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1916 if(ret) hn--;
1917
1918 ret = lttv_trace_find_hook(ts->parent.t,
1919 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1920 LTT_FIELD_PID, 0, 0,
1921 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
1922 hn++));
1923 if(ret) hn--;
1924
1925 ret = lttv_trace_find_hook(ts->parent.t,
1926 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1927 LTT_FIELD_PID, 0, 0,
1928 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1929 if(ret) hn--;
1930
1931 ret = lttv_trace_find_hook(ts->parent.t,
1932 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1933 LTT_FIELD_PID, 0, 0,
1934 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1935 if(ret) hn--;
1936
1937 ret = lttv_trace_find_hook(ts->parent.t,
1938 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1939 LTT_FIELD_FILENAME, 0, 0,
1940 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1941 if(ret) hn--;
1942
1943 /* statedump-related hooks */
1944 ret = lttv_trace_find_hook(ts->parent.t,
1945 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1946 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1947 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1948 if(ret) hn--;
1949
1950 ret = lttv_trace_find_hook(ts->parent.t,
1951 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
1952 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1953 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1954 if(ret) hn--;
1955
1956 ret = lttv_trace_find_hook(ts->parent.t,
1957 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
1958 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1959 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1960 if(ret) hn--;
1961
1962 hooks = g_array_set_size(hooks, hn);
1963
1964 /* Add these hooks to each event_by_id hooks list */
1965
1966 nb_tracefile = ts->parent.tracefiles->len;
1967
1968 for(j = 0 ; j < nb_tracefile ; j++) {
1969 tfs =
1970 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1971 LttvTracefileContext*, j));
1972
1973 for(k = 0 ; k < hooks->len ; k++) {
1974 hook = &g_array_index(hooks, LttvTraceHook, k);
1975 for(l=0;l<hook->fac_list->len;l++) {
1976 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1977 lttv_hooks_add(
1978 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1979 thf->h,
1980 thf,
1981 LTTV_PRIO_STATE);
1982 }
1983 }
1984 }
1985 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1986 *(val.v_pointer) = hooks;
1987 }
1988 }
1989
1990 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1991 {
1992 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1993
1994 lttv_state_remove_event_hooks(tss);
1995
1996 return 0;
1997 }
1998
1999 void lttv_state_remove_event_hooks(LttvTracesetState *self)
2000 {
2001 LttvTraceset *traceset = self->parent.ts;
2002
2003 guint i, j, k, l, nb_trace, nb_tracefile;
2004
2005 LttvTraceState *ts;
2006
2007 LttvTracefileState *tfs;
2008
2009 GArray *hooks;
2010
2011 LttvTraceHook *hook;
2012
2013 LttvTraceHookByFacility *thf;
2014
2015 LttvAttributeValue val;
2016
2017 nb_trace = lttv_traceset_number(traceset);
2018 for(i = 0 ; i < nb_trace ; i++) {
2019 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2020 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2021 hooks = *(val.v_pointer);
2022
2023 /* Remove these hooks from each event_by_id hooks list */
2024
2025 nb_tracefile = ts->parent.tracefiles->len;
2026
2027 for(j = 0 ; j < nb_tracefile ; j++) {
2028 tfs =
2029 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2030 LttvTracefileContext*, j));
2031
2032 for(k = 0 ; k < hooks->len ; k++) {
2033 hook = &g_array_index(hooks, LttvTraceHook, k);
2034 for(l=0;l<hook->fac_list->len;l++) {
2035 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2036
2037 lttv_hooks_remove_data(
2038 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2039 thf->h,
2040 thf);
2041 }
2042 }
2043 }
2044 for(k = 0 ; k < hooks->len ; k++)
2045 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2046 g_array_free(hooks, TRUE);
2047 }
2048 }
2049
2050 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2051 {
2052 guint *event_count = (guint*)hook_data;
2053
2054 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2055 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2056 return FALSE;
2057 else
2058 *event_count = 0;
2059
2060 LttvTracefileState *self = (LttvTracefileState *)call_data;
2061
2062 LttvTracefileState *tfcs;
2063
2064 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2065
2066 LttEventPosition *ep;
2067
2068 guint i;
2069
2070 LttTracefile *tf;
2071
2072 LttvAttribute *saved_states_tree, *saved_state_tree;
2073
2074 LttvAttributeValue value;
2075
2076 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2077 LTTV_STATE_SAVED_STATES);
2078 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2079 value = lttv_attribute_add(saved_states_tree,
2080 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2081 *(value.v_gobject) = (GObject *)saved_state_tree;
2082 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2083 *(value.v_time) = self->parent.timestamp;
2084 lttv_state_save(tcs, saved_state_tree);
2085 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2086 self->parent.timestamp.tv_nsec);
2087
2088 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2089
2090 return FALSE;
2091 }
2092
2093 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2094 {
2095 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2096
2097 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2098
2099 return FALSE;
2100 }
2101
2102 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2103 {
2104 return tfs->cpu;
2105 }
2106
2107
2108
2109 #if 0
2110 static gboolean block_start(void *hook_data, void *call_data)
2111 {
2112 LttvTracefileState *self = (LttvTracefileState *)call_data;
2113
2114 LttvTracefileState *tfcs;
2115
2116 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2117
2118 LttEventPosition *ep;
2119
2120 guint i, nb_block, nb_event, nb_tracefile;
2121
2122 LttTracefile *tf;
2123
2124 LttvAttribute *saved_states_tree, *saved_state_tree;
2125
2126 LttvAttributeValue value;
2127
2128 ep = ltt_event_position_new();
2129
2130 nb_tracefile = tcs->parent.tracefiles->len;
2131
2132 /* Count the number of events added since the last block end in any
2133 tracefile. */
2134
2135 for(i = 0 ; i < nb_tracefile ; i++) {
2136 tfcs =
2137 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2138 LttvTracefileContext, i));
2139 ltt_event_position(tfcs->parent.e, ep);
2140 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2141 tcs->nb_event += nb_event - tfcs->saved_position;
2142 tfcs->saved_position = nb_event;
2143 }
2144 g_free(ep);
2145
2146 if(tcs->nb_event >= tcs->save_interval) {
2147 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2148 LTTV_STATE_SAVED_STATES);
2149 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2150 value = lttv_attribute_add(saved_states_tree,
2151 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2152 *(value.v_gobject) = (GObject *)saved_state_tree;
2153 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2154 *(value.v_time) = self->parent.timestamp;
2155 lttv_state_save(tcs, saved_state_tree);
2156 tcs->nb_event = 0;
2157 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2158 self->parent.timestamp.tv_nsec);
2159 }
2160 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2161 return FALSE;
2162 }
2163 #endif //0
2164
2165 #if 0
2166 static gboolean block_end(void *hook_data, void *call_data)
2167 {
2168 LttvTracefileState *self = (LttvTracefileState *)call_data;
2169
2170 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2171
2172 LttTracefile *tf;
2173
2174 LttEventPosition *ep;
2175
2176 guint nb_block, nb_event;
2177
2178 ep = ltt_event_position_new();
2179 ltt_event_position(self->parent.e, ep);
2180 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2181 tcs->nb_event += nb_event - self->saved_position + 1;
2182 self->saved_position = 0;
2183 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2184 g_free(ep);
2185
2186 return FALSE;
2187 }
2188 #endif //0
2189 #if 0
2190 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2191 {
2192 LttvTraceset *traceset = self->parent.ts;
2193
2194 guint i, j, nb_trace, nb_tracefile;
2195
2196 LttvTraceState *ts;
2197
2198 LttvTracefileState *tfs;
2199
2200 LttvTraceHook hook_start, hook_end;
2201
2202 nb_trace = lttv_traceset_number(traceset);
2203 for(i = 0 ; i < nb_trace ; i++) {
2204 ts = (LttvTraceState *)self->parent.traces[i];
2205
2206 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2207 NULL, NULL, block_start, &hook_start);
2208 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2209 NULL, NULL, block_end, &hook_end);
2210
2211 nb_tracefile = ts->parent.tracefiles->len;
2212
2213 for(j = 0 ; j < nb_tracefile ; j++) {
2214 tfs =
2215 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2216 LttvTracefileContext, j));
2217 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2218 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2219 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2220 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2221 }
2222 }
2223 }
2224 #endif //0
2225
2226 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2227 {
2228 LttvTraceset *traceset = self->parent.ts;
2229
2230 guint i, j, nb_trace, nb_tracefile;
2231
2232 LttvTraceState *ts;
2233
2234 LttvTracefileState *tfs;
2235
2236
2237 nb_trace = lttv_traceset_number(traceset);
2238 for(i = 0 ; i < nb_trace ; i++) {
2239
2240 ts = (LttvTraceState *)self->parent.traces[i];
2241 nb_tracefile = ts->parent.tracefiles->len;
2242
2243 guint *event_count = g_new(guint, 1);
2244 *event_count = 0;
2245
2246 for(j = 0 ; j < nb_tracefile ; j++) {
2247 tfs =
2248 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2249 LttvTracefileContext*, j));
2250 lttv_hooks_add(tfs->parent.event,
2251 state_save_event_hook,
2252 event_count,
2253 LTTV_PRIO_STATE);
2254
2255 }
2256 }
2257
2258 lttv_process_traceset_begin(&self->parent,
2259 NULL, NULL, NULL, NULL, NULL);
2260
2261 }
2262
2263 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2264 {
2265 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2266
2267 lttv_state_save_add_event_hooks(tss);
2268
2269 return 0;
2270 }
2271
2272
2273 #if 0
2274 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2275 {
2276 LttvTraceset *traceset = self->parent.ts;
2277
2278 guint i, j, nb_trace, nb_tracefile;
2279
2280 LttvTraceState *ts;
2281
2282 LttvTracefileState *tfs;
2283
2284 LttvTraceHook hook_start, hook_end;
2285
2286 nb_trace = lttv_traceset_number(traceset);
2287 for(i = 0 ; i < nb_trace ; i++) {
2288 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2289
2290 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2291 NULL, NULL, block_start, &hook_start);
2292
2293 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2294 NULL, NULL, block_end, &hook_end);
2295
2296 nb_tracefile = ts->parent.tracefiles->len;
2297
2298 for(j = 0 ; j < nb_tracefile ; j++) {
2299 tfs =
2300 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2301 LttvTracefileContext, j));
2302 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2303 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2304 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2305 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2306 }
2307 }
2308 }
2309 #endif //0
2310
2311 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2312 {
2313 LttvTraceset *traceset = self->parent.ts;
2314
2315 guint i, j, nb_trace, nb_tracefile;
2316
2317 LttvTraceState *ts;
2318
2319 LttvTracefileState *tfs;
2320
2321 LttvHooks *after_trace = lttv_hooks_new();
2322
2323 lttv_hooks_add(after_trace,
2324 state_save_after_trace_hook,
2325 NULL,
2326 LTTV_PRIO_STATE);
2327
2328
2329 lttv_process_traceset_end(&self->parent,
2330 NULL, after_trace, NULL, NULL, NULL);
2331
2332 lttv_hooks_destroy(after_trace);
2333
2334 nb_trace = lttv_traceset_number(traceset);
2335 for(i = 0 ; i < nb_trace ; i++) {
2336
2337 ts = (LttvTraceState *)self->parent.traces[i];
2338 nb_tracefile = ts->parent.tracefiles->len;
2339
2340 guint *event_count = NULL;
2341
2342 for(j = 0 ; j < nb_tracefile ; j++) {
2343 tfs =
2344 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2345 LttvTracefileContext*, j));
2346 event_count = lttv_hooks_remove(tfs->parent.event,
2347 state_save_event_hook);
2348 }
2349 if(event_count) g_free(event_count);
2350 }
2351 }
2352
2353 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2354 {
2355 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2356
2357 lttv_state_save_remove_event_hooks(tss);
2358
2359 return 0;
2360 }
2361
2362 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2363 {
2364 LttvTraceset *traceset = self->parent.ts;
2365
2366 guint i, nb_trace;
2367
2368 int min_pos, mid_pos, max_pos;
2369
2370 guint call_rest = 0;
2371
2372 LttvTraceState *tcs;
2373
2374 LttvAttributeValue value;
2375
2376 LttvAttributeType type;
2377
2378 LttvAttributeName name;
2379
2380 gboolean is_named;
2381
2382 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2383
2384 //g_tree_destroy(self->parent.pqueue);
2385 //self->parent.pqueue = g_tree_new(compare_tracefile);
2386
2387 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2388
2389 nb_trace = lttv_traceset_number(traceset);
2390 for(i = 0 ; i < nb_trace ; i++) {
2391 tcs = (LttvTraceState *)self->parent.traces[i];
2392
2393 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2394 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2395 LTTV_STATE_SAVED_STATES);
2396 min_pos = -1;
2397
2398 if(saved_states_tree) {
2399 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2400 mid_pos = max_pos / 2;
2401 while(min_pos < max_pos) {
2402 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
2403 &is_named);
2404 g_assert(type == LTTV_GOBJECT);
2405 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2406 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2407 &value);
2408 g_assert(type == LTTV_TIME);
2409 if(ltt_time_compare(*(value.v_time), t) < 0) {
2410 min_pos = mid_pos;
2411 closest_tree = saved_state_tree;
2412 }
2413 else max_pos = mid_pos - 1;
2414
2415 mid_pos = (min_pos + max_pos + 1) / 2;
2416 }
2417 }
2418
2419 /* restore the closest earlier saved state */
2420 if(min_pos != -1) {
2421 lttv_state_restore(tcs, closest_tree);
2422 call_rest = 1;
2423 }
2424
2425 /* There is no saved state, yet we want to have it. Restart at T0 */
2426 else {
2427 restore_init_state(tcs);
2428 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2429 }
2430 }
2431 /* We want to seek quickly without restoring/updating the state */
2432 else {
2433 restore_init_state(tcs);
2434 lttv_process_trace_seek_time(&(tcs->parent), t);
2435 }
2436 }
2437 if(!call_rest) g_info("NOT Calling restore");
2438 }
2439
2440
2441 static void
2442 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2443 {
2444 }
2445
2446
2447 static void
2448 traceset_state_finalize (LttvTracesetState *self)
2449 {
2450 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2451 finalize(G_OBJECT(self));
2452 }
2453
2454
2455 static void
2456 traceset_state_class_init (LttvTracesetContextClass *klass)
2457 {
2458 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2459
2460 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2461 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2462 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2463 klass->new_traceset_context = new_traceset_context;
2464 klass->new_trace_context = new_trace_context;
2465 klass->new_tracefile_context = new_tracefile_context;
2466 }
2467
2468
2469 GType
2470 lttv_traceset_state_get_type(void)
2471 {
2472 static GType type = 0;
2473 if (type == 0) {
2474 static const GTypeInfo info = {
2475 sizeof (LttvTracesetStateClass),
2476 NULL, /* base_init */
2477 NULL, /* base_finalize */
2478 (GClassInitFunc) traceset_state_class_init, /* class_init */
2479 NULL, /* class_finalize */
2480 NULL, /* class_data */
2481 sizeof (LttvTracesetState),
2482 0, /* n_preallocs */
2483 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2484 NULL /* value handling */
2485 };
2486
2487 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2488 &info, 0);
2489 }
2490 return type;
2491 }
2492
2493
2494 static void
2495 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2496 {
2497 }
2498
2499
2500 static void
2501 trace_state_finalize (LttvTraceState *self)
2502 {
2503 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2504 finalize(G_OBJECT(self));
2505 }
2506
2507
2508 static void
2509 trace_state_class_init (LttvTraceStateClass *klass)
2510 {
2511 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2512
2513 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2514 klass->state_save = state_save;
2515 klass->state_restore = state_restore;
2516 klass->state_saved_free = state_saved_free;
2517 }
2518
2519
2520 GType
2521 lttv_trace_state_get_type(void)
2522 {
2523 static GType type = 0;
2524 if (type == 0) {
2525 static const GTypeInfo info = {
2526 sizeof (LttvTraceStateClass),
2527 NULL, /* base_init */
2528 NULL, /* base_finalize */
2529 (GClassInitFunc) trace_state_class_init, /* class_init */
2530 NULL, /* class_finalize */
2531 NULL, /* class_data */
2532 sizeof (LttvTraceState),
2533 0, /* n_preallocs */
2534 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2535 NULL /* value handling */
2536 };
2537
2538 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2539 "LttvTraceStateType", &info, 0);
2540 }
2541 return type;
2542 }
2543
2544
2545 static void
2546 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2547 {
2548 }
2549
2550
2551 static void
2552 tracefile_state_finalize (LttvTracefileState *self)
2553 {
2554 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2555 finalize(G_OBJECT(self));
2556 }
2557
2558
2559 static void
2560 tracefile_state_class_init (LttvTracefileStateClass *klass)
2561 {
2562 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2563
2564 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2565 }
2566
2567
2568 GType
2569 lttv_tracefile_state_get_type(void)
2570 {
2571 static GType type = 0;
2572 if (type == 0) {
2573 static const GTypeInfo info = {
2574 sizeof (LttvTracefileStateClass),
2575 NULL, /* base_init */
2576 NULL, /* base_finalize */
2577 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2578 NULL, /* class_finalize */
2579 NULL, /* class_data */
2580 sizeof (LttvTracefileState),
2581 0, /* n_preallocs */
2582 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2583 NULL /* value handling */
2584 };
2585
2586 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2587 "LttvTracefileStateType", &info, 0);
2588 }
2589 return type;
2590 }
2591
2592
2593 static void module_init()
2594 {
2595 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2596 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2597 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2598 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2599 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2600 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2601 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2602 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2603 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2604 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2605 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2606 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2607 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2608 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2609 LTTV_STATE_RUN = g_quark_from_string("RUN");
2610 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2611 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2612 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2613 LTTV_STATE_PROCESS = g_quark_from_string("process");
2614 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2615 LTTV_STATE_EVENT = g_quark_from_string("event");
2616 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2617 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2618 LTTV_STATE_TIME = g_quark_from_string("time");
2619 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2620 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2621 LTTV_STATE_TRACE_STATE_USE_COUNT =
2622 g_quark_from_string("trace_state_use_count");
2623
2624
2625 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2626 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2627 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2628 LTT_FACILITY_FS = g_quark_from_string("fs");
2629 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2630 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
2631
2632
2633 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2634 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2635 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2636 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2637 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2638 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2639 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2640 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2641 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2642 LTT_EVENT_FORK = g_quark_from_string("fork");
2643 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
2644 LTT_EVENT_EXIT = g_quark_from_string("exit");
2645 LTT_EVENT_FREE = g_quark_from_string("free");
2646 LTT_EVENT_EXEC = g_quark_from_string("exec");
2647 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2648 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2649 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
2650
2651
2652 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2653 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2654 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2655 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2656 LTT_FIELD_OUT = g_quark_from_string("out");
2657 LTT_FIELD_IN = g_quark_from_string("in");
2658 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2659 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2660 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2661 LTT_FIELD_PID = g_quark_from_string("pid");
2662 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2663 LTT_FIELD_NAME = g_quark_from_string("name");
2664 LTT_FIELD_MODE = g_quark_from_string("mode");
2665 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2666 LTT_FIELD_STATUS = g_quark_from_string("status");
2667 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2668 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
2669
2670 }
2671
2672 static void module_destroy()
2673 {
2674 }
2675
2676
2677 LTTV_MODULE("state", "State computation", \
2678 "Update the system state, possibly saving it at intervals", \
2679 module_init, module_destroy)
2680
2681
2682
This page took 0.080242 seconds and 5 git commands to generate.