update end of process
[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 */
0bc55022 2242static void 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
2a2fa4f0 2247 key.pid = process->pid;
348c6ba8 2248 key.cpu = process->cpu;
2a2fa4f0 2249 g_hash_table_remove(ts->processes, &key);
b445142a 2250 g_array_free(process->execution_stack, TRUE);
302efbad 2251 g_array_free(process->user_stack, TRUE);
dc877563 2252 g_free(process);
2253}
2254
2255
b445142a 2256static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 2257{
b445142a 2258 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
302efbad 2259 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
dc877563 2260 g_free(value);
2261}
2262
2263
308711e5 2264static void lttv_state_free_process_table(GHashTable *processes)
dc877563 2265{
2266 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 2267 g_hash_table_destroy(processes);
dc877563 2268}
2269
2270
b445142a 2271static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 2272{
ba576a78 2273 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2274 guint cpu = s->cpu;
2275 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2276 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 2277 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2278 LttvTraceHook *th = (LttvTraceHook *)hook_data;
775c802c 2279 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2280
b445142a 2281 LttvExecutionSubmode submode;
2282
80e0221b 2283 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2284 guint syscall = ltt_event_get_unsigned(e, f);
2285
2286 if(syscall < nb_syscalls) {
2287 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2288 syscall];
2289 } else {
2290 /* Fixup an incomplete syscall table */
2291 GString *string = g_string_new("");
7cd289b0 2292 g_string_printf(string, "syscall %u", syscall);
80e0221b 2293 submode = g_quark_from_string(string->str);
2294 g_string_free(string, TRUE);
2295 }
1e304fa1 2296 /* There can be no system call from PID 0 : unknown state */
2297 if(process->pid != 0)
2298 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 2299 return FALSE;
2300}
2301
2302
b445142a 2303static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 2304{
ba576a78 2305 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2306 guint cpu = s->cpu;
2307 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2308 LttvProcessState *process = ts->running_process[cpu];
dc877563 2309
1e304fa1 2310 /* There can be no system call from PID 0 : unknown state */
2311 if(process->pid != 0)
2312 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 2313 return FALSE;
2314}
2315
2316
b445142a 2317static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 2318{
ba576a78 2319 LttvTracefileState *s = (LttvTracefileState *)call_data;
a81d2a59 2320 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
eed2ef37 2321 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2322 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2323 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2324
b445142a 2325 LttvExecutionSubmode submode;
2326
17ddd1f2 2327 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2328 guint64 trap = ltt_event_get_long_unsigned(e, f);
5e96e7e3 2329
2330 if(trap < nb_traps) {
2331 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2332 } else {
2333 /* Fixup an incomplete trap table */
2334 GString *string = g_string_new("");
fcc08e1e 2335 g_string_printf(string, "trap %llu", trap);
5e96e7e3 2336 submode = g_quark_from_string(string->str);
2337 g_string_free(string, TRUE);
2338 }
2339
b445142a 2340 push_state(s, LTTV_STATE_TRAP, submode);
d3d99fde 2341
2342 /* update cpu status */
2343 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2344
a81d2a59 2345 /* update trap status */
2346 s->cpu_state->last_trap = trap;
2347 ts->trap_states[trap].running++;
2348
dc877563 2349 return FALSE;
2350}
2351
b445142a 2352static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 2353{
ba576a78 2354 LttvTracefileState *s = (LttvTracefileState *)call_data;
a81d2a59 2355 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2356 guint trap = s->cpu_state->last_trap;
dc877563 2357
ffd54a90 2358 pop_state(s, LTTV_STATE_TRAP);
d3d99fde 2359
2360 /* update cpu status */
2361 cpu_pop_mode(s->cpu_state);
2362
a81d2a59 2363 /* update trap status */
2364 if(ts->trap_states[trap].running)
2365 ts->trap_states[trap].running--;
2366
dc877563 2367 return FALSE;
2368}
2369
b445142a 2370static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 2371{
ba576a78 2372 LttvTracefileState *s = (LttvTracefileState *)call_data;
5e563da0 2373 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
eed2ef37 2374 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2375 //guint8 ev_id = ltt_event_eventtype_id(e);
2376 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2377 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
dc877563 2378
b445142a 2379 LttvExecutionSubmode submode;
1bb8d3a5 2380 guint64 irq = ltt_event_get_long_unsigned(e, f);
6214c229 2381 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
b445142a 2382
6214c229 2383 if(irq < nb_irqs) {
2384 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2385 } else {
2386 /* Fixup an incomplete irq table */
2387 GString *string = g_string_new("");
2388 g_string_printf(string, "irq %llu", irq);
2389 submode = g_quark_from_string(string->str);
2390 g_string_free(string, TRUE);
2391 }
b445142a 2392
dc877563 2393 /* Do something with the info about being in user or system mode when int? */
b445142a 2394 push_state(s, LTTV_STATE_IRQ, submode);
598026ba 2395
2396 /* update cpu status */
d3d99fde 2397 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
598026ba 2398
5e563da0 2399 /* update irq status */
8743690d 2400 s->cpu_state->last_irq = irq;
5e563da0 2401 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2402
dc877563 2403 return FALSE;
2404}
2405
302efbad 2406static gboolean soft_irq_exit(void *hook_data, void *call_data)
2407{
2408 LttvTracefileState *s = (LttvTracefileState *)call_data;
0305fe77 2409 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2410 guint softirq = s->cpu_state->last_soft_irq;
302efbad 2411
2412 pop_state(s, LTTV_STATE_SOFT_IRQ);
302efbad 2413
0305fe77 2414 /* update softirq status */
2415 if(ts->soft_irq_states[softirq].running)
2416 ts->soft_irq_states[softirq].running--;
302efbad 2417
d34141ca 2418 /* update cpu status */
2419 cpu_pop_mode(s->cpu_state);
2420
0305fe77 2421 return FALSE;
2422}
dc877563 2423
b445142a 2424static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 2425{
ba576a78 2426 LttvTracefileState *s = (LttvTracefileState *)call_data;
8743690d 2427 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
dc877563 2428
ffd54a90 2429 pop_state(s, LTTV_STATE_IRQ);
598026ba 2430
2431 /* update cpu status */
d3d99fde 2432 cpu_pop_mode(s->cpu_state);
598026ba 2433
8743690d 2434 /* update irq status */
2435 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2436
dc877563 2437 return FALSE;
2438}
2439
faf074a3 2440static gboolean soft_irq_entry(void *hook_data, void *call_data)
2441{
2442 LttvTracefileState *s = (LttvTracefileState *)call_data;
0305fe77 2443 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
faf074a3 2444 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2445 //guint8 ev_id = ltt_event_eventtype_id(e);
2446 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2447 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
faf074a3 2448
2449 LttvExecutionSubmode submode;
1bb8d3a5 2450 guint64 softirq = ltt_event_get_long_unsigned(e, f);
0305fe77 2451 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_soft_irqs;
faf074a3 2452
6214c229 2453 if(softirq < nb_softirqs) {
2454 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2455 } else {
2456 /* Fixup an incomplete irq table */
2457 GString *string = g_string_new("");
2458 g_string_printf(string, "softirq %llu", softirq);
2459 submode = g_quark_from_string(string->str);
2460 g_string_free(string, TRUE);
2461 }
faf074a3 2462
2463 /* Do something with the info about being in user or system mode when int? */
2464 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
0305fe77 2465
d34141ca 2466 /* update cpu status */
2467 cpu_push_mode(s->cpu_state, LTTV_CPU_SOFT_IRQ);
2468
0305fe77 2469 /* update softirq status */
2470 s->cpu_state->last_soft_irq = softirq;
2471 ts->soft_irq_states[softirq].running++;
2472
faf074a3 2473 return FALSE;
2474}
2475
38b73700 2476static gboolean enum_interrupt(void *hook_data, void *call_data)
2477{
2478 LttvTracefileState *s = (LttvTracefileState *)call_data;
2479 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2480 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2481 //guint8 ev_id = ltt_event_eventtype_id(e);
2482 LttvTraceHook *th = (LttvTraceHook *)hook_data;
38b73700 2483
d3a66443 2484 GQuark action = g_quark_from_string(ltt_event_get_string(e,
2485 lttv_trace_get_hook_field(th, 0)));
2486 guint irq = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
38b73700 2487
2488 ts->irq_names[irq] = action;
2489
2490 return FALSE;
2491}
2492
2493
27811799 2494static gboolean bdev_request_issue(void *hook_data, void *call_data)
2495{
2496 LttvTracefileState *s = (LttvTracefileState *)call_data;
2497 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2498 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2499 //guint8 ev_id = ltt_event_eventtype_id(e);
2500 LttvTraceHook *th = (LttvTraceHook *)hook_data;
27811799 2501
d3a66443 2502 guint major = ltt_event_get_long_unsigned(e,
2503 lttv_trace_get_hook_field(th, 0));
2504 guint minor = ltt_event_get_long_unsigned(e,
2505 lttv_trace_get_hook_field(th, 1));
2506 guint oper = ltt_event_get_long_unsigned(e,
2507 lttv_trace_get_hook_field(th, 2));
27811799 2508 guint16 devcode = MKDEV(major,minor);
2509
2510 /* have we seen this block device before? */
98d7814f 2511 gpointer bdev = get_hashed_bdevstate(ts, devcode);
27811799 2512
2513 if(oper == 0)
2514 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2515 else
2516 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2517
2518 return FALSE;
2519}
2520
2521static gboolean bdev_request_complete(void *hook_data, void *call_data)
2522{
2523 LttvTracefileState *s = (LttvTracefileState *)call_data;
2524 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2525 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2526 LttvTraceHook *th = (LttvTraceHook *)hook_data;
27811799 2527
d3a66443 2528 guint major = ltt_event_get_long_unsigned(e,
2529 lttv_trace_get_hook_field(th, 0));
2530 guint minor = ltt_event_get_long_unsigned(e,
2531 lttv_trace_get_hook_field(th, 1));
2532 //guint oper = ltt_event_get_long_unsigned(e,
2533 // lttv_trace_get_hook_field(th, 2));
27811799 2534 guint16 devcode = MKDEV(major,minor);
2535
2536 /* have we seen this block device before? */
98d7814f 2537 gpointer bdev = get_hashed_bdevstate(ts, devcode);
27811799 2538
2539 /* update block device */
2540 bdev_pop_mode(bdev);
2541
2542 return FALSE;
2543}
2544
302efbad 2545static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2546{
2547 guint64 *new_func;
2548
2549 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2550 guint cpu = tfs->cpu;
2551 LttvProcessState *process = ts->running_process[cpu];
faf074a3 2552
302efbad 2553 guint depth = process->user_stack->len;
2554
d3a66443 2555 process->user_stack =
302efbad 2556 g_array_set_size(process->user_stack, depth + 1);
2557
2558 new_func = &g_array_index(process->user_stack, guint64, depth);
80e0221b 2559 *new_func = funcptr;
9bff13df 2560 process->current_function = funcptr;
302efbad 2561}
2562
2563static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2564{
2565 guint cpu = tfs->cpu;
2566 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2567 LttvProcessState *process = ts->running_process[cpu];
2568
302efbad 2569 if(process->current_function != funcptr){
2570 g_info("Different functions (%lu.%09lu): ignore it\n",
2571 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2572 g_info("process state has %llu when pop_function is %llu\n",
80e0221b 2573 process->current_function, funcptr);
7b5f6cf1 2574 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 2575 process->pid,
2576 process->ppid,
2577 g_quark_to_string(process->name),
2578 g_quark_to_string(process->brand),
2579 g_quark_to_string(process->state->s));
302efbad 2580 return;
2581 }
9bff13df 2582 guint depth = process->user_stack->len;
302efbad 2583
2584 if(depth == 0){
2585 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2586 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2587 return;
2588 }
2589
2590 process->user_stack =
2591 g_array_set_size(process->user_stack, depth - 1);
2592 process->current_function =
80e0221b 2593 g_array_index(process->user_stack, guint64, depth - 2);
302efbad 2594}
2595
2596
2597static gboolean function_entry(void *hook_data, void *call_data)
faf074a3 2598{
2599 LttvTracefileState *s = (LttvTracefileState *)call_data;
302efbad 2600 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2601 //guint8 ev_id = ltt_event_eventtype_id(e);
2602 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2603 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
80e0221b 2604 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
faf074a3 2605
302efbad 2606 push_function(s, funcptr);
faf074a3 2607 return FALSE;
2608}
2609
302efbad 2610static gboolean function_exit(void *hook_data, void *call_data)
2611{
2612 LttvTracefileState *s = (LttvTracefileState *)call_data;
2613 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2614 //guint8 ev_id = ltt_event_eventtype_id(e);
2615 LttvTraceHook *th = (LttvTraceHook *)hook_data;
d3a66443 2616 struct marker_field *f = lttv_trace_get_hook_field(th, 0);
80e0221b 2617 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
302efbad 2618
302efbad 2619 pop_function(s, funcptr);
2620 return FALSE;
2621}
dc877563 2622
b445142a 2623static gboolean schedchange(void *hook_data, void *call_data)
dc877563 2624{
ba576a78 2625 LttvTracefileState *s = (LttvTracefileState *)call_data;
ae3d0f50 2626 guint cpu = s->cpu;
348c6ba8 2627 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2628 LttvProcessState *process = ts->running_process[cpu];
5fd4c7a2 2629 //LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 2630
eed2ef37 2631 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2632 LttvTraceHook *th = (LttvTraceHook *)hook_data;
73394fd3 2633 guint pid_in, pid_out;
7092fb86 2634 gint64 state_out;
dc877563 2635
d3a66443 2636 pid_out = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
2637 pid_in = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
2638 state_out = ltt_event_get_long_int(e, lttv_trace_get_hook_field(th, 2));
348c6ba8 2639
2640 if(likely(process != NULL)) {
b445142a 2641
f95bc830 2642 /* We could not know but it was not the idle process executing.
2643 This should only happen at the beginning, before the first schedule
2644 event, and when the initial information (current process for each CPU)
2645 is missing. It is not obvious how we could, after the fact, compensate
2646 the wrongly attributed statistics. */
2647
240f1fea 2648 //This test only makes sense once the state is known and if there is no
48b002b8 2649 //missing events. We need to silently ignore schedchange coming after a
80e0221b 2650 //process_free, or it causes glitches. (FIXME)
348c6ba8 2651 //if(unlikely(process->pid != pid_out)) {
2652 // g_assert(process->pid == 0);
240f1fea 2653 //}
c4a72569 2654 if(process->pid == 0
2655 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2656 if(pid_out == 0) {
2657 /* Scheduling out of pid 0 at beginning of the trace :
2658 * we know for sure it is in syscall mode at this point. */
2659 g_assert(process->execution_stack->len == 1);
2660 process->state->t = LTTV_STATE_SYSCALL;
2661 process->state->s = LTTV_STATE_WAIT;
2662 process->state->change = s->parent.timestamp;
d3670e3d 2663 process->state->entry = s->parent.timestamp;
c4a72569 2664 }
dbd243b1 2665 } else {
c4a72569 2666 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2667 process->state->s = LTTV_STATE_ZOMBIE;
2668 process->state->change = s->parent.timestamp;
2669 } else {
2670 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2671 else process->state->s = LTTV_STATE_WAIT;
2672 process->state->change = s->parent.timestamp;
2673 }
2674
c7620c79 2675 if(state_out == 32 || state_out == 64) { /* EXIT_DEAD || TASK_DEAD */
2676 /* see sched.h for states */
0bc55022 2677 process->state->s = LTTV_STATE_DEAD;
2678 process->state->change = s->parent.timestamp;
c7620c79 2679 }
791dffa6 2680 }
dc877563 2681 }
348c6ba8 2682 process = ts->running_process[cpu] =
2683 lttv_state_find_process_or_create(
2684 (LttvTraceState*)s->parent.t_context,
2685 cpu, pid_in,
2686 &s->parent.timestamp);
2687 process->state->s = LTTV_STATE_RUN;
2688 process->cpu = cpu;
80e0221b 2689 if(process->usertrace)
2690 process->usertrace->cpu = cpu;
348c6ba8 2691 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2692 process->state->change = s->parent.timestamp;
44ffb95f 2693
2694 /* update cpu status */
2695 if(pid_in == 0)
14c7af39 2696 /* going to idle task */
d3d99fde 2697 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
14c7af39 2698 else {
2699 /* scheduling a real task.
2700 * we must be careful here:
2701 * if we just schedule()'ed to a process that is
2702 * in a trap, we must put the cpu in trap mode
2703 */
d3d99fde 2704 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
14c7af39 2705 if(process->state->t == LTTV_STATE_TRAP)
2706 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2707 }
44ffb95f 2708
dc877563 2709 return FALSE;
2710}
2711
eed2ef37 2712static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2713{
eed2ef37 2714 LttvTracefileState *s = (LttvTracefileState *)call_data;
2715 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2716 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2717 guint parent_pid;
fcc08e1e 2718 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2719 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
0ceef9de 2720 //LttvProcessState *zombie_process;
ae3d0f50 2721 guint cpu = s->cpu;
348c6ba8 2722 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2723 LttvProcessState *process = ts->running_process[cpu];
26275aa2 2724 LttvProcessState *child_process;
d3a66443 2725 struct marker_field *f;
2cdc690b 2726
eed2ef37 2727 /* Parent PID */
d3a66443 2728 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
eed2ef37 2729
2cdc690b 2730 /* Child PID */
d3a66443 2731 child_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
33bdc8dd 2732 s->parent.target_pid = child_pid;
2cdc690b 2733
fcc08e1e 2734 /* Child TGID */
d3a66443 2735 f = lttv_trace_get_hook_field(th, 2);
2736 if (likely(f))
2737 child_tgid = ltt_event_get_unsigned(e, f);
2738 else
2739 child_tgid = 0;
fcc08e1e 2740
15b3d537 2741 /* Mathieu : it seems like the process might have been scheduled in before the
2742 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 2743 * in a SMP case where we don't have enough precision on the clocks.
2744 *
2745 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2746#if 0
348c6ba8 2747 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 2748
1d1df11d 2749 if(unlikely(zombie_process != NULL)) {
4ad73431 2750 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 2751 * has been released. FIXME : should know when release_task happens instead.
4ad73431 2752 */
15b3d537 2753 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2754 guint i;
2755 for(i=0; i< num_cpus; i++) {
5ac05980 2756 g_assert(zombie_process != ts->running_process[i]);
15b3d537 2757 }
2758
4ad73431 2759 exit_process(s, zombie_process);
2760 }
791dffa6 2761#endif //0
348c6ba8 2762 g_assert(process->pid != child_pid);
eed2ef37 2763 // FIXME : Add this test in the "known state" section
348c6ba8 2764 // g_assert(process->pid == parent_pid);
26275aa2 2765 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2766 if(child_process == NULL) {
ab893fb1 2767 child_process = lttv_state_create_process(ts, process, cpu,
fcc08e1e 2768 child_pid, child_tgid,
2769 LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 2770 } else {
2771 /* The process has already been created : due to time imprecision between
791dffa6 2772 * multiple CPUs : it has been scheduled in before creation. Note that we
2773 * shouldn't have this kind of imprecision.
26275aa2 2774 *
2775 * Simply put a correct parent.
2776 */
e4d45514 2777 g_error("Process %u has been created before fork on cpu %u. Probably an unsynchronized TSC problem on the traced machine.", child_pid, cpu);
2778 //g_assert(0); /* This is a problematic case : the process has been created
2779 // before the fork event */
26275aa2 2780 child_process->ppid = process->pid;
fcc08e1e 2781 child_process->tgid = child_tgid;
26275aa2 2782 }
0292757b 2783 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2784 child_process->name = process->name;
2785 child_process->brand = process->brand;
4ad73431 2786
dc877563 2787 return FALSE;
2788}
2789
89f8741a 2790/* We stamp a newly created process as kernel_thread.
2791 * The thread should not be running yet. */
7bfd7820 2792static gboolean process_kernel_thread(void *hook_data, void *call_data)
2793{
2794 LttvTracefileState *s = (LttvTracefileState *)call_data;
2795 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2796 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7bfd7820 2797 guint pid;
7bfd7820 2798 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2799 LttvProcessState *process;
2800 LttvExecutionState *es;
2801
2802 /* PID */
d3a66443 2803 pid = (guint)ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2804 s->parent.target_pid = pid;
7bfd7820 2805
61c8808e 2806 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2807 &ltt_time_zero);
c7620c79 2808 if (process->state->s != LTTV_STATE_DEAD) {
2809 process->execution_stack =
2810 g_array_set_size(process->execution_stack, 1);
2811 es = process->state =
2812 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2813 es->t = LTTV_STATE_SYSCALL;
2814 }
80e0221b 2815 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 2816
80e0221b 2817 return FALSE;
7bfd7820 2818}
dc877563 2819
eed2ef37 2820static gboolean process_exit(void *hook_data, void *call_data)
dc877563 2821{
eed2ef37 2822 LttvTracefileState *s = (LttvTracefileState *)call_data;
2823 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2824 LttvTraceHook *th = (LttvTraceHook *)hook_data;
eed2ef37 2825 guint pid;
348c6ba8 2826 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
6f54e0f4 2827 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 2828
d3a66443 2829 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2830 s->parent.target_pid = pid;
eed2ef37 2831
2832 // FIXME : Add this test in the "known state" section
348c6ba8 2833 // g_assert(process->pid == pid);
eed2ef37 2834
6f54e0f4 2835 process = lttv_state_find_process(ts, ANY_CPU, pid);
348c6ba8 2836 if(likely(process != NULL)) {
2837 process->state->s = LTTV_STATE_EXIT;
2cdc690b 2838 }
2839 return FALSE;
2cdc690b 2840}
2841
eed2ef37 2842static gboolean process_free(void *hook_data, void *call_data)
2da61677 2843{
eed2ef37 2844 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 2845 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 2846 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2847 LttvTraceHook *th = (LttvTraceHook *)hook_data;
2da61677 2848 guint release_pid;
2849 LttvProcessState *process;
2850
2851 /* PID of the process to release */
d3a66443 2852 release_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
33bdc8dd 2853 s->parent.target_pid = release_pid;
15b3d537 2854
2855 g_assert(release_pid != 0);
2da61677 2856
348c6ba8 2857 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
c7620c79 2858 if(likely(process != NULL))
2859 exit_process(s, process);
2da61677 2860
2861 return FALSE;
2862}
2863
f4b88a7d 2864
2865static gboolean process_exec(void *hook_data, void *call_data)
2866{
2867 LttvTracefileState *s = (LttvTracefileState *)call_data;
2868 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2869 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2870 LttvTraceHook *th = (LttvTraceHook *)hook_data;
743e50fd 2871 //gchar *name;
ae3d0f50 2872 guint cpu = s->cpu;
f4b88a7d 2873 LttvProcessState *process = ts->running_process[cpu];
2874
f63ebe51 2875#if 0//how to use a sequence that must be transformed in a string
f4b88a7d 2876 /* PID of the process to release */
d3a66443 2877 guint64 name_len = ltt_event_field_element_number(e,
2878 lttv_trace_get_hook_field(th, 0));
2879 //name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
2880 LttField *child = ltt_event_field_element_select(e,
2881 lttv_trace_get_hook_field(th, 0), 0);
f2923fb2 2882 gchar *name_begin =
2883 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 2884 gchar *null_term_name = g_new(gchar, name_len+1);
2885 memcpy(null_term_name, name_begin, name_len);
2886 null_term_name[name_len] = '\0';
743e50fd 2887 process->name = g_quark_from_string(null_term_name);
f63ebe51 2888#endif //0
2889
d3a66443 2890 process->name = g_quark_from_string(ltt_event_get_string(e,
2891 lttv_trace_get_hook_field(th, 0)));
0292757b 2892 process->brand = LTTV_STATE_UNBRANDED;
f63ebe51 2893 //g_free(null_term_name);
f4b88a7d 2894 return FALSE;
2895}
2896
7b5f6cf1 2897static gboolean thread_brand(void *hook_data, void *call_data)
2898{
2899 LttvTracefileState *s = (LttvTracefileState *)call_data;
2900 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2901 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
0ceef9de 2902 LttvTraceHook *th = (LttvTraceHook *)hook_data;
7b5f6cf1 2903 gchar *name;
2904 guint cpu = s->cpu;
2905 LttvProcessState *process = ts->running_process[cpu];
2906
d3a66443 2907 name = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 0));
7b5f6cf1 2908 process->brand = g_quark_from_string(name);
2909
2910 return FALSE;
2911}
2912
c3b3b60b 2913static void fix_process(gpointer key, gpointer value,
2914 gpointer user_data)
2915{
2916 LttvProcessState *process;
2917 LttvExecutionState *es;
2918 process = (LttvProcessState *)value;
c3b3b60b 2919 LttTime *timestamp = (LttTime*)user_data;
2920
c3b3b60b 2921 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2b25224d 2922 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2923 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2924 es->t = LTTV_STATE_SYSCALL;
2b25224d 2925 es->n = LTTV_STATE_SUBMODE_NONE;
2926 es->entry = *timestamp;
2927 es->change = *timestamp;
2928 es->cum_cpu_time = ltt_time_zero;
c4a72569 2929 if(es->s == LTTV_STATE_UNNAMED)
2930 es->s = LTTV_STATE_WAIT;
c3b3b60b 2931 }
2932 } else {
2b25224d 2933 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2934 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
c3b3b60b 2935 es->t = LTTV_STATE_USER_MODE;
2936 es->n = LTTV_STATE_SUBMODE_NONE;
2937 es->entry = *timestamp;
2938 //g_assert(timestamp->tv_sec != 0);
2939 es->change = *timestamp;
2940 es->cum_cpu_time = ltt_time_zero;
c4a72569 2941 if(es->s == LTTV_STATE_UNNAMED)
2942 es->s = LTTV_STATE_RUN;
c3b3b60b 2943
2b25224d 2944 if(process->execution_stack->len == 1) {
89f8741a 2945 /* Still in bottom unknown mode, means never did a system call
2946 * May be either in user mode, syscall mode, running or waiting.*/
2947 /* FIXME : we may be tagging syscall mode when being user mode */
2b25224d 2948 process->execution_stack =
2949 g_array_set_size(process->execution_stack, 2);
2950 es = process->state = &g_array_index(process->execution_stack,
c3b3b60b 2951 LttvExecutionState, 1);
2b25224d 2952 es->t = LTTV_STATE_SYSCALL;
2953 es->n = LTTV_STATE_SUBMODE_NONE;
2954 es->entry = *timestamp;
2955 //g_assert(timestamp->tv_sec != 0);
2956 es->change = *timestamp;
2957 es->cum_cpu_time = ltt_time_zero;
b59b7222 2958 if(es->s == LTTV_STATE_WAIT_FORK)
2959 es->s = LTTV_STATE_WAIT;
2b25224d 2960 }
c3b3b60b 2961 }
2962 }
2963}
2964
2965static gboolean statedump_end(void *hook_data, void *call_data)
2966{
2967 LttvTracefileState *s = (LttvTracefileState *)call_data;
2968 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2969 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
0ceef9de 2970 //LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2971 //LttvTraceHook *th = (LttvTraceHook *)hook_data;
c3b3b60b 2972
2973 /* For all processes */
2974 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2975 /* else, if stack[0] is unknown, set to user mode, running */
2976
2977 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
0ceef9de 2978
2979 return FALSE;
c3b3b60b 2980}
2981
b3fd4c02 2982static gboolean enum_process_state(void *hook_data, void *call_data)
2983{
2984 LttvTracefileState *s = (LttvTracefileState *)call_data;
2985 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
80e0221b 2986 //It's slow : optimise later by doing this before reading trace.
0ceef9de 2987 LttvTraceHook *th = (LttvTraceHook *)hook_data;
b3fd4c02 2988 guint parent_pid;
2989 guint pid;
fcc08e1e 2990 guint tgid;
b3fd4c02 2991 gchar * command;
ae3d0f50 2992 guint cpu = s->cpu;
b3fd4c02 2993 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2994 LttvProcessState *process = ts->running_process[cpu];
2995 LttvProcessState *parent_process;
d3a66443 2996 struct marker_field *f;
80e0221b 2997 GQuark type, mode, submode, status;
2998 LttvExecutionState *es;
c4a72569 2999 guint i, nb_cpus;
f4b88a7d 3000
b3fd4c02 3001 /* PID */
d3a66443 3002 pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 0));
e38d9ea0 3003 s->parent.target_pid = pid;
3004
b3fd4c02 3005 /* Parent PID */
d3a66443 3006 parent_pid = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
b3fd4c02 3007
3008 /* Command name */
d3a66443 3009 command = ltt_event_get_string(e, lttv_trace_get_hook_field(th, 2));
b3fd4c02 3010
80e0221b 3011 /* type */
d3a66443 3012 f = lttv_trace_get_hook_field(th, 3);
deb8b4b2 3013 type = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 3014
b0b1c1dd 3015 //FIXME: type is rarely used, enum must match possible types.
3016
80e0221b 3017 /* mode */
d3a66443 3018 f = lttv_trace_get_hook_field(th, 4);
deb8b4b2 3019 mode = ltt_enum_string_get(f,ltt_event_get_unsigned(e, f));
b3fd4c02 3020
80e0221b 3021 /* submode */
d3a66443 3022 f = lttv_trace_get_hook_field(th, 5);
deb8b4b2 3023 submode = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
b3fd4c02 3024
80e0221b 3025 /* status */
d3a66443 3026 f = lttv_trace_get_hook_field(th, 6);
deb8b4b2 3027 status = ltt_enum_string_get(f, ltt_event_get_unsigned(e, f));
e62e7f3a 3028
fcc08e1e 3029 /* TGID */
d3a66443 3030 f = lttv_trace_get_hook_field(th, 7);
3031 if(f)
3032 tgid = ltt_event_get_unsigned(e, f);
3033 else
3034 tgid = 0;
c4a72569 3035
3036 if(pid == 0) {
3037 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
3038 for(i=0; i<nb_cpus; i++) {
3039 process = lttv_state_find_process(ts, i, pid);
3040 g_assert(process != NULL);
3041
3042 process->ppid = parent_pid;
3043 process->tgid = tgid;
3044 process->name = g_quark_from_string(command);
3045 es =
3046 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 3047 process->type = LTTV_STATE_KERNEL_THREAD;
c4a72569 3048 }
3049
3050 } else {
3051 /* The process might exist if a process was forked while performing the
3052 * state dump. */
3053 process = lttv_state_find_process(ts, ANY_CPU, pid);
3054 if(process == NULL) {
3055 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
3056 process = lttv_state_create_process(ts, parent_process, cpu,
3057 pid, tgid, g_quark_from_string(command),
3058 &s->parent.timestamp);
3059
3060 /* Keep the stack bottom : a running user mode */
3061 /* Disabled because of inconsistencies in the current statedump states. */
3062 if(type == LTTV_STATE_KERNEL_THREAD) {
3063 /* Only keep the bottom
3064 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
3065 /* Will cause expected trap when in fact being syscall (even after end of
3066 * statedump event)
3067 * Will cause expected interrupt when being syscall. (only before end of
3068 * statedump event) */
3069 // This will cause a "popping last state on stack, ignoring it."
3070 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3071 es = process->state = &g_array_index(process->execution_stack,
3072 LttvExecutionState, 0);
3073 process->type = LTTV_STATE_KERNEL_THREAD;
3074 es->t = LTTV_STATE_MODE_UNKNOWN;
3075 es->s = LTTV_STATE_UNNAMED;
3076 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3077 #if 0
3078 es->t = LTTV_STATE_SYSCALL;
3079 es->s = status;
3080 es->n = submode;
3081 #endif //0
3082 } else {
3083 /* User space process :
3084 * bottom : user mode
3085 * either currently running or scheduled out.
3086 * can be scheduled out because interrupted in (user mode or in syscall)
3087 * or because of an explicit call to the scheduler in syscall. Note that
3088 * the scheduler call comes after the irq_exit, so never in interrupt
3089 * context. */
3090 // temp workaround : set size to 1 : only have user mode bottom of stack.
3091 // will cause g_info message of expected syscall mode when in fact being
3092 // in user mode. Can also cause expected trap when in fact being user
3093 // mode in the event of a page fault reenabling interrupts in the handler.
3094 // Expected syscall and trap can also happen after the end of statedump
3095 // This will cause a "popping last state on stack, ignoring it."
3096 process->execution_stack = g_array_set_size(process->execution_stack, 1);
3097 es = process->state = &g_array_index(process->execution_stack,
3098 LttvExecutionState, 0);
3099 es->t = LTTV_STATE_MODE_UNKNOWN;
3100 es->s = LTTV_STATE_UNNAMED;
3101 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3102 #if 0
3103 es->t = LTTV_STATE_USER_MODE;
3104 es->s = status;
3105 es->n = submode;
3106 #endif //0
3107 }
3108 #if 0
3109 /* UNKNOWN STATE */
3110 {
3111 es = process->state = &g_array_index(process->execution_stack,
3112 LttvExecutionState, 1);
3113 es->t = LTTV_STATE_MODE_UNKNOWN;
3114 es->s = LTTV_STATE_UNNAMED;
3115 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
3116 }
3117 #endif //0
80e0221b 3118 } else {
c4a72569 3119 /* The process has already been created :
3120 * Probably was forked while dumping the process state or
3121 * was simply scheduled in prior to get the state dump event.
3122 */
3123 process->ppid = parent_pid;
3124 process->tgid = tgid;
3125 process->name = g_quark_from_string(command);
3126 process->type = type;
3127 es =
3128 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 3129#if 0
c4a72569 3130 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
3131 if(type == LTTV_STATE_KERNEL_THREAD)
3132 es->t = LTTV_STATE_SYSCALL;
3133 else
3134 es->t = LTTV_STATE_USER_MODE;
3135 }
cab321cf 3136#endif //0
c4a72569 3137 /* Don't mess around with the stack, it will eventually become
3138 * ok after the end of state dump. */
80e0221b 3139 }
b3fd4c02 3140 }
3141
3142 return FALSE;
3143}
f4b88a7d 3144
58c88a41 3145gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
3146{
3147 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3148
3149 lttv_state_add_event_hooks(tss);
3150
3151 return 0;
3152}
dc877563 3153
308711e5 3154void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 3155{
ba576a78 3156 LttvTraceset *traceset = self->parent.ts;
dc877563 3157
8979f265 3158 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3159
ba576a78 3160 LttvTraceState *ts;
dc877563 3161
ba576a78 3162 LttvTracefileState *tfs;
dc877563 3163
dc877563 3164 GArray *hooks;
3165
0ceef9de 3166 LttvTraceHook *th;
eed2ef37 3167
dc877563 3168 LttvAttributeValue val;
3169
ba576a78 3170 nb_trace = lttv_traceset_number(traceset);
dc877563 3171 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 3172 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 3173
3174 /* Find the eventtype id for the following events and register the
3175 associated by id hooks. */
3176
c3b3b60b 3177 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
6418800d 3178 //hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
3179 //hn = 0;
b445142a 3180
6418800d 3181 lttv_trace_find_hook(ts->parent.t,
60c5092c 3182 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3183 LTT_EVENT_SYSCALL_ENTRY,
6418800d 3184 FIELD_ARRAY(LTT_FIELD_SYSCALL_ID),
3185 syscall_entry, NULL, &hooks);
cbe7c836 3186
6418800d 3187 lttv_trace_find_hook(ts->parent.t,
60c5092c 3188 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3189 LTT_EVENT_SYSCALL_EXIT,
032ba5da 3190 NULL,
6418800d 3191 syscall_exit, NULL, &hooks);
cbe7c836 3192
6418800d 3193 lttv_trace_find_hook(ts->parent.t,
60c5092c 3194 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3195 LTT_EVENT_TRAP_ENTRY,
6418800d 3196 FIELD_ARRAY(LTT_FIELD_TRAP_ID),
3197 trap_entry, NULL, &hooks);
cbe7c836 3198
032ba5da 3199 lttv_trace_find_hook(ts->parent.t,
60c5092c 3200 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3201 LTT_EVENT_TRAP_EXIT,
032ba5da 3202 NULL,
3203 trap_exit, NULL, &hooks);
cbe7c836 3204
032ba5da 3205 lttv_trace_find_hook(ts->parent.t,
60c5092c 3206 LTT_FACILITY_KERNEL,
0ceef9de 3207 LTT_EVENT_IRQ_ENTRY,
032ba5da 3208 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
3209 irq_entry, NULL, &hooks);
cbe7c836 3210
032ba5da 3211 lttv_trace_find_hook(ts->parent.t,
60c5092c 3212 LTT_FACILITY_KERNEL,
0ceef9de 3213 LTT_EVENT_IRQ_EXIT,
032ba5da 3214 NULL,
3215 irq_exit, NULL, &hooks);
cbe7c836 3216
032ba5da 3217 lttv_trace_find_hook(ts->parent.t,
60c5092c 3218 LTT_FACILITY_KERNEL,
0ceef9de 3219 LTT_EVENT_SOFT_IRQ_ENTRY,
032ba5da 3220 FIELD_ARRAY(LTT_FIELD_SOFT_IRQ_ID),
3221 soft_irq_entry, NULL, &hooks);
faf074a3 3222
032ba5da 3223 lttv_trace_find_hook(ts->parent.t,
60c5092c 3224 LTT_FACILITY_KERNEL,
0ceef9de 3225 LTT_EVENT_SOFT_IRQ_EXIT,
032ba5da 3226 NULL,
3227 soft_irq_exit, NULL, &hooks);
faf074a3 3228
032ba5da 3229 lttv_trace_find_hook(ts->parent.t,
60c5092c 3230 LTT_FACILITY_KERNEL,
0ceef9de 3231 LTT_EVENT_SCHED_SCHEDULE,
032ba5da 3232 FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID,
3233 LTT_FIELD_PREV_STATE),
3234 schedchange, NULL, &hooks);
cbe7c836 3235
032ba5da 3236 lttv_trace_find_hook(ts->parent.t,
60c5092c 3237 LTT_FACILITY_KERNEL,
0ceef9de 3238 LTT_EVENT_PROCESS_FORK,
032ba5da 3239 FIELD_ARRAY(LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID,
3240 LTT_FIELD_CHILD_TGID),
3241 process_fork, NULL, &hooks);
eed2ef37 3242
032ba5da 3243 lttv_trace_find_hook(ts->parent.t,
60c5092c 3244 LTT_FACILITY_KERNEL_ARCH,
0ceef9de 3245 LTT_EVENT_KTHREAD_CREATE,
370231d7 3246 FIELD_ARRAY(LTT_FIELD_PID),
032ba5da 3247 process_kernel_thread, NULL, &hooks);
7bfd7820 3248
032ba5da 3249 lttv_trace_find_hook(ts->parent.t,
60c5092c 3250 LTT_FACILITY_KERNEL,
0ceef9de 3251 LTT_EVENT_PROCESS_EXIT,
032ba5da 3252 FIELD_ARRAY(LTT_FIELD_PID),
3253 process_exit, NULL, &hooks);
eed2ef37 3254
032ba5da 3255 lttv_trace_find_hook(ts->parent.t,
60c5092c 3256 LTT_FACILITY_KERNEL,
0ceef9de 3257 LTT_EVENT_PROCESS_FREE,
032ba5da 3258 FIELD_ARRAY(LTT_FIELD_PID),
3259 process_free, NULL, &hooks);
2cdc690b 3260
032ba5da 3261 lttv_trace_find_hook(ts->parent.t,
43fb1d98 3262 LTT_FACILITY_FS,
0ceef9de 3263 LTT_EVENT_EXEC,
032ba5da 3264 FIELD_ARRAY(LTT_FIELD_FILENAME),
3265 process_exec, NULL, &hooks);
f4b88a7d 3266
032ba5da 3267 lttv_trace_find_hook(ts->parent.t,
60c5092c 3268 LTT_FACILITY_USER_GENERIC,
0ceef9de 3269 LTT_EVENT_THREAD_BRAND,
032ba5da 3270 FIELD_ARRAY(LTT_FIELD_NAME),
3271 thread_brand, NULL, &hooks);
7b5f6cf1 3272
b3fd4c02 3273 /* statedump-related hooks */
032ba5da 3274 lttv_trace_find_hook(ts->parent.t,
60c5092c 3275 LTT_FACILITY_LIST,
0ceef9de 3276 LTT_EVENT_PROCESS_STATE,
d3a66443 3277 FIELD_ARRAY(LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
3278 LTT_FIELD_TYPE, LTT_FIELD_MODE, LTT_FIELD_SUBMODE,
3279 LTT_FIELD_STATUS, LTT_FIELD_TGID),
032ba5da 3280 enum_process_state, NULL, &hooks);
f4b88a7d 3281
032ba5da 3282 lttv_trace_find_hook(ts->parent.t,
60c5092c 3283 LTT_FACILITY_LIST,
0ceef9de 3284 LTT_EVENT_STATEDUMP_END,
032ba5da 3285 NULL,
3286 statedump_end, NULL, &hooks);
c3b3b60b 3287
032ba5da 3288 lttv_trace_find_hook(ts->parent.t,
60c5092c 3289 LTT_FACILITY_LIST,
0ceef9de 3290 LTT_EVENT_LIST_INTERRUPT,
43fb1d98 3291 FIELD_ARRAY(LTT_FIELD_ACTION, LTT_FIELD_IRQ_ID),
032ba5da 3292 enum_interrupt, NULL, &hooks);
38b73700 3293
032ba5da 3294 lttv_trace_find_hook(ts->parent.t,
60c5092c 3295 LTT_FACILITY_BLOCK,
0ceef9de 3296 LTT_EVENT_REQUEST_ISSUE,
032ba5da 3297 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3298 bdev_request_issue, NULL, &hooks);
27811799 3299
032ba5da 3300 lttv_trace_find_hook(ts->parent.t,
60c5092c 3301 LTT_FACILITY_BLOCK,
0ceef9de 3302 LTT_EVENT_REQUEST_COMPLETE,
032ba5da 3303 FIELD_ARRAY(LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION),
3304 bdev_request_complete, NULL, &hooks);
27811799 3305
032ba5da 3306 lttv_trace_find_hook(ts->parent.t,
60c5092c 3307 LTT_FACILITY_USER_GENERIC,
0ceef9de 3308 LTT_EVENT_FUNCTION_ENTRY,
032ba5da 3309 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3310 function_entry, NULL, &hooks);
302efbad 3311
032ba5da 3312 lttv_trace_find_hook(ts->parent.t,
60c5092c 3313 LTT_FACILITY_USER_GENERIC,
0ceef9de 3314 LTT_EVENT_FUNCTION_EXIT,
032ba5da 3315 FIELD_ARRAY(LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE),
3316 function_exit, NULL, &hooks);
302efbad 3317
a5ba1787 3318 /* Add these hooks to each event_by_id hooks list */
dc877563 3319
eed2ef37 3320 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3321
dc877563 3322 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3323 tfs =
9d239bd9 3324 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3325 LttvTracefileContext*, j));
dc877563 3326
3327 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3328 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3329 lttv_hooks_add(
5fd4c7a2 3330 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3331 th->h,
3332 th,
eed2ef37 3333 LTTV_PRIO_STATE);
ffd54a90 3334 }
dc877563 3335 }
f0b795e0 3336 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3337 *(val.v_pointer) = hooks;
dc877563 3338 }
3339}
3340
58c88a41 3341gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3342{
3343 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3344
3345 lttv_state_remove_event_hooks(tss);
3346
3347 return 0;
3348}
dc877563 3349
308711e5 3350void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 3351{
ba576a78 3352 LttvTraceset *traceset = self->parent.ts;
dc877563 3353
8979f265 3354 guint i, j, k, nb_trace, nb_tracefile;
dc877563 3355
ba576a78 3356 LttvTraceState *ts;
dc877563 3357
ba576a78 3358 LttvTracefileState *tfs;
dc877563 3359
dc877563 3360 GArray *hooks;
3361
5fd4c7a2 3362 LttvTraceHook *th;
dc877563 3363
3364 LttvAttributeValue val;
3365
ba576a78 3366 nb_trace = lttv_traceset_number(traceset);
dc877563 3367 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 3368 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
7df20ca4 3369
f0b795e0 3370 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3371 hooks = *(val.v_pointer);
dc877563 3372
a5ba1787 3373 /* Remove these hooks from each event_by_id hooks list */
dc877563 3374
eed2ef37 3375 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3376
dc877563 3377 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3378 tfs =
cb03932a 3379 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3380 LttvTracefileContext*, j));
dc877563 3381
3382 for(k = 0 ; k < hooks->len ; k++) {
8979f265 3383 th = &g_array_index(hooks, LttvTraceHook, k);
eed2ef37 3384 lttv_hooks_remove_data(
5fd4c7a2 3385 lttv_hooks_by_id_find(tfs->parent.event_by_id, th->id),
3386 th->h,
3387 th);
ffd54a90 3388 }
dc877563 3389 }
032ba5da 3390 lttv_trace_hook_remove_all(&hooks);
dc877563 3391 g_array_free(hooks, TRUE);
3392 }
3393}
3394
eed2ef37 3395static gboolean state_save_event_hook(void *hook_data, void *call_data)
3396{
3397 guint *event_count = (guint*)hook_data;
3398
3399 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3400 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3401 return FALSE;
3402 else
18c87975 3403 *event_count = 0;
eed2ef37 3404
3405 LttvTracefileState *self = (LttvTracefileState *)call_data;
3406
eed2ef37 3407 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3408
eed2ef37 3409 LttvAttribute *saved_states_tree, *saved_state_tree;
3410
3411 LttvAttributeValue value;
3412
3413 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3414 LTTV_STATE_SAVED_STATES);
3415 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3416 value = lttv_attribute_add(saved_states_tree,
3417 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3418 *(value.v_gobject) = (GObject *)saved_state_tree;
3419 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3420 *(value.v_time) = self->parent.timestamp;
3421 lttv_state_save(tcs, saved_state_tree);
3422 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3423 self->parent.timestamp.tv_nsec);
3424
3425 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3426
3427 return FALSE;
3428}
3429
14aecf75 3430static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3431{
3432 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3433
3434 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3435
3436 return FALSE;
3437}
3438
ae3d0f50 3439guint lttv_state_current_cpu(LttvTracefileState *tfs)
3440{
80e0221b 3441 return tfs->cpu;
ae3d0f50 3442}
3443
3444
3445
eed2ef37 3446#if 0
08b1c66e 3447static gboolean block_start(void *hook_data, void *call_data)
308711e5 3448{
dbb7bb09 3449 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 3450
dbb7bb09 3451 LttvTracefileState *tfcs;
308711e5 3452
dbb7bb09 3453 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3454
3455 LttEventPosition *ep;
308711e5 3456
dbb7bb09 3457 guint i, nb_block, nb_event, nb_tracefile;
308711e5 3458
3459 LttTracefile *tf;
3460
3461 LttvAttribute *saved_states_tree, *saved_state_tree;
3462
3463 LttvAttributeValue value;
3464
dbb7bb09 3465 ep = ltt_event_position_new();
eed2ef37 3466
3467 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 3468
3469 /* Count the number of events added since the last block end in any
3470 tracefile. */
3471
3472 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 3473 tfcs =
3474 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3475 LttvTracefileContext, i));
dbb7bb09 3476 ltt_event_position(tfcs->parent.e, ep);
3477 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3478 tcs->nb_event += nb_event - tfcs->saved_position;
3479 tfcs->saved_position = nb_event;
3480 }
3481 g_free(ep);
308711e5 3482
308711e5 3483 if(tcs->nb_event >= tcs->save_interval) {
3484 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3485 LTTV_STATE_SAVED_STATES);
3486 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3487 value = lttv_attribute_add(saved_states_tree,
3488 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3489 *(value.v_gobject) = (GObject *)saved_state_tree;
3490 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 3491 *(value.v_time) = self->parent.timestamp;
308711e5 3492 lttv_state_save(tcs, saved_state_tree);
3493 tcs->nb_event = 0;
08b1c66e 3494 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
80e0221b 3495 self->parent.timestamp.tv_nsec);
308711e5 3496 }
dbb7bb09 3497 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 3498 return FALSE;
3499}
eed2ef37 3500#endif //0
308711e5 3501
eed2ef37 3502#if 0
08b1c66e 3503static gboolean block_end(void *hook_data, void *call_data)
3504{
3505 LttvTracefileState *self = (LttvTracefileState *)call_data;
3506
3507 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3508
3509 LttTracefile *tf;
3510
3511 LttEventPosition *ep;
3512
3513 guint nb_block, nb_event;
3514
3515 ep = ltt_event_position_new();
3516 ltt_event_position(self->parent.e, ep);
3517 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3518 tcs->nb_event += nb_event - self->saved_position + 1;
3519 self->saved_position = 0;
3520 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3521 g_free(ep);
00e74b69 3522
3523 return FALSE;
08b1c66e 3524}
eed2ef37 3525#endif //0
3526#if 0
308711e5 3527void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3528{
3529 LttvTraceset *traceset = self->parent.ts;
3530
00e74b69 3531 guint i, j, nb_trace, nb_tracefile;
308711e5 3532
3533 LttvTraceState *ts;
3534
3535 LttvTracefileState *tfs;
3536
08b1c66e 3537 LttvTraceHook hook_start, hook_end;
308711e5 3538
3539 nb_trace = lttv_traceset_number(traceset);
3540 for(i = 0 ; i < nb_trace ; i++) {
3541 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3542
08b1c66e 3543 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3544 NULL, NULL, block_start, &hook_start);
308711e5 3545 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3546 NULL, NULL, block_end, &hook_end);
308711e5 3547
eed2ef37 3548 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3549
dbb7bb09 3550 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3551 tfs =
3552 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3553 LttvTracefileContext, j));
a5ba1787 3554 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3555 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 3556 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3557 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
eed2ef37 3558 }
3559 }
3560}
3561#endif //0
3562
3563void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3564{
3565 LttvTraceset *traceset = self->parent.ts;
3566
3567 guint i, j, nb_trace, nb_tracefile;
3568
3569 LttvTraceState *ts;
3570
3571 LttvTracefileState *tfs;
3572
3573
3574 nb_trace = lttv_traceset_number(traceset);
3575 for(i = 0 ; i < nb_trace ; i++) {
3576
3577 ts = (LttvTraceState *)self->parent.traces[i];
3578 nb_tracefile = ts->parent.tracefiles->len;
3579
ce05e187 3580 if(ts->has_precomputed_states) continue;
3581
3054461a 3582 guint *event_count = g_new(guint, 1);
3583 *event_count = 0;
3584
eed2ef37 3585 for(j = 0 ; j < nb_tracefile ; j++) {
3586 tfs =
cb03932a 3587 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3588 LttvTracefileContext*, j));
eed2ef37 3589 lttv_hooks_add(tfs->parent.event,
3590 state_save_event_hook,
3591 event_count,
3592 LTTV_PRIO_STATE);
3593
308711e5 3594 }
3595 }
14aecf75 3596
3597 lttv_process_traceset_begin(&self->parent,
3598 NULL, NULL, NULL, NULL, NULL);
3599
308711e5 3600}
3601
b56b5fec 3602gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3603{
3604 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3605
3606 lttv_state_save_add_event_hooks(tss);
3607
3608 return 0;
3609}
3610
308711e5 3611
eed2ef37 3612#if 0
308711e5 3613void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3614{
3615 LttvTraceset *traceset = self->parent.ts;
3616
00e74b69 3617 guint i, j, nb_trace, nb_tracefile;
308711e5 3618
3619 LttvTraceState *ts;
3620
3621 LttvTracefileState *tfs;
3622
08b1c66e 3623 LttvTraceHook hook_start, hook_end;
308711e5 3624
3625 nb_trace = lttv_traceset_number(traceset);
3626 for(i = 0 ; i < nb_trace ; i++) {
3627 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 3628
08b1c66e 3629 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3630 NULL, NULL, block_start, &hook_start);
08b1c66e 3631
308711e5 3632 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3633 NULL, NULL, block_end, &hook_end);
308711e5 3634
eed2ef37 3635 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3636
dbb7bb09 3637 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3638 tfs =
3639 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3640 LttvTracefileContext, j));
308711e5 3641 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3642 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 3643 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3644 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 3645 }
3646 }
3647}
eed2ef37 3648#endif //0
3649
3650void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3651{
3652 LttvTraceset *traceset = self->parent.ts;
3653
3654 guint i, j, nb_trace, nb_tracefile;
3655
3656 LttvTraceState *ts;
3657
3658 LttvTracefileState *tfs;
3659
14aecf75 3660 LttvHooks *after_trace = lttv_hooks_new();
3661
3662 lttv_hooks_add(after_trace,
3663 state_save_after_trace_hook,
3664 NULL,
3665 LTTV_PRIO_STATE);
3666
3667
3668 lttv_process_traceset_end(&self->parent,
3669 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 3670
14aecf75 3671 lttv_hooks_destroy(after_trace);
3672
eed2ef37 3673 nb_trace = lttv_traceset_number(traceset);
3674 for(i = 0 ; i < nb_trace ; i++) {
3675
3676 ts = (LttvTraceState *)self->parent.traces[i];
3677 nb_tracefile = ts->parent.tracefiles->len;
3678
ce05e187 3679 if(ts->has_precomputed_states) continue;
3680
22b165e9 3681 guint *event_count = NULL;
eed2ef37 3682
3683 for(j = 0 ; j < nb_tracefile ; j++) {
3684 tfs =
cb03932a 3685 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3686 LttvTracefileContext*, j));
eed2ef37 3687 event_count = lttv_hooks_remove(tfs->parent.event,
3688 state_save_event_hook);
eed2ef37 3689 }
22b165e9 3690 if(event_count) g_free(event_count);
eed2ef37 3691 }
3692}
308711e5 3693
b56b5fec 3694gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3695{
3696 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3697
3698 lttv_state_save_remove_event_hooks(tss);
3699
3700 return 0;
3701}
308711e5 3702
dd025f91 3703void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 3704{
3705 LttvTraceset *traceset = self->parent.ts;
3706
00e74b69 3707 guint i, nb_trace;
308711e5 3708
3709 int min_pos, mid_pos, max_pos;
3710
728d0c3e 3711 guint call_rest = 0;
3712
308711e5 3713 LttvTraceState *tcs;
3714
3715 LttvAttributeValue value;
3716
3717 LttvAttributeType type;
3718
3719 LttvAttributeName name;
3720
80e0221b 3721 gboolean is_named;
c0cb4d12 3722
308711e5 3723 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3724
d448fce2 3725 //g_tree_destroy(self->parent.pqueue);
3726 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 3727
728d0c3e 3728 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3729
308711e5 3730 nb_trace = lttv_traceset_number(traceset);
3731 for(i = 0 ; i < nb_trace ; i++) {
3732 tcs = (LttvTraceState *)self->parent.traces[i];
3733
2a2fa4f0 3734 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3735 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3736 LTTV_STATE_SAVED_STATES);
3737 min_pos = -1;
3738
3739 if(saved_states_tree) {
dd025f91 3740 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3741 mid_pos = max_pos / 2;
3742 while(min_pos < max_pos) {
c0cb4d12 3743 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
80e0221b 3744 &is_named);
dd025f91 3745 g_assert(type == LTTV_GOBJECT);
3746 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3747 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3748 &value);
3749 g_assert(type == LTTV_TIME);
3750 if(ltt_time_compare(*(value.v_time), t) < 0) {
3751 min_pos = mid_pos;
3752 closest_tree = saved_state_tree;
3753 }
3754 else max_pos = mid_pos - 1;
3755
3756 mid_pos = (min_pos + max_pos + 1) / 2;
3757 }
2a2fa4f0 3758 }
dd025f91 3759
2a2fa4f0 3760 /* restore the closest earlier saved state */
f95bc830 3761 if(min_pos != -1) {
3762 lttv_state_restore(tcs, closest_tree);
728d0c3e 3763 call_rest = 1;
f95bc830 3764 }
dd025f91 3765
2a2fa4f0 3766 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 3767 else {
3768 restore_init_state(tcs);
3769 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 3770 }
9444deae 3771 }
dd025f91 3772 /* We want to seek quickly without restoring/updating the state */
3773 else {
308711e5 3774 restore_init_state(tcs);
dd025f91 3775 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 3776 }
308711e5 3777 }
728d0c3e 3778 if(!call_rest) g_info("NOT Calling restore");
308711e5 3779}
3780
3781
3782static void
3783traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3784{
3785}
3786
3787
3788static void
3789traceset_state_finalize (LttvTracesetState *self)
3790{
3791 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3792 finalize(G_OBJECT(self));
3793}
3794
3795
3796static void
3797traceset_state_class_init (LttvTracesetContextClass *klass)
3798{
3799 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3800
3801 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3802 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3803 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3804 klass->new_traceset_context = new_traceset_context;
3805 klass->new_trace_context = new_trace_context;
3806 klass->new_tracefile_context = new_tracefile_context;
3807}
3808
3809
3810GType
3811lttv_traceset_state_get_type(void)
3812{
3813 static GType type = 0;
3814 if (type == 0) {
3815 static const GTypeInfo info = {
3816 sizeof (LttvTracesetStateClass),
3817 NULL, /* base_init */
3818 NULL, /* base_finalize */
3819 (GClassInitFunc) traceset_state_class_init, /* class_init */
3820 NULL, /* class_finalize */
3821 NULL, /* class_data */
dbb7bb09 3822 sizeof (LttvTracesetState),
308711e5 3823 0, /* n_preallocs */
00e74b69 3824 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3825 NULL /* value handling */
308711e5 3826 };
3827
3828 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3829 &info, 0);
3830 }
3831 return type;
3832}
3833
3834
3835static void
3836trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3837{
3838}
3839
3840
3841static void
3842trace_state_finalize (LttvTraceState *self)
3843{
3844 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3845 finalize(G_OBJECT(self));
3846}
3847
3848
3849static void
3850trace_state_class_init (LttvTraceStateClass *klass)
3851{
3852 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3853
3854 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3855 klass->state_save = state_save;
3856 klass->state_restore = state_restore;
3857 klass->state_saved_free = state_saved_free;
3858}
3859
3860
3861GType
3862lttv_trace_state_get_type(void)
3863{
3864 static GType type = 0;
3865 if (type == 0) {
3866 static const GTypeInfo info = {
3867 sizeof (LttvTraceStateClass),
3868 NULL, /* base_init */
3869 NULL, /* base_finalize */
3870 (GClassInitFunc) trace_state_class_init, /* class_init */
3871 NULL, /* class_finalize */
3872 NULL, /* class_data */
3873 sizeof (LttvTraceState),
3874 0, /* n_preallocs */
00e74b69 3875 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3876 NULL /* value handling */
308711e5 3877 };
3878
3879 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3880 "LttvTraceStateType", &info, 0);
3881 }
3882 return type;
3883}
3884
3885
3886static void
3887tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3888{
3889}
3890
3891
3892static void
3893tracefile_state_finalize (LttvTracefileState *self)
3894{
3895 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3896 finalize(G_OBJECT(self));
3897}
3898
3899
3900static void
3901tracefile_state_class_init (LttvTracefileStateClass *klass)
3902{
3903 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3904
3905 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3906}
3907
3908
3909GType
3910lttv_tracefile_state_get_type(void)
3911{
3912 static GType type = 0;
3913 if (type == 0) {
3914 static const GTypeInfo info = {
3915 sizeof (LttvTracefileStateClass),
3916 NULL, /* base_init */
3917 NULL, /* base_finalize */
3918 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3919 NULL, /* class_finalize */
3920 NULL, /* class_data */
3921 sizeof (LttvTracefileState),
3922 0, /* n_preallocs */
00e74b69 3923 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3924 NULL /* value handling */
308711e5 3925 };
3926
3927 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3928 "LttvTracefileStateType", &info, 0);
3929 }
3930 return type;
3931}
3932
3933
08b1c66e 3934static void module_init()
ffd54a90 3935{
b4fa748c 3936 LTTV_STATE_UNNAMED = g_quark_from_string("");
235c78f0 3937 LTTV_STATE_UNBRANDED = g_quark_from_string("");
b3fd4c02 3938 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3939 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3940 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3941 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3942 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3943 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3944 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3945 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3946 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3947 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3948 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3949 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3950 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3951 LTTV_STATE_RUN = g_quark_from_string("RUN");
3952 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
80e0221b 3953 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3954 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
308711e5 3955 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3956 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3957 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 3958 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 3959 LTTV_STATE_EVENT = g_quark_from_string("event");
3960 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 3961 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 3962 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 3963 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 3964 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3965 LTTV_STATE_TRACE_STATE_USE_COUNT =
3966 g_quark_from_string("trace_state_use_count");
fbfbd4db 3967 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
f61bce48 3968 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu count");
98d7814f 3969 LTTV_STATE_RESOURCE_IRQS = g_quark_from_string("irq resource states");
0305fe77 3970 LTTV_STATE_RESOURCE_SOFT_IRQS = g_quark_from_string("soft irq resource states");
38726a78 3971 LTTV_STATE_RESOURCE_TRAPS = g_quark_from_string("trap resource states");
98d7814f 3972 LTTV_STATE_RESOURCE_BLKDEVS = g_quark_from_string("blkdevs resource states");
eed2ef37 3973
3974
3975 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 3976 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
f4b88a7d 3977 LTT_FACILITY_FS = g_quark_from_string("fs");
86c32a8f 3978 LTT_FACILITY_LIST = g_quark_from_string("list");
302efbad 3979 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
27811799 3980 LTT_FACILITY_BLOCK = g_quark_from_string("block");
eed2ef37 3981
3982
3983 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3984 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3985 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3986 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3987 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3988 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
43fb1d98 3989 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("softirq_entry");
3990 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("softirq_exit");
86c32a8f 3991 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3992 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3993 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3994 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
f63ebe51 3995 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
f4b88a7d 3996 LTT_EVENT_EXEC = g_quark_from_string("exec");
86c32a8f 3997 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
c3b3b60b 3998 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
302efbad 3999 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
4000 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
7b5f6cf1 4001 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
27811799 4002 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
4003 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
38b73700 4004 LTT_EVENT_LIST_INTERRUPT = g_quark_from_string("interrupt");;
eed2ef37 4005
4006
4007 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
4008 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
4009 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 4010 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
f63ebe51 4011 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
4012 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
4013 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
eed2ef37 4014 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
4015 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
4016 LTT_FIELD_PID = g_quark_from_string("pid");
fcc08e1e 4017 LTT_FIELD_TGID = g_quark_from_string("tgid");
f63ebe51 4018 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
f4b88a7d 4019 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 4020 LTT_FIELD_NAME = g_quark_from_string("name");
e62e7f3a 4021 LTT_FIELD_TYPE = g_quark_from_string("type");
b3fd4c02 4022 LTT_FIELD_MODE = g_quark_from_string("mode");
4023 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
4024 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 4025 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
4026 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
27811799 4027 LTT_FIELD_MAJOR = g_quark_from_string("major");
4028 LTT_FIELD_MINOR = g_quark_from_string("minor");
4029 LTT_FIELD_OPERATION = g_quark_from_string("direction");
38b73700 4030 LTT_FIELD_ACTION = g_quark_from_string("action");
eed2ef37 4031
44ffb95f 4032 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
4033 LTTV_CPU_IDLE = g_quark_from_string("idle");
4034 LTTV_CPU_BUSY = g_quark_from_string("busy");
598026ba 4035 LTTV_CPU_IRQ = g_quark_from_string("irq");
d34141ca 4036 LTTV_CPU_SOFT_IRQ = g_quark_from_string("softirq");
d3d99fde 4037 LTTV_CPU_TRAP = g_quark_from_string("trap");
5e563da0 4038
4039 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
4040 LTTV_IRQ_IDLE = g_quark_from_string("idle");
4041 LTTV_IRQ_BUSY = g_quark_from_string("busy");
27811799 4042
4043 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
4044 LTTV_BDEV_IDLE = g_quark_from_string("idle");
4045 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
4046 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
ffd54a90 4047}
dc877563 4048
08b1c66e 4049static void module_destroy()
ffd54a90 4050{
4051}
dc877563 4052
4053
08b1c66e 4054LTTV_MODULE("state", "State computation", \
4055 "Update the system state, possibly saving it at intervals", \
4056 module_init, module_destroy)
4057
dc877563 4058
4059
This page took 0.327849 seconds and 4 git commands to generate.