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