fix a segfault in LTTV (temporary solution)
[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++) {
1158 g_array_free(states[i].mode_stack, FALSE);
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++) {
1187 g_array_free(states[i].mode_stack, FALSE);
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{
1224 g_array_free(bds->mode_stack, FALSE);
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)
d3d99fde 2568 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
44ffb95f 2569 else
d3d99fde 2570 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
44ffb95f 2571
dc877563 2572 return FALSE;
2573}
2574
eed2ef37 2575static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2576{
eed2ef37 2577 LttvTracefileState *s = (LttvTracefileState *)call_data;
2578 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2579 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2580 guint parent_pid;
fcc08e1e 2581 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2582 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
0ceef9de 2583 //LttvProcessState *zombie_process;
ae3d0f50 2584 guint cpu = s->cpu;
348c6ba8 2585 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2586 LttvProcessState *process = ts->running_process[cpu];
26275aa2 2587 LttvProcessState *child_process;
d3a66443 2588 struct marker_field *f;
2cdc690b 2589
eed2ef37 2590 /* Parent PID */
d3a66443 2591 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
eed2ef37 2592
2cdc690b 2593 /* Child PID */
d3a66443 2594 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
33bdc8dd 2595 s->parent.target_pid = child_pid;
2cdc690b 2596
fcc08e1e 2597 /* Child TGID */
d3a66443 2598 f = lttv_trace_get_hook_field(th, 2);
2599 if (likely(f))
2600 child_tgid = ltt_event_get_unsigned(e, f);
2601 else
2602 child_tgid = 0;
fcc08e1e 2603
15b3d537 2604 /* Mathieu : it seems like the process might have been scheduled in before the
2605 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 2606 * in a SMP case where we don't have enough precision on the clocks.
2607 *
2608 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2609#if 0
348c6ba8 2610 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 2611
1d1df11d 2612 if(unlikely(zombie_process != NULL)) {
4ad73431 2613 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 2614 * has been released. FIXME : should know when release_task happens instead.
4ad73431 2615 */
15b3d537 2616 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2617 guint i;
2618 for(i=0; i< num_cpus; i++) {
5ac05980 2619 g_assert(zombie_process != ts->running_process[i]);
15b3d537 2620 }
2621
4ad73431 2622 exit_process(s, zombie_process);
2623 }
791dffa6 2624#endif //0
348c6ba8 2625 g_assert(process->pid != child_pid);
eed2ef37 2626 // FIXME : Add this test in the "known state" section
348c6ba8 2627 // g_assert(process->pid == parent_pid);
26275aa2 2628 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2629 if(child_process == NULL) {
ab893fb1 2630 child_process = lttv_state_create_process(ts, process, cpu,
fcc08e1e 2631 child_pid, child_tgid,
2632 LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 2633 } else {
2634 /* The process has already been created : due to time imprecision between
791dffa6 2635 * multiple CPUs : it has been scheduled in before creation. Note that we
2636 * shouldn't have this kind of imprecision.
26275aa2 2637 *
2638 * Simply put a correct parent.
2639 */
6806b3c6 2640 g_assert(0); /* This is a problematic case : the process has been created
2641 before the fork event */
26275aa2 2642 child_process->ppid = process->pid;
fcc08e1e 2643 child_process->tgid = child_tgid;
26275aa2 2644 }
0292757b 2645 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2646 child_process->name = process->name;
2647 child_process->brand = process->brand;
4ad73431 2648
dc877563 2649 return FALSE;
2650}
2651
89f8741a 2652/* We stamp a newly created process as kernel_thread.
2653 * The thread should not be running yet. */
7bfd7820 2654static gboolean process_kernel_thread(void *hook_data, void *call_data)
2655{
2656 LttvTracefileState *s = (LttvTracefileState *)call_data;
2657 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2658 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7bfd7820 2659 guint pid;
7bfd7820 2660 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2661 LttvProcessState *process;
2662 LttvExecutionState *es;
2663
2664 /* PID */
d3a66443 2665 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2666 s->parent.target_pid = pid;
7bfd7820 2667
61c8808e 2668 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2669 &ltt_time_zero);
15f3a340 2670 process->execution_stack =
2671 g_array_set_size(process->execution_stack, 1);
2672 es = process->state =
2673 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2674 es->t = LTTV_STATE_SYSCALL;
2675 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 2676
80e0221b 2677 return FALSE;
7bfd7820 2678}
dc877563 2679
eed2ef37 2680static gboolean process_exit(void *hook_data, void *call_data)
dc877563 2681{
eed2ef37 2682 LttvTracefileState *s = (LttvTracefileState *)call_data;
2683 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2684 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2685 guint pid;
348c6ba8 2686 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
6f54e0f4 2687 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 2688
d3a66443 2689 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2690 s->parent.target_pid = pid;
eed2ef37 2691
2692 // FIXME : Add this test in the "known state" section
348c6ba8 2693 // g_assert(process->pid == pid);
eed2ef37 2694
6f54e0f4 2695 process = lttv_state_find_process(ts, ANY_CPU, pid);
348c6ba8 2696 if(likely(process != NULL)) {
2697 process->state->s = LTTV_STATE_EXIT;
2cdc690b 2698 }
2699 return FALSE;
2cdc690b 2700}
2701
eed2ef37 2702static gboolean process_free(void *hook_data, void *call_data)
2da61677 2703{
eed2ef37 2704 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 2705 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 2706 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2707 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2da61677 2708 guint release_pid;
2709 LttvProcessState *process;
2710
2711 /* PID of the process to release */
d3a66443 2712 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2713 s->parent.target_pid = release_pid;
15b3d537 2714
2715 g_assert(release_pid != 0);
2da61677 2716
348c6ba8 2717 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 2718
2719 if(likely(process != NULL)) {
2720 /* release_task is happening at kernel level : we can now safely release
2721 * the data structure of the process */
5562ddce 2722 //This test is fun, though, as it may happen that
2723 //at time t : CPU 0 : process_free
2724 //at time t+150ns : CPU 1 : schedule out
2725 //Clearly due to time imprecision, we disable it. (Mathieu)
2726 //If this weird case happen, we have no choice but to put the
2727 //Currently running process on the cpu to 0.
791dffa6 2728 //I re-enable it following time precision fixes. (Mathieu)
2729 //Well, in the case where an process is freed by a process on another CPU
2730 //and still scheduled, it happens that this is the schedchange that will
2731 //drop the last reference count. Do not free it here!
0bd2f89c 2732 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2733 guint i;
2734 for(i=0; i< num_cpus; i++) {
5562ddce 2735 //g_assert(process != ts->running_process[i]);
2736 if(process == ts->running_process[i]) {
791dffa6 2737 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2738 break;
5562ddce 2739 }
0bd2f89c 2740 }
6f54e0f4 2741 if(i == num_cpus) /* process is not scheduled */
2742 exit_process(s, process);
2da61677 2743 }
2744
2745 return FALSE;
2746}
2747
f4b88a7d 2748
2749static gboolean process_exec(void *hook_data, void *call_data)
2750{
2751 LttvTracefileState *s = (LttvTracefileState *)call_data;
2752 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2753 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2754 LttvTraceHook *th = (LttvTraceHook *)hook_data;
743e50fd 2755 //gchar *name;
ae3d0f50 2756 guint cpu = s->cpu;
f4b88a7d 2757 LttvProcessState *process = ts->running_process[cpu];
2758
f63ebe51 2759#if 0//how to use a sequence that must be transformed in a string
f4b88a7d 2760 /* PID of the process to release */
d3a66443 2761 guint64 name_len = ltt_event_field_element_number(e,
2762 lttv_trace_get_hook_field(th, 0));
2763 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2764 LttField *child = ltt_event_field_element_select(e,
2765 lttv_trace_get_hook_field(th, 0), 0);
f2923fb2 2766 gchar *name_begin =
2767 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 2768 gchar *null_term_name = g_new(gchar, name_len+1);
2769 memcpy(null_term_name, name_begin, name_len);
2770 null_term_name[name_len] = '\0';
743e50fd 2771 process->name = g_quark_from_string(null_term_name);
f63ebe51 2772#endif //0
2773
d3a66443 2774 process->name = g_quark_from_string(ltt_event_get_string(e,
2775 lttv_trace_get_hook_field(th, 0)));
0292757b 2776 process->brand = LTTV_STATE_UNBRANDED;
f63ebe51 2777 //g_free(null_term_name);
f4b88a7d 2778 return FALSE;
2779}
2780
7b5f6cf1 2781static gboolean thread_brand(void *hook_data, void *call_data)
2782{
2783 LttvTracefileState *s = (LttvTracefileState *)call_data;
2784 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2785 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2786 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7b5f6cf1 2787 gchar *name;
2788 guint cpu = s->cpu;
2789 LttvProcessState *process = ts->running_process[cpu];
2790
d3a66443 2791 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
7b5f6cf1 2792 process->brand = g_quark_from_string(name);
2793
2794 return FALSE;
2795}
2796
c3b3b60b 2797static void fix_process(gpointer key, gpointer value,
2798 gpointer user_data)
2799{
2800 LttvProcessState *process;
2801 LttvExecutionState *es;
2802 process = (LttvProcessState *)value;
c3b3b60b 2803 LttTime *timestamp = (LttTime*)user_data;
2804
c3b3b60b 2805 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2b25224d 2806 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2807 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2808 es->t = LTTV_STATE_SYSCALL;
2b25224d 2809 es->n = LTTV_STATE_SUBMODE_NONE;
2810 es->entry = *timestamp;
2811 es->change = *timestamp;
2812 es->cum_cpu_time = ltt_time_zero;
c4a72569 2813 if(es->s == LTTV_STATE_UNNAMED)
2814 es->s = LTTV_STATE_WAIT;
c3b3b60b 2815 }
2816 } else {
2b25224d 2817 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2818 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
c3b3b60b 2819 es->t = LTTV_STATE_USER_MODE;
2820 es->n = LTTV_STATE_SUBMODE_NONE;
2821 es->entry = *timestamp;
2822 //g_assert(timestamp->tv_sec != 0);
2823 es->change = *timestamp;
2824 es->cum_cpu_time = ltt_time_zero;
c4a72569 2825 if(es->s == LTTV_STATE_UNNAMED)
2826 es->s = LTTV_STATE_RUN;
c3b3b60b 2827
2b25224d 2828 if(process->execution_stack->len == 1) {
89f8741a 2829 /* Still in bottom unknown mode, means never did a system call
2830 * May be either in user mode, syscall mode, running or waiting.*/
2831 /* FIXME : we may be tagging syscall mode when being user mode */
2b25224d 2832 process->execution_stack =
2833 g_array_set_size(process->execution_stack, 2);
2834 es = process->state = &g_array_index(process->execution_stack,
c3b3b60b 2835 LttvExecutionState, 1);
2b25224d 2836 es->t = LTTV_STATE_SYSCALL;
2837 es->n = LTTV_STATE_SUBMODE_NONE;
2838 es->entry = *timestamp;
2839 //g_assert(timestamp->tv_sec != 0);
2840 es->change = *timestamp;
2841 es->cum_cpu_time = ltt_time_zero;
b59b7222 2842 if(es->s == LTTV_STATE_WAIT_FORK)
2843 es->s = LTTV_STATE_WAIT;
2b25224d 2844 }
c3b3b60b 2845 }
2846 }
2847}
2848
2849static gboolean statedump_end(void *hook_data, void *call_data)
2850{
2851 LttvTracefileState *s = (LttvTracefileState *)call_data;
2852 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2853 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
0ceef9de 2854 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2855 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
c3b3b60b 2856
2857 /* For all processes */
2858 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2859 /* else, if stack[0] is unknown, set to user mode, running */
2860
2861 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
0ceef9de 2862
2863 return FALSE;
c3b3b60b 2864}
2865
b3fd4c02 2866static gboolean enum_process_state(void *hook_data, void *call_data)
2867{
2868 LttvTracefileState *s = (LttvTracefileState *)call_data;
2869 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
80e0221b 2870 //It's slow : optimise later by doing this before reading trace.
0ceef9de 2871 LttvTraceHook *th = (LttvTraceHook *)hook_data;
b3fd4c02 2872 guint parent_pid;
2873 guint pid;
fcc08e1e 2874 guint tgid;
b3fd4c02 2875 gchar * command;
ae3d0f50 2876 guint cpu = s->cpu;
b3fd4c02 2877 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2878 LttvProcessState *process = ts->running_process[cpu];
2879 LttvProcessState *parent_process;
d3a66443 2880 struct marker_field *f;
80e0221b 2881 GQuark type, mode, submode, status;
2882 LttvExecutionState *es;
c4a72569 2883 guint i, nb_cpus;
f4b88a7d 2884
b3fd4c02 2885 /* PID */
d3a66443 2886 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
e38d9ea0 2887 s->parent.target_pid = pid;
2888
b3fd4c02 2889 /* Parent PID */
d3a66443 2890 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
b3fd4c02 2891
2892 /* Command name */
d3a66443 2893 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
b3fd4c02 2894
80e0221b 2895 /* type */
d3a66443 2896 f = lttv_trace_get_hook_field(th, 3);
deb8b4b2 2897 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 2898
b0b1c1dd 2899 //FIXME: type is rarely used, enum must match possible types.
2900
80e0221b 2901 /* mode */
d3a66443 2902 f = lttv_trace_get_hook_field(th, 4);
deb8b4b2 2903 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
b3fd4c02 2904
80e0221b 2905 /* submode */
d3a66443 2906 f = lttv_trace_get_hook_field(th, 5);
deb8b4b2 2907 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 2908
80e0221b 2909 /* status */
d3a66443 2910 f = lttv_trace_get_hook_field(th, 6);
deb8b4b2 2911 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
e62e7f3a 2912
fcc08e1e 2913 /* TGID */
d3a66443 2914 f = lttv_trace_get_hook_field(th, 7);
2915 if(f)
2916 tgid = ltt_event_get_unsigned(e, f);
2917 else
2918 tgid = 0;
c4a72569 2919
2920 if(pid == 0) {
2921 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2922 for(i=0; i<nb_cpus; i++) {
2923 process = lttv_state_find_process(ts, i, pid);
2924 g_assert(process != NULL);
2925
2926 process->ppid = parent_pid;
2927 process->tgid = tgid;
2928 process->name = g_quark_from_string(command);
2929 es =
2930 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2931 process->type = LTTV_STATE_KERNEL_THREAD;
c4a72569 2932 }
2933
2934 } else {
2935 /* The process might exist if a process was forked while performing the
2936 * state dump. */
2937 process = lttv_state_find_process(ts, ANY_CPU, pid);
2938 if(process == NULL) {
2939 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2940 process = lttv_state_create_process(ts, parent_process, cpu,
2941 pid, tgid, g_quark_from_string(command),
2942 &s->parent.timestamp);
2943
2944 /* Keep the stack bottom : a running user mode */
2945 /* Disabled because of inconsistencies in the current statedump states. */
2946 if(type == LTTV_STATE_KERNEL_THREAD) {
2947 /* Only keep the bottom
2948 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2949 /* Will cause expected trap when in fact being syscall (even after end of
2950 * statedump event)
2951 * Will cause expected interrupt when being syscall. (only before end of
2952 * statedump event) */
2953 // This will cause a "popping last state on stack, ignoring it."
2954 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2955 es = process->state = &g_array_index(process->execution_stack,
2956 LttvExecutionState, 0);
2957 process->type = LTTV_STATE_KERNEL_THREAD;
2958 es->t = LTTV_STATE_MODE_UNKNOWN;
2959 es->s = LTTV_STATE_UNNAMED;
2960 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2961 #if 0
2962 es->t = LTTV_STATE_SYSCALL;
2963 es->s = status;
2964 es->n = submode;
2965 #endif //0
2966 } else {
2967 /* User space process :
2968 * bottom : user mode
2969 * either currently running or scheduled out.
2970 * can be scheduled out because interrupted in (user mode or in syscall)
2971 * or because of an explicit call to the scheduler in syscall. Note that
2972 * the scheduler call comes after the irq_exit, so never in interrupt
2973 * context. */
2974 // temp workaround : set size to 1 : only have user mode bottom of stack.
2975 // will cause g_info message of expected syscall mode when in fact being
2976 // in user mode. Can also cause expected trap when in fact being user
2977 // mode in the event of a page fault reenabling interrupts in the handler.
2978 // Expected syscall and trap can also happen after the end of statedump
2979 // This will cause a "popping last state on stack, ignoring it."
2980 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2981 es = process->state = &g_array_index(process->execution_stack,
2982 LttvExecutionState, 0);
2983 es->t = LTTV_STATE_MODE_UNKNOWN;
2984 es->s = LTTV_STATE_UNNAMED;
2985 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2986 #if 0
2987 es->t = LTTV_STATE_USER_MODE;
2988 es->s = status;
2989 es->n = submode;
2990 #endif //0
2991 }
2992 #if 0
2993 /* UNKNOWN STATE */
2994 {
2995 es = process->state = &g_array_index(process->execution_stack,
2996 LttvExecutionState, 1);
2997 es->t = LTTV_STATE_MODE_UNKNOWN;
2998 es->s = LTTV_STATE_UNNAMED;
2999 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3000 }
3001 #endif //0
80e0221b 3002 } else {
c4a72569 3003 /* The process has already been created :
3004 * Probably was forked while dumping the process state or
3005 * was simply scheduled in prior to get the state dump event.
3006 */
3007 process->ppid = parent_pid;
3008 process->tgid = tgid;
3009 process->name = g_quark_from_string(command);
3010 process->type = type;
3011 es =
3012 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 3013#if 0
c4a72569 3014 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3015 if(type == LTTV_STATE_KERNEL_THREAD)
3016 es->t = LTTV_STATE_SYSCALL;
3017 else
3018 es->t = LTTV_STATE_USER_MODE;
3019 }
cab321cf 3020#endif //0
c4a72569 3021 /* Don't mess around with the stack, it will eventually become
3022 * ok after the end of state dump. */
80e0221b 3023 }
b3fd4c02 3024 }
3025
3026 return FALSE;
3027}
f4b88a7d 3028
58c88a41 3029gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3030{
3031 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3032
3033 lttv_state_add_event_hooks(tss);
3034
3035 return 0;
3036}
dc877563 3037
308711e5 3038void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 3039{
ba576a78 3040 LttvTraceset *traceset = self->parent.ts;
dc877563 3041
8979f265 3042 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3043
ba576a78 3044 LttvTraceState *ts;
dc877563 3045
ba576a78 3046 LttvTracefileState *tfs;
dc877563 3047
dc877563 3048 GArray *hooks;
3049
0ceef9de 3050 LttvTraceHook *th;
eed2ef37 3051
dc877563 3052 LttvAttributeValue val;
3053
ba576a78 3054 nb_trace = lttv_traceset_number(traceset);
dc877563 3055 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 3056 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 3057
3058 /* Find the eventtype id for the following events and register the
3059 associated by id hooks. */
3060
c3b3b60b 3061 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
6418800d 3062 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3063 //hn = 0;
b445142a 3064
6418800d 3065 lttv_trace_find_hook(ts->parent.t,
60c5092c 3066 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3067 LTT_EVENT_SYSCALL_ENTRY,
6418800d 3068 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3069 syscall_entry, NULL, &hooks);
cbe7c836 3070
6418800d 3071 lttv_trace_find_hook(ts->parent.t,
60c5092c 3072 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3073 LTT_EVENT_SYSCALL_EXIT,
032ba5da 3074 NULL,
6418800d 3075 syscall_exit, NULL, &hooks);
cbe7c836 3076
6418800d 3077 lttv_trace_find_hook(ts->parent.t,
60c5092c 3078 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3079 LTT_EVENT_TRAP_ENTRY,
6418800d 3080 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3081 trap_entry, NULL, &hooks);
cbe7c836 3082
032ba5da 3083 lttv_trace_find_hook(ts->parent.t,
60c5092c 3084 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3085 LTT_EVENT_TRAP_EXIT,
032ba5da 3086 NULL,
3087 trap_exit, NULL, &hooks);
cbe7c836 3088
032ba5da 3089 lttv_trace_find_hook(ts->parent.t,
60c5092c 3090 LTT_FACILITY_KERNEL,
0ceef9de 3091 LTT_EVENT_IRQ_ENTRY,
032ba5da 3092 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3093 irq_entry, NULL, &hooks);
cbe7c836 3094
032ba5da 3095 lttv_trace_find_hook(ts->parent.t,
60c5092c 3096 LTT_FACILITY_KERNEL,
0ceef9de 3097 LTT_EVENT_IRQ_EXIT,
032ba5da 3098 NULL,
3099 irq_exit, NULL, &hooks);
cbe7c836 3100
032ba5da 3101 lttv_trace_find_hook(ts->parent.t,
60c5092c 3102 LTT_FACILITY_KERNEL,
0ceef9de 3103 LTT_EVENT_SOFT_IRQ_ENTRY,
032ba5da 3104 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3105 soft_irq_entry, NULL, &hooks);
faf074a3 3106
032ba5da 3107 lttv_trace_find_hook(ts->parent.t,
60c5092c 3108 LTT_FACILITY_KERNEL,
0ceef9de 3109 LTT_EVENT_SOFT_IRQ_EXIT,
032ba5da 3110 NULL,
3111 soft_irq_exit, NULL, &hooks);
faf074a3 3112
032ba5da 3113 lttv_trace_find_hook(ts->parent.t,
60c5092c 3114 LTT_FACILITY_KERNEL,
0ceef9de 3115 LTT_EVENT_SCHED_SCHEDULE,
032ba5da 3116 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3117 LTT_FIELD_PREV_STATE),
3118 schedchange, NULL, &hooks);
cbe7c836 3119
032ba5da 3120 lttv_trace_find_hook(ts->parent.t,
60c5092c 3121 LTT_FACILITY_KERNEL,
0ceef9de 3122 LTT_EVENT_PROCESS_FORK,
032ba5da 3123 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3124 LTT_FIELD_CHILD_TGID),
3125 process_fork, NULL, &hooks);
eed2ef37 3126
032ba5da 3127 lttv_trace_find_hook(ts->parent.t,
60c5092c 3128 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3129 LTT_EVENT_KTHREAD_CREATE,
370231d7 3130 FIELD_ARRAY(LTT_FIELD_PID),
032ba5da 3131 process_kernel_thread, NULL, &hooks);
7bfd7820 3132
032ba5da 3133 lttv_trace_find_hook(ts->parent.t,
60c5092c 3134 LTT_FACILITY_KERNEL,
0ceef9de 3135 LTT_EVENT_PROCESS_EXIT,
032ba5da 3136 FIELD_ARRAY(LTT_FIELD_PID),
3137 process_exit, NULL, &hooks);
eed2ef37 3138
032ba5da 3139 lttv_trace_find_hook(ts->parent.t,
60c5092c 3140 LTT_FACILITY_KERNEL,
0ceef9de 3141 LTT_EVENT_PROCESS_FREE,
032ba5da 3142 FIELD_ARRAY(LTT_FIELD_PID),
3143 process_free, NULL, &hooks);
2cdc690b 3144
032ba5da 3145 lttv_trace_find_hook(ts->parent.t,
43fb1d98 3146 LTT_FACILITY_FS,
0ceef9de 3147 LTT_EVENT_EXEC,
032ba5da 3148 FIELD_ARRAY(LTT_FIELD_FILENAME),
3149 process_exec, NULL, &hooks);
f4b88a7d 3150
032ba5da 3151 lttv_trace_find_hook(ts->parent.t,
60c5092c 3152 LTT_FACILITY_USER_GENERIC,
0ceef9de 3153 LTT_EVENT_THREAD_BRAND,
032ba5da 3154 FIELD_ARRAY(LTT_FIELD_NAME),
3155 thread_brand, NULL, &hooks);
7b5f6cf1 3156
b3fd4c02 3157 /* statedump-related hooks */
032ba5da 3158 lttv_trace_find_hook(ts->parent.t,
60c5092c 3159 LTT_FACILITY_LIST,
0ceef9de 3160 LTT_EVENT_PROCESS_STATE,
d3a66443 3161 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3162 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3163 LTT_FIELD_STATUS, LTT_FIELD_TGID),
032ba5da 3164 enum_process_state, NULL, &hooks);
f4b88a7d 3165
032ba5da 3166 lttv_trace_find_hook(ts->parent.t,
60c5092c 3167 LTT_FACILITY_LIST,
0ceef9de 3168 LTT_EVENT_STATEDUMP_END,
032ba5da 3169 NULL,
3170 statedump_end, NULL, &hooks);
c3b3b60b 3171
032ba5da 3172 lttv_trace_find_hook(ts->parent.t,
60c5092c 3173 LTT_FACILITY_LIST,
0ceef9de 3174 LTT_EVENT_LIST_INTERRUPT,
43fb1d98 3175 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
032ba5da 3176 enum_interrupt, NULL, &hooks);
38b73700 3177
032ba5da 3178 lttv_trace_find_hook(ts->parent.t,
60c5092c 3179 LTT_FACILITY_BLOCK,
0ceef9de 3180 LTT_EVENT_REQUEST_ISSUE,
032ba5da 3181 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3182 bdev_request_issue, NULL, &hooks);
27811799 3183
032ba5da 3184 lttv_trace_find_hook(ts->parent.t,
60c5092c 3185 LTT_FACILITY_BLOCK,
0ceef9de 3186 LTT_EVENT_REQUEST_COMPLETE,
032ba5da 3187 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3188 bdev_request_complete, NULL, &hooks);
27811799 3189
032ba5da 3190 lttv_trace_find_hook(ts->parent.t,
60c5092c 3191 LTT_FACILITY_USER_GENERIC,
0ceef9de 3192 LTT_EVENT_FUNCTION_ENTRY,
032ba5da 3193 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3194 function_entry, NULL, &hooks);
302efbad 3195
032ba5da 3196 lttv_trace_find_hook(ts->parent.t,
60c5092c 3197 LTT_FACILITY_USER_GENERIC,
0ceef9de 3198 LTT_EVENT_FUNCTION_EXIT,
032ba5da 3199 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3200 function_exit, NULL, &hooks);
302efbad 3201
a5ba1787 3202 /* Add these hooks to each event_by_id hooks list */
dc877563 3203
eed2ef37 3204 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3205
dc877563 3206 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3207 tfs =
9d239bd9 3208 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3209 LttvTracefileContext*, j));
dc877563 3210
3211 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3212 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3213 lttv_hooks_add(
5fd4c7a2 3214 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3215 th->h,
3216 th,
eed2ef37 3217 LTTV_PRIO_STATE);
ffd54a90 3218 }
dc877563 3219 }
f0b795e0 3220 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3221 *(val.v_pointer) = hooks;
dc877563 3222 }
3223}
3224
58c88a41 3225gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3226{
3227 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3228
3229 lttv_state_remove_event_hooks(tss);
3230
3231 return 0;
3232}
dc877563 3233
308711e5 3234void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 3235{
ba576a78 3236 LttvTraceset *traceset = self->parent.ts;
dc877563 3237
8979f265 3238 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3239
ba576a78 3240 LttvTraceState *ts;
dc877563 3241
ba576a78 3242 LttvTracefileState *tfs;
dc877563 3243
dc877563 3244 GArray *hooks;
3245
5fd4c7a2 3246 LttvTraceHook *th;
dc877563 3247
3248 LttvAttributeValue val;
3249
ba576a78 3250 nb_trace = lttv_traceset_number(traceset);
dc877563 3251 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 3252 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
7df20ca4 3253
f0b795e0 3254 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3255 hooks = *(val.v_pointer);
dc877563 3256
a5ba1787 3257 /* Remove these hooks from each event_by_id hooks list */
dc877563 3258
eed2ef37 3259 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3260
dc877563 3261 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3262 tfs =
cb03932a 3263 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3264 LttvTracefileContext*, j));
dc877563 3265
3266 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3267 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3268 lttv_hooks_remove_data(
5fd4c7a2 3269 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3270 th->h,
3271 th);
ffd54a90 3272 }
dc877563 3273 }
032ba5da 3274 lttv_trace_hook_remove_all(&hooks);
dc877563 3275 g_array_free(hooks, TRUE);
3276 }
3277}
3278
eed2ef37 3279static gboolean state_save_event_hook(void *hook_data, void *call_data)
3280{
3281 guint *event_count = (guint*)hook_data;
3282
3283 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3284 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3285 return FALSE;
3286 else
18c87975 3287 *event_count = 0;
eed2ef37 3288
3289 LttvTracefileState *self = (LttvTracefileState *)call_data;
3290
eed2ef37 3291 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3292
eed2ef37 3293 LttvAttribute *saved_states_tree, *saved_state_tree;
3294
3295 LttvAttributeValue value;
3296
3297 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3298 LTTV_STATE_SAVED_STATES);
3299 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3300 value = lttv_attribute_add(saved_states_tree,
3301 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3302 *(value.v_gobject) = (GObject *)saved_state_tree;
3303 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3304 *(value.v_time) = self->parent.timestamp;
3305 lttv_state_save(tcs, saved_state_tree);
3306 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3307 self->parent.timestamp.tv_nsec);
3308
3309 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3310
3311 return FALSE;
3312}
3313
14aecf75 3314static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3315{
3316 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3317
3318 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3319
3320 return FALSE;
3321}
3322
ae3d0f50 3323guint lttv_state_current_cpu(LttvTracefileState *tfs)
3324{
80e0221b 3325 return tfs->cpu;
ae3d0f50 3326}
3327
3328
3329
eed2ef37 3330#if 0
08b1c66e 3331static gboolean block_start(void *hook_data, void *call_data)
308711e5 3332{
dbb7bb09 3333 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 3334
dbb7bb09 3335 LttvTracefileState *tfcs;
308711e5 3336
dbb7bb09 3337 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3338
3339 LttEventPosition *ep;
308711e5 3340
dbb7bb09 3341 guint i, nb_block, nb_event, nb_tracefile;
308711e5 3342
3343 LttTracefile *tf;
3344
3345 LttvAttribute *saved_states_tree, *saved_state_tree;
3346
3347 LttvAttributeValue value;
3348
dbb7bb09 3349 ep = ltt_event_position_new();
eed2ef37 3350
3351 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 3352
3353 /* Count the number of events added since the last block end in any
3354 tracefile. */
3355
3356 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 3357 tfcs =
3358 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3359 LttvTracefileContext, i));
dbb7bb09 3360 ltt_event_position(tfcs->parent.e, ep);
3361 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3362 tcs->nb_event += nb_event - tfcs->saved_position;
3363 tfcs->saved_position = nb_event;
3364 }
3365 g_free(ep);
308711e5 3366
308711e5 3367 if(tcs->nb_event >= tcs->save_interval) {
3368 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3369 LTTV_STATE_SAVED_STATES);
3370 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3371 value = lttv_attribute_add(saved_states_tree,
3372 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3373 *(value.v_gobject) = (GObject *)saved_state_tree;
3374 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 3375 *(value.v_time) = self->parent.timestamp;
308711e5 3376 lttv_state_save(tcs, saved_state_tree);
3377 tcs->nb_event = 0;
08b1c66e 3378 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
80e0221b 3379 self->parent.timestamp.tv_nsec);
308711e5 3380 }
dbb7bb09 3381 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 3382 return FALSE;
3383}
eed2ef37 3384#endif //0
308711e5 3385
eed2ef37 3386#if 0
08b1c66e 3387static gboolean block_end(void *hook_data, void *call_data)
3388{
3389 LttvTracefileState *self = (LttvTracefileState *)call_data;
3390
3391 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3392
3393 LttTracefile *tf;
3394
3395 LttEventPosition *ep;
3396
3397 guint nb_block, nb_event;
3398
3399 ep = ltt_event_position_new();
3400 ltt_event_position(self->parent.e, ep);
3401 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3402 tcs->nb_event += nb_event - self->saved_position + 1;
3403 self->saved_position = 0;
3404 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3405 g_free(ep);
00e74b69 3406
3407 return FALSE;
08b1c66e 3408}
eed2ef37 3409#endif //0
3410#if 0
308711e5 3411void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3412{
3413 LttvTraceset *traceset = self->parent.ts;
3414
00e74b69 3415 guint i, j, nb_trace, nb_tracefile;
308711e5 3416
3417 LttvTraceState *ts;
3418
3419 LttvTracefileState *tfs;
3420
08b1c66e 3421 LttvTraceHook hook_start, hook_end;
308711e5 3422
3423 nb_trace = lttv_traceset_number(traceset);
3424 for(i = 0 ; i < nb_trace ; i++) {
3425 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3426
08b1c66e 3427 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3428 NULL, NULL, block_start, &hook_start);
308711e5 3429 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3430 NULL, NULL, block_end, &hook_end);
308711e5 3431
eed2ef37 3432 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3433
dbb7bb09 3434 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3435 tfs =
3436 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3437 LttvTracefileContext, j));
a5ba1787 3438 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3439 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 3440 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3441 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
eed2ef37 3442 }
3443 }
3444}
3445#endif //0
3446
3447void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3448{
3449 LttvTraceset *traceset = self->parent.ts;
3450
3451 guint i, j, nb_trace, nb_tracefile;
3452
3453 LttvTraceState *ts;
3454
3455 LttvTracefileState *tfs;
3456
3457
3458 nb_trace = lttv_traceset_number(traceset);
3459 for(i = 0 ; i < nb_trace ; i++) {
3460
3461 ts = (LttvTraceState *)self->parent.traces[i];
3462 nb_tracefile = ts->parent.tracefiles->len;
3463
ce05e187 3464 if(ts->has_precomputed_states) continue;
3465
3054461a 3466 guint *event_count = g_new(guint, 1);
3467 *event_count = 0;
3468
eed2ef37 3469 for(j = 0 ; j < nb_tracefile ; j++) {
3470 tfs =
cb03932a 3471 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3472 LttvTracefileContext*, j));
eed2ef37 3473 lttv_hooks_add(tfs->parent.event,
3474 state_save_event_hook,
3475 event_count,
3476 LTTV_PRIO_STATE);
3477
308711e5 3478 }
3479 }
14aecf75 3480
3481 lttv_process_traceset_begin(&self->parent,
3482 NULL, NULL, NULL, NULL, NULL);
3483
308711e5 3484}
3485
b56b5fec 3486gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3487{
3488 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3489
3490 lttv_state_save_add_event_hooks(tss);
3491
3492 return 0;
3493}
3494
308711e5 3495
eed2ef37 3496#if 0
308711e5 3497void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3498{
3499 LttvTraceset *traceset = self->parent.ts;
3500
00e74b69 3501 guint i, j, nb_trace, nb_tracefile;
308711e5 3502
3503 LttvTraceState *ts;
3504
3505 LttvTracefileState *tfs;
3506
08b1c66e 3507 LttvTraceHook hook_start, hook_end;
308711e5 3508
3509 nb_trace = lttv_traceset_number(traceset);
3510 for(i = 0 ; i < nb_trace ; i++) {
3511 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 3512
08b1c66e 3513 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3514 NULL, NULL, block_start, &hook_start);
08b1c66e 3515
308711e5 3516 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3517 NULL, NULL, block_end, &hook_end);
308711e5 3518
eed2ef37 3519 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3520
dbb7bb09 3521 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3522 tfs =
3523 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3524 LttvTracefileContext, j));
308711e5 3525 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3526 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 3527 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3528 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 3529 }
3530 }
3531}
eed2ef37 3532#endif //0
3533
3534void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3535{
3536 LttvTraceset *traceset = self->parent.ts;
3537
3538 guint i, j, nb_trace, nb_tracefile;
3539
3540 LttvTraceState *ts;
3541
3542 LttvTracefileState *tfs;
3543
14aecf75 3544 LttvHooks *after_trace = lttv_hooks_new();
3545
3546 lttv_hooks_add(after_trace,
3547 state_save_after_trace_hook,
3548 NULL,
3549 LTTV_PRIO_STATE);
3550
3551
3552 lttv_process_traceset_end(&self->parent,
3553 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 3554
14aecf75 3555 lttv_hooks_destroy(after_trace);
3556
eed2ef37 3557 nb_trace = lttv_traceset_number(traceset);
3558 for(i = 0 ; i < nb_trace ; i++) {
3559
3560 ts = (LttvTraceState *)self->parent.traces[i];
3561 nb_tracefile = ts->parent.tracefiles->len;
3562
ce05e187 3563 if(ts->has_precomputed_states) continue;
3564
22b165e9 3565 guint *event_count = NULL;
eed2ef37 3566
3567 for(j = 0 ; j < nb_tracefile ; j++) {
3568 tfs =
cb03932a 3569 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3570 LttvTracefileContext*, j));
eed2ef37 3571 event_count = lttv_hooks_remove(tfs->parent.event,
3572 state_save_event_hook);
eed2ef37 3573 }
22b165e9 3574 if(event_count) g_free(event_count);
eed2ef37 3575 }
3576}
308711e5 3577
b56b5fec 3578gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3579{
3580 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3581
3582 lttv_state_save_remove_event_hooks(tss);
3583
3584 return 0;
3585}
308711e5 3586
dd025f91 3587void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 3588{
3589 LttvTraceset *traceset = self->parent.ts;
3590
00e74b69 3591 guint i, nb_trace;
308711e5 3592
3593 int min_pos, mid_pos, max_pos;
3594
728d0c3e 3595 guint call_rest = 0;
3596
308711e5 3597 LttvTraceState *tcs;
3598
3599 LttvAttributeValue value;
3600
3601 LttvAttributeType type;
3602
3603 LttvAttributeName name;
3604
80e0221b 3605 gboolean is_named;
c0cb4d12 3606
308711e5 3607 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3608
d448fce2 3609 //g_tree_destroy(self->parent.pqueue);
3610 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 3611
728d0c3e 3612 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3613
308711e5 3614 nb_trace = lttv_traceset_number(traceset);
3615 for(i = 0 ; i < nb_trace ; i++) {
3616 tcs = (LttvTraceState *)self->parent.traces[i];
3617
2a2fa4f0 3618 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3619 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3620 LTTV_STATE_SAVED_STATES);
3621 min_pos = -1;
3622
3623 if(saved_states_tree) {
dd025f91 3624 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3625 mid_pos = max_pos / 2;
3626 while(min_pos < max_pos) {
c0cb4d12 3627 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
80e0221b 3628 &is_named);
dd025f91 3629 g_assert(type == LTTV_GOBJECT);
3630 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3631 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3632 &value);
3633 g_assert(type == LTTV_TIME);
3634 if(ltt_time_compare(*(value.v_time), t) < 0) {
3635 min_pos = mid_pos;
3636 closest_tree = saved_state_tree;
3637 }
3638 else max_pos = mid_pos - 1;
3639
3640 mid_pos = (min_pos + max_pos + 1) / 2;
3641 }
2a2fa4f0 3642 }
dd025f91 3643
2a2fa4f0 3644 /* restore the closest earlier saved state */
f95bc830 3645 if(min_pos != -1) {
3646 lttv_state_restore(tcs, closest_tree);
728d0c3e 3647 call_rest = 1;
f95bc830 3648 }
dd025f91 3649
2a2fa4f0 3650 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 3651 else {
3652 restore_init_state(tcs);
3653 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 3654 }
9444deae 3655 }
dd025f91 3656 /* We want to seek quickly without restoring/updating the state */
3657 else {
308711e5 3658 restore_init_state(tcs);
dd025f91 3659 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 3660 }
308711e5 3661 }
728d0c3e 3662 if(!call_rest) g_info("NOT Calling restore");
308711e5 3663}
3664
3665
3666static void
3667traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3668{
3669}
3670
3671
3672static void
3673traceset_state_finalize (LttvTracesetState *self)
3674{
3675 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3676 finalize(G_OBJECT(self));
3677}
3678
3679
3680static void
3681traceset_state_class_init (LttvTracesetContextClass *klass)
3682{
3683 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3684
3685 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3686 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3687 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3688 klass->new_traceset_context = new_traceset_context;
3689 klass->new_trace_context = new_trace_context;
3690 klass->new_tracefile_context = new_tracefile_context;
3691}
3692
3693
3694GType
3695lttv_traceset_state_get_type(void)
3696{
3697 static GType type = 0;
3698 if (type == 0) {
3699 static const GTypeInfo info = {
3700 sizeof (LttvTracesetStateClass),
3701 NULL, /* base_init */
3702 NULL, /* base_finalize */
3703 (GClassInitFunc) traceset_state_class_init, /* class_init */
3704 NULL, /* class_finalize */
3705 NULL, /* class_data */
dbb7bb09 3706 sizeof (LttvTracesetState),
308711e5 3707 0, /* n_preallocs */
00e74b69 3708 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3709 NULL /* value handling */
308711e5 3710 };
3711
3712 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3713 &info, 0);
3714 }
3715 return type;
3716}
3717
3718
3719static void
3720trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3721{
3722}
3723
3724
3725static void
3726trace_state_finalize (LttvTraceState *self)
3727{
3728 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3729 finalize(G_OBJECT(self));
3730}
3731
3732
3733static void
3734trace_state_class_init (LttvTraceStateClass *klass)
3735{
3736 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3737
3738 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3739 klass->state_save = state_save;
3740 klass->state_restore = state_restore;
3741 klass->state_saved_free = state_saved_free;
3742}
3743
3744
3745GType
3746lttv_trace_state_get_type(void)
3747{
3748 static GType type = 0;
3749 if (type == 0) {
3750 static const GTypeInfo info = {
3751 sizeof (LttvTraceStateClass),
3752 NULL, /* base_init */
3753 NULL, /* base_finalize */
3754 (GClassInitFunc) trace_state_class_init, /* class_init */
3755 NULL, /* class_finalize */
3756 NULL, /* class_data */
3757 sizeof (LttvTraceState),
3758 0, /* n_preallocs */
00e74b69 3759 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3760 NULL /* value handling */
308711e5 3761 };
3762
3763 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3764 "LttvTraceStateType", &info, 0);
3765 }
3766 return type;
3767}
3768
3769
3770static void
3771tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3772{
3773}
3774
3775
3776static void
3777tracefile_state_finalize (LttvTracefileState *self)
3778{
3779 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3780 finalize(G_OBJECT(self));
3781}
3782
3783
3784static void
3785tracefile_state_class_init (LttvTracefileStateClass *klass)
3786{
3787 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3788
3789 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3790}
3791
3792
3793GType
3794lttv_tracefile_state_get_type(void)
3795{
3796 static GType type = 0;
3797 if (type == 0) {
3798 static const GTypeInfo info = {
3799 sizeof (LttvTracefileStateClass),
3800 NULL, /* base_init */
3801 NULL, /* base_finalize */
3802 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3803 NULL, /* class_finalize */
3804 NULL, /* class_data */
3805 sizeof (LttvTracefileState),
3806 0, /* n_preallocs */
00e74b69 3807 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3808 NULL /* value handling */
308711e5 3809 };
3810
3811 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3812 "LttvTracefileStateType", &info, 0);
3813 }
3814 return type;
3815}
3816
3817
08b1c66e 3818static void module_init()
ffd54a90 3819{
b4fa748c 3820 LTTV_STATE_UNNAMED = g_quark_from_string("");
235c78f0 3821 LTTV_STATE_UNBRANDED = g_quark_from_string("");
b3fd4c02 3822 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3823 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3824 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3825 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3826 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3827 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3828 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3829 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3830 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3831 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3832 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3833 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3834 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3835 LTTV_STATE_RUN = g_quark_from_string("RUN");
3836 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
80e0221b 3837 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3838 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
308711e5 3839 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3840 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3841 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 3842 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 3843 LTTV_STATE_EVENT = g_quark_from_string("event");
3844 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 3845 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 3846 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 3847 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 3848 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3849 LTTV_STATE_TRACE_STATE_USE_COUNT =
3850 g_quark_from_string("trace_state_use_count");
fbfbd4db 3851 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
f61bce48 3852 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
98d7814f 3853 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
3854 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
eed2ef37 3855
3856
3857 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 3858 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
f4b88a7d 3859 LTT_FACILITY_FS = g_quark_from_string("fs");
86c32a8f 3860 LTT_FACILITY_LIST = g_quark_from_string("list");
302efbad 3861 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
27811799 3862 LTT_FACILITY_BLOCK = g_quark_from_string("block");
eed2ef37 3863
3864
3865 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3866 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3867 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3868 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3869 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3870 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
43fb1d98 3871 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
3872 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
86c32a8f 3873 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3874 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3875 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3876 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
f63ebe51 3877 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
f4b88a7d 3878 LTT_EVENT_EXEC = g_quark_from_string("exec");
86c32a8f 3879 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
c3b3b60b 3880 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
302efbad 3881 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3882 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
7b5f6cf1 3883 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
27811799 3884 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
3885 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
38b73700 3886 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
eed2ef37 3887
3888
3889 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3890 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3891 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 3892 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
f63ebe51 3893 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3894 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3895 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
eed2ef37 3896 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3897 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3898 LTT_FIELD_PID = g_quark_from_string("pid");
fcc08e1e 3899 LTT_FIELD_TGID = g_quark_from_string("tgid");
f63ebe51 3900 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
f4b88a7d 3901 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 3902 LTT_FIELD_NAME = g_quark_from_string("name");
e62e7f3a 3903 LTT_FIELD_TYPE = g_quark_from_string("type");
b3fd4c02 3904 LTT_FIELD_MODE = g_quark_from_string("mode");
3905 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3906 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 3907 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3908 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
27811799 3909 LTT_FIELD_MAJOR = g_quark_from_string("major");
3910 LTT_FIELD_MINOR = g_quark_from_string("minor");
3911 LTT_FIELD_OPERATION = g_quark_from_string("direction");
38b73700 3912 LTT_FIELD_ACTION = g_quark_from_string("action");
eed2ef37 3913
44ffb95f 3914 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3915 LTTV_CPU_IDLE = g_quark_from_string("idle");
3916 LTTV_CPU_BUSY = g_quark_from_string("busy");
598026ba 3917 LTTV_CPU_IRQ = g_quark_from_string("irq");
d3d99fde 3918 LTTV_CPU_TRAP = g_quark_from_string("trap");
5e563da0 3919
3920 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
3921 LTTV_IRQ_IDLE = g_quark_from_string("idle");
3922 LTTV_IRQ_BUSY = g_quark_from_string("busy");
27811799 3923
3924 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
3925 LTTV_BDEV_IDLE = g_quark_from_string("idle");
3926 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
3927 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
ffd54a90 3928}
dc877563 3929
08b1c66e 3930static void module_destroy()
ffd54a90 3931{
3932}
dc877563 3933
3934
08b1c66e 3935LTTV_MODULE("state", "State computation", \
3936 "Update the system state, possibly saving it at intervals", \
3937 module_init, module_destroy)
3938
dc877563 3939
3940
This page took 0.281393 seconds and 4 git commands to generate.