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