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