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