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