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