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