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