thread fix
[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
4e4d11b3 19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
dc877563 22
08b1c66e 23#include <lttv/lttv.h>
24#include <lttv/module.h>
dc877563 25#include <lttv/state.h>
ba576a78 26#include <ltt/facility.h>
27#include <ltt/trace.h>
308711e5 28#include <ltt/event.h>
a5dcde2f 29#include <ltt/type.h>
f95bc830 30#include <stdio.h>
b3fd4c02 31#include <string.h>
dc877563 32
e8f2280c 33#define PREALLOCATED_EXECUTION_STACK 10
34
eed2ef37 35/* Facilities Quarks */
36
37GQuark
38 LTT_FACILITY_KERNEL,
f5d7967f 39 LTT_FACILITY_KERNEL_ARCH,
f4b88a7d 40 LTT_FACILITY_PROCESS,
b3fd4c02 41 LTT_FACILITY_FS,
42 LTT_FACILITY_STATEDUMP;
eed2ef37 43
44/* Events Quarks */
45
46GQuark
47 LTT_EVENT_SYSCALL_ENTRY,
48 LTT_EVENT_SYSCALL_EXIT,
49 LTT_EVENT_TRAP_ENTRY,
50 LTT_EVENT_TRAP_EXIT,
51 LTT_EVENT_IRQ_ENTRY,
52 LTT_EVENT_IRQ_EXIT,
faf074a3 53 LTT_EVENT_SOFT_IRQ_ENTRY,
54 LTT_EVENT_SOFT_IRQ_EXIT,
eed2ef37 55 LTT_EVENT_SCHEDCHANGE,
56 LTT_EVENT_FORK,
7bfd7820 57 LTT_EVENT_KERNEL_THREAD,
eed2ef37 58 LTT_EVENT_EXIT,
f4b88a7d 59 LTT_EVENT_FREE,
b3fd4c02 60 LTT_EVENT_EXEC,
61 LTT_EVENT_ENUM_PROCESS_STATE;
eed2ef37 62
63/* Fields Quarks */
64
65GQuark
66 LTT_FIELD_SYSCALL_ID,
67 LTT_FIELD_TRAP_ID,
68 LTT_FIELD_IRQ_ID,
faf074a3 69 LTT_FIELD_SOFT_IRQ_ID,
eed2ef37 70 LTT_FIELD_OUT,
71 LTT_FIELD_IN,
72 LTT_FIELD_OUT_STATE,
73 LTT_FIELD_PARENT_PID,
74 LTT_FIELD_CHILD_PID,
f4b88a7d 75 LTT_FIELD_PID,
b3fd4c02 76 LTT_FIELD_FILENAME,
77 LTT_FIELD_NAME,
78 LTT_FIELD_MODE,
79 LTT_FIELD_SUBMODE,
80 LTT_FIELD_STATUS;
eed2ef37 81
b445142a 82LttvExecutionMode
83 LTTV_STATE_MODE_UNKNOWN,
ffd54a90 84 LTTV_STATE_USER_MODE,
85 LTTV_STATE_SYSCALL,
86 LTTV_STATE_TRAP,
faf074a3 87 LTTV_STATE_IRQ,
88 LTTV_STATE_SOFT_IRQ;
ffd54a90 89
b445142a 90LttvExecutionSubmode
91 LTTV_STATE_SUBMODE_UNKNOWN,
92 LTTV_STATE_SUBMODE_NONE;
ffd54a90 93
94LttvProcessStatus
95 LTTV_STATE_UNNAMED,
96 LTTV_STATE_WAIT_FORK,
97 LTTV_STATE_WAIT_CPU,
dbd243b1 98 LTTV_STATE_EXIT,
0828099d 99 LTTV_STATE_ZOMBIE,
ffd54a90 100 LTTV_STATE_WAIT,
791dffa6 101 LTTV_STATE_RUN,
102 LTTV_STATE_DEAD;
ffd54a90 103
ba576a78 104static GQuark
308711e5 105 LTTV_STATE_TRACEFILES,
106 LTTV_STATE_PROCESSES,
107 LTTV_STATE_PROCESS,
348c6ba8 108 LTTV_STATE_RUNNING_PROCESS,
308711e5 109 LTTV_STATE_EVENT,
110 LTTV_STATE_SAVED_STATES,
dbb7bb09 111 LTTV_STATE_SAVED_STATES_TIME,
308711e5 112 LTTV_STATE_TIME,
f95bc830 113 LTTV_STATE_HOOKS,
114 LTTV_STATE_NAME_TABLES,
115 LTTV_STATE_TRACE_STATE_USE_COUNT;
ba576a78 116
f95bc830 117static void create_max_time(LttvTraceState *tcs);
118
119static void get_max_time(LttvTraceState *tcs);
120
121static void free_max_time(LttvTraceState *tcs);
122
123static void create_name_tables(LttvTraceState *tcs);
124
125static void get_name_tables(LttvTraceState *tcs);
b445142a 126
127static void free_name_tables(LttvTraceState *tcs);
128
f95bc830 129static void free_saved_state(LttvTraceState *tcs);
130
308711e5 131static void lttv_state_free_process_table(GHashTable *processes);
ba576a78 132
dc877563 133
308711e5 134void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
135{
136 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
137}
138
139
140void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
141{
142 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
143}
144
145
2d262115 146void lttv_state_state_saved_free(LttvTraceState *self,
308711e5 147 LttvAttribute *container)
148{
f95bc830 149 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
308711e5 150}
151
152
2a2fa4f0 153guint process_hash(gconstpointer key)
154{
7893f726 155 guint pid = ((const LttvProcessState *)key)->pid;
156 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
2a2fa4f0 157}
158
159
1d1df11d 160/* If the hash table hash function is well distributed,
161 * the process_equal should compare different pid */
2a2fa4f0 162gboolean process_equal(gconstpointer a, gconstpointer b)
163{
00e74b69 164 const LttvProcessState *process_a, *process_b;
1d1df11d 165 gboolean ret = TRUE;
166
00e74b69 167 process_a = (const LttvProcessState *)a;
168 process_b = (const LttvProcessState *)b;
1d1df11d 169
170 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
171 else if(likely(process_a->pid == 0 &&
348c6ba8 172 process_a->cpu != process_b->cpu)) ret = FALSE;
2a2fa4f0 173
1d1df11d 174 return ret;
2a2fa4f0 175}
176
177
308711e5 178static void
179restore_init_state(LttvTraceState *self)
180{
348c6ba8 181 guint i, nb_cpus;
308711e5 182
183 LttvTracefileState *tfcs;
184
348c6ba8 185 /* Free the process tables */
308711e5 186 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
2a2fa4f0 187 self->processes = g_hash_table_new(process_hash, process_equal);
308711e5 188 self->nb_event = 0;
189
348c6ba8 190 /* Seek time to beginning */
9ba3aaaf 191 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
192 // closest. It's the tracecontext job to seek the trace to the beginning
193 // anyway : the init state might be used at the middle of the trace as well...
194 //g_tree_destroy(self->parent.ts_context->pqueue);
195 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
348c6ba8 196
9ba3aaaf 197
198 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
348c6ba8 199
200 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
201
202 /* Put the per cpu running_process to beginning state : process 0. */
203 for(i=0; i< nb_cpus; i++) {
204 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0,
b3fd4c02 205 LTTV_STATE_UNNAMED, &ltt_time_zero);
348c6ba8 206 self->running_process[i]->state->s = LTTV_STATE_RUN;
207 self->running_process[i]->cpu = i;
208 }
209
210#if 0
eed2ef37 211 nb_tracefile = self->parent.tracefiles->len;
308711e5 212
dbb7bb09 213 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 214 tfcs =
cb03932a 215 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
216 LttvTracefileContext*, i));
d3e01c7a 217 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
eed2ef37 218// tfcs->saved_position = 0;
2a2fa4f0 219 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
220 tfcs->process->state->s = LTTV_STATE_RUN;
221 tfcs->process->last_cpu = tfcs->cpu_name;
2c82c4dc 222 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
308711e5 223 }
348c6ba8 224#endif //0
308711e5 225}
226
348c6ba8 227//static LttTime time_zero = {0,0};
308711e5 228
dc877563 229static void
230init(LttvTracesetState *self, LttvTraceset *ts)
231{
dbb7bb09 232 guint i, j, nb_trace, nb_tracefile;
dc877563 233
ffd54a90 234 LttvTraceContext *tc;
dc877563 235
ffd54a90 236 LttvTraceState *tcs;
237
ffd54a90 238 LttvTracefileState *tfcs;
3d27549e 239
dbb7bb09 240 LttvAttributeValue v;
241
b445142a 242 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
243 init((LttvTracesetContext *)self, ts);
dc877563 244
245 nb_trace = lttv_traceset_number(ts);
246 for(i = 0 ; i < nb_trace ; i++) {
b445142a 247 tc = self->parent.traces[i];
021eeb41 248 tcs = LTTV_TRACE_STATE(tc);
eed2ef37 249 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
f95bc830 250 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
251 LTTV_UINT, &v);
252 (*v.v_uint)++;
dbb7bb09 253
f95bc830 254 if(*(v.v_uint) == 1) {
255 create_name_tables(tcs);
256 create_max_time(tcs);
257 }
258 get_name_tables(tcs);
259 get_max_time(tcs);
dc877563 260
eed2ef37 261 nb_tracefile = tc->tracefiles->len;
348c6ba8 262#if 0
dc877563 263 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 264 tfcs =
cb03932a 265 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
266 LttvTracefileContext*, j));
348c6ba8 267 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
dc877563 268 }
348c6ba8 269#endif //0
308711e5 270 tcs->processes = NULL;
348c6ba8 271 tcs->running_process = g_new(LttvProcessState*,
272 ltt_trace_get_num_cpu(tc->t));
308711e5 273 restore_init_state(tcs);
dc877563 274 }
275}
276
277
278static void
279fini(LttvTracesetState *self)
280{
00e74b69 281 guint i, nb_trace;
dc877563 282
ffd54a90 283 LttvTraceState *tcs;
dc877563 284
ffd54a90 285 LttvTracefileState *tfcs;
dc877563 286
f95bc830 287 LttvAttributeValue v;
288
ffd54a90 289 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
dc877563 290 for(i = 0 ; i < nb_trace ; i++) {
ffd54a90 291 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
f95bc830 292 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
293 LTTV_UINT, &v);
00e74b69 294
295 g_assert(*(v.v_uint) != 0);
f95bc830 296 (*v.v_uint)--;
297
f95bc830 298 if(*(v.v_uint) == 0) {
299 free_name_tables(tcs);
300 free_max_time(tcs);
301 free_saved_state(tcs);
302 }
348c6ba8 303 g_free(tcs->running_process);
304 tcs->running_process = NULL;
308711e5 305 lttv_state_free_process_table(tcs->processes);
306 tcs->processes = NULL;
dc877563 307 }
b445142a 308 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
309 fini((LttvTracesetContext *)self);
dc877563 310}
311
312
c432246e 313static LttvTracesetContext *
dc877563 314new_traceset_context(LttvTracesetContext *self)
315{
ffd54a90 316 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
dc877563 317}
318
319
c432246e 320static LttvTraceContext *
dc877563 321new_trace_context(LttvTracesetContext *self)
322{
ffd54a90 323 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
dc877563 324}
325
326
c432246e 327static LttvTracefileContext *
dc877563 328new_tracefile_context(LttvTracesetContext *self)
329{
ffd54a90 330 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
331}
332
333
dbb7bb09 334/* Write the process state of the trace */
335
336static void write_process_state(gpointer key, gpointer value,
337 gpointer user_data)
338{
339 LttvProcessState *process;
340
341 LttvExecutionState *es;
342
343 FILE *fp = (FILE *)user_data;
344
345 guint i;
346
347 process = (LttvProcessState *)value;
348 fprintf(fp,
348c6ba8 349" <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%u\">\n",
f95bc830 350 process, process->pid, process->ppid, process->creation_time.tv_sec,
dbb7bb09 351 process->creation_time.tv_nsec, g_quark_to_string(process->name),
348c6ba8 352 process->cpu);
dbb7bb09 353
354 for(i = 0 ; i < process->execution_stack->len; i++) {
355 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
356 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
357 g_quark_to_string(es->t), g_quark_to_string(es->n),
358 es->entry.tv_sec, es->entry.tv_nsec);
359 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
360 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
361 }
362 fprintf(fp, " </PROCESS>\n");
363}
364
365
366void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
367{
eed2ef37 368 guint i, nb_tracefile, nb_block, offset;
369 guint64 tsc;
dbb7bb09 370
371 LttvTracefileState *tfcs;
372
373 LttTracefile *tf;
374
375 LttEventPosition *ep;
376
348c6ba8 377 guint nb_cpus;
378
dbb7bb09 379 ep = ltt_event_position_new();
380
381 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
382
383 g_hash_table_foreach(self->processes, write_process_state, fp);
348c6ba8 384
385 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
386 for(i=0;i<nb_cpus;i++) {
387 fprintf(fp,"<CPU NUM=%u RUNNING_PROCESS=%u>\n",
388 i, self->running_process[i]->pid);
389 }
dbb7bb09 390
eed2ef37 391 nb_tracefile = self->parent.tracefiles->len;
dbb7bb09 392
393 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 394 tfcs =
cb03932a 395 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
396 LttvTracefileContext*, i));
348c6ba8 397 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
398 tfcs->parent.timestamp.tv_sec,
08b1c66e 399 tfcs->parent.timestamp.tv_nsec);
eed2ef37 400 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
401 if(e == NULL) fprintf(fp,"/>\n");
dbb7bb09 402 else {
eed2ef37 403 ltt_event_position(e, ep);
404 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
27304273 405 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
eed2ef37 406 tsc);
dbb7bb09 407 }
408 }
409 g_free(ep);
410 fprintf(fp,"</PROCESS_STATE>");
411}
412
413
414/* Copy each process from an existing hash table to a new one */
415
308711e5 416static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
ffd54a90 417{
308711e5 418 LttvProcessState *process, *new_process;
ffd54a90 419
308711e5 420 GHashTable *new_processes = (GHashTable *)user_data;
ffd54a90 421
308711e5 422 guint i;
423
424 process = (LttvProcessState *)value;
425 new_process = g_new(LttvProcessState, 1);
426 *new_process = *process;
e8f2280c 427 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
428 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
e05fc742 429 new_process->execution_stack =
430 g_array_set_size(new_process->execution_stack,
431 process->execution_stack->len);
308711e5 432 for(i = 0 ; i < process->execution_stack->len; i++) {
433 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
434 g_array_index(process->execution_stack, LttvExecutionState, i);
435 }
436 new_process->state = &g_array_index(new_process->execution_stack,
437 LttvExecutionState, new_process->execution_stack->len - 1);
2a2fa4f0 438 g_hash_table_insert(new_processes, new_process, new_process);
ffd54a90 439}
440
441
308711e5 442static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
ffd54a90 443{
2a2fa4f0 444 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
ffd54a90 445
308711e5 446 g_hash_table_foreach(processes, copy_process_state, new_processes);
447 return new_processes;
dc877563 448}
449
450
308711e5 451/* The saved state for each trace contains a member "processes", which
452 stores a copy of the process table, and a member "tracefiles" with
453 one entry per tracefile. Each tracefile has a "process" member pointing
454 to the current process and a "position" member storing the tracefile
455 position (needed to seek to the current "next" event. */
456
457static void state_save(LttvTraceState *self, LttvAttribute *container)
dc877563 458{
348c6ba8 459 guint i, nb_tracefile, nb_cpus;
dc877563 460
308711e5 461 LttvTracefileState *tfcs;
462
463 LttvAttribute *tracefiles_tree, *tracefile_tree;
348c6ba8 464
465 guint *running_process;
308711e5 466
467 LttvAttributeType type;
468
469 LttvAttributeValue value;
470
471 LttvAttributeName name;
472
473 LttEventPosition *ep;
474
475 tracefiles_tree = lttv_attribute_find_subdir(container,
476 LTTV_STATE_TRACEFILES);
477
478 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
479 LTTV_POINTER);
480 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
481
348c6ba8 482 /* Add the currently running processes array */
483 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
484 running_process = g_new(guint, nb_cpus);
485 for(i=0;i<nb_cpus;i++) {
486 running_process[i] = self->running_process[i]->pid;
487 }
488 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
489 LTTV_POINTER);
490 *(value.v_pointer) = running_process;
728d0c3e 491
492 g_info("State save");
348c6ba8 493
eed2ef37 494 nb_tracefile = self->parent.tracefiles->len;
308711e5 495
496 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 497 tfcs =
cb03932a 498 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
499 LttvTracefileContext*, i));
308711e5 500 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
501 value = lttv_attribute_add(tracefiles_tree, i,
502 LTTV_GOBJECT);
503 *(value.v_gobject) = (GObject *)tracefile_tree;
348c6ba8 504#if 0
308711e5 505 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
506 LTTV_UINT);
507 *(value.v_uint) = tfcs->process->pid;
348c6ba8 508#endif //0
308711e5 509 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
510 LTTV_POINTER);
3054461a 511 /* Only save the position if the tfs has not infinite time. */
512 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
513 // && current_tfcs != tfcs) {
514 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1986f254 515 *(value.v_pointer) = NULL;
516 } else {
517 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
a5dcde2f 518 ep = ltt_event_position_new();
eed2ef37 519 ltt_event_position(e, ep);
308711e5 520 *(value.v_pointer) = ep;
08b1c66e 521
eed2ef37 522 guint nb_block, offset;
523 guint64 tsc;
08b1c66e 524 LttTracefile *tf;
eed2ef37 525 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
728d0c3e 526 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
eed2ef37 527 tsc,
08b1c66e 528 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
308711e5 529 }
dc877563 530 }
dc877563 531}
532
533
308711e5 534static void state_restore(LttvTraceState *self, LttvAttribute *container)
dc877563 535{
348c6ba8 536 guint i, nb_tracefile, pid, nb_cpus;
dc877563 537
308711e5 538 LttvTracefileState *tfcs;
dc877563 539
308711e5 540 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 541
348c6ba8 542 guint *running_process;
543
308711e5 544 LttvAttributeType type;
dc877563 545
308711e5 546 LttvAttributeValue value;
dc877563 547
308711e5 548 LttvAttributeName name;
dc877563 549
308711e5 550 LttEventPosition *ep;
dc877563 551
27304273 552 LttvTracesetContext *tsc = self->parent.ts_context;
553
308711e5 554 tracefiles_tree = lttv_attribute_find_subdir(container,
555 LTTV_STATE_TRACEFILES);
dc877563 556
308711e5 557 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
558 &value);
559 g_assert(type == LTTV_POINTER);
560 lttv_state_free_process_table(self->processes);
561 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
562
348c6ba8 563 /* Add the currently running processes array */
564 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
565 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
566 &value);
567 g_assert(type == LTTV_POINTER);
568 running_process = *(value.v_pointer);
569 for(i=0;i<nb_cpus;i++) {
570 pid = running_process[i];
571 self->running_process[i] = lttv_state_find_process(self, i, pid);
572 g_assert(self->running_process[i] != NULL);
573 }
574
575
eed2ef37 576 nb_tracefile = self->parent.tracefiles->len;
308711e5 577
d448fce2 578 //g_tree_destroy(tsc->pqueue);
579 //tsc->pqueue = g_tree_new(compare_tracefile);
e7f5e89d 580
308711e5 581 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 582 tfcs =
cb03932a 583 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
584 LttvTracefileContext*, i));
308711e5 585 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
586 g_assert(type == LTTV_GOBJECT);
587 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
348c6ba8 588#if 0
308711e5 589 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
590 &value);
591 g_assert(type == LTTV_UINT);
2a2fa4f0 592 pid = *(value.v_uint);
593 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
348c6ba8 594#endif //0
308711e5 595 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
596 &value);
597 g_assert(type == LTTV_POINTER);
e7f5e89d 598 //g_assert(*(value.v_pointer) != NULL);
eed2ef37 599 ep = *(value.v_pointer);
600 g_assert(tfcs->parent.t_context != NULL);
27304273 601
27304273 602 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
d448fce2 603 g_tree_remove(tsc->pqueue, tfc);
27304273 604
1986f254 605 if(ep != NULL) {
606 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
607 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
e7f5e89d 608 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1986f254 609 g_tree_insert(tsc->pqueue, tfc, tfc);
728d0c3e 610 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1986f254 611 } else {
612 tfc->timestamp = ltt_time_infinite;
613 }
dc877563 614 }
dc877563 615}
616
617
308711e5 618static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 619{
348c6ba8 620 guint i, nb_tracefile, nb_cpus;
dc877563 621
308711e5 622 LttvTracefileState *tfcs;
dc877563 623
308711e5 624 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 625
348c6ba8 626 guint *running_process;
627
308711e5 628 LttvAttributeType type;
dc877563 629
308711e5 630 LttvAttributeValue value;
dc877563 631
308711e5 632 LttvAttributeName name;
dc877563 633
308711e5 634 LttEventPosition *ep;
dc877563 635
308711e5 636 tracefiles_tree = lttv_attribute_find_subdir(container,
637 LTTV_STATE_TRACEFILES);
c47a6dc6 638 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 639 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 640
308711e5 641 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
642 &value);
643 g_assert(type == LTTV_POINTER);
644 lttv_state_free_process_table(*(value.v_pointer));
645 *(value.v_pointer) = NULL;
646 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
647
348c6ba8 648 /* Free running processes array */
649 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
728d0c3e 650 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
348c6ba8 651 &value);
652 g_assert(type == LTTV_POINTER);
653 running_process = *(value.v_pointer);
654 g_free(running_process);
655
eed2ef37 656 nb_tracefile = self->parent.tracefiles->len;
308711e5 657
658 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 659 tfcs =
cb03932a 660 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
661 LttvTracefileContext*, i));
308711e5 662 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
663 g_assert(type == LTTV_GOBJECT);
664 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
665
666 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
667 &value);
668 g_assert(type == LTTV_POINTER);
669 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 670 }
c47a6dc6 671 g_object_unref(G_OBJECT(tracefiles_tree));
dc877563 672}
673
674
f95bc830 675static void free_saved_state(LttvTraceState *self)
676{
677 guint i, nb;
678
679 LttvAttributeType type;
680
681 LttvAttributeValue value;
682
683 LttvAttributeName name;
684
685 LttvAttribute *saved_states;
686
687 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
688 LTTV_STATE_SAVED_STATES);
689
690 nb = lttv_attribute_get_number(saved_states);
691 for(i = 0 ; i < nb ; i++) {
692 type = lttv_attribute_get(saved_states, i, &name, &value);
693 g_assert(type == LTTV_GOBJECT);
694 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
695 }
696
697 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
f95bc830 698}
699
700
701static void
702create_max_time(LttvTraceState *tcs)
703{
704 LttvAttributeValue v;
705
706 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
707 LTTV_POINTER, &v);
708 g_assert(*(v.v_pointer) == NULL);
709 *(v.v_pointer) = g_new(LttTime,1);
348c6ba8 710 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
f95bc830 711}
712
713
714static void
715get_max_time(LttvTraceState *tcs)
716{
717 LttvAttributeValue v;
718
719 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
720 LTTV_POINTER, &v);
721 g_assert(*(v.v_pointer) != NULL);
722 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
723}
724
725
726static void
727free_max_time(LttvTraceState *tcs)
728{
729 LttvAttributeValue v;
730
731 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
732 LTTV_POINTER, &v);
733 g_free(*(v.v_pointer));
734 *(v.v_pointer) = NULL;
735}
736
737
738typedef struct _LttvNameTables {
eed2ef37 739 // FIXME GQuark *eventtype_names;
f95bc830 740 GQuark *syscall_names;
741 GQuark *trap_names;
742 GQuark *irq_names;
faf074a3 743 GQuark *soft_irq_names;
f95bc830 744} LttvNameTables;
745
746
b445142a 747static void
f95bc830 748create_name_tables(LttvTraceState *tcs)
b445142a 749{
750 int i, nb;
dc877563 751
eed2ef37 752 GQuark f_name, e_name;
753
021eeb41 754 LttvTraceHook h;
dc877563 755
eed2ef37 756 LttvTraceHookByFacility *thf;
b445142a 757
758 LttEventType *et;
759
760 LttType *t;
761
762 GString *fe_name = g_string_new("");
763
f95bc830 764 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
765
766 LttvAttributeValue v;
767
768 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
769 LTTV_POINTER, &v);
770 g_assert(*(v.v_pointer) == NULL);
771 *(v.v_pointer) = name_tables;
eed2ef37 772#if 0 // Use iteration over the facilities_by_name and then list all event
773 // types of each facility
b445142a 774 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 775 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 776 for(i = 0 ; i < nb ; i++) {
777 et = ltt_trace_eventtype_get(tcs->parent.t, i);
778 e_name = ltt_eventtype_name(et);
779 f_name = ltt_facility_name(ltt_eventtype_facility(et));
780 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 781 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 782 }
eed2ef37 783#endif //0
784 if(lttv_trace_find_hook(tcs->parent.t,
f5d7967f 785 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 786 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 787 NULL, NULL, &h))
eed2ef37 788 return;
789
021eeb41 790 thf = lttv_trace_hook_get_first(&h);
eed2ef37 791
792 t = ltt_field_type(thf->f1);
d3cd9e86 793 nb = ltt_type_element_number(t);
eed2ef37 794
021eeb41 795 lttv_trace_hook_destroy(&h);
b445142a 796
f95bc830 797 name_tables->syscall_names = g_new(GQuark, nb);
b445142a 798
799 for(i = 0 ; i < nb ; i++) {
d3cd9e86 800 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
b445142a 801 }
b445142a 802
d3cd9e86 803 //name_tables->syscall_names = g_new(GQuark, 256);
804 //for(i = 0 ; i < 256 ; i++) {
805 // g_string_printf(fe_name, "syscall %d", i);
806 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
807 //}
b445142a 808
eed2ef37 809 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
810 LTT_EVENT_TRAP_ENTRY,
811 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 812 NULL, NULL, &h))
eed2ef37 813 return;
814
021eeb41 815 thf = lttv_trace_hook_get_first(&h);
eed2ef37 816
817 t = ltt_field_type(thf->f1);
2312de30 818 //nb = ltt_type_element_number(t);
b445142a 819
021eeb41 820 lttv_trace_hook_destroy(&h);
eed2ef37 821
b445142a 822 /*
f95bc830 823 name_tables->trap_names = g_new(GQuark, nb);
b445142a 824 for(i = 0 ; i < nb ; i++) {
f95bc830 825 name_tables->trap_names[i] = g_quark_from_string(
826 ltt_enum_string_get(t, i));
b445142a 827 }
828 */
829
f95bc830 830 name_tables->trap_names = g_new(GQuark, 256);
b445142a 831 for(i = 0 ; i < 256 ; i++) {
832 g_string_printf(fe_name, "trap %d", i);
f95bc830 833 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
b445142a 834 }
835
eed2ef37 836 if(lttv_trace_find_hook(tcs->parent.t,
837 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
838 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 839 NULL, NULL, &h))
eed2ef37 840 return;
841
021eeb41 842 thf = lttv_trace_hook_get_first(&h);
eed2ef37 843
844 t = ltt_field_type(thf->f1);
2312de30 845 //nb = ltt_type_element_number(t);
b445142a 846
021eeb41 847 lttv_trace_hook_destroy(&h);
eed2ef37 848
b445142a 849 /*
f95bc830 850 name_tables->irq_names = g_new(GQuark, nb);
b445142a 851 for(i = 0 ; i < nb ; i++) {
f95bc830 852 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
b445142a 853 }
854 */
855
f95bc830 856 name_tables->irq_names = g_new(GQuark, 256);
b445142a 857 for(i = 0 ; i < 256 ; i++) {
858 g_string_printf(fe_name, "irq %d", i);
f95bc830 859 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
b445142a 860 }
861
faf074a3 862 /*
863 name_tables->soft_irq_names = g_new(GQuark, nb);
864 for(i = 0 ; i < nb ; i++) {
865 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
866 }
867 */
868
869 name_tables->soft_irq_names = g_new(GQuark, 256);
870 for(i = 0 ; i < 256 ; i++) {
871 g_string_printf(fe_name, "softirq %d", i);
872 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
873 }
874
875
b445142a 876 g_string_free(fe_name, TRUE);
877}
878
879
f95bc830 880static void
881get_name_tables(LttvTraceState *tcs)
882{
883 LttvNameTables *name_tables;
884
885 LttvAttributeValue v;
886
887 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
888 LTTV_POINTER, &v);
889 g_assert(*(v.v_pointer) != NULL);
890 name_tables = (LttvNameTables *)*(v.v_pointer);
eed2ef37 891 //tcs->eventtype_names = name_tables->eventtype_names;
f95bc830 892 tcs->syscall_names = name_tables->syscall_names;
893 tcs->trap_names = name_tables->trap_names;
894 tcs->irq_names = name_tables->irq_names;
faf074a3 895 tcs->soft_irq_names = name_tables->soft_irq_names;
f95bc830 896}
897
898
b445142a 899static void
900free_name_tables(LttvTraceState *tcs)
901{
f95bc830 902 LttvNameTables *name_tables;
903
904 LttvAttributeValue v;
905
906 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
907 LTTV_POINTER, &v);
908 name_tables = (LttvNameTables *)*(v.v_pointer);
909 *(v.v_pointer) = NULL;
910
eed2ef37 911 // g_free(name_tables->eventtype_names);
f95bc830 912 g_free(name_tables->syscall_names);
913 g_free(name_tables->trap_names);
914 g_free(name_tables->irq_names);
faf074a3 915 g_free(name_tables->soft_irq_names);
f95bc830 916 g_free(name_tables);
b445142a 917}
dc877563 918
15b3d537 919#ifdef HASH_TABLE_DEBUG
920
921static void test_process(gpointer key, gpointer value, gpointer user_data)
922{
923 LttvProcessState *process = (LttvProcessState *)value;
924
925 /* Test for process corruption */
926 guint stack_len = process->execution_stack->len;
927}
928
929static void hash_table_check(GHashTable *table)
930{
931 g_hash_table_foreach(table, test_process, NULL);
932}
933
934
935#endif
936
937
b445142a 938static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 939 guint state_id)
dc877563 940{
b445142a 941 LttvExecutionState *es;
348c6ba8 942
943 guint cpu = ltt_tracefile_num(tfs->parent.tf);
944 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
15b3d537 945
946#ifdef HASH_TABLE_DEBUG
947 hash_table_check(ts->processes);
948#endif
348c6ba8 949 LttvProcessState *process = ts->running_process[cpu];
dc877563 950
b445142a 951 guint depth = process->execution_stack->len;
dc877563 952
e05fc742 953 process->execution_stack =
954 g_array_set_size(process->execution_stack, depth + 1);
955 /* Keep in sync */
956 process->state =
957 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
958
b445142a 959 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
960 es->t = t;
961 es->n = state_id;
962 es->entry = es->change = tfs->parent.timestamp;
963 es->s = process->state->s;
964 process->state = es;
dc877563 965}
966
967
b445142a 968static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 969{
348c6ba8 970 guint cpu = ltt_tracefile_num(tfs->parent.tf);
971 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
972 LttvProcessState *process = ts->running_process[cpu];
dc877563 973
f95bc830 974 guint depth = process->execution_stack->len;
dc877563 975
3d27549e 976 if(process->state->t != t){
00e74b69 977 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 978 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 979 g_info("process state has %s when pop_int is %s\n",
8e8e6b64 980 g_quark_to_string(process->state->t),
981 g_quark_to_string(t));
08b1c66e 982 g_info("{ %u, %u, %s, %s }\n",
8e8e6b64 983 process->pid,
984 process->ppid,
985 g_quark_to_string(process->name),
986 g_quark_to_string(process->state->s));
3d27549e 987 return;
988 }
b445142a 989
f95bc830 990 if(depth == 1){
00e74b69 991 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 992 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
993 return;
994 }
995
e05fc742 996 process->execution_stack =
997 g_array_set_size(process->execution_stack, depth - 1);
b445142a 998 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 999 depth - 2);
b445142a 1000 process->state->change = tfs->parent.timestamp;
dc877563 1001}
1002
1003
2a2fa4f0 1004LttvProcessState *
348c6ba8 1005lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
b3fd4c02 1006 guint cpu, guint pid, GQuark name, const LttTime *timestamp)
dc877563 1007{
1008 LttvProcessState *process = g_new(LttvProcessState, 1);
1009
b445142a 1010 LttvExecutionState *es;
dc877563 1011
348c6ba8 1012 LttvTraceContext *tc = (LttvTraceContext*)tcs;
ba576a78 1013
b445142a 1014 char buffer[128];
ffd54a90 1015
dc877563 1016 process->pid = pid;
348c6ba8 1017 process->cpu = cpu;
b3fd4c02 1018 process->name = name;
348c6ba8 1019 //process->last_cpu = tfs->cpu_name;
1020 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
7bfd7820 1021 process->kernel_thread = 0;
1022
cb03932a 1023 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 1024 g_hash_table_insert(tcs->processes, process, process);
b445142a 1025
1026 if(parent) {
1027 process->ppid = parent->pid;
348c6ba8 1028 process->creation_time = *timestamp;
b445142a 1029 }
2a2fa4f0 1030
1031 /* No parent. This process exists but we are missing all information about
1032 its creation. The birth time is set to zero but we remember the time of
1033 insertion */
1034
b445142a 1035 else {
1036 process->ppid = 0;
2a2fa4f0 1037 process->creation_time = ltt_time_zero;
b445142a 1038 }
1039
348c6ba8 1040 process->insertion_time = *timestamp;
b445142a 1041 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1042 process->creation_time.tv_nsec);
1043 process->pid_time = g_quark_from_string(buffer);
348c6ba8 1044 process->cpu = cpu;
1045 //process->last_cpu = tfs->cpu_name;
1046 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 1047 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1048 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
c607371b 1049 process->execution_stack = g_array_set_size(process->execution_stack, 2);
b445142a 1050 es = process->state = &g_array_index(process->execution_stack,
1051 LttvExecutionState, 0);
1052 es->t = LTTV_STATE_USER_MODE;
1053 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 1054 es->entry = *timestamp;
1055 //g_assert(timestamp->tv_sec != 0);
1056 es->change = *timestamp;
c607371b 1057 es->s = LTTV_STATE_RUN;
1058
1059 es = process->state = &g_array_index(process->execution_stack,
1060 LttvExecutionState, 1);
1061 es->t = LTTV_STATE_SYSCALL;
1062 es->n = LTTV_STATE_SUBMODE_NONE;
1063 es->entry = *timestamp;
1064 //g_assert(timestamp->tv_sec != 0);
1065 es->change = *timestamp;
b445142a 1066 es->s = LTTV_STATE_WAIT_FORK;
cbe7c836 1067
1068 return process;
dc877563 1069}
1070
348c6ba8 1071LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 1072 guint pid)
dc877563 1073{
2a2fa4f0 1074 LttvProcessState key;
1075 LttvProcessState *process;
1076
1077 key.pid = pid;
348c6ba8 1078 key.cpu = cpu;
2a2fa4f0 1079 process = g_hash_table_lookup(ts->processes, &key);
dc877563 1080 return process;
1081}
1082
2a2fa4f0 1083LttvProcessState *
348c6ba8 1084lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1085 LttTime *timestamp)
2a2fa4f0 1086{
348c6ba8 1087 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
7bfd7820 1088 LttvExecutionState *es;
348c6ba8 1089
1090 /* Put ltt_time_zero creation time for unexisting processes */
7bfd7820 1091 if(unlikely(process == NULL)) {
1092 process = lttv_state_create_process(ts,
b3fd4c02 1093 NULL, cpu, pid, LTTV_STATE_UNNAMED, timestamp);
7bfd7820 1094 /* We are not sure is it's a kernel thread or normal thread, put the
1095 * bottom stack state to unknown */
1096 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1097 es->t = LTTV_STATE_MODE_UNKNOWN;
1098 }
2a2fa4f0 1099 return process;
1100}
1101
41c7f803 1102/* FIXME : this function should be called when we receive an event telling that
1103 * release_task has been called in the kernel. In happens generally when
1104 * the parent waits for its child terminaison, but may also happen in special
1105 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1106 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1107 * of a killed thread ground, but isn't the leader.
41c7f803 1108 */
b445142a 1109static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 1110{
ba576a78 1111 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 1112 LttvProcessState key;
ba576a78 1113
2a2fa4f0 1114 key.pid = process->pid;
348c6ba8 1115 key.cpu = process->cpu;
2a2fa4f0 1116 g_hash_table_remove(ts->processes, &key);
b445142a 1117 g_array_free(process->execution_stack, TRUE);
dc877563 1118 g_free(process);
1119}
1120
1121
b445142a 1122static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 1123{
b445142a 1124 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 1125 g_free(value);
1126}
1127
1128
308711e5 1129static void lttv_state_free_process_table(GHashTable *processes)
dc877563 1130{
1131 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 1132 g_hash_table_destroy(processes);
dc877563 1133}
1134
1135
b445142a 1136static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 1137{
ba576a78 1138 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1139 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1140 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1141 LttField *f = thf->f1;
dc877563 1142
b445142a 1143 LttvExecutionSubmode submode;
1144
1145 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
eed2ef37 1146 ltt_event_get_unsigned(e, f)];
b445142a 1147 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 1148 return FALSE;
1149}
1150
1151
b445142a 1152static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 1153{
ba576a78 1154 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1155
ffd54a90 1156 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 1157 return FALSE;
1158}
1159
1160
b445142a 1161static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 1162{
ba576a78 1163 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1164 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1165 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1166 LttField *f = thf->f1;
dc877563 1167
b445142a 1168 LttvExecutionSubmode submode;
1169
1170 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
eed2ef37 1171 ltt_event_get_unsigned(e, f)];
b445142a 1172 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 1173 return FALSE;
1174}
1175
1176
b445142a 1177static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 1178{
ba576a78 1179 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1180
ffd54a90 1181 pop_state(s, LTTV_STATE_TRAP);
dc877563 1182 return FALSE;
1183}
1184
1185
b445142a 1186static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 1187{
ba576a78 1188 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1189 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 1190 guint8 fac_id = ltt_event_facility_id(e);
1191 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 1192 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 1193 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1194 g_assert(thf->f1 != NULL);
1195 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 1196 LttField *f = thf->f1;
dc877563 1197
b445142a 1198 LttvExecutionSubmode submode;
1199
1200 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
eed2ef37 1201 ltt_event_get_unsigned(e, f)];
b445142a 1202
dc877563 1203 /* Do something with the info about being in user or system mode when int? */
b445142a 1204 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 1205 return FALSE;
1206}
1207
1208
b445142a 1209static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 1210{
ba576a78 1211 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1212
ffd54a90 1213 pop_state(s, LTTV_STATE_IRQ);
dc877563 1214 return FALSE;
1215}
1216
faf074a3 1217static gboolean soft_irq_entry(void *hook_data, void *call_data)
1218{
1219 LttvTracefileState *s = (LttvTracefileState *)call_data;
1220 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1221 guint8 fac_id = ltt_event_facility_id(e);
1222 guint8 ev_id = ltt_event_eventtype_id(e);
1223 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1224 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1225 g_assert(thf->f1 != NULL);
1226 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
1227 LttField *f = thf->f1;
1228
1229 LttvExecutionSubmode submode;
1230
1231 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[
1232 ltt_event_get_unsigned(e, f)];
1233
1234 /* Do something with the info about being in user or system mode when int? */
1235 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
1236 return FALSE;
1237}
1238
1239
1240static gboolean soft_irq_exit(void *hook_data, void *call_data)
1241{
1242 LttvTracefileState *s = (LttvTracefileState *)call_data;
1243
1244 pop_state(s, LTTV_STATE_SOFT_IRQ);
1245 return FALSE;
1246}
1247
dc877563 1248
b445142a 1249static gboolean schedchange(void *hook_data, void *call_data)
dc877563 1250{
ba576a78 1251 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1252 guint cpu = ltt_tracefile_num(s->parent.tf);
1253 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1254 LttvProcessState *process = ts->running_process[cpu];
48b002b8 1255 LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 1256
eed2ef37 1257 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1258 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 1259 guint pid_in, pid_out;
1260 gint state_out;
dc877563 1261
eed2ef37 1262 pid_out = ltt_event_get_unsigned(e, thf->f1);
1263 pid_in = ltt_event_get_unsigned(e, thf->f2);
73394fd3 1264 state_out = ltt_event_get_int(e, thf->f3);
348c6ba8 1265
1266 if(likely(process != NULL)) {
b445142a 1267
f95bc830 1268 /* We could not know but it was not the idle process executing.
1269 This should only happen at the beginning, before the first schedule
1270 event, and when the initial information (current process for each CPU)
1271 is missing. It is not obvious how we could, after the fact, compensate
1272 the wrongly attributed statistics. */
1273
240f1fea 1274 //This test only makes sense once the state is known and if there is no
48b002b8 1275 //missing events. We need to silently ignore schedchange coming after a
1276 //process_free, or it causes glitches. (FIXME)
348c6ba8 1277 //if(unlikely(process->pid != pid_out)) {
1278 // g_assert(process->pid == 0);
240f1fea 1279 //}
f95bc830 1280
348c6ba8 1281 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1282 process->state->s = LTTV_STATE_ZOMBIE;
791dffa6 1283 process->state->change = s->parent.timestamp;
dbd243b1 1284 } else {
348c6ba8 1285 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1286 else process->state->s = LTTV_STATE_WAIT;
791dffa6 1287 process->state->change = s->parent.timestamp;
1288 }
48b002b8 1289
1290 if(state_out == 32)
791dffa6 1291 exit_process(s, process); /* EXIT_DEAD */
1292 /* see sched.h for states */
dc877563 1293 }
348c6ba8 1294 process = ts->running_process[cpu] =
1295 lttv_state_find_process_or_create(
1296 (LttvTraceState*)s->parent.t_context,
1297 cpu, pid_in,
1298 &s->parent.timestamp);
1299 process->state->s = LTTV_STATE_RUN;
1300 process->cpu = cpu;
1301 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1302 process->state->change = s->parent.timestamp;
dc877563 1303 return FALSE;
1304}
1305
eed2ef37 1306static gboolean process_fork(void *hook_data, void *call_data)
dc877563 1307{
eed2ef37 1308 LttvTracefileState *s = (LttvTracefileState *)call_data;
1309 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1310 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1311 guint parent_pid;
2cdc690b 1312 guint child_pid;
4ad73431 1313 LttvProcessState *zombie_process;
348c6ba8 1314 guint cpu = ltt_tracefile_num(s->parent.tf);
1315 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1316 LttvProcessState *process = ts->running_process[cpu];
26275aa2 1317 LttvProcessState *child_process;
2cdc690b 1318
eed2ef37 1319 /* Parent PID */
b3fd4c02 1320 parent_pid = ltt_event_get_unsigned(e, thf->f1);
eed2ef37 1321
2cdc690b 1322 /* Child PID */
b3fd4c02 1323 child_pid = ltt_event_get_unsigned(e, thf->f2);
2cdc690b 1324
15b3d537 1325 /* Mathieu : it seems like the process might have been scheduled in before the
1326 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 1327 * in a SMP case where we don't have enough precision on the clocks.
1328 *
1329 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 1330#if 0
348c6ba8 1331 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 1332
1d1df11d 1333 if(unlikely(zombie_process != NULL)) {
4ad73431 1334 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 1335 * has been released. FIXME : should know when release_task happens instead.
4ad73431 1336 */
15b3d537 1337 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1338 guint i;
1339 for(i=0; i< num_cpus; i++) {
5ac05980 1340 g_assert(zombie_process != ts->running_process[i]);
15b3d537 1341 }
1342
4ad73431 1343 exit_process(s, zombie_process);
1344 }
791dffa6 1345#endif //0
348c6ba8 1346 g_assert(process->pid != child_pid);
eed2ef37 1347 // FIXME : Add this test in the "known state" section
348c6ba8 1348 // g_assert(process->pid == parent_pid);
26275aa2 1349 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1350 if(child_process == NULL) {
ab893fb1 1351 child_process = lttv_state_create_process(ts, process, cpu,
b3fd4c02 1352 child_pid, LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 1353 } else {
1354 /* The process has already been created : due to time imprecision between
791dffa6 1355 * multiple CPUs : it has been scheduled in before creation. Note that we
1356 * shouldn't have this kind of imprecision.
26275aa2 1357 *
1358 * Simply put a correct parent.
1359 */
791dffa6 1360 g_assert(0); /* This is a problematic case : the process has been created
1361 before the fork event */
26275aa2 1362 child_process->ppid = process->pid;
1363 }
ab893fb1 1364 g_assert(child_process->name == LTTV_STATE_UNNAMED);
1365 child_process->name = process->name;
4ad73431 1366
dc877563 1367 return FALSE;
1368}
1369
7bfd7820 1370/* We stamp a newly created process as kernel_thread */
1371static gboolean process_kernel_thread(void *hook_data, void *call_data)
1372{
1373 LttvTracefileState *s = (LttvTracefileState *)call_data;
1374 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1375 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1376 guint pid;
1377 guint cpu = ltt_tracefile_num(s->parent.tf);
1378 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1379 LttvProcessState *process;
1380 LttvExecutionState *es;
1381
1382 /* PID */
1383 pid = ltt_event_get_unsigned(e, thf->f1);
1384
1385 process = lttv_state_find_process(ts, ANY_CPU, pid);
1386 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
1387 es->t = LTTV_STATE_SYSCALL;
1388 process->kernel_thread = 1;
1389
1390 return FALSE;
1391}
dc877563 1392
eed2ef37 1393static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1394{
eed2ef37 1395 LttvTracefileState *s = (LttvTracefileState *)call_data;
1396 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1397 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1398 LttField *f;
1399 guint pid;
348c6ba8 1400 guint cpu = ltt_tracefile_num(s->parent.tf);
1401 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1402 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1403
1404 pid = ltt_event_get_unsigned(e, thf->f1);
1405
1406 // FIXME : Add this test in the "known state" section
348c6ba8 1407 // g_assert(process->pid == pid);
eed2ef37 1408
348c6ba8 1409 if(likely(process != NULL)) {
1410 process->state->s = LTTV_STATE_EXIT;
2cdc690b 1411 }
1412 return FALSE;
2cdc690b 1413}
1414
eed2ef37 1415static gboolean process_free(void *hook_data, void *call_data)
2da61677 1416{
eed2ef37 1417 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1418 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 1419 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1420 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 1421 guint release_pid;
1422 LttvProcessState *process;
1423
1424 /* PID of the process to release */
eed2ef37 1425 release_pid = ltt_event_get_unsigned(e, thf->f1);
15b3d537 1426
1427 g_assert(release_pid != 0);
2da61677 1428
348c6ba8 1429 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 1430
1431 if(likely(process != NULL)) {
1432 /* release_task is happening at kernel level : we can now safely release
1433 * the data structure of the process */
5562ddce 1434 //This test is fun, though, as it may happen that
1435 //at time t : CPU 0 : process_free
1436 //at time t+150ns : CPU 1 : schedule out
1437 //Clearly due to time imprecision, we disable it. (Mathieu)
1438 //If this weird case happen, we have no choice but to put the
1439 //Currently running process on the cpu to 0.
791dffa6 1440 //I re-enable it following time precision fixes. (Mathieu)
1441 //Well, in the case where an process is freed by a process on another CPU
1442 //and still scheduled, it happens that this is the schedchange that will
1443 //drop the last reference count. Do not free it here!
0bd2f89c 1444 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1445 guint i;
1446 for(i=0; i< num_cpus; i++) {
5562ddce 1447 //g_assert(process != ts->running_process[i]);
1448 if(process == ts->running_process[i]) {
791dffa6 1449 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1450 break;
5562ddce 1451 }
0bd2f89c 1452 }
48b002b8 1453 //if(i == num_cpus) /* process is not scheduled */
1454 //exit_process(s, process); // do nothing : wait for the schedchange to
1455 //delete the process.
2da61677 1456 }
1457
1458 return FALSE;
1459}
1460
f4b88a7d 1461
1462static gboolean process_exec(void *hook_data, void *call_data)
1463{
1464 LttvTracefileState *s = (LttvTracefileState *)call_data;
1465 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1466 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1467 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
743e50fd 1468 //gchar *name;
f4b88a7d 1469 guint cpu = ltt_tracefile_num(s->parent.tf);
1470 LttvProcessState *process = ts->running_process[cpu];
1471
1472 /* PID of the process to release */
743e50fd 1473 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
1474 //name = ltt_event_get_string(e, thf->f1);
f2923fb2 1475 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
1476 gchar *name_begin =
1477 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 1478 gchar *null_term_name = g_new(gchar, name_len+1);
1479 memcpy(null_term_name, name_begin, name_len);
1480 null_term_name[name_len] = '\0';
1481
1482 process->name = g_quark_from_string(null_term_name);
f2923fb2 1483 g_free(null_term_name);
f4b88a7d 1484 return FALSE;
1485}
1486
b3fd4c02 1487static gboolean enum_process_state(void *hook_data, void *call_data)
1488{
1489 LttvTracefileState *s = (LttvTracefileState *)call_data;
1490 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1491 //It's slow : optimise later by doing this before reading trace.
1492 LttEventType *et = ltt_event_eventtype(e);
1493 //
1494 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1495 guint parent_pid;
1496 guint pid;
1497 gchar * command;
1498 guint cpu = ltt_tracefile_num(s->parent.tf);
1499 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1500 LttvProcessState *process = ts->running_process[cpu];
1501 LttvProcessState *parent_process;
1502 LttField *f4, *f5, *f6;
1503 GQuark mode, submode, status;
f4b88a7d 1504
b3fd4c02 1505 /* PID */
1506 pid = ltt_event_get_unsigned(e, thf->f1);
f4b88a7d 1507
b3fd4c02 1508 /* Parent PID */
1509 parent_pid = ltt_event_get_unsigned(e, thf->f2);
1510
1511 /* Command name */
1512 command = ltt_event_get_string(e, thf->f3);
1513
1514 /* mode */
1515 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
1516 mode = ltt_enum_string_get(ltt_field_type(f4),
1517 ltt_event_get_unsigned(e, f4));
1518
1519 /* submode */
1520 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
1521 submode = ltt_enum_string_get(ltt_field_type(f5),
1522 ltt_event_get_unsigned(e, f5));
1523
1524 /* status */
1525 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
1526 status = ltt_enum_string_get(ltt_field_type(f6),
1527 ltt_event_get_unsigned(e, f6));
1528
1529 /* The process might exist if a process was forked while performing the sate dump. */
1530 process = lttv_state_find_process(ts, ANY_CPU, pid);
1531 if(process == NULL) {
1532 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
1533 process = lttv_state_create_process(ts, parent_process, cpu,
1534 pid, g_quark_from_string(command),
1535 &s->parent.timestamp);
1536
1537 /* Keep the stack bottom : a running user mode */
ab893fb1 1538#if 0
1539 /* Disabled because of inconsistencies in the current statedump states. */
b3fd4c02 1540 if(mode == LTTV_STATE_USER_MODE) {
1541 /* Only keep the bottom */
1542 process->execution_stack = g_array_set_size(process->execution_stack, 1);
1543 } else {
1544 /* On top of it : */
1545 LttvExecutionState *es;
1546 es = process->state = &g_array_index(process->execution_stack,
1547 LttvExecutionState, 1);
1548 es->t = mode;
1549 es->s = status;
1550 es->n = submode;
1551 }
ab893fb1 1552#endif //0
b3fd4c02 1553
ab893fb1 1554 /* UNKNOWN STATE */
1555 {
1556 LttvExecutionState *es;
1557 es = process->state = &g_array_index(process->execution_stack,
1558 LttvExecutionState, 1);
1559 es->t = LTTV_STATE_MODE_UNKNOWN;
1560 es->s = LTTV_STATE_UNNAMED;
1561 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
1562 }
b3fd4c02 1563 } else {
1564 /* The process has already been created :
1565 * Probably was forked while dumping the process state or
1566 * was simply scheduled in prior to get the state dump event.
1567 */
1568 process->ppid = parent_pid;
1569 process->name = g_quark_from_string(command);
1570 /* Don't mess around with the stack, it will eventually become
1571 * ok after the end of state dump. */
1572 }
1573
1574 return FALSE;
1575}
f4b88a7d 1576
58c88a41 1577gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1578{
1579 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1580
1581 lttv_state_add_event_hooks(tss);
1582
1583 return 0;
1584}
dc877563 1585
308711e5 1586void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1587{
ba576a78 1588 LttvTraceset *traceset = self->parent.ts;
dc877563 1589
eed2ef37 1590 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1591
ba576a78 1592 LttvTraceState *ts;
dc877563 1593
ba576a78 1594 LttvTracefileState *tfs;
dc877563 1595
dc877563 1596 GArray *hooks;
1597
eed2ef37 1598 LttvTraceHookByFacility *thf;
1599
1600 LttvTraceHook *hook;
dc877563 1601
1602 LttvAttributeValue val;
1603
9d239bd9 1604 gint ret;
1605
ba576a78 1606 nb_trace = lttv_traceset_number(traceset);
dc877563 1607 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1608 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1609
1610 /* Find the eventtype id for the following events and register the
1611 associated by id hooks. */
1612
7bfd7820 1613 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 15);
1614 hooks = g_array_set_size(hooks, 15);
b445142a 1615
9d239bd9 1616 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 1617 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 1618 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 1619 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
9d239bd9 1620 g_assert(!ret);
cbe7c836 1621
9d239bd9 1622 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 1623 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
eed2ef37 1624 0, 0, 0,
2c82c4dc 1625 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
9d239bd9 1626 g_assert(!ret);
cbe7c836 1627
9d239bd9 1628 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1629 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1630 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 1631 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
9d239bd9 1632 g_assert(!ret);
cbe7c836 1633
9d239bd9 1634 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1635 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1636 0, 0, 0,
2c82c4dc 1637 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
9d239bd9 1638 g_assert(!ret);
cbe7c836 1639
9d239bd9 1640 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1641 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1642 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 1643 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
9d239bd9 1644 g_assert(!ret);
cbe7c836 1645
9d239bd9 1646 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1647 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1648 0, 0, 0,
2c82c4dc 1649 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
9d239bd9 1650 g_assert(!ret);
cbe7c836 1651
faf074a3 1652 ret = lttv_trace_find_hook(ts->parent.t,
1653 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
1654 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
1655 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 6));
1656 g_assert(!ret);
1657
1658 ret = lttv_trace_find_hook(ts->parent.t,
1659 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
1660 0, 0, 0,
1661 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 7));
1662 g_assert(!ret);
1663
9d239bd9 1664 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1665 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1666 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
faf074a3 1667 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 8));
9d239bd9 1668 g_assert(!ret);
cbe7c836 1669
9d239bd9 1670 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1671 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1672 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
faf074a3 1673 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 9));
9d239bd9 1674 g_assert(!ret);
eed2ef37 1675
7bfd7820 1676 ret = lttv_trace_find_hook(ts->parent.t,
1677 LTT_FACILITY_PROCESS, LTT_EVENT_KERNEL_THREAD,
1678 LTT_FIELD_PID, 0, 0,
1679 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1680 g_assert(!ret);
1681
9d239bd9 1682 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1683 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1684 LTT_FIELD_PID, 0, 0,
7bfd7820 1685 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 11));
9d239bd9 1686 g_assert(!ret);
eed2ef37 1687
9d239bd9 1688 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1689 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1690 LTT_FIELD_PID, 0, 0,
7bfd7820 1691 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 12));
9d239bd9 1692 g_assert(!ret);
2cdc690b 1693
f4b88a7d 1694 ret = lttv_trace_find_hook(ts->parent.t,
1695 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1696 LTT_FIELD_FILENAME, 0, 0,
7bfd7820 1697 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 13));
f4b88a7d 1698 g_assert(!ret);
1699
b3fd4c02 1700 /* statedump-related hooks */
1701 ret = lttv_trace_find_hook(ts->parent.t,
1702 LTT_FACILITY_STATEDUMP, LTT_EVENT_ENUM_PROCESS_STATE,
1703 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
7bfd7820 1704 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, 14));
b3fd4c02 1705 g_assert(!ret);
f4b88a7d 1706
b3fd4c02 1707
a5ba1787 1708 /* Add these hooks to each event_by_id hooks list */
dc877563 1709
eed2ef37 1710 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1711
dc877563 1712 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1713 tfs =
9d239bd9 1714 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1715 LttvTracefileContext*, j));
dc877563 1716
1717 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1718 hook = &g_array_index(hooks, LttvTraceHook, k);
1719 for(l=0;l<hook->fac_list->len;l++) {
1720 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1721 lttv_hooks_add(
1722 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1723 thf->h,
d052ffc3 1724 thf,
eed2ef37 1725 LTTV_PRIO_STATE);
1726 }
ffd54a90 1727 }
dc877563 1728 }
f0b795e0 1729 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 1730 *(val.v_pointer) = hooks;
dc877563 1731 }
1732}
1733
58c88a41 1734gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1735{
1736 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1737
1738 lttv_state_remove_event_hooks(tss);
1739
1740 return 0;
1741}
dc877563 1742
308711e5 1743void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1744{
ba576a78 1745 LttvTraceset *traceset = self->parent.ts;
dc877563 1746
eed2ef37 1747 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1748
ba576a78 1749 LttvTraceState *ts;
dc877563 1750
ba576a78 1751 LttvTracefileState *tfs;
dc877563 1752
dc877563 1753 GArray *hooks;
1754
eed2ef37 1755 LttvTraceHook *hook;
1756
1757 LttvTraceHookByFacility *thf;
dc877563 1758
1759 LttvAttributeValue val;
1760
ba576a78 1761 nb_trace = lttv_traceset_number(traceset);
dc877563 1762 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 1763 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
f0b795e0 1764 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 1765 hooks = *(val.v_pointer);
dc877563 1766
a5ba1787 1767 /* Remove these hooks from each event_by_id hooks list */
dc877563 1768
eed2ef37 1769 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1770
dc877563 1771 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1772 tfs =
cb03932a 1773 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1774 LttvTracefileContext*, j));
dc877563 1775
1776 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1777 hook = &g_array_index(hooks, LttvTraceHook, k);
1778 for(l=0;l<hook->fac_list->len;l++) {
1779 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1780
1781 lttv_hooks_remove_data(
1782 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1783 thf->h,
d052ffc3 1784 thf);
eed2ef37 1785 }
ffd54a90 1786 }
dc877563 1787 }
1986f254 1788 for(k = 0 ; k < hooks->len ; k++)
1789 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 1790 g_array_free(hooks, TRUE);
1791 }
1792}
1793
eed2ef37 1794static gboolean state_save_event_hook(void *hook_data, void *call_data)
1795{
1796 guint *event_count = (guint*)hook_data;
1797
1798 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1799 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1800 return FALSE;
1801 else
18c87975 1802 *event_count = 0;
eed2ef37 1803
1804 LttvTracefileState *self = (LttvTracefileState *)call_data;
1805
1806 LttvTracefileState *tfcs;
1807
1808 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1809
1810 LttEventPosition *ep;
1811
1812 guint i;
1813
1814 LttTracefile *tf;
1815
1816 LttvAttribute *saved_states_tree, *saved_state_tree;
1817
1818 LttvAttributeValue value;
1819
1820 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1821 LTTV_STATE_SAVED_STATES);
1822 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1823 value = lttv_attribute_add(saved_states_tree,
1824 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1825 *(value.v_gobject) = (GObject *)saved_state_tree;
1826 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1827 *(value.v_time) = self->parent.timestamp;
1828 lttv_state_save(tcs, saved_state_tree);
1829 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1830 self->parent.timestamp.tv_nsec);
1831
1832 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1833
1834 return FALSE;
1835}
1836
14aecf75 1837static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1838{
1839 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1840
1841 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1842
1843 return FALSE;
1844}
1845
eed2ef37 1846#if 0
08b1c66e 1847static gboolean block_start(void *hook_data, void *call_data)
308711e5 1848{
dbb7bb09 1849 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1850
dbb7bb09 1851 LttvTracefileState *tfcs;
308711e5 1852
dbb7bb09 1853 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1854
1855 LttEventPosition *ep;
308711e5 1856
dbb7bb09 1857 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1858
1859 LttTracefile *tf;
1860
1861 LttvAttribute *saved_states_tree, *saved_state_tree;
1862
1863 LttvAttributeValue value;
1864
dbb7bb09 1865 ep = ltt_event_position_new();
eed2ef37 1866
1867 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 1868
1869 /* Count the number of events added since the last block end in any
1870 tracefile. */
1871
1872 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1873 tfcs =
1874 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1875 LttvTracefileContext, i));
dbb7bb09 1876 ltt_event_position(tfcs->parent.e, ep);
1877 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1878 tcs->nb_event += nb_event - tfcs->saved_position;
1879 tfcs->saved_position = nb_event;
1880 }
1881 g_free(ep);
308711e5 1882
308711e5 1883 if(tcs->nb_event >= tcs->save_interval) {
1884 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1885 LTTV_STATE_SAVED_STATES);
1886 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1887 value = lttv_attribute_add(saved_states_tree,
1888 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1889 *(value.v_gobject) = (GObject *)saved_state_tree;
1890 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1891 *(value.v_time) = self->parent.timestamp;
308711e5 1892 lttv_state_save(tcs, saved_state_tree);
1893 tcs->nb_event = 0;
08b1c66e 1894 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1895 self->parent.timestamp.tv_nsec);
308711e5 1896 }
dbb7bb09 1897 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1898 return FALSE;
1899}
eed2ef37 1900#endif //0
308711e5 1901
eed2ef37 1902#if 0
08b1c66e 1903static gboolean block_end(void *hook_data, void *call_data)
1904{
1905 LttvTracefileState *self = (LttvTracefileState *)call_data;
1906
1907 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1908
1909 LttTracefile *tf;
1910
1911 LttEventPosition *ep;
1912
1913 guint nb_block, nb_event;
1914
1915 ep = ltt_event_position_new();
1916 ltt_event_position(self->parent.e, ep);
1917 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1918 tcs->nb_event += nb_event - self->saved_position + 1;
1919 self->saved_position = 0;
1920 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1921 g_free(ep);
00e74b69 1922
1923 return FALSE;
08b1c66e 1924}
eed2ef37 1925#endif //0
1926#if 0
308711e5 1927void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1928{
1929 LttvTraceset *traceset = self->parent.ts;
1930
00e74b69 1931 guint i, j, nb_trace, nb_tracefile;
308711e5 1932
1933 LttvTraceState *ts;
1934
1935 LttvTracefileState *tfs;
1936
08b1c66e 1937 LttvTraceHook hook_start, hook_end;
308711e5 1938
1939 nb_trace = lttv_traceset_number(traceset);
1940 for(i = 0 ; i < nb_trace ; i++) {
1941 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 1942
08b1c66e 1943 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1944 NULL, NULL, block_start, &hook_start);
308711e5 1945 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1946 NULL, NULL, block_end, &hook_end);
308711e5 1947
eed2ef37 1948 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1949
dbb7bb09 1950 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1951 tfs =
1952 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1953 LttvTracefileContext, j));
a5ba1787 1954 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1955 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 1956 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1957 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1958 }
1959 }
1960}
1961#endif //0
1962
1963void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1964{
1965 LttvTraceset *traceset = self->parent.ts;
1966
1967 guint i, j, nb_trace, nb_tracefile;
1968
1969 LttvTraceState *ts;
1970
1971 LttvTracefileState *tfs;
1972
1973
1974 nb_trace = lttv_traceset_number(traceset);
1975 for(i = 0 ; i < nb_trace ; i++) {
1976
1977 ts = (LttvTraceState *)self->parent.traces[i];
1978 nb_tracefile = ts->parent.tracefiles->len;
1979
3054461a 1980 guint *event_count = g_new(guint, 1);
1981 *event_count = 0;
1982
eed2ef37 1983 for(j = 0 ; j < nb_tracefile ; j++) {
1984 tfs =
cb03932a 1985 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1986 LttvTracefileContext*, j));
eed2ef37 1987 lttv_hooks_add(tfs->parent.event,
1988 state_save_event_hook,
1989 event_count,
1990 LTTV_PRIO_STATE);
1991
308711e5 1992 }
1993 }
14aecf75 1994
1995 lttv_process_traceset_begin(&self->parent,
1996 NULL, NULL, NULL, NULL, NULL);
1997
308711e5 1998}
1999
b56b5fec 2000gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
2001{
2002 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2003
2004 lttv_state_save_add_event_hooks(tss);
2005
2006 return 0;
2007}
2008
308711e5 2009
eed2ef37 2010#if 0
308711e5 2011void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2012{
2013 LttvTraceset *traceset = self->parent.ts;
2014
00e74b69 2015 guint i, j, nb_trace, nb_tracefile;
308711e5 2016
2017 LttvTraceState *ts;
2018
2019 LttvTracefileState *tfs;
2020
08b1c66e 2021 LttvTraceHook hook_start, hook_end;
308711e5 2022
2023 nb_trace = lttv_traceset_number(traceset);
2024 for(i = 0 ; i < nb_trace ; i++) {
2025 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 2026
08b1c66e 2027 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
2028 NULL, NULL, block_start, &hook_start);
2029
308711e5 2030 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 2031 NULL, NULL, block_end, &hook_end);
308711e5 2032
eed2ef37 2033 nb_tracefile = ts->parent.tracefiles->len;
308711e5 2034
dbb7bb09 2035 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 2036 tfs =
2037 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
2038 LttvTracefileContext, j));
308711e5 2039 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 2040 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 2041 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 2042 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 2043 }
2044 }
2045}
eed2ef37 2046#endif //0
2047
2048void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
2049{
2050 LttvTraceset *traceset = self->parent.ts;
2051
2052 guint i, j, nb_trace, nb_tracefile;
2053
2054 LttvTraceState *ts;
2055
2056 LttvTracefileState *tfs;
2057
14aecf75 2058 LttvHooks *after_trace = lttv_hooks_new();
2059
2060 lttv_hooks_add(after_trace,
2061 state_save_after_trace_hook,
2062 NULL,
2063 LTTV_PRIO_STATE);
2064
2065
2066 lttv_process_traceset_end(&self->parent,
2067 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 2068
14aecf75 2069 lttv_hooks_destroy(after_trace);
2070
eed2ef37 2071 nb_trace = lttv_traceset_number(traceset);
2072 for(i = 0 ; i < nb_trace ; i++) {
2073
2074 ts = (LttvTraceState *)self->parent.traces[i];
2075 nb_tracefile = ts->parent.tracefiles->len;
2076
22b165e9 2077 guint *event_count = NULL;
eed2ef37 2078
2079 for(j = 0 ; j < nb_tracefile ; j++) {
2080 tfs =
cb03932a 2081 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2082 LttvTracefileContext*, j));
eed2ef37 2083 event_count = lttv_hooks_remove(tfs->parent.event,
2084 state_save_event_hook);
eed2ef37 2085 }
22b165e9 2086 if(event_count) g_free(event_count);
eed2ef37 2087 }
2088}
308711e5 2089
b56b5fec 2090gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
2091{
2092 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2093
2094 lttv_state_save_remove_event_hooks(tss);
2095
2096 return 0;
2097}
308711e5 2098
dd025f91 2099void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 2100{
2101 LttvTraceset *traceset = self->parent.ts;
2102
00e74b69 2103 guint i, nb_trace;
308711e5 2104
2105 int min_pos, mid_pos, max_pos;
2106
728d0c3e 2107 guint call_rest = 0;
2108
308711e5 2109 LttvTraceState *tcs;
2110
2111 LttvAttributeValue value;
2112
2113 LttvAttributeType type;
2114
2115 LttvAttributeName name;
2116
2117 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
2118
d448fce2 2119 //g_tree_destroy(self->parent.pqueue);
2120 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 2121
728d0c3e 2122 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
2123
308711e5 2124 nb_trace = lttv_traceset_number(traceset);
2125 for(i = 0 ; i < nb_trace ; i++) {
2126 tcs = (LttvTraceState *)self->parent.traces[i];
2127
2a2fa4f0 2128 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
2129 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2130 LTTV_STATE_SAVED_STATES);
2131 min_pos = -1;
2132
2133 if(saved_states_tree) {
dd025f91 2134 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
2135 mid_pos = max_pos / 2;
2136 while(min_pos < max_pos) {
2137 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
2138 g_assert(type == LTTV_GOBJECT);
2139 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
2140 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
2141 &value);
2142 g_assert(type == LTTV_TIME);
2143 if(ltt_time_compare(*(value.v_time), t) < 0) {
2144 min_pos = mid_pos;
2145 closest_tree = saved_state_tree;
2146 }
2147 else max_pos = mid_pos - 1;
2148
2149 mid_pos = (min_pos + max_pos + 1) / 2;
2150 }
2a2fa4f0 2151 }
dd025f91 2152
2a2fa4f0 2153 /* restore the closest earlier saved state */
f95bc830 2154 if(min_pos != -1) {
2155 lttv_state_restore(tcs, closest_tree);
728d0c3e 2156 call_rest = 1;
f95bc830 2157 }
dd025f91 2158
2a2fa4f0 2159 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 2160 else {
2161 restore_init_state(tcs);
2162 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 2163 }
9444deae 2164 }
dd025f91 2165 /* We want to seek quickly without restoring/updating the state */
2166 else {
308711e5 2167 restore_init_state(tcs);
dd025f91 2168 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 2169 }
308711e5 2170 }
728d0c3e 2171 if(!call_rest) g_info("NOT Calling restore");
308711e5 2172}
2173
2174
2175static void
2176traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
2177{
2178}
2179
2180
2181static void
2182traceset_state_finalize (LttvTracesetState *self)
2183{
2184 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
2185 finalize(G_OBJECT(self));
2186}
2187
2188
2189static void
2190traceset_state_class_init (LttvTracesetContextClass *klass)
2191{
2192 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2193
2194 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
2195 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
2196 klass->fini = (void (*)(LttvTracesetContext *self))fini;
2197 klass->new_traceset_context = new_traceset_context;
2198 klass->new_trace_context = new_trace_context;
2199 klass->new_tracefile_context = new_tracefile_context;
2200}
2201
2202
2203GType
2204lttv_traceset_state_get_type(void)
2205{
2206 static GType type = 0;
2207 if (type == 0) {
2208 static const GTypeInfo info = {
2209 sizeof (LttvTracesetStateClass),
2210 NULL, /* base_init */
2211 NULL, /* base_finalize */
2212 (GClassInitFunc) traceset_state_class_init, /* class_init */
2213 NULL, /* class_finalize */
2214 NULL, /* class_data */
dbb7bb09 2215 sizeof (LttvTracesetState),
308711e5 2216 0, /* n_preallocs */
00e74b69 2217 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2218 NULL /* value handling */
308711e5 2219 };
2220
2221 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2222 &info, 0);
2223 }
2224 return type;
2225}
2226
2227
2228static void
2229trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2230{
2231}
2232
2233
2234static void
2235trace_state_finalize (LttvTraceState *self)
2236{
2237 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2238 finalize(G_OBJECT(self));
2239}
2240
2241
2242static void
2243trace_state_class_init (LttvTraceStateClass *klass)
2244{
2245 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2246
2247 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2248 klass->state_save = state_save;
2249 klass->state_restore = state_restore;
2250 klass->state_saved_free = state_saved_free;
2251}
2252
2253
2254GType
2255lttv_trace_state_get_type(void)
2256{
2257 static GType type = 0;
2258 if (type == 0) {
2259 static const GTypeInfo info = {
2260 sizeof (LttvTraceStateClass),
2261 NULL, /* base_init */
2262 NULL, /* base_finalize */
2263 (GClassInitFunc) trace_state_class_init, /* class_init */
2264 NULL, /* class_finalize */
2265 NULL, /* class_data */
2266 sizeof (LttvTraceState),
2267 0, /* n_preallocs */
00e74b69 2268 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2269 NULL /* value handling */
308711e5 2270 };
2271
2272 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2273 "LttvTraceStateType", &info, 0);
2274 }
2275 return type;
2276}
2277
2278
2279static void
2280tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2281{
2282}
2283
2284
2285static void
2286tracefile_state_finalize (LttvTracefileState *self)
2287{
2288 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2289 finalize(G_OBJECT(self));
2290}
2291
2292
2293static void
2294tracefile_state_class_init (LttvTracefileStateClass *klass)
2295{
2296 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2297
2298 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2299}
2300
2301
2302GType
2303lttv_tracefile_state_get_type(void)
2304{
2305 static GType type = 0;
2306 if (type == 0) {
2307 static const GTypeInfo info = {
2308 sizeof (LttvTracefileStateClass),
2309 NULL, /* base_init */
2310 NULL, /* base_finalize */
2311 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2312 NULL, /* class_finalize */
2313 NULL, /* class_data */
2314 sizeof (LttvTracefileState),
2315 0, /* n_preallocs */
00e74b69 2316 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2317 NULL /* value handling */
308711e5 2318 };
2319
2320 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2321 "LttvTracefileStateType", &info, 0);
2322 }
2323 return type;
2324}
2325
2326
08b1c66e 2327static void module_init()
ffd54a90 2328{
2329 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b3fd4c02 2330 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
2331 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
2332 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
2333 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
2334 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
2335 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
2336 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
2337 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
2338 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
2339 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
2340 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
2341 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
2342 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
2343 LTTV_STATE_RUN = g_quark_from_string("RUN");
2344 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
308711e5 2345 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2346 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2347 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 2348 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 2349 LTTV_STATE_EVENT = g_quark_from_string("event");
2350 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 2351 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 2352 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 2353 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 2354 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2355 LTTV_STATE_TRACE_STATE_USE_COUNT =
2356 g_quark_from_string("trace_state_use_count");
eed2ef37 2357
2358
2359 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 2360 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
eed2ef37 2361 LTT_FACILITY_PROCESS = g_quark_from_string("process");
f4b88a7d 2362 LTT_FACILITY_FS = g_quark_from_string("fs");
b3fd4c02 2363 LTT_FACILITY_STATEDUMP = g_quark_from_string("statedump");
eed2ef37 2364
2365
2366 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2367 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2368 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2369 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2370 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2371 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
faf074a3 2372 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
2373 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
eed2ef37 2374 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2375 LTT_EVENT_FORK = g_quark_from_string("fork");
7bfd7820 2376 LTT_EVENT_KERNEL_THREAD = g_quark_from_string("kernel_thread");
eed2ef37 2377 LTT_EVENT_EXIT = g_quark_from_string("exit");
2378 LTT_EVENT_FREE = g_quark_from_string("free");
f4b88a7d 2379 LTT_EVENT_EXEC = g_quark_from_string("exec");
b3fd4c02 2380 LTT_EVENT_ENUM_PROCESS_STATE = g_quark_from_string("enumerate_process_state");
eed2ef37 2381
2382
2383 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2384 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2385 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 2386 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
eed2ef37 2387 LTT_FIELD_OUT = g_quark_from_string("out");
2388 LTT_FIELD_IN = g_quark_from_string("in");
2389 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2390 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2391 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2392 LTT_FIELD_PID = g_quark_from_string("pid");
f4b88a7d 2393 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 2394 LTT_FIELD_NAME = g_quark_from_string("name");
2395 LTT_FIELD_MODE = g_quark_from_string("mode");
2396 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
2397 LTT_FIELD_STATUS = g_quark_from_string("status");
eed2ef37 2398
ffd54a90 2399}
dc877563 2400
08b1c66e 2401static void module_destroy()
ffd54a90 2402{
2403}
dc877563 2404
2405
08b1c66e 2406LTTV_MODULE("state", "State computation", \
2407 "Update the system state, possibly saving it at intervals", \
2408 module_init, module_destroy)
2409
dc877563 2410
2411
This page took 0.168387 seconds and 4 git commands to generate.