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