fix precomputed information load
[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 return;
1636 }
1637
1638 if(depth == 1){
1639 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1640 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1641 return;
1642 }
1643
1644 process->execution_stack =
1645 g_array_set_size(process->execution_stack, depth - 1);
1646 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1647 depth - 2);
1648 process->state->change = tfs->parent.timestamp;
1649 }
1650
1651 struct search_result {
1652 const LttTime *time; /* Requested time */
1653 LttTime *best; /* Best result */
1654 };
1655
1656 static gint search_usertrace(gconstpointer a, gconstpointer b)
1657 {
1658 const LttTime *elem_time = (const LttTime*)a;
1659 /* Explicit non const cast */
1660 struct search_result *res = (struct search_result *)b;
1661
1662 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1663 /* The usertrace was created before the schedchange */
1664 /* Get larger keys */
1665 return 1;
1666 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1667 /* The usertrace was created after the schedchange time */
1668 /* Get smaller keys */
1669 if(res->best) {
1670 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1671 res->best = elem_time;
1672 }
1673 } else {
1674 res->best = elem_time;
1675 }
1676 return -1;
1677 }
1678 return 0;
1679 }
1680
1681 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1682 guint pid, const LttTime *timestamp)
1683 {
1684 LttvTracefileState *tfs = NULL;
1685 struct search_result res;
1686 /* Find the usertrace associated with a pid and time interval.
1687 * Search in the usertraces by PID (within a hash) and then, for each
1688 * corresponding element of the array, find the first one with creation
1689 * timestamp the lowest, but higher or equal to "timestamp". */
1690 res.time = timestamp;
1691 res.best = NULL;
1692 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1693 if(usertrace_tree) {
1694 g_tree_search(usertrace_tree, search_usertrace, &res);
1695 if(res.best)
1696 tfs = g_tree_lookup(usertrace_tree, res.best);
1697 }
1698
1699 return tfs;
1700 }
1701
1702
1703 LttvProcessState *
1704 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
1705 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
1706 {
1707 LttvProcessState *process = g_new(LttvProcessState, 1);
1708
1709 LttvExecutionState *es;
1710
1711 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1712
1713 char buffer[128];
1714
1715 process->pid = pid;
1716 process->tgid = tgid;
1717 process->cpu = cpu;
1718 process->name = name;
1719 process->brand = LTTV_STATE_UNBRANDED;
1720 //process->last_cpu = tfs->cpu_name;
1721 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1722 process->type = LTTV_STATE_USER_THREAD;
1723 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1724 process->current_function = 0; //function 0x0 by default.
1725
1726 g_info("Process %u, core %p", process->pid, process);
1727 g_hash_table_insert(tcs->processes, process, process);
1728
1729 if(parent) {
1730 process->ppid = parent->pid;
1731 process->creation_time = *timestamp;
1732 }
1733
1734 /* No parent. This process exists but we are missing all information about
1735 its creation. The birth time is set to zero but we remember the time of
1736 insertion */
1737
1738 else {
1739 process->ppid = 0;
1740 process->creation_time = ltt_time_zero;
1741 }
1742
1743 process->insertion_time = *timestamp;
1744 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1745 process->creation_time.tv_nsec);
1746 process->pid_time = g_quark_from_string(buffer);
1747 process->cpu = cpu;
1748 //process->last_cpu = tfs->cpu_name;
1749 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1750 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1751 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1752 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1753 es = process->state = &g_array_index(process->execution_stack,
1754 LttvExecutionState, 0);
1755 es->t = LTTV_STATE_USER_MODE;
1756 es->n = LTTV_STATE_SUBMODE_NONE;
1757 es->entry = *timestamp;
1758 //g_assert(timestamp->tv_sec != 0);
1759 es->change = *timestamp;
1760 es->cum_cpu_time = ltt_time_zero;
1761 es->s = LTTV_STATE_RUN;
1762
1763 es = process->state = &g_array_index(process->execution_stack,
1764 LttvExecutionState, 1);
1765 es->t = LTTV_STATE_SYSCALL;
1766 es->n = LTTV_STATE_SUBMODE_NONE;
1767 es->entry = *timestamp;
1768 //g_assert(timestamp->tv_sec != 0);
1769 es->change = *timestamp;
1770 es->cum_cpu_time = ltt_time_zero;
1771 es->s = LTTV_STATE_WAIT_FORK;
1772
1773 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1774 process->user_stack = g_array_sized_new(FALSE, FALSE,
1775 sizeof(guint64), 0);
1776
1777 return process;
1778 }
1779
1780 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1781 guint pid)
1782 {
1783 LttvProcessState key;
1784 LttvProcessState *process;
1785
1786 key.pid = pid;
1787 key.cpu = cpu;
1788 process = g_hash_table_lookup(ts->processes, &key);
1789 return process;
1790 }
1791
1792 LttvProcessState *
1793 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1794 const LttTime *timestamp)
1795 {
1796 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1797 LttvExecutionState *es;
1798
1799 /* Put ltt_time_zero creation time for unexisting processes */
1800 if(unlikely(process == NULL)) {
1801 process = lttv_state_create_process(ts,
1802 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
1803 /* We are not sure is it's a kernel thread or normal thread, put the
1804 * bottom stack state to unknown */
1805 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1806 es->t = LTTV_STATE_MODE_UNKNOWN;
1807 }
1808 return process;
1809 }
1810
1811 /* FIXME : this function should be called when we receive an event telling that
1812 * release_task has been called in the kernel. In happens generally when
1813 * the parent waits for its child terminaison, but may also happen in special
1814 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1815 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1816 * of a killed thread ground, but isn't the leader.
1817 */
1818 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1819 {
1820 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1821 LttvProcessState key;
1822
1823 key.pid = process->pid;
1824 key.cpu = process->cpu;
1825 g_hash_table_remove(ts->processes, &key);
1826 g_array_free(process->execution_stack, TRUE);
1827 g_array_free(process->user_stack, TRUE);
1828 g_free(process);
1829 }
1830
1831
1832 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1833 {
1834 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1835 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
1836 g_free(value);
1837 }
1838
1839
1840 static void lttv_state_free_process_table(GHashTable *processes)
1841 {
1842 g_hash_table_foreach(processes, free_process_state, NULL);
1843 g_hash_table_destroy(processes);
1844 }
1845
1846
1847 static gboolean syscall_entry(void *hook_data, void *call_data)
1848 {
1849 LttvTracefileState *s = (LttvTracefileState *)call_data;
1850 guint cpu = s->cpu;
1851 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1852 LttvProcessState *process = ts->running_process[cpu];
1853 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1854 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1855 LttField *f = thf->f1;
1856
1857 LttvExecutionSubmode submode;
1858
1859 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1860 guint syscall = ltt_event_get_unsigned(e, f);
1861
1862 if(syscall < nb_syscalls) {
1863 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1864 syscall];
1865 } else {
1866 /* Fixup an incomplete syscall table */
1867 GString *string = g_string_new("");
1868 g_string_printf(string, "syscall %u", syscall);
1869 submode = g_quark_from_string(string->str);
1870 g_string_free(string, TRUE);
1871 }
1872 /* There can be no system call from PID 0 : unknown state */
1873 if(process->pid != 0)
1874 push_state(s, LTTV_STATE_SYSCALL, submode);
1875 return FALSE;
1876 }
1877
1878
1879 static gboolean syscall_exit(void *hook_data, void *call_data)
1880 {
1881 LttvTracefileState *s = (LttvTracefileState *)call_data;
1882 guint cpu = s->cpu;
1883 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1884 LttvProcessState *process = ts->running_process[cpu];
1885
1886 /* There can be no system call from PID 0 : unknown state */
1887 if(process->pid != 0)
1888 pop_state(s, LTTV_STATE_SYSCALL);
1889 return FALSE;
1890 }
1891
1892
1893 static gboolean trap_entry(void *hook_data, void *call_data)
1894 {
1895 LttvTracefileState *s = (LttvTracefileState *)call_data;
1896 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1897 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1898 LttField *f = thf->f1;
1899
1900 LttvExecutionSubmode submode;
1901
1902 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
1903 guint64 trap = ltt_event_get_long_unsigned(e, f);
1904
1905 if(trap < nb_traps) {
1906 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
1907 } else {
1908 /* Fixup an incomplete trap table */
1909 GString *string = g_string_new("");
1910 g_string_printf(string, "trap %llu", trap);
1911 submode = g_quark_from_string(string->str);
1912 g_string_free(string, TRUE);
1913 }
1914
1915 push_state(s, LTTV_STATE_TRAP, submode);
1916 return FALSE;
1917 }
1918
1919
1920 static gboolean trap_exit(void *hook_data, void *call_data)
1921 {
1922 LttvTracefileState *s = (LttvTracefileState *)call_data;
1923
1924 pop_state(s, LTTV_STATE_TRAP);
1925 return FALSE;
1926 }
1927
1928
1929 static gboolean irq_entry(void *hook_data, void *call_data)
1930 {
1931 LttvTracefileState *s = (LttvTracefileState *)call_data;
1932 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1933 guint8 fac_id = ltt_event_facility_id(e);
1934 guint8 ev_id = ltt_event_eventtype_id(e);
1935 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1936 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1937 g_assert(thf->f1 != NULL);
1938 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1939 LttField *f = thf->f1;
1940
1941 LttvExecutionSubmode submode;
1942
1943 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
1944 ltt_event_get_unsigned(e, f)];
1945
1946 /* Do something with the info about being in user or system mode when int? */
1947 push_state(s, LTTV_STATE_IRQ, submode);
1948 return FALSE;
1949 }
1950
1951 static gboolean soft_irq_exit(void *hook_data, void *call_data)
1952 {
1953 LttvTracefileState *s = (LttvTracefileState *)call_data;
1954
1955 pop_state(s, LTTV_STATE_SOFT_IRQ);
1956 return FALSE;
1957 }
1958
1959
1960
1961 static gboolean irq_exit(void *hook_data, void *call_data)
1962 {
1963 LttvTracefileState *s = (LttvTracefileState *)call_data;
1964
1965 pop_state(s, LTTV_STATE_IRQ);
1966 return FALSE;
1967 }
1968
1969 static gboolean soft_irq_entry(void *hook_data, void *call_data)
1970 {
1971 LttvTracefileState *s = (LttvTracefileState *)call_data;
1972 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1973 guint8 fac_id = ltt_event_facility_id(e);
1974 guint8 ev_id = ltt_event_eventtype_id(e);
1975 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1976 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1977 g_assert(thf->f1 != NULL);
1978 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1979 LttField *f = thf->f1;
1980
1981 LttvExecutionSubmode submode;
1982
1983 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1984 ltt_event_get_long_unsigned(e, f)];
1985
1986 /* Do something with the info about being in user or system mode when int? */
1987 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1988 return FALSE;
1989 }
1990
1991 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
1992 {
1993 guint64 *new_func;
1994
1995 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1996 guint cpu = tfs->cpu;
1997 LttvProcessState *process = ts->running_process[cpu];
1998
1999 guint depth = process->user_stack->len;
2000
2001 process->user_stack =
2002 g_array_set_size(process->user_stack, depth + 1);
2003
2004 new_func = &g_array_index(process->user_stack, guint64, depth);
2005 *new_func = funcptr;
2006 process->current_function = funcptr;
2007 }
2008
2009 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2010 {
2011 guint cpu = tfs->cpu;
2012 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2013 LttvProcessState *process = ts->running_process[cpu];
2014
2015 if(process->current_function != funcptr){
2016 g_info("Different functions (%lu.%09lu): ignore it\n",
2017 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2018 g_info("process state has %llu when pop_function is %llu\n",
2019 process->current_function, funcptr);
2020 g_info("{ %u, %u, %s, %s, %s }\n",
2021 process->pid,
2022 process->ppid,
2023 g_quark_to_string(process->name),
2024 g_quark_to_string(process->brand),
2025 g_quark_to_string(process->state->s));
2026 return;
2027 }
2028 guint depth = process->user_stack->len;
2029
2030 if(depth == 0){
2031 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2032 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2033 return;
2034 }
2035
2036 process->user_stack =
2037 g_array_set_size(process->user_stack, depth - 1);
2038 process->current_function =
2039 g_array_index(process->user_stack, guint64, depth - 2);
2040 }
2041
2042
2043 static gboolean function_entry(void *hook_data, void *call_data)
2044 {
2045 LttvTracefileState *s = (LttvTracefileState *)call_data;
2046 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2047 guint8 fac_id = ltt_event_facility_id(e);
2048 guint8 ev_id = ltt_event_eventtype_id(e);
2049 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2050 g_assert(thf->f1 != NULL);
2051 LttField *f = thf->f1;
2052 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2053
2054 push_function(s, funcptr);
2055 return FALSE;
2056 }
2057
2058 static gboolean function_exit(void *hook_data, void *call_data)
2059 {
2060 LttvTracefileState *s = (LttvTracefileState *)call_data;
2061 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2062 guint8 fac_id = ltt_event_facility_id(e);
2063 guint8 ev_id = ltt_event_eventtype_id(e);
2064 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2065 g_assert(thf->f1 != NULL);
2066 LttField *f = thf->f1;
2067 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2068
2069 LttvExecutionSubmode submode;
2070
2071 pop_function(s, funcptr);
2072 return FALSE;
2073 }
2074
2075 static gboolean schedchange(void *hook_data, void *call_data)
2076 {
2077 LttvTracefileState *s = (LttvTracefileState *)call_data;
2078 guint cpu = s->cpu;
2079 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2080 LttvProcessState *process = ts->running_process[cpu];
2081 LttvProcessState *old_process = ts->running_process[cpu];
2082
2083 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2084 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2085 guint pid_in, pid_out;
2086 gint state_out;
2087
2088 pid_out = ltt_event_get_unsigned(e, thf->f1);
2089 pid_in = ltt_event_get_unsigned(e, thf->f2);
2090 state_out = ltt_event_get_int(e, thf->f3);
2091
2092 if(likely(process != NULL)) {
2093
2094 /* We could not know but it was not the idle process executing.
2095 This should only happen at the beginning, before the first schedule
2096 event, and when the initial information (current process for each CPU)
2097 is missing. It is not obvious how we could, after the fact, compensate
2098 the wrongly attributed statistics. */
2099
2100 //This test only makes sense once the state is known and if there is no
2101 //missing events. We need to silently ignore schedchange coming after a
2102 //process_free, or it causes glitches. (FIXME)
2103 //if(unlikely(process->pid != pid_out)) {
2104 // g_assert(process->pid == 0);
2105 //}
2106 if(process->pid == 0 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2107 /* Scheduling out of pid 0 at beginning of the trace :
2108 * we know for sure it is in syscall mode at this point. */
2109 g_assert(process->execution_stack->len == 1);
2110 process->state->t = LTTV_STATE_SYSCALL;
2111 }
2112 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2113 process->state->s = LTTV_STATE_ZOMBIE;
2114 process->state->change = s->parent.timestamp;
2115 } else {
2116 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2117 else process->state->s = LTTV_STATE_WAIT;
2118 process->state->change = s->parent.timestamp;
2119 }
2120
2121 if(state_out == 32)
2122 exit_process(s, process); /* EXIT_DEAD */
2123 /* see sched.h for states */
2124 }
2125 process = ts->running_process[cpu] =
2126 lttv_state_find_process_or_create(
2127 (LttvTraceState*)s->parent.t_context,
2128 cpu, pid_in,
2129 &s->parent.timestamp);
2130 process->state->s = LTTV_STATE_RUN;
2131 process->cpu = cpu;
2132 if(process->usertrace)
2133 process->usertrace->cpu = cpu;
2134 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2135 process->state->change = s->parent.timestamp;
2136 return FALSE;
2137 }
2138
2139 static gboolean process_fork(void *hook_data, void *call_data)
2140 {
2141 LttvTracefileState *s = (LttvTracefileState *)call_data;
2142 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2143 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2144 guint parent_pid;
2145 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2146 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2147 LttvProcessState *zombie_process;
2148 guint cpu = s->cpu;
2149 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2150 LttvProcessState *process = ts->running_process[cpu];
2151 LttvProcessState *child_process;
2152
2153 /* Parent PID */
2154 parent_pid = ltt_event_get_unsigned(e, thf->f1);
2155
2156 /* Child PID */
2157 child_pid = ltt_event_get_unsigned(e, thf->f2);
2158 s->parent.target_pid = child_pid;
2159
2160 /* Child TGID */
2161 if(thf->f3) child_tgid = ltt_event_get_unsigned(e, thf->f3);
2162 else child_tgid = 0;
2163
2164 /* Mathieu : it seems like the process might have been scheduled in before the
2165 * fork, and, in a rare case, might be the current process. This might happen
2166 * in a SMP case where we don't have enough precision on the clocks.
2167 *
2168 * Test reenabled after precision fixes on time. (Mathieu) */
2169 #if 0
2170 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2171
2172 if(unlikely(zombie_process != NULL)) {
2173 /* Reutilisation of PID. Only now we are sure that the old PID
2174 * has been released. FIXME : should know when release_task happens instead.
2175 */
2176 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2177 guint i;
2178 for(i=0; i< num_cpus; i++) {
2179 g_assert(zombie_process != ts->running_process[i]);
2180 }
2181
2182 exit_process(s, zombie_process);
2183 }
2184 #endif //0
2185 g_assert(process->pid != child_pid);
2186 // FIXME : Add this test in the "known state" section
2187 // g_assert(process->pid == parent_pid);
2188 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2189 if(child_process == NULL) {
2190 child_process = lttv_state_create_process(ts, process, cpu,
2191 child_pid, child_tgid,
2192 LTTV_STATE_UNNAMED, &s->parent.timestamp);
2193 } else {
2194 /* The process has already been created : due to time imprecision between
2195 * multiple CPUs : it has been scheduled in before creation. Note that we
2196 * shouldn't have this kind of imprecision.
2197 *
2198 * Simply put a correct parent.
2199 */
2200 g_assert(0); /* This is a problematic case : the process has been created
2201 before the fork event */
2202 child_process->ppid = process->pid;
2203 child_process->tgid = child_tgid;
2204 }
2205 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2206 child_process->name = process->name;
2207 child_process->brand = process->brand;
2208
2209 return FALSE;
2210 }
2211
2212 /* We stamp a newly created process as kernel_thread */
2213 static gboolean process_kernel_thread(void *hook_data, void *call_data)
2214 {
2215 LttvTracefileState *s = (LttvTracefileState *)call_data;
2216 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2217 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2218 guint pid;
2219 guint cpu = s->cpu;
2220 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2221 LttvProcessState *process;
2222 LttvExecutionState *es;
2223
2224 /* PID */
2225 pid = ltt_event_get_unsigned(e, thf->f1);
2226 s->parent.target_pid = pid;
2227
2228 process = lttv_state_find_process(ts, ANY_CPU, pid);
2229 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2230 es->t = LTTV_STATE_SYSCALL;
2231 process->type = LTTV_STATE_KERNEL_THREAD;
2232
2233 return FALSE;
2234 }
2235
2236 static gboolean process_exit(void *hook_data, void *call_data)
2237 {
2238 LttvTracefileState *s = (LttvTracefileState *)call_data;
2239 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2240 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2241 LttField *f;
2242 guint pid;
2243 guint cpu = s->cpu;
2244 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2245 LttvProcessState *process; // = ts->running_process[cpu];
2246
2247 pid = ltt_event_get_unsigned(e, thf->f1);
2248 s->parent.target_pid = pid;
2249
2250 // FIXME : Add this test in the "known state" section
2251 // g_assert(process->pid == pid);
2252
2253 process = lttv_state_find_process(ts, ANY_CPU, pid);
2254 if(likely(process != NULL)) {
2255 process->state->s = LTTV_STATE_EXIT;
2256 }
2257 return FALSE;
2258 }
2259
2260 static gboolean process_free(void *hook_data, void *call_data)
2261 {
2262 LttvTracefileState *s = (LttvTracefileState *)call_data;
2263 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2264 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2265 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2266 guint release_pid;
2267 LttvProcessState *process;
2268
2269 /* PID of the process to release */
2270 release_pid = ltt_event_get_unsigned(e, thf->f1);
2271 s->parent.target_pid = release_pid;
2272
2273 g_assert(release_pid != 0);
2274
2275 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2276
2277 if(likely(process != NULL)) {
2278 /* release_task is happening at kernel level : we can now safely release
2279 * the data structure of the process */
2280 //This test is fun, though, as it may happen that
2281 //at time t : CPU 0 : process_free
2282 //at time t+150ns : CPU 1 : schedule out
2283 //Clearly due to time imprecision, we disable it. (Mathieu)
2284 //If this weird case happen, we have no choice but to put the
2285 //Currently running process on the cpu to 0.
2286 //I re-enable it following time precision fixes. (Mathieu)
2287 //Well, in the case where an process is freed by a process on another CPU
2288 //and still scheduled, it happens that this is the schedchange that will
2289 //drop the last reference count. Do not free it here!
2290 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2291 guint i;
2292 for(i=0; i< num_cpus; i++) {
2293 //g_assert(process != ts->running_process[i]);
2294 if(process == ts->running_process[i]) {
2295 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2296 break;
2297 }
2298 }
2299 if(i == num_cpus) /* process is not scheduled */
2300 exit_process(s, process);
2301 }
2302
2303 return FALSE;
2304 }
2305
2306
2307 static gboolean process_exec(void *hook_data, void *call_data)
2308 {
2309 LttvTracefileState *s = (LttvTracefileState *)call_data;
2310 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2311 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2312 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2313 //gchar *name;
2314 guint cpu = s->cpu;
2315 LttvProcessState *process = ts->running_process[cpu];
2316
2317 /* PID of the process to release */
2318 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
2319 //name = ltt_event_get_string(e, thf->f1);
2320 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
2321 gchar *name_begin =
2322 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
2323 gchar *null_term_name = g_new(gchar, name_len+1);
2324 memcpy(null_term_name, name_begin, name_len);
2325 null_term_name[name_len] = '\0';
2326
2327 process->name = g_quark_from_string(null_term_name);
2328 process->brand = LTTV_STATE_UNBRANDED;
2329 g_free(null_term_name);
2330 return FALSE;
2331 }
2332
2333 static gboolean thread_brand(void *hook_data, void *call_data)
2334 {
2335 LttvTracefileState *s = (LttvTracefileState *)call_data;
2336 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2337 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2338 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2339 gchar *name;
2340 guint cpu = s->cpu;
2341 LttvProcessState *process = ts->running_process[cpu];
2342
2343 name = ltt_event_get_string(e, thf->f1);
2344 process->brand = g_quark_from_string(name);
2345
2346 return FALSE;
2347 }
2348
2349 static gboolean enum_process_state(void *hook_data, void *call_data)
2350 {
2351 LttvTracefileState *s = (LttvTracefileState *)call_data;
2352 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2353 //It's slow : optimise later by doing this before reading trace.
2354 LttEventType *et = ltt_event_eventtype(e);
2355 //
2356 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2357 guint parent_pid;
2358 guint pid;
2359 guint tgid;
2360 gchar * command;
2361 guint cpu = s->cpu;
2362 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2363 LttvProcessState *process = ts->running_process[cpu];
2364 LttvProcessState *parent_process;
2365 LttField *f4, *f5, *f6, *f7, *f8;
2366 GQuark type, mode, submode, status;
2367 LttvExecutionState *es;
2368
2369 /* PID */
2370 pid = ltt_event_get_unsigned(e, thf->f1);
2371 s->parent.target_pid = pid;
2372
2373 /* Parent PID */
2374 parent_pid = ltt_event_get_unsigned(e, thf->f2);
2375
2376 /* Command name */
2377 command = ltt_event_get_string(e, thf->f3);
2378
2379 /* type */
2380 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
2381 type = ltt_enum_string_get(ltt_field_type(f4),
2382 ltt_event_get_unsigned(e, f4));
2383
2384 /* mode */
2385 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
2386 mode = ltt_enum_string_get(ltt_field_type(f5),
2387 ltt_event_get_unsigned(e, f5));
2388
2389 /* submode */
2390 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
2391 submode = ltt_enum_string_get(ltt_field_type(f6),
2392 ltt_event_get_unsigned(e, f6));
2393
2394 /* status */
2395 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
2396 status = ltt_enum_string_get(ltt_field_type(f7),
2397 ltt_event_get_unsigned(e, f7));
2398
2399 /* TGID */
2400 f8 = ltt_eventtype_field_by_name(et, LTT_FIELD_TGID);
2401 if(f8) tgid = ltt_event_get_unsigned(e, f8);
2402 else tgid = 0;
2403
2404 /* The process might exist if a process was forked while performing the state
2405 * dump. */
2406 process = lttv_state_find_process(ts, ANY_CPU, pid);
2407 if(process == NULL) {
2408 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2409 process = lttv_state_create_process(ts, parent_process, cpu,
2410 pid, tgid, g_quark_from_string(command),
2411 &s->parent.timestamp);
2412
2413 /* Keep the stack bottom : a running user mode */
2414 /* Disabled because of inconsistencies in the current statedump states. */
2415 if(type == LTTV_STATE_KERNEL_THREAD) {
2416 /* Only keep the bottom */
2417 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2418 es = process->state = &g_array_index(process->execution_stack,
2419 LttvExecutionState, 0);
2420 es->t = LTTV_STATE_SYSCALL;
2421 es->s = status;
2422 es->n = submode;
2423 } else {
2424 /* On top of it : */
2425 es = process->state = &g_array_index(process->execution_stack,
2426 LttvExecutionState, 1);
2427 es->t = LTTV_STATE_USER_MODE;
2428 es->s = status;
2429 es->n = submode;
2430 }
2431 #if 0
2432 /* UNKNOWN STATE */
2433 {
2434 es = process->state = &g_array_index(process->execution_stack,
2435 LttvExecutionState, 1);
2436 es->t = LTTV_STATE_MODE_UNKNOWN;
2437 es->s = LTTV_STATE_UNNAMED;
2438 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2439 }
2440 #endif //0
2441 } else {
2442 /* The process has already been created :
2443 * Probably was forked while dumping the process state or
2444 * was simply scheduled in prior to get the state dump event.
2445 * We know for sure if it is a user space thread.
2446 */
2447 process->ppid = parent_pid;
2448 process->tgid = tgid;
2449 process->name = g_quark_from_string(command);
2450 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2451 if(type != LTTV_STATE_KERNEL_THREAD)
2452 es->t = LTTV_STATE_USER_MODE;
2453 /* Don't mess around with the stack, it will eventually become
2454 * ok after the end of state dump. */
2455 }
2456
2457 return FALSE;
2458 }
2459
2460 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
2461 {
2462 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2463
2464 lttv_state_add_event_hooks(tss);
2465
2466 return 0;
2467 }
2468
2469 void lttv_state_add_event_hooks(LttvTracesetState *self)
2470 {
2471 LttvTraceset *traceset = self->parent.ts;
2472
2473 guint i, j, k, l, nb_trace, nb_tracefile;
2474
2475 LttvTraceState *ts;
2476
2477 LttvTracefileState *tfs;
2478
2479 GArray *hooks;
2480
2481 LttvTraceHookByFacility *thf;
2482
2483 LttvTraceHook *hook;
2484
2485 LttvAttributeValue val;
2486
2487 gint ret;
2488 gint hn;
2489
2490 nb_trace = lttv_traceset_number(traceset);
2491 for(i = 0 ; i < nb_trace ; i++) {
2492 ts = (LttvTraceState *)self->parent.traces[i];
2493
2494 /* Find the eventtype id for the following events and register the
2495 associated by id hooks. */
2496
2497 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 18);
2498 hooks = g_array_set_size(hooks, 18); // Max possible number of hooks.
2499 hn = 0;
2500
2501 ret = lttv_trace_find_hook(ts->parent.t,
2502 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
2503 LTT_FIELD_SYSCALL_ID, 0, 0,
2504 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2505 if(ret) hn--;
2506
2507 ret = lttv_trace_find_hook(ts->parent.t,
2508 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
2509 0, 0, 0,
2510 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2511 if(ret) hn--;
2512
2513 ret = lttv_trace_find_hook(ts->parent.t,
2514 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
2515 LTT_FIELD_TRAP_ID, 0, 0,
2516 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2517 if(ret) hn--;
2518
2519 ret = lttv_trace_find_hook(ts->parent.t,
2520 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
2521 0, 0, 0,
2522 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2523 if(ret) hn--;
2524
2525 ret = lttv_trace_find_hook(ts->parent.t,
2526 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
2527 LTT_FIELD_IRQ_ID, 0, 0,
2528 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2529 if(ret) hn--;
2530
2531 ret = lttv_trace_find_hook(ts->parent.t,
2532 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
2533 0, 0, 0,
2534 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2535 if(ret) hn--;
2536
2537 ret = lttv_trace_find_hook(ts->parent.t,
2538 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
2539 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
2540 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2541 if(ret) hn--;
2542
2543 ret = lttv_trace_find_hook(ts->parent.t,
2544 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
2545 0, 0, 0,
2546 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2547 if(ret) hn--;
2548
2549 ret = lttv_trace_find_hook(ts->parent.t,
2550 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
2551 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
2552 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2553 if(ret) hn--;
2554
2555 ret = lttv_trace_find_hook(ts->parent.t,
2556 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
2557 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, LTT_FIELD_TGID,
2558 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2559 if(ret) hn--;
2560
2561 ret = lttv_trace_find_hook(ts->parent.t,
2562 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
2563 LTT_FIELD_PID, 0, 0,
2564 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
2565 hn++));
2566 if(ret) hn--;
2567
2568 ret = lttv_trace_find_hook(ts->parent.t,
2569 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
2570 LTT_FIELD_PID, 0, 0,
2571 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2572 if(ret) hn--;
2573
2574 ret = lttv_trace_find_hook(ts->parent.t,
2575 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
2576 LTT_FIELD_PID, 0, 0,
2577 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2578 if(ret) hn--;
2579
2580 ret = lttv_trace_find_hook(ts->parent.t,
2581 LTT_FACILITY_FS, LTT_EVENT_EXEC,
2582 LTT_FIELD_FILENAME, 0, 0,
2583 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2584 if(ret) hn--;
2585
2586 ret = lttv_trace_find_hook(ts->parent.t,
2587 LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
2588 LTT_FIELD_NAME, 0, 0,
2589 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2590 if(ret) hn--;
2591
2592 /* statedump-related hooks */
2593 ret = lttv_trace_find_hook(ts->parent.t,
2594 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
2595 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
2596 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2597 if(ret) hn--;
2598
2599 ret = lttv_trace_find_hook(ts->parent.t,
2600 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2601 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2602 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2603 if(ret) hn--;
2604
2605 ret = lttv_trace_find_hook(ts->parent.t,
2606 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2607 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2608 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2609 if(ret) hn--;
2610
2611 hooks = g_array_set_size(hooks, hn);
2612
2613 /* Add these hooks to each event_by_id hooks list */
2614
2615 nb_tracefile = ts->parent.tracefiles->len;
2616
2617 for(j = 0 ; j < nb_tracefile ; j++) {
2618 tfs =
2619 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2620 LttvTracefileContext*, j));
2621
2622 for(k = 0 ; k < hooks->len ; k++) {
2623 hook = &g_array_index(hooks, LttvTraceHook, k);
2624 for(l=0;l<hook->fac_list->len;l++) {
2625 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2626 lttv_hooks_add(
2627 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2628 thf->h,
2629 thf,
2630 LTTV_PRIO_STATE);
2631 }
2632 }
2633 }
2634 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2635 *(val.v_pointer) = hooks;
2636 }
2637 }
2638
2639 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2640 {
2641 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2642
2643 lttv_state_remove_event_hooks(tss);
2644
2645 return 0;
2646 }
2647
2648 void lttv_state_remove_event_hooks(LttvTracesetState *self)
2649 {
2650 LttvTraceset *traceset = self->parent.ts;
2651
2652 guint i, j, k, l, nb_trace, nb_tracefile;
2653
2654 LttvTraceState *ts;
2655
2656 LttvTracefileState *tfs;
2657
2658 GArray *hooks;
2659
2660 LttvTraceHook *hook;
2661
2662 LttvTraceHookByFacility *thf;
2663
2664 LttvAttributeValue val;
2665
2666 nb_trace = lttv_traceset_number(traceset);
2667 for(i = 0 ; i < nb_trace ; i++) {
2668 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2669
2670 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2671 hooks = *(val.v_pointer);
2672
2673 /* Remove these hooks from each event_by_id hooks list */
2674
2675 nb_tracefile = ts->parent.tracefiles->len;
2676
2677 for(j = 0 ; j < nb_tracefile ; j++) {
2678 tfs =
2679 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2680 LttvTracefileContext*, j));
2681
2682 for(k = 0 ; k < hooks->len ; k++) {
2683 hook = &g_array_index(hooks, LttvTraceHook, k);
2684 for(l=0;l<hook->fac_list->len;l++) {
2685 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2686
2687 lttv_hooks_remove_data(
2688 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2689 thf->h,
2690 thf);
2691 }
2692 }
2693 }
2694 for(k = 0 ; k < hooks->len ; k++)
2695 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2696 g_array_free(hooks, TRUE);
2697 }
2698 }
2699
2700 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2701 {
2702 guint *event_count = (guint*)hook_data;
2703
2704 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2705 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2706 return FALSE;
2707 else
2708 *event_count = 0;
2709
2710 LttvTracefileState *self = (LttvTracefileState *)call_data;
2711
2712 LttvTracefileState *tfcs;
2713
2714 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2715
2716 LttEventPosition *ep;
2717
2718 guint i;
2719
2720 LttTracefile *tf;
2721
2722 LttvAttribute *saved_states_tree, *saved_state_tree;
2723
2724 LttvAttributeValue value;
2725
2726 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2727 LTTV_STATE_SAVED_STATES);
2728 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2729 value = lttv_attribute_add(saved_states_tree,
2730 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2731 *(value.v_gobject) = (GObject *)saved_state_tree;
2732 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2733 *(value.v_time) = self->parent.timestamp;
2734 lttv_state_save(tcs, saved_state_tree);
2735 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2736 self->parent.timestamp.tv_nsec);
2737
2738 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2739
2740 return FALSE;
2741 }
2742
2743 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2744 {
2745 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2746
2747 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2748
2749 return FALSE;
2750 }
2751
2752 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2753 {
2754 return tfs->cpu;
2755 }
2756
2757
2758
2759 #if 0
2760 static gboolean block_start(void *hook_data, void *call_data)
2761 {
2762 LttvTracefileState *self = (LttvTracefileState *)call_data;
2763
2764 LttvTracefileState *tfcs;
2765
2766 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2767
2768 LttEventPosition *ep;
2769
2770 guint i, nb_block, nb_event, nb_tracefile;
2771
2772 LttTracefile *tf;
2773
2774 LttvAttribute *saved_states_tree, *saved_state_tree;
2775
2776 LttvAttributeValue value;
2777
2778 ep = ltt_event_position_new();
2779
2780 nb_tracefile = tcs->parent.tracefiles->len;
2781
2782 /* Count the number of events added since the last block end in any
2783 tracefile. */
2784
2785 for(i = 0 ; i < nb_tracefile ; i++) {
2786 tfcs =
2787 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
2788 LttvTracefileContext, i));
2789 ltt_event_position(tfcs->parent.e, ep);
2790 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2791 tcs->nb_event += nb_event - tfcs->saved_position;
2792 tfcs->saved_position = nb_event;
2793 }
2794 g_free(ep);
2795
2796 if(tcs->nb_event >= tcs->save_interval) {
2797 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2798 LTTV_STATE_SAVED_STATES);
2799 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2800 value = lttv_attribute_add(saved_states_tree,
2801 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2802 *(value.v_gobject) = (GObject *)saved_state_tree;
2803 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2804 *(value.v_time) = self->parent.timestamp;
2805 lttv_state_save(tcs, saved_state_tree);
2806 tcs->nb_event = 0;
2807 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2808 self->parent.timestamp.tv_nsec);
2809 }
2810 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2811 return FALSE;
2812 }
2813 #endif //0
2814
2815 #if 0
2816 static gboolean block_end(void *hook_data, void *call_data)
2817 {
2818 LttvTracefileState *self = (LttvTracefileState *)call_data;
2819
2820 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2821
2822 LttTracefile *tf;
2823
2824 LttEventPosition *ep;
2825
2826 guint nb_block, nb_event;
2827
2828 ep = ltt_event_position_new();
2829 ltt_event_position(self->parent.e, ep);
2830 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
2831 tcs->nb_event += nb_event - self->saved_position + 1;
2832 self->saved_position = 0;
2833 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2834 g_free(ep);
2835
2836 return FALSE;
2837 }
2838 #endif //0
2839 #if 0
2840 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2841 {
2842 LttvTraceset *traceset = self->parent.ts;
2843
2844 guint i, j, nb_trace, nb_tracefile;
2845
2846 LttvTraceState *ts;
2847
2848 LttvTracefileState *tfs;
2849
2850 LttvTraceHook hook_start, hook_end;
2851
2852 nb_trace = lttv_traceset_number(traceset);
2853 for(i = 0 ; i < nb_trace ; i++) {
2854 ts = (LttvTraceState *)self->parent.traces[i];
2855
2856 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2857 NULL, NULL, block_start, &hook_start);
2858 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2859 NULL, NULL, block_end, &hook_end);
2860
2861 nb_tracefile = ts->parent.tracefiles->len;
2862
2863 for(j = 0 ; j < nb_tracefile ; j++) {
2864 tfs =
2865 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2866 LttvTracefileContext, j));
2867 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2868 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
2869 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
2870 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
2871 }
2872 }
2873 }
2874 #endif //0
2875
2876 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
2877 {
2878 LttvTraceset *traceset = self->parent.ts;
2879
2880 guint i, j, nb_trace, nb_tracefile;
2881
2882 LttvTraceState *ts;
2883
2884 LttvTracefileState *tfs;
2885
2886
2887 nb_trace = lttv_traceset_number(traceset);
2888 for(i = 0 ; i < nb_trace ; i++) {
2889
2890 ts = (LttvTraceState *)self->parent.traces[i];
2891 nb_tracefile = ts->parent.tracefiles->len;
2892
2893 if(ts->has_precomputed_states) continue;
2894
2895 guint *event_count = g_new(guint, 1);
2896 *event_count = 0;
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(tfs->parent.event,
2903 state_save_event_hook,
2904 event_count,
2905 LTTV_PRIO_STATE);
2906
2907 }
2908 }
2909
2910 lttv_process_traceset_begin(&self->parent,
2911 NULL, NULL, NULL, NULL, NULL);
2912
2913 }
2914
2915 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2916 {
2917 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2918
2919 lttv_state_save_add_event_hooks(tss);
2920
2921 return 0;
2922 }
2923
2924
2925 #if 0
2926 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2927 {
2928 LttvTraceset *traceset = self->parent.ts;
2929
2930 guint i, j, nb_trace, nb_tracefile;
2931
2932 LttvTraceState *ts;
2933
2934 LttvTracefileState *tfs;
2935
2936 LttvTraceHook hook_start, hook_end;
2937
2938 nb_trace = lttv_traceset_number(traceset);
2939 for(i = 0 ; i < nb_trace ; i++) {
2940 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2941
2942 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2943 NULL, NULL, block_start, &hook_start);
2944
2945 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
2946 NULL, NULL, block_end, &hook_end);
2947
2948 nb_tracefile = ts->parent.tracefiles->len;
2949
2950 for(j = 0 ; j < nb_tracefile ; j++) {
2951 tfs =
2952 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2953 LttvTracefileContext, j));
2954 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2955 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
2956 lttv_hooks_remove_data(lttv_hooks_by_id_find(
2957 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
2958 }
2959 }
2960 }
2961 #endif //0
2962
2963 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2964 {
2965 LttvTraceset *traceset = self->parent.ts;
2966
2967 guint i, j, nb_trace, nb_tracefile;
2968
2969 LttvTraceState *ts;
2970
2971 LttvTracefileState *tfs;
2972
2973 LttvHooks *after_trace = lttv_hooks_new();
2974
2975 lttv_hooks_add(after_trace,
2976 state_save_after_trace_hook,
2977 NULL,
2978 LTTV_PRIO_STATE);
2979
2980
2981 lttv_process_traceset_end(&self->parent,
2982 NULL, after_trace, NULL, NULL, NULL);
2983
2984 lttv_hooks_destroy(after_trace);
2985
2986 nb_trace = lttv_traceset_number(traceset);
2987 for(i = 0 ; i < nb_trace ; i++) {
2988
2989 ts = (LttvTraceState *)self->parent.traces[i];
2990 nb_tracefile = ts->parent.tracefiles->len;
2991
2992 if(ts->has_precomputed_states) continue;
2993
2994 guint *event_count = NULL;
2995
2996 for(j = 0 ; j < nb_tracefile ; j++) {
2997 tfs =
2998 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2999 LttvTracefileContext*, j));
3000 event_count = lttv_hooks_remove(tfs->parent.event,
3001 state_save_event_hook);
3002 }
3003 if(event_count) g_free(event_count);
3004 }
3005 }
3006
3007 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3008 {
3009 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3010
3011 lttv_state_save_remove_event_hooks(tss);
3012
3013 return 0;
3014 }
3015
3016 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
3017 {
3018 LttvTraceset *traceset = self->parent.ts;
3019
3020 guint i, nb_trace;
3021
3022 int min_pos, mid_pos, max_pos;
3023
3024 guint call_rest = 0;
3025
3026 LttvTraceState *tcs;
3027
3028 LttvAttributeValue value;
3029
3030 LttvAttributeType type;
3031
3032 LttvAttributeName name;
3033
3034 gboolean is_named;
3035
3036 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3037
3038 //g_tree_destroy(self->parent.pqueue);
3039 //self->parent.pqueue = g_tree_new(compare_tracefile);
3040
3041 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3042
3043 nb_trace = lttv_traceset_number(traceset);
3044 for(i = 0 ; i < nb_trace ; i++) {
3045 tcs = (LttvTraceState *)self->parent.traces[i];
3046
3047 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3048 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3049 LTTV_STATE_SAVED_STATES);
3050 min_pos = -1;
3051
3052 if(saved_states_tree) {
3053 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3054 mid_pos = max_pos / 2;
3055 while(min_pos < max_pos) {
3056 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
3057 &is_named);
3058 g_assert(type == LTTV_GOBJECT);
3059 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3060 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3061 &value);
3062 g_assert(type == LTTV_TIME);
3063 if(ltt_time_compare(*(value.v_time), t) < 0) {
3064 min_pos = mid_pos;
3065 closest_tree = saved_state_tree;
3066 }
3067 else max_pos = mid_pos - 1;
3068
3069 mid_pos = (min_pos + max_pos + 1) / 2;
3070 }
3071 }
3072
3073 /* restore the closest earlier saved state */
3074 if(min_pos != -1) {
3075 lttv_state_restore(tcs, closest_tree);
3076 call_rest = 1;
3077 }
3078
3079 /* There is no saved state, yet we want to have it. Restart at T0 */
3080 else {
3081 restore_init_state(tcs);
3082 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
3083 }
3084 }
3085 /* We want to seek quickly without restoring/updating the state */
3086 else {
3087 restore_init_state(tcs);
3088 lttv_process_trace_seek_time(&(tcs->parent), t);
3089 }
3090 }
3091 if(!call_rest) g_info("NOT Calling restore");
3092 }
3093
3094
3095 static void
3096 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3097 {
3098 }
3099
3100
3101 static void
3102 traceset_state_finalize (LttvTracesetState *self)
3103 {
3104 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3105 finalize(G_OBJECT(self));
3106 }
3107
3108
3109 static void
3110 traceset_state_class_init (LttvTracesetContextClass *klass)
3111 {
3112 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3113
3114 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3115 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3116 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3117 klass->new_traceset_context = new_traceset_context;
3118 klass->new_trace_context = new_trace_context;
3119 klass->new_tracefile_context = new_tracefile_context;
3120 }
3121
3122
3123 GType
3124 lttv_traceset_state_get_type(void)
3125 {
3126 static GType type = 0;
3127 if (type == 0) {
3128 static const GTypeInfo info = {
3129 sizeof (LttvTracesetStateClass),
3130 NULL, /* base_init */
3131 NULL, /* base_finalize */
3132 (GClassInitFunc) traceset_state_class_init, /* class_init */
3133 NULL, /* class_finalize */
3134 NULL, /* class_data */
3135 sizeof (LttvTracesetState),
3136 0, /* n_preallocs */
3137 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3138 NULL /* value handling */
3139 };
3140
3141 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3142 &info, 0);
3143 }
3144 return type;
3145 }
3146
3147
3148 static void
3149 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3150 {
3151 }
3152
3153
3154 static void
3155 trace_state_finalize (LttvTraceState *self)
3156 {
3157 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3158 finalize(G_OBJECT(self));
3159 }
3160
3161
3162 static void
3163 trace_state_class_init (LttvTraceStateClass *klass)
3164 {
3165 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3166
3167 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3168 klass->state_save = state_save;
3169 klass->state_restore = state_restore;
3170 klass->state_saved_free = state_saved_free;
3171 }
3172
3173
3174 GType
3175 lttv_trace_state_get_type(void)
3176 {
3177 static GType type = 0;
3178 if (type == 0) {
3179 static const GTypeInfo info = {
3180 sizeof (LttvTraceStateClass),
3181 NULL, /* base_init */
3182 NULL, /* base_finalize */
3183 (GClassInitFunc) trace_state_class_init, /* class_init */
3184 NULL, /* class_finalize */
3185 NULL, /* class_data */
3186 sizeof (LttvTraceState),
3187 0, /* n_preallocs */
3188 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3189 NULL /* value handling */
3190 };
3191
3192 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3193 "LttvTraceStateType", &info, 0);
3194 }
3195 return type;
3196 }
3197
3198
3199 static void
3200 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3201 {
3202 }
3203
3204
3205 static void
3206 tracefile_state_finalize (LttvTracefileState *self)
3207 {
3208 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3209 finalize(G_OBJECT(self));
3210 }
3211
3212
3213 static void
3214 tracefile_state_class_init (LttvTracefileStateClass *klass)
3215 {
3216 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3217
3218 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3219 }
3220
3221
3222 GType
3223 lttv_tracefile_state_get_type(void)
3224 {
3225 static GType type = 0;
3226 if (type == 0) {
3227 static const GTypeInfo info = {
3228 sizeof (LttvTracefileStateClass),
3229 NULL, /* base_init */
3230 NULL, /* base_finalize */
3231 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3232 NULL, /* class_finalize */
3233 NULL, /* class_data */
3234 sizeof (LttvTracefileState),
3235 0, /* n_preallocs */
3236 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3237 NULL /* value handling */
3238 };
3239
3240 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3241 "LttvTracefileStateType", &info, 0);
3242 }
3243 return type;
3244 }
3245
3246
3247 static void module_init()
3248 {
3249 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
3250 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
3251 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3252 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3253 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3254 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3255 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3256 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3257 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3258 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3259 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3260 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3261 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3262 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3263 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3264 LTTV_STATE_RUN = g_quark_from_string("RUN");
3265 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
3266 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3267 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
3268 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3269 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3270 LTTV_STATE_PROCESS = g_quark_from_string("process");
3271 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
3272 LTTV_STATE_EVENT = g_quark_from_string("event");
3273 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
3274 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
3275 LTTV_STATE_TIME = g_quark_from_string("time");
3276 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
3277 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3278 LTTV_STATE_TRACE_STATE_USE_COUNT =
3279 g_quark_from_string("trace_state_use_count");
3280
3281
3282 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
3283 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
3284 LTT_FACILITY_PROCESS = g_quark_from_string("process");
3285 LTT_FACILITY_FS = g_quark_from_string("fs");
3286 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
3287 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
3288
3289
3290 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3291 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3292 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3293 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3294 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3295 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
3296 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
3297 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
3298 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
3299 LTT_EVENT_FORK = g_quark_from_string("fork");
3300 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
3301 LTT_EVENT_EXIT = g_quark_from_string("exit");
3302 LTT_EVENT_FREE = g_quark_from_string("free");
3303 LTT_EVENT_EXEC = g_quark_from_string("exec");
3304 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
3305 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3306 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
3307 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
3308
3309
3310 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3311 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3312 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
3313 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
3314 LTT_FIELD_OUT = g_quark_from_string("out");
3315 LTT_FIELD_IN = g_quark_from_string("in");
3316 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
3317 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3318 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3319 LTT_FIELD_PID = g_quark_from_string("pid");
3320 LTT_FIELD_TGID = g_quark_from_string("tgid");
3321 LTT_FIELD_FILENAME = g_quark_from_string("filename");
3322 LTT_FIELD_NAME = g_quark_from_string("name");
3323 LTT_FIELD_TYPE = g_quark_from_string("type");
3324 LTT_FIELD_MODE = g_quark_from_string("mode");
3325 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3326 LTT_FIELD_STATUS = g_quark_from_string("status");
3327 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3328 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
3329
3330 }
3331
3332 static void module_destroy()
3333 {
3334 }
3335
3336
3337 LTTV_MODULE("state", "State computation", \
3338 "Update the system state, possibly saving it at intervals", \
3339 module_init, module_destroy)
3340
3341
3342
This page took 0.117542 seconds and 4 git commands to generate.