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