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