update compat
[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->s = process->state->s;
1049 process->state = es;
1050 }
1051
1052
1053 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1054 {
1055 guint cpu = tfs->cpu;
1056 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1057 LttvProcessState *process = ts->running_process[cpu];
1058
1059 guint depth = process->execution_stack->len;
1060
1061 if(process->state->t != t){
1062 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1063 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1064 g_info("process state has %s when pop_int is %s\n",
1065 g_quark_to_string(process->state->t),
1066 g_quark_to_string(t));
1067 g_info("{ %u, %u, %s, %s }\n",
1068 process->pid,
1069 process->ppid,
1070 g_quark_to_string(process->name),
1071 g_quark_to_string(process->state->s));
1072 return;
1073 }
1074
1075 if(depth == 1){
1076 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1077 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1078 return;
1079 }
1080
1081 process->execution_stack =
1082 g_array_set_size(process->execution_stack, depth - 1);
1083 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1084 depth - 2);
1085 process->state->change = tfs->parent.timestamp;
1086 }
1087
1088 struct search_result {
1089 const LttTime *time; /* Requested time */
1090 LttTime *best; /* Best result */
1091 };
1092
1093 static gint search_usertrace(gconstpointer a, gconstpointer b)
1094 {
1095 const LttTime *elem_time = (const LttTime*)a;
1096 /* Explicit non const cast */
1097 struct search_result *res = (struct search_result *)b;
1098
1099 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1100 /* The usertrace was created before the schedchange */
1101 /* Get larger keys */
1102 return 1;
1103 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1104 /* The usertrace was created after the schedchange time */
1105 /* Get smaller keys */
1106 if(res->best) {
1107 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1108 res->best = elem_time;
1109 }
1110 } else {
1111 res->best = elem_time;
1112 }
1113 return -1;
1114 }
1115 return 0;
1116 }
1117
1118 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1119 guint pid, const LttTime *timestamp)
1120 {
1121 LttvTracefileState *tfs = NULL;
1122 struct search_result res;
1123 /* Find the usertrace associated with a pid and time interval.
1124 * Search in the usertraces by PID (within a hash) and then, for each
1125 * corresponding element of the array, find the first one with creation
1126 * timestamp the lowest, but higher or equal to "timestamp". */
1127 res.time = timestamp;
1128 res.best = NULL;
1129 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1130 if(usertrace_tree) {
1131 g_tree_search(usertrace_tree, search_usertrace, &res);
1132 if(res.best)
1133 tfs = g_tree_lookup(usertrace_tree, res.best);
1134 }
1135
1136 return tfs;
1137 }
1138
1139
1140 LttvProcessState *
1141 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
1142 guint cpu, guint pid, GQuark name, const LttTime *timestamp)
1143 {
1144 LttvProcessState *process = g_new(LttvProcessState, 1);
1145
1146 LttvExecutionState *es;
1147
1148 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1149
1150 char buffer[128];
1151
1152 process->pid = pid;
1153 process->cpu = cpu;
1154 process->name = name;
1155 //process->last_cpu = tfs->cpu_name;
1156 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1157 process->kernel_thread = 0;
1158 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1159 process->current_function = 0; //function 0x0 by default.
1160
1161 g_info("Process %u, core %p", process->pid, process);
1162 g_hash_table_insert(tcs->processes, process, process);
1163
1164 if(parent) {
1165 process->ppid = parent->pid;
1166 process->creation_time = *timestamp;
1167 }
1168
1169 /* No parent. This process exists but we are missing all information about
1170 its creation. The birth time is set to zero but we remember the time of
1171 insertion */
1172
1173 else {
1174 process->ppid = 0;
1175 process->creation_time = ltt_time_zero;
1176 }
1177
1178 process->insertion_time = *timestamp;
1179 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1180 process->creation_time.tv_nsec);
1181 process->pid_time = g_quark_from_string(buffer);
1182 process->cpu = cpu;
1183 //process->last_cpu = tfs->cpu_name;
1184 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1185 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1186 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1187 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1188 es = process->state = &g_array_index(process->execution_stack,
1189 LttvExecutionState, 0);
1190 es->t = LTTV_STATE_USER_MODE;
1191 es->n = LTTV_STATE_SUBMODE_NONE;
1192 es->entry = *timestamp;
1193 //g_assert(timestamp->tv_sec != 0);
1194 es->change = *timestamp;
1195 es->s = LTTV_STATE_RUN;
1196
1197 es = process->state = &g_array_index(process->execution_stack,
1198 LttvExecutionState, 1);
1199 es->t = LTTV_STATE_SYSCALL;
1200 es->n = LTTV_STATE_SUBMODE_NONE;
1201 es->entry = *timestamp;
1202 //g_assert(timestamp->tv_sec != 0);
1203 es->change = *timestamp;
1204 es->s = LTTV_STATE_WAIT_FORK;
1205
1206 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1207 process->user_stack = g_array_sized_new(FALSE, FALSE,
1208 sizeof(guint64), 0);
1209
1210 return process;
1211 }
1212
1213 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1214 guint pid)
1215 {
1216 LttvProcessState key;
1217 LttvProcessState *process;
1218
1219 key.pid = pid;
1220 key.cpu = cpu;
1221 process = g_hash_table_lookup(ts->processes, &key);
1222 return process;
1223 }
1224
1225 LttvProcessState *
1226 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1227 LttTime *timestamp)
1228 {
1229 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1230 LttvExecutionState *es;
1231
1232 /* Put ltt_time_zero creation time for unexisting processes */
1233 if(unlikely(process == NULL)) {
1234 process = lttv_state_create_process(ts,
1235 NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
1236 /* We are not sure is it's a kernel thread or normal thread, put the
1237 * bottom stack state to unknown */
1238 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1239 es->t = LTTV_STATE_MODE_UNKNOWN;
1240 }
1241 return process;
1242 }
1243
1244 /* FIXME : this function should be called when we receive an event telling that
1245 * release_task has been called in the kernel. In happens generally when
1246 * the parent waits for its child terminaison, but may also happen in special
1247 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1248 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1249 * of a killed thread ground, but isn't the leader.
1250 */
1251 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1252 {
1253 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1254 LttvProcessState key;
1255
1256 key.pid = process->pid;
1257 key.cpu = process->cpu;
1258 g_hash_table_remove(ts->processes, &key);
1259 g_array_free(process->execution_stack, TRUE);
1260 g_array_free(process->user_stack, TRUE);
1261 g_free(process);
1262 }
1263
1264
1265 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1266 {
1267 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1268 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
1269 g_free(value);
1270 }
1271
1272
1273 static void lttv_state_free_process_table(GHashTable *processes)
1274 {
1275 g_hash_table_foreach(processes, free_process_state, NULL);
1276 g_hash_table_destroy(processes);
1277 }
1278
1279
1280 static gboolean syscall_entry(void *hook_data, void *call_data)
1281 {
1282 LttvTracefileState *s = (LttvTracefileState *)call_data;
1283 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1284 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1285 LttField *f = thf->f1;
1286
1287 LttvExecutionSubmode submode;
1288
1289 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1290 guint syscall = ltt_event_get_unsigned(e, f);
1291
1292 if(syscall < nb_syscalls) {
1293 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1294 syscall];
1295 } else {
1296 /* Fixup an incomplete syscall table */
1297 GString *string = g_string_new("");
1298 g_string_printf(string, "syscall %u", syscall);
1299 submode = g_quark_from_string(string->str);
1300 g_string_free(string, TRUE);
1301 }
1302 push_state(s, LTTV_STATE_SYSCALL, submode);
1303 return FALSE;
1304 }
1305
1306
1307 static gboolean syscall_exit(void *hook_data, void *call_data)
1308 {
1309 LttvTracefileState *s = (LttvTracefileState *)call_data;
1310
1311 pop_state(s, LTTV_STATE_SYSCALL);
1312 return FALSE;
1313 }
1314
1315
1316 static gboolean trap_entry(void *hook_data, void *call_data)
1317 {
1318 LttvTracefileState *s = (LttvTracefileState *)call_data;
1319 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1320 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1321 LttField *f = thf->f1;
1322
1323 LttvExecutionSubmode submode;
1324
1325 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
1326 ltt_event_get_unsigned(e, f)];
1327 push_state(s, LTTV_STATE_TRAP, submode);
1328 return FALSE;
1329 }
1330
1331
1332 static gboolean trap_exit(void *hook_data, void *call_data)
1333 {
1334 LttvTracefileState *s = (LttvTracefileState *)call_data;
1335
1336 pop_state(s, LTTV_STATE_TRAP);
1337 return FALSE;
1338 }
1339
1340
1341 static gboolean irq_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 guint8 fac_id = ltt_event_facility_id(e);
1346 guint8 ev_id = ltt_event_eventtype_id(e);
1347 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1348 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1349 g_assert(thf->f1 != NULL);
1350 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1351 LttField *f = thf->f1;
1352
1353 LttvExecutionSubmode submode;
1354
1355 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1356 ltt_event_get_unsigned(e, f)];
1357
1358 /* Do something with the info about being in user or system mode when int? */
1359 push_state(s, LTTV_STATE_IRQ, submode);
1360 return FALSE;
1361 }
1362
1363 static gboolean soft_irq_exit(void *hook_data, void *call_data)
1364 {
1365 LttvTracefileState *s = (LttvTracefileState *)call_data;
1366
1367 pop_state(s, LTTV_STATE_SOFT_IRQ);
1368 return FALSE;
1369 }
1370
1371
1372
1373 static gboolean irq_exit(void *hook_data, void *call_data)
1374 {
1375 LttvTracefileState *s = (LttvTracefileState *)call_data;
1376
1377 pop_state(s, LTTV_STATE_IRQ);
1378 return FALSE;
1379 }
1380
1381 static gboolean soft_irq_entry(void *hook_data, void *call_data)
1382 {
1383 LttvTracefileState *s = (LttvTracefileState *)call_data;
1384 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1385 guint8 fac_id = ltt_event_facility_id(e);
1386 guint8 ev_id = ltt_event_eventtype_id(e);
1387 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1388 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1389 g_assert(thf->f1 != NULL);
1390 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1391 LttField *f = thf->f1;
1392
1393 LttvExecutionSubmode submode;
1394
1395 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1396 ltt_event_get_unsigned(e, f)];
1397
1398 /* Do something with the info about being in user or system mode when int? */
1399 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1400 return FALSE;
1401 }
1402
1403 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
1404 {
1405 guint64 *new_func;
1406
1407 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1408 guint cpu = tfs->cpu;
1409 LttvProcessState *process = ts->running_process[cpu];
1410
1411 guint depth = process->user_stack->len;
1412
1413 process->user_stack =
1414 g_array_set_size(process->user_stack, depth + 1);
1415
1416 new_func = &g_array_index(process->user_stack, guint64, depth);
1417 *new_func = funcptr;
1418 process->current_function = funcptr;
1419 }
1420
1421 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
1422 {
1423 guint cpu = tfs->cpu;
1424 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1425 LttvProcessState *process = ts->running_process[cpu];
1426
1427 if(process->current_function != funcptr){
1428 g_info("Different functions (%lu.%09lu): ignore it\n",
1429 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1430 g_info("process state has %llu when pop_function is %llu\n",
1431 process->current_function, funcptr);
1432 g_info("{ %u, %u, %s, %s }\n",
1433 process->pid,
1434 process->ppid,
1435 g_quark_to_string(process->name),
1436 g_quark_to_string(process->state->s));
1437 return;
1438 }
1439 guint depth = process->user_stack->len;
1440
1441 if(depth == 0){
1442 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
1443 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1444 return;
1445 }
1446
1447 process->user_stack =
1448 g_array_set_size(process->user_stack, depth - 1);
1449 process->current_function =
1450 g_array_index(process->user_stack, guint64, depth - 2);
1451 }
1452
1453
1454 static gboolean function_entry(void *hook_data, void *call_data)
1455 {
1456 LttvTracefileState *s = (LttvTracefileState *)call_data;
1457 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1458 guint8 fac_id = ltt_event_facility_id(e);
1459 guint8 ev_id = ltt_event_eventtype_id(e);
1460 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1461 g_assert(thf->f1 != NULL);
1462 LttField *f = thf->f1;
1463 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1464
1465 push_function(s, funcptr);
1466 return FALSE;
1467 }
1468
1469 static gboolean function_exit(void *hook_data, void *call_data)
1470 {
1471 LttvTracefileState *s = (LttvTracefileState *)call_data;
1472 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1473 guint8 fac_id = ltt_event_facility_id(e);
1474 guint8 ev_id = ltt_event_eventtype_id(e);
1475 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1476 g_assert(thf->f1 != NULL);
1477 LttField *f = thf->f1;
1478 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
1479
1480 LttvExecutionSubmode submode;
1481
1482 pop_function(s, funcptr);
1483 return FALSE;
1484 }
1485
1486 static gboolean schedchange(void *hook_data, void *call_data)
1487 {
1488 LttvTracefileState *s = (LttvTracefileState *)call_data;
1489 guint cpu = s->cpu;
1490 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1491 LttvProcessState *process = ts->running_process[cpu];
1492 LttvProcessState *old_process = ts->running_process[cpu];
1493
1494 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1495 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1496 guint pid_in, pid_out;
1497 gint state_out;
1498
1499 pid_out = ltt_event_get_unsigned(e, thf->f1);
1500 pid_in = ltt_event_get_unsigned(e, thf->f2);
1501 state_out = ltt_event_get_int(e, thf->f3);
1502
1503 if(likely(process != NULL)) {
1504
1505 /* We could not know but it was not the idle process executing.
1506 This should only happen at the beginning, before the first schedule
1507 event, and when the initial information (current process for each CPU)
1508 is missing. It is not obvious how we could, after the fact, compensate
1509 the wrongly attributed statistics. */
1510
1511 //This test only makes sense once the state is known and if there is no
1512 //missing events. We need to silently ignore schedchange coming after a
1513 //process_free, or it causes glitches. (FIXME)
1514 //if(unlikely(process->pid != pid_out)) {
1515 // g_assert(process->pid == 0);
1516 //}
1517
1518 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1519 process->state->s = LTTV_STATE_ZOMBIE;
1520 process->state->change = s->parent.timestamp;
1521 } else {
1522 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1523 else process->state->s = LTTV_STATE_WAIT;
1524 process->state->change = s->parent.timestamp;
1525 }
1526
1527 if(state_out == 32)
1528 exit_process(s, process); /* EXIT_DEAD */
1529 /* see sched.h for states */
1530 }
1531 process = ts->running_process[cpu] =
1532 lttv_state_find_process_or_create(
1533 (LttvTraceState*)s->parent.t_context,
1534 cpu, pid_in,
1535 &s->parent.timestamp);
1536 process->state->s = LTTV_STATE_RUN;
1537 process->cpu = cpu;
1538 if(process->usertrace)
1539 process->usertrace->cpu = cpu;
1540 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1541 process->state->change = s->parent.timestamp;
1542 return FALSE;
1543 }
1544
1545 static gboolean process_fork(void *hook_data, void *call_data)
1546 {
1547 LttvTracefileState *s = (LttvTracefileState *)call_data;
1548 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1549 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1550 guint parent_pid;
1551 guint child_pid;
1552 LttvProcessState *zombie_process;
1553 guint cpu = s->cpu;
1554 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1555 LttvProcessState *process = ts->running_process[cpu];
1556 LttvProcessState *child_process;
1557
1558 /* Parent PID */
1559 parent_pid = ltt_event_get_unsigned(e, thf->f1);
1560
1561 /* Child PID */
1562 child_pid = ltt_event_get_unsigned(e, thf->f2);
1563
1564 /* Mathieu : it seems like the process might have been scheduled in before the
1565 * fork, and, in a rare case, might be the current process. This might happen
1566 * in a SMP case where we don't have enough precision on the clocks.
1567 *
1568 * Test reenabled after precision fixes on time. (Mathieu) */
1569 #if 0
1570 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1571
1572 if(unlikely(zombie_process != NULL)) {
1573 /* Reutilisation of PID. Only now we are sure that the old PID
1574 * has been released. FIXME : should know when release_task happens instead.
1575 */
1576 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1577 guint i;
1578 for(i=0; i< num_cpus; i++) {
1579 g_assert(zombie_process != ts->running_process[i]);
1580 }
1581
1582 exit_process(s, zombie_process);
1583 }
1584 #endif //0
1585 g_assert(process->pid != child_pid);
1586 // FIXME : Add this test in the "known state" section
1587 // g_assert(process->pid == parent_pid);
1588 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1589 if(child_process == NULL) {
1590 child_process = lttv_state_create_process(ts, process, cpu,
1591 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
1592 } else {
1593 /* The process has already been created : due to time imprecision between
1594 * multiple CPUs : it has been scheduled in before creation. Note that we
1595 * shouldn't have this kind of imprecision.
1596 *
1597 * Simply put a correct parent.
1598 */
1599 g_assert(0); /* This is a problematic case : the process has been created
1600 before the fork event */
1601 child_process->ppid = process->pid;
1602 }
1603 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1604 child_process->name = process->name;
1605
1606 return FALSE;
1607 }
1608
1609 /* We stamp a newly created process as kernel_thread */
1610 static gboolean process_kernel_thread(void *hook_data, void *call_data)
1611 {
1612 LttvTracefileState *s = (LttvTracefileState *)call_data;
1613 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1614 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1615 guint pid;
1616 guint cpu = s->cpu;
1617 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1618 LttvProcessState *process;
1619 LttvExecutionState *es;
1620
1621 /* PID */
1622 pid = ltt_event_get_unsigned(e, thf->f1);
1623
1624 process = lttv_state_find_process(ts, ANY_CPU, pid);
1625 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1626 es->t = LTTV_STATE_SYSCALL;
1627 process->kernel_thread = 1;
1628
1629 return FALSE;
1630 }
1631
1632 static gboolean process_exit(void *hook_data, void *call_data)
1633 {
1634 LttvTracefileState *s = (LttvTracefileState *)call_data;
1635 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1636 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1637 LttField *f;
1638 guint pid;
1639 guint cpu = s->cpu;
1640 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1641 LttvProcessState *process = ts->running_process[cpu];
1642
1643 pid = ltt_event_get_unsigned(e, thf->f1);
1644
1645 // FIXME : Add this test in the "known state" section
1646 // g_assert(process->pid == pid);
1647
1648 if(likely(process != NULL)) {
1649 process->state->s = LTTV_STATE_EXIT;
1650 }
1651 return FALSE;
1652 }
1653
1654 static gboolean process_free(void *hook_data, void *call_data)
1655 {
1656 LttvTracefileState *s = (LttvTracefileState *)call_data;
1657 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1658 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1659 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1660 guint release_pid;
1661 LttvProcessState *process;
1662
1663 /* PID of the process to release */
1664 release_pid = ltt_event_get_unsigned(e, thf->f1);
1665
1666 g_assert(release_pid != 0);
1667
1668 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1669
1670 if(likely(process != NULL)) {
1671 /* release_task is happening at kernel level : we can now safely release
1672 * the data structure of the process */
1673 //This test is fun, though, as it may happen that
1674 //at time t : CPU 0 : process_free
1675 //at time t+150ns : CPU 1 : schedule out
1676 //Clearly due to time imprecision, we disable it. (Mathieu)
1677 //If this weird case happen, we have no choice but to put the
1678 //Currently running process on the cpu to 0.
1679 //I re-enable it following time precision fixes. (Mathieu)
1680 //Well, in the case where an process is freed by a process on another CPU
1681 //and still scheduled, it happens that this is the schedchange that will
1682 //drop the last reference count. Do not free it here!
1683 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1684 guint i;
1685 for(i=0; i< num_cpus; i++) {
1686 //g_assert(process != ts->running_process[i]);
1687 if(process == ts->running_process[i]) {
1688 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1689 break;
1690 }
1691 }
1692 //if(i == num_cpus) /* process is not scheduled */
1693 //exit_process(s, process); // do nothing : wait for the schedchange to
1694 //delete the process.
1695 }
1696
1697 return FALSE;
1698 }
1699
1700
1701 static gboolean process_exec(void *hook_data, void *call_data)
1702 {
1703 LttvTracefileState *s = (LttvTracefileState *)call_data;
1704 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1705 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1706 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1707 //gchar *name;
1708 guint cpu = s->cpu;
1709 LttvProcessState *process = ts->running_process[cpu];
1710
1711 /* PID of the process to release */
1712 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1713 //name = ltt_event_get_string(e, thf->f1);
1714 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1715 gchar *name_begin =
1716 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1717 gchar *null_term_name = g_new(gchar, name_len+1);
1718 memcpy(null_term_name, name_begin, name_len);
1719 null_term_name[name_len] = '\0';
1720
1721 process->name = g_quark_from_string(null_term_name);
1722 g_free(null_term_name);
1723 return FALSE;
1724 }
1725
1726 static gboolean enum_process_state(void *hook_data, void *call_data)
1727 {
1728 LttvTracefileState *s = (LttvTracefileState *)call_data;
1729 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1730 //It's slow : optimise later by doing this before reading trace.
1731 LttEventType *et = ltt_event_eventtype(e);
1732 //
1733 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1734 guint parent_pid;
1735 guint pid;
1736 gchar * command;
1737 guint cpu = s->cpu;
1738 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1739 LttvProcessState *process = ts->running_process[cpu];
1740 LttvProcessState *parent_process;
1741 LttField *f4, *f5, *f6;
1742 GQuark mode, submode, status;
1743
1744 /* PID */
1745 pid = ltt_event_get_unsigned(e, thf->f1);
1746
1747 /* Parent PID */
1748 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1749
1750 /* Command name */
1751 command = ltt_event_get_string(e, thf->f3);
1752
1753 /* mode */
1754 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1755 mode = ltt_enum_string_get(ltt_field_type(f4),
1756 ltt_event_get_unsigned(e, f4));
1757
1758 /* submode */
1759 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1760 submode = ltt_enum_string_get(ltt_field_type(f5),
1761 ltt_event_get_unsigned(e, f5));
1762
1763 /* status */
1764 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1765 status = ltt_enum_string_get(ltt_field_type(f6),
1766 ltt_event_get_unsigned(e, f6));
1767
1768 /* The process might exist if a process was forked while performing the sate dump. */
1769 process = lttv_state_find_process(ts, ANY_CPU, pid);
1770 if(process == NULL) {
1771 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1772 process = lttv_state_create_process(ts, parent_process, cpu,
1773 pid, g_quark_from_string(command),
1774 &s->parent.timestamp);
1775
1776 /* Keep the stack bottom : a running user mode */
1777 #if 0
1778 /* Disabled because of inconsistencies in the current statedump states. */
1779 if(mode == LTTV_STATE_USER_MODE) {
1780 /* Only keep the bottom */
1781 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1782 } else {
1783 /* On top of it : */
1784 LttvExecutionState *es;
1785 es = process->state = &g_array_index(process->execution_stack,
1786 LttvExecutionState, 1);
1787 es->t = mode;
1788 es->s = status;
1789 es->n = submode;
1790 }
1791 #endif //0
1792
1793 /* UNKNOWN STATE */
1794 {
1795 LttvExecutionState *es;
1796 es = process->state = &g_array_index(process->execution_stack,
1797 LttvExecutionState, 1);
1798 es->t = LTTV_STATE_MODE_UNKNOWN;
1799 es->s = LTTV_STATE_UNNAMED;
1800 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1801 }
1802 } else {
1803 /* The process has already been created :
1804 * Probably was forked while dumping the process state or
1805 * was simply scheduled in prior to get the state dump event.
1806 */
1807 process->ppid = parent_pid;
1808 process->name = g_quark_from_string(command);
1809 /* Don't mess around with the stack, it will eventually become
1810 * ok after the end of state dump. */
1811 }
1812
1813 return FALSE;
1814 }
1815
1816 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1817 {
1818 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1819
1820 lttv_state_add_event_hooks(tss);
1821
1822 return 0;
1823 }
1824
1825 void lttv_state_add_event_hooks(LttvTracesetState *self)
1826 {
1827 LttvTraceset *traceset = self->parent.ts;
1828
1829 guint i, j, k, l, nb_trace, nb_tracefile;
1830
1831 LttvTraceState *ts;
1832
1833 LttvTracefileState *tfs;
1834
1835 GArray *hooks;
1836
1837 LttvTraceHookByFacility *thf;
1838
1839 LttvTraceHook *hook;
1840
1841 LttvAttributeValue val;
1842
1843 gint ret;
1844 gint hn;
1845
1846 nb_trace = lttv_traceset_number(traceset);
1847 for(i = 0 ; i < nb_trace ; i++) {
1848 ts = (LttvTraceState *)self->parent.traces[i];
1849
1850 /* Find the eventtype id for the following events and register the
1851 associated by id hooks. */
1852
1853 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 17);
1854 hooks = g_array_set_size(hooks, 17); // Max possible number of hooks.
1855 hn = 0;
1856
1857 ret = lttv_trace_find_hook(ts->parent.t,
1858 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1859 LTT_FIELD_SYSCALL_ID, 0, 0,
1860 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1861 if(ret) hn--;
1862
1863 ret = lttv_trace_find_hook(ts->parent.t,
1864 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1865 0, 0, 0,
1866 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1867 if(ret) hn--;
1868
1869 ret = lttv_trace_find_hook(ts->parent.t,
1870 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1871 LTT_FIELD_TRAP_ID, 0, 0,
1872 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1873 if(ret) hn--;
1874
1875 ret = lttv_trace_find_hook(ts->parent.t,
1876 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1877 0, 0, 0,
1878 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1879 if(ret) hn--;
1880
1881 ret = lttv_trace_find_hook(ts->parent.t,
1882 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1883 LTT_FIELD_IRQ_ID, 0, 0,
1884 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1885 if(ret) hn--;
1886
1887 ret = lttv_trace_find_hook(ts->parent.t,
1888 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1889 0, 0, 0,
1890 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1891 if(ret) hn--;
1892
1893 ret = lttv_trace_find_hook(ts->parent.t,
1894 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1895 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1896 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1897 if(ret) hn--;
1898
1899 ret = lttv_trace_find_hook(ts->parent.t,
1900 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1901 0, 0, 0,
1902 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1903 if(ret) hn--;
1904
1905 ret = lttv_trace_find_hook(ts->parent.t,
1906 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1907 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1908 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1909 if(ret) hn--;
1910
1911 ret = lttv_trace_find_hook(ts->parent.t,
1912 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1913 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
1914 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1915 if(ret) hn--;
1916
1917 ret = lttv_trace_find_hook(ts->parent.t,
1918 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1919 LTT_FIELD_PID, 0, 0,
1920 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
1921 hn++));
1922 if(ret) hn--;
1923
1924 ret = lttv_trace_find_hook(ts->parent.t,
1925 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1926 LTT_FIELD_PID, 0, 0,
1927 process_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_FREE,
1932 LTT_FIELD_PID, 0, 0,
1933 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1934 if(ret) hn--;
1935
1936 ret = lttv_trace_find_hook(ts->parent.t,
1937 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1938 LTT_FIELD_FILENAME, 0, 0,
1939 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1940 if(ret) hn--;
1941
1942 /* statedump-related hooks */
1943 ret = lttv_trace_find_hook(ts->parent.t,
1944 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1945 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
1946 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1947 if(ret) hn--;
1948
1949 ret = lttv_trace_find_hook(ts->parent.t,
1950 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
1951 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1952 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1953 if(ret) hn--;
1954
1955 ret = lttv_trace_find_hook(ts->parent.t,
1956 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
1957 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
1958 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1959 if(ret) hn--;
1960
1961 hooks = g_array_set_size(hooks, hn);
1962
1963 /* Add these hooks to each event_by_id hooks list */
1964
1965 nb_tracefile = ts->parent.tracefiles->len;
1966
1967 for(j = 0 ; j < nb_tracefile ; j++) {
1968 tfs =
1969 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1970 LttvTracefileContext*, j));
1971
1972 for(k = 0 ; k < hooks->len ; k++) {
1973 hook = &g_array_index(hooks, LttvTraceHook, k);
1974 for(l=0;l<hook->fac_list->len;l++) {
1975 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1976 lttv_hooks_add(
1977 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1978 thf->h,
1979 thf,
1980 LTTV_PRIO_STATE);
1981 }
1982 }
1983 }
1984 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1985 *(val.v_pointer) = hooks;
1986 }
1987 }
1988
1989 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1990 {
1991 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1992
1993 lttv_state_remove_event_hooks(tss);
1994
1995 return 0;
1996 }
1997
1998 void lttv_state_remove_event_hooks(LttvTracesetState *self)
1999 {
2000 LttvTraceset *traceset = self->parent.ts;
2001
2002 guint i, j, k, l, nb_trace, nb_tracefile;
2003
2004 LttvTraceState *ts;
2005
2006 LttvTracefileState *tfs;
2007
2008 GArray *hooks;
2009
2010 LttvTraceHook *hook;
2011
2012 LttvTraceHookByFacility *thf;
2013
2014 LttvAttributeValue val;
2015
2016 nb_trace = lttv_traceset_number(traceset);
2017 for(i = 0 ; i < nb_trace ; i++) {
2018 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2019 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2020 hooks = *(val.v_pointer);
2021
2022 /* Remove these hooks from each event_by_id hooks list */
2023
2024 nb_tracefile = ts->parent.tracefiles->len;
2025
2026 for(j = 0 ; j < nb_tracefile ; j++) {
2027 tfs =
2028 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2029 LttvTracefileContext*, j));
2030
2031 for(k = 0 ; k < hooks->len ; k++) {
2032 hook = &g_array_index(hooks, LttvTraceHook, k);
2033 for(l=0;l<hook->fac_list->len;l++) {
2034 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2035
2036 lttv_hooks_remove_data(
2037 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2038 thf->h,
2039 thf);
2040 }
2041 }
2042 }
2043 for(k = 0 ; k < hooks->len ; k++)
2044 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2045 g_array_free(hooks, TRUE);
2046 }
2047 }
2048
2049 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2050 {
2051 guint *event_count = (guint*)hook_data;
2052
2053 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2054 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2055 return FALSE;
2056 else
2057 *event_count = 0;
2058
2059 LttvTracefileState *self = (LttvTracefileState *)call_data;
2060
2061 LttvTracefileState *tfcs;
2062
2063 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2064
2065 LttEventPosition *ep;
2066
2067 guint i;
2068
2069 LttTracefile *tf;
2070
2071 LttvAttribute *saved_states_tree, *saved_state_tree;
2072
2073 LttvAttributeValue value;
2074
2075 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2076 LTTV_STATE_SAVED_STATES);
2077 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2078 value = lttv_attribute_add(saved_states_tree,
2079 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2080 *(value.v_gobject) = (GObject *)saved_state_tree;
2081 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2082 *(value.v_time) = self->parent.timestamp;
2083 lttv_state_save(tcs, saved_state_tree);
2084 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2085 self->parent.timestamp.tv_nsec);
2086
2087 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2088
2089 return FALSE;
2090 }
2091
2092 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2093 {
2094 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2095
2096 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2097
2098 return FALSE;
2099 }
2100
2101 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2102 {
2103 return tfs->cpu;
2104 }
2105
2106
2107
2108 #if 0
2109 static gboolean block_start(void *hook_data, void *call_data)
2110 {
2111 LttvTracefileState *self = (LttvTracefileState *)call_data;
2112
2113 LttvTracefileState *tfcs;
2114
2115 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2116
2117 LttEventPosition *ep;
2118
2119 guint i, nb_block, nb_event, nb_tracefile;
2120
2121 LttTracefile *tf;
2122
2123 LttvAttribute *saved_states_tree, *saved_state_tree;
2124
2125 LttvAttributeValue value;
2126
2127 ep = ltt_event_position_new();
2128
2129 nb_tracefile = tcs->parent.tracefiles->len;
2130
2131 /* Count the number of events added since the last block end in any
2132 tracefile. */
2133
2134 for(i = 0 ; i < nb_tracefile ; i++) {
2135 tfcs =
2136 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2137 LttvTracefileContext, i));
2138 ltt_event_position(tfcs->parent.e, ep);
2139 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2140 tcs->nb_event += nb_event - tfcs->saved_position;
2141 tfcs->saved_position = nb_event;
2142 }
2143 g_free(ep);
2144
2145 if(tcs->nb_event >= tcs->save_interval) {
2146 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2147 LTTV_STATE_SAVED_STATES);
2148 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2149 value = lttv_attribute_add(saved_states_tree,
2150 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2151 *(value.v_gobject) = (GObject *)saved_state_tree;
2152 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2153 *(value.v_time) = self->parent.timestamp;
2154 lttv_state_save(tcs, saved_state_tree);
2155 tcs->nb_event = 0;
2156 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2157 self->parent.timestamp.tv_nsec);
2158 }
2159 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2160 return FALSE;
2161 }
2162 #endif //0
2163
2164 #if 0
2165 static gboolean block_end(void *hook_data, void *call_data)
2166 {
2167 LttvTracefileState *self = (LttvTracefileState *)call_data;
2168
2169 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2170
2171 LttTracefile *tf;
2172
2173 LttEventPosition *ep;
2174
2175 guint nb_block, nb_event;
2176
2177 ep = ltt_event_position_new();
2178 ltt_event_position(self->parent.e, ep);
2179 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2180 tcs->nb_event += nb_event - self->saved_position + 1;
2181 self->saved_position = 0;
2182 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2183 g_free(ep);
2184
2185 return FALSE;
2186 }
2187 #endif //0
2188 #if 0
2189 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2190 {
2191 LttvTraceset *traceset = self->parent.ts;
2192
2193 guint i, j, nb_trace, nb_tracefile;
2194
2195 LttvTraceState *ts;
2196
2197 LttvTracefileState *tfs;
2198
2199 LttvTraceHook hook_start, hook_end;
2200
2201 nb_trace = lttv_traceset_number(traceset);
2202 for(i = 0 ; i < nb_trace ; i++) {
2203 ts = (LttvTraceState *)self->parent.traces[i];
2204
2205 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2206 NULL, NULL, block_start, &hook_start);
2207 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2208 NULL, NULL, block_end, &hook_end);
2209
2210 nb_tracefile = ts->parent.tracefiles->len;
2211
2212 for(j = 0 ; j < nb_tracefile ; j++) {
2213 tfs =
2214 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2215 LttvTracefileContext, j));
2216 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2217 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2218 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2219 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2220 }
2221 }
2222 }
2223 #endif //0
2224
2225 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2226 {
2227 LttvTraceset *traceset = self->parent.ts;
2228
2229 guint i, j, nb_trace, nb_tracefile;
2230
2231 LttvTraceState *ts;
2232
2233 LttvTracefileState *tfs;
2234
2235
2236 nb_trace = lttv_traceset_number(traceset);
2237 for(i = 0 ; i < nb_trace ; i++) {
2238
2239 ts = (LttvTraceState *)self->parent.traces[i];
2240 nb_tracefile = ts->parent.tracefiles->len;
2241
2242 guint *event_count = g_new(guint, 1);
2243 *event_count = 0;
2244
2245 for(j = 0 ; j < nb_tracefile ; j++) {
2246 tfs =
2247 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2248 LttvTracefileContext*, j));
2249 lttv_hooks_add(tfs->parent.event,
2250 state_save_event_hook,
2251 event_count,
2252 LTTV_PRIO_STATE);
2253
2254 }
2255 }
2256
2257 lttv_process_traceset_begin(&self->parent,
2258 NULL, NULL, NULL, NULL, NULL);
2259
2260 }
2261
2262 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2263 {
2264 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2265
2266 lttv_state_save_add_event_hooks(tss);
2267
2268 return 0;
2269 }
2270
2271
2272 #if 0
2273 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2274 {
2275 LttvTraceset *traceset = self->parent.ts;
2276
2277 guint i, j, nb_trace, nb_tracefile;
2278
2279 LttvTraceState *ts;
2280
2281 LttvTracefileState *tfs;
2282
2283 LttvTraceHook hook_start, hook_end;
2284
2285 nb_trace = lttv_traceset_number(traceset);
2286 for(i = 0 ; i < nb_trace ; i++) {
2287 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2288
2289 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2290 NULL, NULL, block_start, &hook_start);
2291
2292 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2293 NULL, NULL, block_end, &hook_end);
2294
2295 nb_tracefile = ts->parent.tracefiles->len;
2296
2297 for(j = 0 ; j < nb_tracefile ; j++) {
2298 tfs =
2299 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2300 LttvTracefileContext, j));
2301 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2302 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2303 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2304 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2305 }
2306 }
2307 }
2308 #endif //0
2309
2310 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2311 {
2312 LttvTraceset *traceset = self->parent.ts;
2313
2314 guint i, j, nb_trace, nb_tracefile;
2315
2316 LttvTraceState *ts;
2317
2318 LttvTracefileState *tfs;
2319
2320 LttvHooks *after_trace = lttv_hooks_new();
2321
2322 lttv_hooks_add(after_trace,
2323 state_save_after_trace_hook,
2324 NULL,
2325 LTTV_PRIO_STATE);
2326
2327
2328 lttv_process_traceset_end(&self->parent,
2329 NULL, after_trace, NULL, NULL, NULL);
2330
2331 lttv_hooks_destroy(after_trace);
2332
2333 nb_trace = lttv_traceset_number(traceset);
2334 for(i = 0 ; i < nb_trace ; i++) {
2335
2336 ts = (LttvTraceState *)self->parent.traces[i];
2337 nb_tracefile = ts->parent.tracefiles->len;
2338
2339 guint *event_count = NULL;
2340
2341 for(j = 0 ; j < nb_tracefile ; j++) {
2342 tfs =
2343 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2344 LttvTracefileContext*, j));
2345 event_count = lttv_hooks_remove(tfs->parent.event,
2346 state_save_event_hook);
2347 }
2348 if(event_count) g_free(event_count);
2349 }
2350 }
2351
2352 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2353 {
2354 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2355
2356 lttv_state_save_remove_event_hooks(tss);
2357
2358 return 0;
2359 }
2360
2361 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2362 {
2363 LttvTraceset *traceset = self->parent.ts;
2364
2365 guint i, nb_trace;
2366
2367 int min_pos, mid_pos, max_pos;
2368
2369 guint call_rest = 0;
2370
2371 LttvTraceState *tcs;
2372
2373 LttvAttributeValue value;
2374
2375 LttvAttributeType type;
2376
2377 LttvAttributeName name;
2378
2379 gboolean is_named;
2380
2381 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2382
2383 //g_tree_destroy(self->parent.pqueue);
2384 //self->parent.pqueue = g_tree_new(compare_tracefile);
2385
2386 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2387
2388 nb_trace = lttv_traceset_number(traceset);
2389 for(i = 0 ; i < nb_trace ; i++) {
2390 tcs = (LttvTraceState *)self->parent.traces[i];
2391
2392 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2393 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2394 LTTV_STATE_SAVED_STATES);
2395 min_pos = -1;
2396
2397 if(saved_states_tree) {
2398 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2399 mid_pos = max_pos / 2;
2400 while(min_pos < max_pos) {
2401 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
2402 &is_named);
2403 g_assert(type == LTTV_GOBJECT);
2404 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2405 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2406 &value);
2407 g_assert(type == LTTV_TIME);
2408 if(ltt_time_compare(*(value.v_time), t) < 0) {
2409 min_pos = mid_pos;
2410 closest_tree = saved_state_tree;
2411 }
2412 else max_pos = mid_pos - 1;
2413
2414 mid_pos = (min_pos + max_pos + 1) / 2;
2415 }
2416 }
2417
2418 /* restore the closest earlier saved state */
2419 if(min_pos != -1) {
2420 lttv_state_restore(tcs, closest_tree);
2421 call_rest = 1;
2422 }
2423
2424 /* There is no saved state, yet we want to have it. Restart at T0 */
2425 else {
2426 restore_init_state(tcs);
2427 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2428 }
2429 }
2430 /* We want to seek quickly without restoring/updating the state */
2431 else {
2432 restore_init_state(tcs);
2433 lttv_process_trace_seek_time(&(tcs->parent), t);
2434 }
2435 }
2436 if(!call_rest) g_info("NOT Calling restore");
2437 }
2438
2439
2440 static void
2441 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2442 {
2443 }
2444
2445
2446 static void
2447 traceset_state_finalize (LttvTracesetState *self)
2448 {
2449 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2450 finalize(G_OBJECT(self));
2451 }
2452
2453
2454 static void
2455 traceset_state_class_init (LttvTracesetContextClass *klass)
2456 {
2457 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2458
2459 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2460 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2461 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2462 klass->new_traceset_context = new_traceset_context;
2463 klass->new_trace_context = new_trace_context;
2464 klass->new_tracefile_context = new_tracefile_context;
2465 }
2466
2467
2468 GType
2469 lttv_traceset_state_get_type(void)
2470 {
2471 static GType type = 0;
2472 if (type == 0) {
2473 static const GTypeInfo info = {
2474 sizeof (LttvTracesetStateClass),
2475 NULL, /* base_init */
2476 NULL, /* base_finalize */
2477 (GClassInitFunc) traceset_state_class_init, /* class_init */
2478 NULL, /* class_finalize */
2479 NULL, /* class_data */
2480 sizeof (LttvTracesetState),
2481 0, /* n_preallocs */
2482 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2483 NULL /* value handling */
2484 };
2485
2486 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2487 &info, 0);
2488 }
2489 return type;
2490 }
2491
2492
2493 static void
2494 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2495 {
2496 }
2497
2498
2499 static void
2500 trace_state_finalize (LttvTraceState *self)
2501 {
2502 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2503 finalize(G_OBJECT(self));
2504 }
2505
2506
2507 static void
2508 trace_state_class_init (LttvTraceStateClass *klass)
2509 {
2510 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2511
2512 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2513 klass->state_save = state_save;
2514 klass->state_restore = state_restore;
2515 klass->state_saved_free = state_saved_free;
2516 }
2517
2518
2519 GType
2520 lttv_trace_state_get_type(void)
2521 {
2522 static GType type = 0;
2523 if (type == 0) {
2524 static const GTypeInfo info = {
2525 sizeof (LttvTraceStateClass),
2526 NULL, /* base_init */
2527 NULL, /* base_finalize */
2528 (GClassInitFunc) trace_state_class_init, /* class_init */
2529 NULL, /* class_finalize */
2530 NULL, /* class_data */
2531 sizeof (LttvTraceState),
2532 0, /* n_preallocs */
2533 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2534 NULL /* value handling */
2535 };
2536
2537 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2538 "LttvTraceStateType", &info, 0);
2539 }
2540 return type;
2541 }
2542
2543
2544 static void
2545 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2546 {
2547 }
2548
2549
2550 static void
2551 tracefile_state_finalize (LttvTracefileState *self)
2552 {
2553 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2554 finalize(G_OBJECT(self));
2555 }
2556
2557
2558 static void
2559 tracefile_state_class_init (LttvTracefileStateClass *klass)
2560 {
2561 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2562
2563 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2564 }
2565
2566
2567 GType
2568 lttv_tracefile_state_get_type(void)
2569 {
2570 static GType type = 0;
2571 if (type == 0) {
2572 static const GTypeInfo info = {
2573 sizeof (LttvTracefileStateClass),
2574 NULL, /* base_init */
2575 NULL, /* base_finalize */
2576 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2577 NULL, /* class_finalize */
2578 NULL, /* class_data */
2579 sizeof (LttvTracefileState),
2580 0, /* n_preallocs */
2581 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2582 NULL /* value handling */
2583 };
2584
2585 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2586 "LttvTracefileStateType", &info, 0);
2587 }
2588 return type;
2589 }
2590
2591
2592 static void module_init()
2593 {
2594 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
2595 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2596 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2597 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2598 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2599 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2600 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2601 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2602 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2603 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2604 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2605 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2606 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2607 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2608 LTTV_STATE_RUN = g_quark_from_string("RUN");
2609 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2610 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2611 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2612 LTTV_STATE_PROCESS = g_quark_from_string("process");
2613 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2614 LTTV_STATE_EVENT = g_quark_from_string("event");
2615 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2616 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2617 LTTV_STATE_TIME = g_quark_from_string("time");
2618 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2619 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2620 LTTV_STATE_TRACE_STATE_USE_COUNT =
2621 g_quark_from_string("trace_state_use_count");
2622
2623
2624 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2625 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2626 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2627 LTT_FACILITY_FS = g_quark_from_string("fs");
2628 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2629 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
2630
2631
2632 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2633 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2634 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2635 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2636 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2637 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2638 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2639 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2640 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2641 LTT_EVENT_FORK = g_quark_from_string("fork");
2642 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
2643 LTT_EVENT_EXIT = g_quark_from_string("exit");
2644 LTT_EVENT_FREE = g_quark_from_string("free");
2645 LTT_EVENT_EXEC = g_quark_from_string("exec");
2646 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2647 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2648 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
2649
2650
2651 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2652 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2653 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2654 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2655 LTT_FIELD_OUT = g_quark_from_string("out");
2656 LTT_FIELD_IN = g_quark_from_string("in");
2657 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2658 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2659 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2660 LTT_FIELD_PID = g_quark_from_string("pid");
2661 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2662 LTT_FIELD_NAME = g_quark_from_string("name");
2663 LTT_FIELD_MODE = g_quark_from_string("mode");
2664 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2665 LTT_FIELD_STATUS = g_quark_from_string("status");
2666 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2667 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
2668
2669 }
2670
2671 static void module_destroy()
2672 {
2673 }
2674
2675
2676 LTTV_MODULE("state", "State computation", \
2677 "Update the system state, possibly saving it at intervals", \
2678 module_init, module_destroy)
2679
2680
2681
This page took 0.082792 seconds and 5 git commands to generate.