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