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