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