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