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