thread 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
1666 return FALSE;
1667 }
1668
1669 /* We stamp a newly created process as kernel_thread */
1670 static gboolean process_kernel_thread(void *hook_data, void *call_data)
1671 {
1672 LttvTracefileState *s = (LttvTracefileState *)call_data;
1673 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1674 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1675 guint pid;
1676 guint cpu = s->cpu;
1677 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1678 LttvProcessState *process;
1679 LttvExecutionState *es;
1680
1681 /* PID */
1682 pid = ltt_event_get_unsigned(e, thf->f1);
1683
1684 process = lttv_state_find_process(ts, ANY_CPU, pid);
1685 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1686 es->t = LTTV_STATE_SYSCALL;
1687 process->type = LTTV_STATE_KERNEL_THREAD;
1688
1689 return FALSE;
1690 }
1691
1692 static gboolean process_exit(void *hook_data, void *call_data)
1693 {
1694 LttvTracefileState *s = (LttvTracefileState *)call_data;
1695 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1696 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1697 LttField *f;
1698 guint pid;
1699 guint cpu = s->cpu;
1700 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1701 LttvProcessState *process; // = ts->running_process[cpu];
1702
1703 pid = ltt_event_get_unsigned(e, thf->f1);
1704
1705 // FIXME : Add this test in the "known state" section
1706 // g_assert(process->pid == pid);
1707
1708 process = lttv_state_find_process(ts, ANY_CPU, pid);
1709 if(likely(process != NULL)) {
1710 process->state->s = LTTV_STATE_EXIT;
1711 }
1712 return FALSE;
1713 }
1714
1715 static gboolean process_free(void *hook_data, void *call_data)
1716 {
1717 LttvTracefileState *s = (LttvTracefileState *)call_data;
1718 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1719 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1720 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1721 guint release_pid;
1722 LttvProcessState *process;
1723
1724 /* PID of the process to release */
1725 release_pid = ltt_event_get_unsigned(e, thf->f1);
1726
1727 g_assert(release_pid != 0);
1728
1729 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
1730
1731 if(likely(process != NULL)) {
1732 /* release_task is happening at kernel level : we can now safely release
1733 * the data structure of the process */
1734 //This test is fun, though, as it may happen that
1735 //at time t : CPU 0 : process_free
1736 //at time t+150ns : CPU 1 : schedule out
1737 //Clearly due to time imprecision, we disable it. (Mathieu)
1738 //If this weird case happen, we have no choice but to put the
1739 //Currently running process on the cpu to 0.
1740 //I re-enable it following time precision fixes. (Mathieu)
1741 //Well, in the case where an process is freed by a process on another CPU
1742 //and still scheduled, it happens that this is the schedchange that will
1743 //drop the last reference count. Do not free it here!
1744 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1745 guint i;
1746 for(i=0; i< num_cpus; i++) {
1747 //g_assert(process != ts->running_process[i]);
1748 if(process == ts->running_process[i]) {
1749 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1750 break;
1751 }
1752 }
1753 if(i == num_cpus) /* process is not scheduled */
1754 exit_process(s, process);
1755 }
1756
1757 return FALSE;
1758 }
1759
1760
1761 static gboolean process_exec(void *hook_data, void *call_data)
1762 {
1763 LttvTracefileState *s = (LttvTracefileState *)call_data;
1764 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1765 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1766 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1767 //gchar *name;
1768 guint cpu = s->cpu;
1769 LttvProcessState *process = ts->running_process[cpu];
1770
1771 /* PID of the process to release */
1772 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1773 //name = ltt_event_get_string(e, thf->f1);
1774 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1775 gchar *name_begin =
1776 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
1777 gchar *null_term_name = g_new(gchar, name_len+1);
1778 memcpy(null_term_name, name_begin, name_len);
1779 null_term_name[name_len] = '\0';
1780
1781 process->name = g_quark_from_string(null_term_name);
1782 g_free(null_term_name);
1783 return FALSE;
1784 }
1785
1786 static gboolean thread_brand(void *hook_data, void *call_data)
1787 {
1788 LttvTracefileState *s = (LttvTracefileState *)call_data;
1789 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1790 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1791 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1792 gchar *name;
1793 guint cpu = s->cpu;
1794 LttvProcessState *process = ts->running_process[cpu];
1795
1796 name = ltt_event_get_string(e, thf->f1);
1797 process->brand = g_quark_from_string(name);
1798
1799 return FALSE;
1800 }
1801
1802 static gboolean enum_process_state(void *hook_data, void *call_data)
1803 {
1804 LttvTracefileState *s = (LttvTracefileState *)call_data;
1805 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1806 //It's slow : optimise later by doing this before reading trace.
1807 LttEventType *et = ltt_event_eventtype(e);
1808 //
1809 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1810 guint parent_pid;
1811 guint pid;
1812 gchar * command;
1813 guint cpu = s->cpu;
1814 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1815 LttvProcessState *process = ts->running_process[cpu];
1816 LttvProcessState *parent_process;
1817 LttField *f4, *f5, *f6, *f7;
1818 GQuark type, mode, submode, status;
1819 LttvExecutionState *es;
1820
1821 /* PID */
1822 pid = ltt_event_get_unsigned(e, thf->f1);
1823
1824 /* Parent PID */
1825 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1826
1827 /* Command name */
1828 command = ltt_event_get_string(e, thf->f3);
1829
1830 /* type */
1831 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
1832 type = ltt_enum_string_get(ltt_field_type(f4),
1833 ltt_event_get_unsigned(e, f4));
1834
1835 /* mode */
1836 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1837 mode = ltt_enum_string_get(ltt_field_type(f5),
1838 ltt_event_get_unsigned(e, f5));
1839
1840 /* submode */
1841 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1842 submode = ltt_enum_string_get(ltt_field_type(f6),
1843 ltt_event_get_unsigned(e, f6));
1844
1845 /* status */
1846 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1847 status = ltt_enum_string_get(ltt_field_type(f7),
1848 ltt_event_get_unsigned(e, f7));
1849
1850 /* The process might exist if a process was forked while performing the sate dump. */
1851 process = lttv_state_find_process(ts, ANY_CPU, pid);
1852 if(process == NULL) {
1853 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1854 process = lttv_state_create_process(ts, parent_process, cpu,
1855 pid, g_quark_from_string(command),
1856 &s->parent.timestamp);
1857
1858 /* Keep the stack bottom : a running user mode */
1859 /* Disabled because of inconsistencies in the current statedump states. */
1860 if(type == LTTV_STATE_KERNEL_THREAD) {
1861 /* Only keep the bottom */
1862 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1863 es = process->state = &g_array_index(process->execution_stack,
1864 LttvExecutionState, 0);
1865 es->t = LTTV_STATE_SYSCALL;
1866 es->s = status;
1867 es->n = submode;
1868 } else {
1869 /* On top of it : */
1870 es = process->state = &g_array_index(process->execution_stack,
1871 LttvExecutionState, 1);
1872 es->t = LTTV_STATE_USER_MODE;
1873 es->s = status;
1874 es->n = submode;
1875 }
1876 #if 0
1877 /* UNKNOWN STATE */
1878 {
1879 es = process->state = &g_array_index(process->execution_stack,
1880 LttvExecutionState, 1);
1881 es->t = LTTV_STATE_MODE_UNKNOWN;
1882 es->s = LTTV_STATE_UNNAMED;
1883 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1884 }
1885 #endif //0
1886 } else {
1887 /* The process has already been created :
1888 * Probably was forked while dumping the process state or
1889 * was simply scheduled in prior to get the state dump event.
1890 * We know for sure if it is a user space thread.
1891 */
1892 process->ppid = parent_pid;
1893 process->name = g_quark_from_string(command);
1894 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1895 if(type != LTTV_STATE_KERNEL_THREAD)
1896 es->t = LTTV_STATE_USER_MODE;
1897 /* Don't mess around with the stack, it will eventually become
1898 * ok after the end of state dump. */
1899 }
1900
1901 return FALSE;
1902 }
1903
1904 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1905 {
1906 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1907
1908 lttv_state_add_event_hooks(tss);
1909
1910 return 0;
1911 }
1912
1913 void lttv_state_add_event_hooks(LttvTracesetState *self)
1914 {
1915 LttvTraceset *traceset = self->parent.ts;
1916
1917 guint i, j, k, l, nb_trace, nb_tracefile;
1918
1919 LttvTraceState *ts;
1920
1921 LttvTracefileState *tfs;
1922
1923 GArray *hooks;
1924
1925 LttvTraceHookByFacility *thf;
1926
1927 LttvTraceHook *hook;
1928
1929 LttvAttributeValue val;
1930
1931 gint ret;
1932 gint hn;
1933
1934 nb_trace = lttv_traceset_number(traceset);
1935 for(i = 0 ; i < nb_trace ; i++) {
1936 ts = (LttvTraceState *)self->parent.traces[i];
1937
1938 /* Find the eventtype id for the following events and register the
1939 associated by id hooks. */
1940
1941 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 18);
1942 hooks = g_array_set_size(hooks, 18); // Max possible number of hooks.
1943 hn = 0;
1944
1945 ret = lttv_trace_find_hook(ts->parent.t,
1946 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1947 LTT_FIELD_SYSCALL_ID, 0, 0,
1948 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1949 if(ret) hn--;
1950
1951 ret = lttv_trace_find_hook(ts->parent.t,
1952 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
1953 0, 0, 0,
1954 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1955 if(ret) hn--;
1956
1957 ret = lttv_trace_find_hook(ts->parent.t,
1958 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1959 LTT_FIELD_TRAP_ID, 0, 0,
1960 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1961 if(ret) hn--;
1962
1963 ret = lttv_trace_find_hook(ts->parent.t,
1964 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1965 0, 0, 0,
1966 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1967 if(ret) hn--;
1968
1969 ret = lttv_trace_find_hook(ts->parent.t,
1970 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1971 LTT_FIELD_IRQ_ID, 0, 0,
1972 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1973 if(ret) hn--;
1974
1975 ret = lttv_trace_find_hook(ts->parent.t,
1976 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1977 0, 0, 0,
1978 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1979 if(ret) hn--;
1980
1981 ret = lttv_trace_find_hook(ts->parent.t,
1982 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1983 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1984 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1985 if(ret) hn--;
1986
1987 ret = lttv_trace_find_hook(ts->parent.t,
1988 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1989 0, 0, 0,
1990 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1991 if(ret) hn--;
1992
1993 ret = lttv_trace_find_hook(ts->parent.t,
1994 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1995 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
1996 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
1997 if(ret) hn--;
1998
1999 ret = lttv_trace_find_hook(ts->parent.t,
2000 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
2001 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
2002 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2003 if(ret) hn--;
2004
2005 ret = lttv_trace_find_hook(ts->parent.t,
2006 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
2007 LTT_FIELD_PID, 0, 0,
2008 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
2009 hn++));
2010 if(ret) hn--;
2011
2012 ret = lttv_trace_find_hook(ts->parent.t,
2013 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
2014 LTT_FIELD_PID, 0, 0,
2015 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2016 if(ret) hn--;
2017
2018 ret = lttv_trace_find_hook(ts->parent.t,
2019 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
2020 LTT_FIELD_PID, 0, 0,
2021 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2022 if(ret) hn--;
2023
2024 ret = lttv_trace_find_hook(ts->parent.t,
2025 LTT_FACILITY_FS, LTT_EVENT_EXEC,
2026 LTT_FIELD_FILENAME, 0, 0,
2027 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2028 if(ret) hn--;
2029
2030 ret = lttv_trace_find_hook(ts->parent.t,
2031 LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
2032 LTT_FIELD_NAME, 0, 0,
2033 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2034 if(ret) hn--;
2035
2036 /* statedump-related hooks */
2037 ret = lttv_trace_find_hook(ts->parent.t,
2038 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
2039 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
2040 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2041 if(ret) hn--;
2042
2043 ret = lttv_trace_find_hook(ts->parent.t,
2044 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2045 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2046 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2047 if(ret) hn--;
2048
2049 ret = lttv_trace_find_hook(ts->parent.t,
2050 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2051 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2052 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2053 if(ret) hn--;
2054
2055 hooks = g_array_set_size(hooks, hn);
2056
2057 /* Add these hooks to each event_by_id hooks list */
2058
2059 nb_tracefile = ts->parent.tracefiles->len;
2060
2061 for(j = 0 ; j < nb_tracefile ; j++) {
2062 tfs =
2063 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2064 LttvTracefileContext*, j));
2065
2066 for(k = 0 ; k < hooks->len ; k++) {
2067 hook = &g_array_index(hooks, LttvTraceHook, k);
2068 for(l=0;l<hook->fac_list->len;l++) {
2069 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2070 lttv_hooks_add(
2071 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2072 thf->h,
2073 thf,
2074 LTTV_PRIO_STATE);
2075 }
2076 }
2077 }
2078 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2079 *(val.v_pointer) = hooks;
2080 }
2081 }
2082
2083 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2084 {
2085 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2086
2087 lttv_state_remove_event_hooks(tss);
2088
2089 return 0;
2090 }
2091
2092 void lttv_state_remove_event_hooks(LttvTracesetState *self)
2093 {
2094 LttvTraceset *traceset = self->parent.ts;
2095
2096 guint i, j, k, l, nb_trace, nb_tracefile;
2097
2098 LttvTraceState *ts;
2099
2100 LttvTracefileState *tfs;
2101
2102 GArray *hooks;
2103
2104 LttvTraceHook *hook;
2105
2106 LttvTraceHookByFacility *thf;
2107
2108 LttvAttributeValue val;
2109
2110 nb_trace = lttv_traceset_number(traceset);
2111 for(i = 0 ; i < nb_trace ; i++) {
2112 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2113 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2114 hooks = *(val.v_pointer);
2115
2116 /* Remove these hooks from each event_by_id hooks list */
2117
2118 nb_tracefile = ts->parent.tracefiles->len;
2119
2120 for(j = 0 ; j < nb_tracefile ; j++) {
2121 tfs =
2122 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2123 LttvTracefileContext*, j));
2124
2125 for(k = 0 ; k < hooks->len ; k++) {
2126 hook = &g_array_index(hooks, LttvTraceHook, k);
2127 for(l=0;l<hook->fac_list->len;l++) {
2128 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2129
2130 lttv_hooks_remove_data(
2131 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2132 thf->h,
2133 thf);
2134 }
2135 }
2136 }
2137 for(k = 0 ; k < hooks->len ; k++)
2138 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2139 g_array_free(hooks, TRUE);
2140 }
2141 }
2142
2143 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2144 {
2145 guint *event_count = (guint*)hook_data;
2146
2147 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2148 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2149 return FALSE;
2150 else
2151 *event_count = 0;
2152
2153 LttvTracefileState *self = (LttvTracefileState *)call_data;
2154
2155 LttvTracefileState *tfcs;
2156
2157 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2158
2159 LttEventPosition *ep;
2160
2161 guint i;
2162
2163 LttTracefile *tf;
2164
2165 LttvAttribute *saved_states_tree, *saved_state_tree;
2166
2167 LttvAttributeValue value;
2168
2169 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2170 LTTV_STATE_SAVED_STATES);
2171 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2172 value = lttv_attribute_add(saved_states_tree,
2173 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2174 *(value.v_gobject) = (GObject *)saved_state_tree;
2175 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2176 *(value.v_time) = self->parent.timestamp;
2177 lttv_state_save(tcs, saved_state_tree);
2178 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2179 self->parent.timestamp.tv_nsec);
2180
2181 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2182
2183 return FALSE;
2184 }
2185
2186 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2187 {
2188 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2189
2190 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2191
2192 return FALSE;
2193 }
2194
2195 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2196 {
2197 return tfs->cpu;
2198 }
2199
2200
2201
2202 #if 0
2203 static gboolean block_start(void *hook_data, void *call_data)
2204 {
2205 LttvTracefileState *self = (LttvTracefileState *)call_data;
2206
2207 LttvTracefileState *tfcs;
2208
2209 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2210
2211 LttEventPosition *ep;
2212
2213 guint i, nb_block, nb_event, nb_tracefile;
2214
2215 LttTracefile *tf;
2216
2217 LttvAttribute *saved_states_tree, *saved_state_tree;
2218
2219 LttvAttributeValue value;
2220
2221 ep = ltt_event_position_new();
2222
2223 nb_tracefile = tcs->parent.tracefiles->len;
2224
2225 /* Count the number of events added since the last block end in any
2226 tracefile. */
2227
2228 for(i = 0 ; i < nb_tracefile ; i++) {
2229 tfcs =
2230 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2231 LttvTracefileContext, i));
2232 ltt_event_position(tfcs->parent.e, ep);
2233 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2234 tcs->nb_event += nb_event - tfcs->saved_position;
2235 tfcs->saved_position = nb_event;
2236 }
2237 g_free(ep);
2238
2239 if(tcs->nb_event >= tcs->save_interval) {
2240 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2241 LTTV_STATE_SAVED_STATES);
2242 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2243 value = lttv_attribute_add(saved_states_tree,
2244 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2245 *(value.v_gobject) = (GObject *)saved_state_tree;
2246 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2247 *(value.v_time) = self->parent.timestamp;
2248 lttv_state_save(tcs, saved_state_tree);
2249 tcs->nb_event = 0;
2250 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2251 self->parent.timestamp.tv_nsec);
2252 }
2253 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2254 return FALSE;
2255 }
2256 #endif //0
2257
2258 #if 0
2259 static gboolean block_end(void *hook_data, void *call_data)
2260 {
2261 LttvTracefileState *self = (LttvTracefileState *)call_data;
2262
2263 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2264
2265 LttTracefile *tf;
2266
2267 LttEventPosition *ep;
2268
2269 guint nb_block, nb_event;
2270
2271 ep = ltt_event_position_new();
2272 ltt_event_position(self->parent.e, ep);
2273 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2274 tcs->nb_event += nb_event - self->saved_position + 1;
2275 self->saved_position = 0;
2276 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2277 g_free(ep);
2278
2279 return FALSE;
2280 }
2281 #endif //0
2282 #if 0
2283 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2284 {
2285 LttvTraceset *traceset = self->parent.ts;
2286
2287 guint i, j, nb_trace, nb_tracefile;
2288
2289 LttvTraceState *ts;
2290
2291 LttvTracefileState *tfs;
2292
2293 LttvTraceHook hook_start, hook_end;
2294
2295 nb_trace = lttv_traceset_number(traceset);
2296 for(i = 0 ; i < nb_trace ; i++) {
2297 ts = (LttvTraceState *)self->parent.traces[i];
2298
2299 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2300 NULL, NULL, block_start, &hook_start);
2301 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2302 NULL, NULL, block_end, &hook_end);
2303
2304 nb_tracefile = ts->parent.tracefiles->len;
2305
2306 for(j = 0 ; j < nb_tracefile ; j++) {
2307 tfs =
2308 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2309 LttvTracefileContext, j));
2310 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2311 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2312 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2313 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2314 }
2315 }
2316 }
2317 #endif //0
2318
2319 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2320 {
2321 LttvTraceset *traceset = self->parent.ts;
2322
2323 guint i, j, nb_trace, nb_tracefile;
2324
2325 LttvTraceState *ts;
2326
2327 LttvTracefileState *tfs;
2328
2329
2330 nb_trace = lttv_traceset_number(traceset);
2331 for(i = 0 ; i < nb_trace ; i++) {
2332
2333 ts = (LttvTraceState *)self->parent.traces[i];
2334 nb_tracefile = ts->parent.tracefiles->len;
2335
2336 guint *event_count = g_new(guint, 1);
2337 *event_count = 0;
2338
2339 for(j = 0 ; j < nb_tracefile ; j++) {
2340 tfs =
2341 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2342 LttvTracefileContext*, j));
2343 lttv_hooks_add(tfs->parent.event,
2344 state_save_event_hook,
2345 event_count,
2346 LTTV_PRIO_STATE);
2347
2348 }
2349 }
2350
2351 lttv_process_traceset_begin(&self->parent,
2352 NULL, NULL, NULL, NULL, NULL);
2353
2354 }
2355
2356 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2357 {
2358 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2359
2360 lttv_state_save_add_event_hooks(tss);
2361
2362 return 0;
2363 }
2364
2365
2366 #if 0
2367 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2368 {
2369 LttvTraceset *traceset = self->parent.ts;
2370
2371 guint i, j, nb_trace, nb_tracefile;
2372
2373 LttvTraceState *ts;
2374
2375 LttvTracefileState *tfs;
2376
2377 LttvTraceHook hook_start, hook_end;
2378
2379 nb_trace = lttv_traceset_number(traceset);
2380 for(i = 0 ; i < nb_trace ; i++) {
2381 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2382
2383 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2384 NULL, NULL, block_start, &hook_start);
2385
2386 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2387 NULL, NULL, block_end, &hook_end);
2388
2389 nb_tracefile = ts->parent.tracefiles->len;
2390
2391 for(j = 0 ; j < nb_tracefile ; j++) {
2392 tfs =
2393 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2394 LttvTracefileContext, j));
2395 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2396 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2397 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2398 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2399 }
2400 }
2401 }
2402 #endif //0
2403
2404 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2405 {
2406 LttvTraceset *traceset = self->parent.ts;
2407
2408 guint i, j, nb_trace, nb_tracefile;
2409
2410 LttvTraceState *ts;
2411
2412 LttvTracefileState *tfs;
2413
2414 LttvHooks *after_trace = lttv_hooks_new();
2415
2416 lttv_hooks_add(after_trace,
2417 state_save_after_trace_hook,
2418 NULL,
2419 LTTV_PRIO_STATE);
2420
2421
2422 lttv_process_traceset_end(&self->parent,
2423 NULL, after_trace, NULL, NULL, NULL);
2424
2425 lttv_hooks_destroy(after_trace);
2426
2427 nb_trace = lttv_traceset_number(traceset);
2428 for(i = 0 ; i < nb_trace ; i++) {
2429
2430 ts = (LttvTraceState *)self->parent.traces[i];
2431 nb_tracefile = ts->parent.tracefiles->len;
2432
2433 guint *event_count = NULL;
2434
2435 for(j = 0 ; j < nb_tracefile ; j++) {
2436 tfs =
2437 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2438 LttvTracefileContext*, j));
2439 event_count = lttv_hooks_remove(tfs->parent.event,
2440 state_save_event_hook);
2441 }
2442 if(event_count) g_free(event_count);
2443 }
2444 }
2445
2446 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2447 {
2448 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2449
2450 lttv_state_save_remove_event_hooks(tss);
2451
2452 return 0;
2453 }
2454
2455 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
2456 {
2457 LttvTraceset *traceset = self->parent.ts;
2458
2459 guint i, nb_trace;
2460
2461 int min_pos, mid_pos, max_pos;
2462
2463 guint call_rest = 0;
2464
2465 LttvTraceState *tcs;
2466
2467 LttvAttributeValue value;
2468
2469 LttvAttributeType type;
2470
2471 LttvAttributeName name;
2472
2473 gboolean is_named;
2474
2475 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2476
2477 //g_tree_destroy(self->parent.pqueue);
2478 //self->parent.pqueue = g_tree_new(compare_tracefile);
2479
2480 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2481
2482 nb_trace = lttv_traceset_number(traceset);
2483 for(i = 0 ; i < nb_trace ; i++) {
2484 tcs = (LttvTraceState *)self->parent.traces[i];
2485
2486 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2487 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2488 LTTV_STATE_SAVED_STATES);
2489 min_pos = -1;
2490
2491 if(saved_states_tree) {
2492 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2493 mid_pos = max_pos / 2;
2494 while(min_pos < max_pos) {
2495 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
2496 &is_named);
2497 g_assert(type == LTTV_GOBJECT);
2498 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2499 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2500 &value);
2501 g_assert(type == LTTV_TIME);
2502 if(ltt_time_compare(*(value.v_time), t) < 0) {
2503 min_pos = mid_pos;
2504 closest_tree = saved_state_tree;
2505 }
2506 else max_pos = mid_pos - 1;
2507
2508 mid_pos = (min_pos + max_pos + 1) / 2;
2509 }
2510 }
2511
2512 /* restore the closest earlier saved state */
2513 if(min_pos != -1) {
2514 lttv_state_restore(tcs, closest_tree);
2515 call_rest = 1;
2516 }
2517
2518 /* There is no saved state, yet we want to have it. Restart at T0 */
2519 else {
2520 restore_init_state(tcs);
2521 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
2522 }
2523 }
2524 /* We want to seek quickly without restoring/updating the state */
2525 else {
2526 restore_init_state(tcs);
2527 lttv_process_trace_seek_time(&(tcs->parent), t);
2528 }
2529 }
2530 if(!call_rest) g_info("NOT Calling restore");
2531 }
2532
2533
2534 static void
2535 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2536 {
2537 }
2538
2539
2540 static void
2541 traceset_state_finalize (LttvTracesetState *self)
2542 {
2543 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2544 finalize(G_OBJECT(self));
2545 }
2546
2547
2548 static void
2549 traceset_state_class_init (LttvTracesetContextClass *klass)
2550 {
2551 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2552
2553 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2554 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2555 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2556 klass->new_traceset_context = new_traceset_context;
2557 klass->new_trace_context = new_trace_context;
2558 klass->new_tracefile_context = new_tracefile_context;
2559 }
2560
2561
2562 GType
2563 lttv_traceset_state_get_type(void)
2564 {
2565 static GType type = 0;
2566 if (type == 0) {
2567 static const GTypeInfo info = {
2568 sizeof (LttvTracesetStateClass),
2569 NULL, /* base_init */
2570 NULL, /* base_finalize */
2571 (GClassInitFunc) traceset_state_class_init, /* class_init */
2572 NULL, /* class_finalize */
2573 NULL, /* class_data */
2574 sizeof (LttvTracesetState),
2575 0, /* n_preallocs */
2576 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2577 NULL /* value handling */
2578 };
2579
2580 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2581 &info, 0);
2582 }
2583 return type;
2584 }
2585
2586
2587 static void
2588 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2589 {
2590 }
2591
2592
2593 static void
2594 trace_state_finalize (LttvTraceState *self)
2595 {
2596 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2597 finalize(G_OBJECT(self));
2598 }
2599
2600
2601 static void
2602 trace_state_class_init (LttvTraceStateClass *klass)
2603 {
2604 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2605
2606 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2607 klass->state_save = state_save;
2608 klass->state_restore = state_restore;
2609 klass->state_saved_free = state_saved_free;
2610 }
2611
2612
2613 GType
2614 lttv_trace_state_get_type(void)
2615 {
2616 static GType type = 0;
2617 if (type == 0) {
2618 static const GTypeInfo info = {
2619 sizeof (LttvTraceStateClass),
2620 NULL, /* base_init */
2621 NULL, /* base_finalize */
2622 (GClassInitFunc) trace_state_class_init, /* class_init */
2623 NULL, /* class_finalize */
2624 NULL, /* class_data */
2625 sizeof (LttvTraceState),
2626 0, /* n_preallocs */
2627 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2628 NULL /* value handling */
2629 };
2630
2631 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2632 "LttvTraceStateType", &info, 0);
2633 }
2634 return type;
2635 }
2636
2637
2638 static void
2639 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2640 {
2641 }
2642
2643
2644 static void
2645 tracefile_state_finalize (LttvTracefileState *self)
2646 {
2647 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2648 finalize(G_OBJECT(self));
2649 }
2650
2651
2652 static void
2653 tracefile_state_class_init (LttvTracefileStateClass *klass)
2654 {
2655 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2656
2657 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2658 }
2659
2660
2661 GType
2662 lttv_tracefile_state_get_type(void)
2663 {
2664 static GType type = 0;
2665 if (type == 0) {
2666 static const GTypeInfo info = {
2667 sizeof (LttvTracefileStateClass),
2668 NULL, /* base_init */
2669 NULL, /* base_finalize */
2670 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2671 NULL, /* class_finalize */
2672 NULL, /* class_data */
2673 sizeof (LttvTracefileState),
2674 0, /* n_preallocs */
2675 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2676 NULL /* value handling */
2677 };
2678
2679 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2680 "LttvTracefileStateType", &info, 0);
2681 }
2682 return type;
2683 }
2684
2685
2686 static void module_init()
2687 {
2688 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
2689 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
2690 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2691 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2692 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2693 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2694 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2695 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2696 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2697 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2698 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2699 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2700 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2701 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2702 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2703 LTTV_STATE_RUN = g_quark_from_string("RUN");
2704 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
2705 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
2706 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
2707 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2708 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2709 LTTV_STATE_PROCESS = g_quark_from_string("process");
2710 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
2711 LTTV_STATE_EVENT = g_quark_from_string("event");
2712 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
2713 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
2714 LTTV_STATE_TIME = g_quark_from_string("time");
2715 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
2716 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2717 LTTV_STATE_TRACE_STATE_USE_COUNT =
2718 g_quark_from_string("trace_state_use_count");
2719
2720
2721 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2722 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
2723 LTT_FACILITY_PROCESS = g_quark_from_string("process");
2724 LTT_FACILITY_FS = g_quark_from_string("fs");
2725 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
2726 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
2727
2728
2729 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2730 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2731 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2732 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2733 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2734 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2735 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2736 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
2737 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2738 LTT_EVENT_FORK = g_quark_from_string("fork");
2739 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
2740 LTT_EVENT_EXIT = g_quark_from_string("exit");
2741 LTT_EVENT_FREE = g_quark_from_string("free");
2742 LTT_EVENT_EXEC = g_quark_from_string("exec");
2743 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
2744 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
2745 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
2746 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
2747
2748
2749 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2750 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2751 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2752 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
2753 LTT_FIELD_OUT = g_quark_from_string("out");
2754 LTT_FIELD_IN = g_quark_from_string("in");
2755 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2756 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2757 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2758 LTT_FIELD_PID = g_quark_from_string("pid");
2759 LTT_FIELD_FILENAME = g_quark_from_string("filename");
2760 LTT_FIELD_NAME = g_quark_from_string("name");
2761 LTT_FIELD_TYPE = g_quark_from_string("type");
2762 LTT_FIELD_MODE = g_quark_from_string("mode");
2763 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2764 LTT_FIELD_STATUS = g_quark_from_string("status");
2765 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
2766 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
2767
2768 }
2769
2770 static void module_destroy()
2771 {
2772 }
2773
2774
2775 LTTV_MODULE("state", "State computation", \
2776 "Update the system state, possibly saving it at intervals", \
2777 module_init, module_destroy)
2778
2779
2780
This page took 0.086759 seconds and 4 git commands to generate.