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