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