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