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