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