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