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