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