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