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