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