fix seek so that adding and removing a trace from a traceset will work
[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
d448fce2 564 //g_tree_destroy(tsc->pqueue);
565 //tsc->pqueue = g_tree_new(compare_tracefile);
e7f5e89d 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);
d448fce2 589 g_tree_remove(tsc->pqueue, tfc);
27304273 590
1986f254 591 if(ep != NULL) {
592 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
593 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
e7f5e89d 594 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1986f254 595 g_tree_insert(tsc->pqueue, tfc, tfc);
728d0c3e 596 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1986f254 597 } else {
598 tfc->timestamp = ltt_time_infinite;
599 }
dc877563 600 }
dc877563 601}
602
603
308711e5 604static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 605{
348c6ba8 606 guint i, nb_tracefile, nb_cpus;
dc877563 607
308711e5 608 LttvTracefileState *tfcs;
dc877563 609
308711e5 610 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 611
348c6ba8 612 guint *running_process;
613
308711e5 614 LttvAttributeType type;
dc877563 615
308711e5 616 LttvAttributeValue value;
dc877563 617
308711e5 618 LttvAttributeName name;
dc877563 619
308711e5 620 LttEventPosition *ep;
dc877563 621
308711e5 622 tracefiles_tree = lttv_attribute_find_subdir(container,
623 LTTV_STATE_TRACEFILES);
c47a6dc6 624 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 625 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 626
308711e5 627 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
628 &value);
629 g_assert(type == LTTV_POINTER);
630 lttv_state_free_process_table(*(value.v_pointer));
631 *(value.v_pointer) = NULL;
632 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
633
348c6ba8 634 /* Free running processes array */
635 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
728d0c3e 636 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
348c6ba8 637 &value);
638 g_assert(type == LTTV_POINTER);
639 running_process = *(value.v_pointer);
640 g_free(running_process);
641
eed2ef37 642 nb_tracefile = self->parent.tracefiles->len;
308711e5 643
644 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 645 tfcs =
cb03932a 646 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
647 LttvTracefileContext*, i));
308711e5 648 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
649 g_assert(type == LTTV_GOBJECT);
650 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
651
652 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
653 &value);
654 g_assert(type == LTTV_POINTER);
655 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 656 }
c47a6dc6 657 g_object_unref(G_OBJECT(tracefiles_tree));
dc877563 658}
659
660
f95bc830 661static void free_saved_state(LttvTraceState *self)
662{
663 guint i, nb;
664
665 LttvAttributeType type;
666
667 LttvAttributeValue value;
668
669 LttvAttributeName name;
670
671 LttvAttribute *saved_states;
672
673 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
674 LTTV_STATE_SAVED_STATES);
675
676 nb = lttv_attribute_get_number(saved_states);
677 for(i = 0 ; i < nb ; i++) {
678 type = lttv_attribute_get(saved_states, i, &name, &value);
679 g_assert(type == LTTV_GOBJECT);
680 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
681 }
682
683 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
f95bc830 684}
685
686
687static void
688create_max_time(LttvTraceState *tcs)
689{
690 LttvAttributeValue v;
691
692 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
693 LTTV_POINTER, &v);
694 g_assert(*(v.v_pointer) == NULL);
695 *(v.v_pointer) = g_new(LttTime,1);
348c6ba8 696 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
f95bc830 697}
698
699
700static void
701get_max_time(LttvTraceState *tcs)
702{
703 LttvAttributeValue v;
704
705 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
706 LTTV_POINTER, &v);
707 g_assert(*(v.v_pointer) != NULL);
708 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
709}
710
711
712static void
713free_max_time(LttvTraceState *tcs)
714{
715 LttvAttributeValue v;
716
717 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
718 LTTV_POINTER, &v);
719 g_free(*(v.v_pointer));
720 *(v.v_pointer) = NULL;
721}
722
723
724typedef struct _LttvNameTables {
eed2ef37 725 // FIXME GQuark *eventtype_names;
f95bc830 726 GQuark *syscall_names;
727 GQuark *trap_names;
728 GQuark *irq_names;
729} LttvNameTables;
730
731
b445142a 732static void
f95bc830 733create_name_tables(LttvTraceState *tcs)
b445142a 734{
735 int i, nb;
dc877563 736
eed2ef37 737 GQuark f_name, e_name;
738
021eeb41 739 LttvTraceHook h;
dc877563 740
eed2ef37 741 LttvTraceHookByFacility *thf;
b445142a 742
743 LttEventType *et;
744
745 LttType *t;
746
747 GString *fe_name = g_string_new("");
748
f95bc830 749 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
750
751 LttvAttributeValue v;
752
753 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
754 LTTV_POINTER, &v);
755 g_assert(*(v.v_pointer) == NULL);
756 *(v.v_pointer) = name_tables;
eed2ef37 757#if 0 // Use iteration over the facilities_by_name and then list all event
758 // types of each facility
b445142a 759 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 760 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 761 for(i = 0 ; i < nb ; i++) {
762 et = ltt_trace_eventtype_get(tcs->parent.t, i);
763 e_name = ltt_eventtype_name(et);
764 f_name = ltt_facility_name(ltt_eventtype_facility(et));
765 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 766 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 767 }
eed2ef37 768#endif //0
769 if(lttv_trace_find_hook(tcs->parent.t,
770 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
771 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 772 NULL, NULL, &h))
eed2ef37 773 return;
774
021eeb41 775 thf = lttv_trace_hook_get_first(&h);
eed2ef37 776
777 t = ltt_field_type(thf->f1);
b445142a 778 nb = ltt_type_element_number(t);
eed2ef37 779
021eeb41 780 lttv_trace_hook_destroy(&h);
b445142a 781
eed2ef37 782 /* CHECK syscalls should be an enum but currently are not!
f95bc830 783 name_tables->syscall_names = g_new(GQuark, nb);
b445142a 784
785 for(i = 0 ; i < nb ; i++) {
f95bc830 786 name_tables->syscall_names[i] = g_quark_from_string(
787 ltt_enum_string_get(t, i));
b445142a 788 }
789 */
790
f95bc830 791 name_tables->syscall_names = g_new(GQuark, 256);
b445142a 792 for(i = 0 ; i < 256 ; i++) {
793 g_string_printf(fe_name, "syscall %d", i);
f95bc830 794 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
b445142a 795 }
796
eed2ef37 797 if(lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL,
798 LTT_EVENT_TRAP_ENTRY,
799 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 800 NULL, NULL, &h))
eed2ef37 801 return;
802
021eeb41 803 thf = lttv_trace_hook_get_first(&h);
eed2ef37 804
805 t = ltt_field_type(thf->f1);
b445142a 806 nb = ltt_type_element_number(t);
807
021eeb41 808 lttv_trace_hook_destroy(&h);
eed2ef37 809
b445142a 810 /*
f95bc830 811 name_tables->trap_names = g_new(GQuark, nb);
b445142a 812 for(i = 0 ; i < nb ; i++) {
f95bc830 813 name_tables->trap_names[i] = g_quark_from_string(
814 ltt_enum_string_get(t, i));
b445142a 815 }
816 */
817
f95bc830 818 name_tables->trap_names = g_new(GQuark, 256);
b445142a 819 for(i = 0 ; i < 256 ; i++) {
820 g_string_printf(fe_name, "trap %d", i);
f95bc830 821 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
b445142a 822 }
823
eed2ef37 824 if(lttv_trace_find_hook(tcs->parent.t,
825 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
826 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 827 NULL, NULL, &h))
eed2ef37 828 return;
829
021eeb41 830 thf = lttv_trace_hook_get_first(&h);
eed2ef37 831
832 t = ltt_field_type(thf->f1);
b445142a 833 nb = ltt_type_element_number(t);
834
021eeb41 835 lttv_trace_hook_destroy(&h);
eed2ef37 836
b445142a 837 /*
f95bc830 838 name_tables->irq_names = g_new(GQuark, nb);
b445142a 839 for(i = 0 ; i < nb ; i++) {
f95bc830 840 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
b445142a 841 }
842 */
843
f95bc830 844 name_tables->irq_names = g_new(GQuark, 256);
b445142a 845 for(i = 0 ; i < 256 ; i++) {
846 g_string_printf(fe_name, "irq %d", i);
f95bc830 847 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
b445142a 848 }
849
850 g_string_free(fe_name, TRUE);
851}
852
853
f95bc830 854static void
855get_name_tables(LttvTraceState *tcs)
856{
857 LttvNameTables *name_tables;
858
859 LttvAttributeValue v;
860
861 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
862 LTTV_POINTER, &v);
863 g_assert(*(v.v_pointer) != NULL);
864 name_tables = (LttvNameTables *)*(v.v_pointer);
eed2ef37 865 //tcs->eventtype_names = name_tables->eventtype_names;
f95bc830 866 tcs->syscall_names = name_tables->syscall_names;
867 tcs->trap_names = name_tables->trap_names;
868 tcs->irq_names = name_tables->irq_names;
869}
870
871
b445142a 872static void
873free_name_tables(LttvTraceState *tcs)
874{
f95bc830 875 LttvNameTables *name_tables;
876
877 LttvAttributeValue v;
878
879 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
880 LTTV_POINTER, &v);
881 name_tables = (LttvNameTables *)*(v.v_pointer);
882 *(v.v_pointer) = NULL;
883
eed2ef37 884 // g_free(name_tables->eventtype_names);
f95bc830 885 g_free(name_tables->syscall_names);
886 g_free(name_tables->trap_names);
887 g_free(name_tables->irq_names);
888 g_free(name_tables);
b445142a 889}
dc877563 890
15b3d537 891#ifdef HASH_TABLE_DEBUG
892
893static void test_process(gpointer key, gpointer value, gpointer user_data)
894{
895 LttvProcessState *process = (LttvProcessState *)value;
896
897 /* Test for process corruption */
898 guint stack_len = process->execution_stack->len;
899}
900
901static void hash_table_check(GHashTable *table)
902{
903 g_hash_table_foreach(table, test_process, NULL);
904}
905
906
907#endif
908
909
b445142a 910static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 911 guint state_id)
dc877563 912{
b445142a 913 LttvExecutionState *es;
348c6ba8 914
915 guint cpu = ltt_tracefile_num(tfs->parent.tf);
916 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
15b3d537 917
918#ifdef HASH_TABLE_DEBUG
919 hash_table_check(ts->processes);
920#endif
348c6ba8 921 LttvProcessState *process = ts->running_process[cpu];
dc877563 922
b445142a 923 guint depth = process->execution_stack->len;
dc877563 924
e05fc742 925 process->execution_stack =
926 g_array_set_size(process->execution_stack, depth + 1);
927 /* Keep in sync */
928 process->state =
929 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
930
b445142a 931 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
932 es->t = t;
933 es->n = state_id;
934 es->entry = es->change = tfs->parent.timestamp;
935 es->s = process->state->s;
936 process->state = es;
dc877563 937}
938
939
b445142a 940static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 941{
348c6ba8 942 guint cpu = ltt_tracefile_num(tfs->parent.tf);
943 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
944 LttvProcessState *process = ts->running_process[cpu];
dc877563 945
f95bc830 946 guint depth = process->execution_stack->len;
dc877563 947
3d27549e 948 if(process->state->t != t){
00e74b69 949 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 950 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 951 g_info("process state has %s when pop_int is %s\n",
8e8e6b64 952 g_quark_to_string(process->state->t),
953 g_quark_to_string(t));
08b1c66e 954 g_info("{ %u, %u, %s, %s }\n",
8e8e6b64 955 process->pid,
956 process->ppid,
957 g_quark_to_string(process->name),
958 g_quark_to_string(process->state->s));
3d27549e 959 return;
960 }
b445142a 961
f95bc830 962 if(depth == 1){
00e74b69 963 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 964 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
965 return;
966 }
967
e05fc742 968 process->execution_stack =
969 g_array_set_size(process->execution_stack, depth - 1);
b445142a 970 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 971 depth - 2);
b445142a 972 process->state->change = tfs->parent.timestamp;
dc877563 973}
974
975
2a2fa4f0 976LttvProcessState *
348c6ba8 977lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
978 guint cpu, guint pid, const LttTime *timestamp)
dc877563 979{
980 LttvProcessState *process = g_new(LttvProcessState, 1);
981
b445142a 982 LttvExecutionState *es;
dc877563 983
348c6ba8 984 LttvTraceContext *tc = (LttvTraceContext*)tcs;
ba576a78 985
b445142a 986 char buffer[128];
ffd54a90 987
dc877563 988 process->pid = pid;
348c6ba8 989 process->cpu = cpu;
990 //process->last_cpu = tfs->cpu_name;
991 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
cb03932a 992 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 993 g_hash_table_insert(tcs->processes, process, process);
b445142a 994
995 if(parent) {
996 process->ppid = parent->pid;
997 process->name = parent->name;
348c6ba8 998 process->creation_time = *timestamp;
b445142a 999 }
2a2fa4f0 1000
1001 /* No parent. This process exists but we are missing all information about
1002 its creation. The birth time is set to zero but we remember the time of
1003 insertion */
1004
b445142a 1005 else {
1006 process->ppid = 0;
1007 process->name = LTTV_STATE_UNNAMED;
2a2fa4f0 1008 process->creation_time = ltt_time_zero;
b445142a 1009 }
1010
348c6ba8 1011 process->insertion_time = *timestamp;
b445142a 1012 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1013 process->creation_time.tv_nsec);
1014 process->pid_time = g_quark_from_string(buffer);
348c6ba8 1015 process->cpu = cpu;
1016 //process->last_cpu = tfs->cpu_name;
1017 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 1018 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1019 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
e05fc742 1020 process->execution_stack = g_array_set_size(process->execution_stack, 1);
b445142a 1021 es = process->state = &g_array_index(process->execution_stack,
1022 LttvExecutionState, 0);
1023 es->t = LTTV_STATE_USER_MODE;
1024 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 1025 es->entry = *timestamp;
1026 //g_assert(timestamp->tv_sec != 0);
1027 es->change = *timestamp;
b445142a 1028 es->s = LTTV_STATE_WAIT_FORK;
cbe7c836 1029
1030 return process;
dc877563 1031}
1032
348c6ba8 1033LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 1034 guint pid)
dc877563 1035{
2a2fa4f0 1036 LttvProcessState key;
1037 LttvProcessState *process;
1038
1039 key.pid = pid;
348c6ba8 1040 key.cpu = cpu;
2a2fa4f0 1041 process = g_hash_table_lookup(ts->processes, &key);
dc877563 1042 return process;
1043}
1044
2a2fa4f0 1045LttvProcessState *
348c6ba8 1046lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1047 LttTime *timestamp)
2a2fa4f0 1048{
348c6ba8 1049 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1050
1051 /* Put ltt_time_zero creation time for unexisting processes */
1052 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1053 NULL, cpu, pid, timestamp);
2a2fa4f0 1054 return process;
1055}
1056
41c7f803 1057/* FIXME : this function should be called when we receive an event telling that
1058 * release_task has been called in the kernel. In happens generally when
1059 * the parent waits for its child terminaison, but may also happen in special
1060 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1061 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1062 * of a killed thread ground, but isn't the leader.
41c7f803 1063 */
b445142a 1064static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 1065{
ba576a78 1066 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 1067 LttvProcessState key;
ba576a78 1068
2a2fa4f0 1069 key.pid = process->pid;
348c6ba8 1070 key.cpu = process->cpu;
2a2fa4f0 1071 g_hash_table_remove(ts->processes, &key);
b445142a 1072 g_array_free(process->execution_stack, TRUE);
dc877563 1073 g_free(process);
1074}
1075
1076
b445142a 1077static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 1078{
b445142a 1079 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 1080 g_free(value);
1081}
1082
1083
308711e5 1084static void lttv_state_free_process_table(GHashTable *processes)
dc877563 1085{
1086 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 1087 g_hash_table_destroy(processes);
dc877563 1088}
1089
1090
b445142a 1091static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 1092{
ba576a78 1093 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1094 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1095 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1096 LttField *f = thf->f1;
dc877563 1097
b445142a 1098 LttvExecutionSubmode submode;
1099
1100 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
eed2ef37 1101 ltt_event_get_unsigned(e, f)];
b445142a 1102 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 1103 return FALSE;
1104}
1105
1106
b445142a 1107static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 1108{
ba576a78 1109 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1110
ffd54a90 1111 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 1112 return FALSE;
1113}
1114
1115
b445142a 1116static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 1117{
ba576a78 1118 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1119 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1120 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1121 LttField *f = thf->f1;
dc877563 1122
b445142a 1123 LttvExecutionSubmode submode;
1124
1125 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
eed2ef37 1126 ltt_event_get_unsigned(e, f)];
b445142a 1127 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 1128 return FALSE;
1129}
1130
1131
b445142a 1132static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 1133{
ba576a78 1134 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1135
ffd54a90 1136 pop_state(s, LTTV_STATE_TRAP);
dc877563 1137 return FALSE;
1138}
1139
1140
b445142a 1141static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 1142{
ba576a78 1143 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1144 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 1145 guint8 fac_id = ltt_event_facility_id(e);
1146 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 1147 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 1148 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1149 g_assert(thf->f1 != NULL);
1150 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 1151 LttField *f = thf->f1;
dc877563 1152
b445142a 1153 LttvExecutionSubmode submode;
1154
1155 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
eed2ef37 1156 ltt_event_get_unsigned(e, f)];
b445142a 1157
dc877563 1158 /* Do something with the info about being in user or system mode when int? */
b445142a 1159 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 1160 return FALSE;
1161}
1162
1163
b445142a 1164static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 1165{
ba576a78 1166 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1167
ffd54a90 1168 pop_state(s, LTTV_STATE_IRQ);
dc877563 1169 return FALSE;
1170}
1171
1172
b445142a 1173static gboolean schedchange(void *hook_data, void *call_data)
dc877563 1174{
ba576a78 1175 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1176 guint cpu = ltt_tracefile_num(s->parent.tf);
1177 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1178 LttvProcessState *process = ts->running_process[cpu];
1179
eed2ef37 1180 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1181 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 1182 guint pid_in, pid_out;
1183 gint state_out;
dc877563 1184
eed2ef37 1185 pid_out = ltt_event_get_unsigned(e, thf->f1);
1186 pid_in = ltt_event_get_unsigned(e, thf->f2);
73394fd3 1187 state_out = ltt_event_get_int(e, thf->f3);
348c6ba8 1188
1189 if(likely(process != NULL)) {
b445142a 1190
f95bc830 1191 /* We could not know but it was not the idle process executing.
1192 This should only happen at the beginning, before the first schedule
1193 event, and when the initial information (current process for each CPU)
1194 is missing. It is not obvious how we could, after the fact, compensate
1195 the wrongly attributed statistics. */
1196
240f1fea 1197 //This test only makes sense once the state is known and if there is no
1198 //missing events.
348c6ba8 1199 //if(unlikely(process->pid != pid_out)) {
1200 // g_assert(process->pid == 0);
240f1fea 1201 //}
f95bc830 1202
348c6ba8 1203 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1204 process->state->s = LTTV_STATE_ZOMBIE;
dbd243b1 1205 } else {
348c6ba8 1206 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1207 else process->state->s = LTTV_STATE_WAIT;
41c7f803 1208 } /* FIXME : we do not remove process here, because the kernel
1209 * still has them : they may be zombies. We need to know
1210 * exactly when release_task is executed on the PID to
0828099d 1211 * know when the zombie is destroyed.
41c7f803 1212 */
1213 //else
348c6ba8 1214 // exit_process(s, process);
3d27549e 1215
348c6ba8 1216 process->state->change = s->parent.timestamp;
dc877563 1217 }
348c6ba8 1218 process = ts->running_process[cpu] =
1219 lttv_state_find_process_or_create(
1220 (LttvTraceState*)s->parent.t_context,
1221 cpu, pid_in,
1222 &s->parent.timestamp);
1223 process->state->s = LTTV_STATE_RUN;
1224 process->cpu = cpu;
1225 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1226 process->state->change = s->parent.timestamp;
dc877563 1227 return FALSE;
1228}
1229
eed2ef37 1230static gboolean process_fork(void *hook_data, void *call_data)
dc877563 1231{
eed2ef37 1232 LttvTracefileState *s = (LttvTracefileState *)call_data;
1233 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1234 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2cdc690b 1235 LttField *f;
eed2ef37 1236 guint parent_pid;
2cdc690b 1237 guint child_pid;
4ad73431 1238 LttvProcessState *zombie_process;
348c6ba8 1239 guint cpu = ltt_tracefile_num(s->parent.tf);
1240 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1241 LttvProcessState *process = ts->running_process[cpu];
26275aa2 1242 LttvProcessState *child_process;
2cdc690b 1243
eed2ef37 1244 /* Parent PID */
1245 f = thf->f1;
1246 parent_pid = ltt_event_get_unsigned(e, f);
1247
2cdc690b 1248 /* Child PID */
eed2ef37 1249 f = thf->f2;
1250 child_pid = ltt_event_get_unsigned(e, f);
2cdc690b 1251
15b3d537 1252 /* Mathieu : it seems like the process might have been scheduled in before the
1253 * fork, and, in a rare case, might be the current process. This might happen
1254 * in a SMP case where we don't have enough precision on the clocks */
1255#if 0
348c6ba8 1256 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 1257
1d1df11d 1258 if(unlikely(zombie_process != NULL)) {
4ad73431 1259 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 1260 * has been released. FIXME : should know when release_task happens instead.
4ad73431 1261 */
15b3d537 1262 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1263 guint i;
1264 for(i=0; i< num_cpus; i++) {
1265 g_assert(process != ts->running_process[i]);
1266 }
1267
4ad73431 1268 exit_process(s, zombie_process);
1269 }
15b3d537 1270#endif //0
348c6ba8 1271 g_assert(process->pid != child_pid);
eed2ef37 1272 // FIXME : Add this test in the "known state" section
348c6ba8 1273 // g_assert(process->pid == parent_pid);
26275aa2 1274 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1275 if(child_process == NULL) {
1276 lttv_state_create_process(ts, process, cpu,
1277 child_pid, &s->parent.timestamp);
1278 } else {
1279 /* The process has already been created : due to time imprecision between
1280 * multiple CPUs : it has been scheduled in before creation.
1281 *
1282 * Simply put a correct parent.
1283 */
1284 child_process->ppid = process->pid;
1285 }
4ad73431 1286
dc877563 1287 return FALSE;
1288}
1289
1290
eed2ef37 1291static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1292{
eed2ef37 1293 LttvTracefileState *s = (LttvTracefileState *)call_data;
1294 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1295 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1296 LttField *f;
1297 guint pid;
348c6ba8 1298 guint cpu = ltt_tracefile_num(s->parent.tf);
1299 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1300 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1301
1302 pid = ltt_event_get_unsigned(e, thf->f1);
1303
1304 // FIXME : Add this test in the "known state" section
348c6ba8 1305 // g_assert(process->pid == pid);
eed2ef37 1306
348c6ba8 1307 if(likely(process != NULL)) {
1308 process->state->s = LTTV_STATE_EXIT;
2cdc690b 1309 }
1310 return FALSE;
2cdc690b 1311}
1312
eed2ef37 1313static gboolean process_free(void *hook_data, void *call_data)
2da61677 1314{
eed2ef37 1315 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1316 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 1317 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1318 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 1319 guint release_pid;
1320 LttvProcessState *process;
1321
1322 /* PID of the process to release */
eed2ef37 1323 release_pid = ltt_event_get_unsigned(e, thf->f1);
15b3d537 1324
1325 g_assert(release_pid != 0);
2da61677 1326
348c6ba8 1327 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 1328
1329 if(likely(process != NULL)) {
1330 /* release_task is happening at kernel level : we can now safely release
1331 * the data structure of the process */
0bd2f89c 1332 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1333 guint i;
1334 for(i=0; i< num_cpus; i++) {
1335 g_assert(process != ts->running_process[i]);
1336 }
2da61677 1337 exit_process(s, process);
1338 }
1339
1340 return FALSE;
1341}
1342
f4b88a7d 1343
1344static gboolean process_exec(void *hook_data, void *call_data)
1345{
1346 LttvTracefileState *s = (LttvTracefileState *)call_data;
1347 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1348 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1349 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1350 gchar *name;
1351 guint cpu = ltt_tracefile_num(s->parent.tf);
1352 LttvProcessState *process = ts->running_process[cpu];
1353
1354 /* PID of the process to release */
1355 name = ltt_event_get_string(e, thf->f1);
1356
1357 process->name = g_quark_from_string(name);
1358
1359 return FALSE;
1360}
1361
1362
1363
1364
58c88a41 1365gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1366{
1367 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1368
1369 lttv_state_add_event_hooks(tss);
1370
1371 return 0;
1372}
dc877563 1373
308711e5 1374void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1375{
ba576a78 1376 LttvTraceset *traceset = self->parent.ts;
dc877563 1377
eed2ef37 1378 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1379
ba576a78 1380 LttvTraceState *ts;
dc877563 1381
ba576a78 1382 LttvTracefileState *tfs;
dc877563 1383
dc877563 1384 GArray *hooks;
1385
eed2ef37 1386 LttvTraceHookByFacility *thf;
1387
1388 LttvTraceHook *hook;
dc877563 1389
1390 LttvAttributeValue val;
1391
9d239bd9 1392 gint ret;
1393
ba576a78 1394 nb_trace = lttv_traceset_number(traceset);
dc877563 1395 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1396 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1397
1398 /* Find the eventtype id for the following events and register the
1399 associated by id hooks. */
1400
f4b88a7d 1401 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1402 hooks = g_array_set_size(hooks, 11);
b445142a 1403
9d239bd9 1404 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1405 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1406 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 1407 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
9d239bd9 1408 g_assert(!ret);
cbe7c836 1409
9d239bd9 1410 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1411 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1412 0, 0, 0,
2c82c4dc 1413 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
9d239bd9 1414 g_assert(!ret);
cbe7c836 1415
9d239bd9 1416 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1417 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1418 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 1419 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
9d239bd9 1420 g_assert(!ret);
cbe7c836 1421
9d239bd9 1422 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1423 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1424 0, 0, 0,
2c82c4dc 1425 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
9d239bd9 1426 g_assert(!ret);
cbe7c836 1427
9d239bd9 1428 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1429 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1430 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 1431 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
9d239bd9 1432 g_assert(!ret);
cbe7c836 1433
9d239bd9 1434 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1435 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1436 0, 0, 0,
2c82c4dc 1437 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
9d239bd9 1438 g_assert(!ret);
cbe7c836 1439
9d239bd9 1440 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1441 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1442 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
2c82c4dc 1443 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
9d239bd9 1444 g_assert(!ret);
cbe7c836 1445
9d239bd9 1446 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1447 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1448 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
2c82c4dc 1449 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
9d239bd9 1450 g_assert(!ret);
eed2ef37 1451
9d239bd9 1452 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1453 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1454 LTT_FIELD_PID, 0, 0,
2c82c4dc 1455 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
9d239bd9 1456 g_assert(!ret);
eed2ef37 1457
9d239bd9 1458 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1459 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1460 LTT_FIELD_PID, 0, 0,
2c82c4dc 1461 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
9d239bd9 1462 g_assert(!ret);
2cdc690b 1463
f4b88a7d 1464 ret = lttv_trace_find_hook(ts->parent.t,
1465 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1466 LTT_FIELD_FILENAME, 0, 0,
1467 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1468 g_assert(!ret);
1469
1470
cbe7c836 1471
a5ba1787 1472 /* Add these hooks to each event_by_id hooks list */
dc877563 1473
eed2ef37 1474 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1475
dc877563 1476 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1477 tfs =
9d239bd9 1478 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1479 LttvTracefileContext*, j));
dc877563 1480
1481 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1482 hook = &g_array_index(hooks, LttvTraceHook, k);
1483 for(l=0;l<hook->fac_list->len;l++) {
1484 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1485 lttv_hooks_add(
1486 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1487 thf->h,
d052ffc3 1488 thf,
eed2ef37 1489 LTTV_PRIO_STATE);
1490 }
ffd54a90 1491 }
dc877563 1492 }
ba576a78 1493 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1494 *(val.v_pointer) = hooks;
dc877563 1495 }
1496}
1497
58c88a41 1498gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1499{
1500 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1501
1502 lttv_state_remove_event_hooks(tss);
1503
1504 return 0;
1505}
dc877563 1506
308711e5 1507void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1508{
ba576a78 1509 LttvTraceset *traceset = self->parent.ts;
dc877563 1510
eed2ef37 1511 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1512
ba576a78 1513 LttvTraceState *ts;
dc877563 1514
ba576a78 1515 LttvTracefileState *tfs;
dc877563 1516
dc877563 1517 GArray *hooks;
1518
eed2ef37 1519 LttvTraceHook *hook;
1520
1521 LttvTraceHookByFacility *thf;
dc877563 1522
1523 LttvAttributeValue val;
1524
ba576a78 1525 nb_trace = lttv_traceset_number(traceset);
dc877563 1526 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 1527 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
ba576a78 1528 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1529 hooks = *(val.v_pointer);
dc877563 1530
a5ba1787 1531 /* Remove these hooks from each event_by_id hooks list */
dc877563 1532
eed2ef37 1533 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1534
dc877563 1535 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1536 tfs =
cb03932a 1537 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1538 LttvTracefileContext*, j));
dc877563 1539
1540 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1541 hook = &g_array_index(hooks, LttvTraceHook, k);
1542 for(l=0;l<hook->fac_list->len;l++) {
1543 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1544
1545 lttv_hooks_remove_data(
1546 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1547 thf->h,
d052ffc3 1548 thf);
eed2ef37 1549 }
ffd54a90 1550 }
dc877563 1551 }
1986f254 1552 for(k = 0 ; k < hooks->len ; k++)
1553 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 1554 g_array_free(hooks, TRUE);
1555 }
1556}
1557
eed2ef37 1558static gboolean state_save_event_hook(void *hook_data, void *call_data)
1559{
1560 guint *event_count = (guint*)hook_data;
1561
1562 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1563 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1564 return FALSE;
1565 else
18c87975 1566 *event_count = 0;
eed2ef37 1567
1568 LttvTracefileState *self = (LttvTracefileState *)call_data;
1569
1570 LttvTracefileState *tfcs;
1571
1572 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1573
1574 LttEventPosition *ep;
1575
1576 guint i;
1577
1578 LttTracefile *tf;
1579
1580 LttvAttribute *saved_states_tree, *saved_state_tree;
1581
1582 LttvAttributeValue value;
1583
1584 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1585 LTTV_STATE_SAVED_STATES);
1586 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1587 value = lttv_attribute_add(saved_states_tree,
1588 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1589 *(value.v_gobject) = (GObject *)saved_state_tree;
1590 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1591 *(value.v_time) = self->parent.timestamp;
1592 lttv_state_save(tcs, saved_state_tree);
1593 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1594 self->parent.timestamp.tv_nsec);
1595
1596 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1597
1598 return FALSE;
1599}
1600
14aecf75 1601static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1602{
1603 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1604
1605 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1606
1607 return FALSE;
1608}
1609
eed2ef37 1610#if 0
08b1c66e 1611static gboolean block_start(void *hook_data, void *call_data)
308711e5 1612{
dbb7bb09 1613 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1614
dbb7bb09 1615 LttvTracefileState *tfcs;
308711e5 1616
dbb7bb09 1617 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1618
1619 LttEventPosition *ep;
308711e5 1620
dbb7bb09 1621 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1622
1623 LttTracefile *tf;
1624
1625 LttvAttribute *saved_states_tree, *saved_state_tree;
1626
1627 LttvAttributeValue value;
1628
dbb7bb09 1629 ep = ltt_event_position_new();
eed2ef37 1630
1631 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 1632
1633 /* Count the number of events added since the last block end in any
1634 tracefile. */
1635
1636 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1637 tfcs =
1638 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1639 LttvTracefileContext, i));
dbb7bb09 1640 ltt_event_position(tfcs->parent.e, ep);
1641 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1642 tcs->nb_event += nb_event - tfcs->saved_position;
1643 tfcs->saved_position = nb_event;
1644 }
1645 g_free(ep);
308711e5 1646
308711e5 1647 if(tcs->nb_event >= tcs->save_interval) {
1648 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1649 LTTV_STATE_SAVED_STATES);
1650 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1651 value = lttv_attribute_add(saved_states_tree,
1652 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1653 *(value.v_gobject) = (GObject *)saved_state_tree;
1654 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1655 *(value.v_time) = self->parent.timestamp;
308711e5 1656 lttv_state_save(tcs, saved_state_tree);
1657 tcs->nb_event = 0;
08b1c66e 1658 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1659 self->parent.timestamp.tv_nsec);
308711e5 1660 }
dbb7bb09 1661 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1662 return FALSE;
1663}
eed2ef37 1664#endif //0
308711e5 1665
eed2ef37 1666#if 0
08b1c66e 1667static gboolean block_end(void *hook_data, void *call_data)
1668{
1669 LttvTracefileState *self = (LttvTracefileState *)call_data;
1670
1671 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1672
1673 LttTracefile *tf;
1674
1675 LttEventPosition *ep;
1676
1677 guint nb_block, nb_event;
1678
1679 ep = ltt_event_position_new();
1680 ltt_event_position(self->parent.e, ep);
1681 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1682 tcs->nb_event += nb_event - self->saved_position + 1;
1683 self->saved_position = 0;
1684 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1685 g_free(ep);
00e74b69 1686
1687 return FALSE;
08b1c66e 1688}
eed2ef37 1689#endif //0
1690#if 0
308711e5 1691void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1692{
1693 LttvTraceset *traceset = self->parent.ts;
1694
00e74b69 1695 guint i, j, nb_trace, nb_tracefile;
308711e5 1696
1697 LttvTraceState *ts;
1698
1699 LttvTracefileState *tfs;
1700
08b1c66e 1701 LttvTraceHook hook_start, hook_end;
308711e5 1702
1703 nb_trace = lttv_traceset_number(traceset);
1704 for(i = 0 ; i < nb_trace ; i++) {
1705 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 1706
08b1c66e 1707 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1708 NULL, NULL, block_start, &hook_start);
308711e5 1709 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1710 NULL, NULL, block_end, &hook_end);
308711e5 1711
eed2ef37 1712 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1713
dbb7bb09 1714 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1715 tfs =
1716 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1717 LttvTracefileContext, j));
a5ba1787 1718 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1719 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 1720 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1721 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1722 }
1723 }
1724}
1725#endif //0
1726
1727void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1728{
1729 LttvTraceset *traceset = self->parent.ts;
1730
1731 guint i, j, nb_trace, nb_tracefile;
1732
1733 LttvTraceState *ts;
1734
1735 LttvTracefileState *tfs;
1736
1737
1738 nb_trace = lttv_traceset_number(traceset);
1739 for(i = 0 ; i < nb_trace ; i++) {
1740
1741 ts = (LttvTraceState *)self->parent.traces[i];
1742 nb_tracefile = ts->parent.tracefiles->len;
1743
3054461a 1744 guint *event_count = g_new(guint, 1);
1745 *event_count = 0;
1746
eed2ef37 1747 for(j = 0 ; j < nb_tracefile ; j++) {
1748 tfs =
cb03932a 1749 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1750 LttvTracefileContext*, j));
eed2ef37 1751 lttv_hooks_add(tfs->parent.event,
1752 state_save_event_hook,
1753 event_count,
1754 LTTV_PRIO_STATE);
1755
308711e5 1756 }
1757 }
14aecf75 1758
1759 lttv_process_traceset_begin(&self->parent,
1760 NULL, NULL, NULL, NULL, NULL);
1761
308711e5 1762}
1763
b56b5fec 1764gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1765{
1766 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1767
1768 lttv_state_save_add_event_hooks(tss);
1769
1770 return 0;
1771}
1772
308711e5 1773
eed2ef37 1774#if 0
308711e5 1775void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1776{
1777 LttvTraceset *traceset = self->parent.ts;
1778
00e74b69 1779 guint i, j, nb_trace, nb_tracefile;
308711e5 1780
1781 LttvTraceState *ts;
1782
1783 LttvTracefileState *tfs;
1784
08b1c66e 1785 LttvTraceHook hook_start, hook_end;
308711e5 1786
1787 nb_trace = lttv_traceset_number(traceset);
1788 for(i = 0 ; i < nb_trace ; i++) {
1789 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 1790
08b1c66e 1791 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1792 NULL, NULL, block_start, &hook_start);
1793
308711e5 1794 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1795 NULL, NULL, block_end, &hook_end);
308711e5 1796
eed2ef37 1797 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1798
dbb7bb09 1799 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1800 tfs =
1801 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1802 LttvTracefileContext, j));
308711e5 1803 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1804 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1805 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1806 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1807 }
1808 }
1809}
eed2ef37 1810#endif //0
1811
1812void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1813{
1814 LttvTraceset *traceset = self->parent.ts;
1815
1816 guint i, j, nb_trace, nb_tracefile;
1817
1818 LttvTraceState *ts;
1819
1820 LttvTracefileState *tfs;
1821
14aecf75 1822 LttvHooks *after_trace = lttv_hooks_new();
1823
1824 lttv_hooks_add(after_trace,
1825 state_save_after_trace_hook,
1826 NULL,
1827 LTTV_PRIO_STATE);
1828
1829
1830 lttv_process_traceset_end(&self->parent,
1831 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 1832
14aecf75 1833 lttv_hooks_destroy(after_trace);
1834
eed2ef37 1835 nb_trace = lttv_traceset_number(traceset);
1836 for(i = 0 ; i < nb_trace ; i++) {
1837
1838 ts = (LttvTraceState *)self->parent.traces[i];
1839 nb_tracefile = ts->parent.tracefiles->len;
1840
1841 guint *event_count;
1842
1843 for(j = 0 ; j < nb_tracefile ; j++) {
1844 tfs =
cb03932a 1845 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1846 LttvTracefileContext*, j));
eed2ef37 1847 event_count = lttv_hooks_remove(tfs->parent.event,
1848 state_save_event_hook);
eed2ef37 1849 }
3054461a 1850 g_free(event_count);
eed2ef37 1851 }
1852}
308711e5 1853
b56b5fec 1854gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1855{
1856 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1857
1858 lttv_state_save_remove_event_hooks(tss);
1859
1860 return 0;
1861}
308711e5 1862
dd025f91 1863void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1864{
1865 LttvTraceset *traceset = self->parent.ts;
1866
00e74b69 1867 guint i, nb_trace;
308711e5 1868
1869 int min_pos, mid_pos, max_pos;
1870
728d0c3e 1871 guint call_rest = 0;
1872
308711e5 1873 LttvTraceState *tcs;
1874
1875 LttvAttributeValue value;
1876
1877 LttvAttributeType type;
1878
1879 LttvAttributeName name;
1880
1881 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1882
d448fce2 1883 //g_tree_destroy(self->parent.pqueue);
1884 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 1885
728d0c3e 1886 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1887
308711e5 1888 nb_trace = lttv_traceset_number(traceset);
1889 for(i = 0 ; i < nb_trace ; i++) {
1890 tcs = (LttvTraceState *)self->parent.traces[i];
1891
2a2fa4f0 1892 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1893 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1894 LTTV_STATE_SAVED_STATES);
1895 min_pos = -1;
1896
1897 if(saved_states_tree) {
dd025f91 1898 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1899 mid_pos = max_pos / 2;
1900 while(min_pos < max_pos) {
1901 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1902 g_assert(type == LTTV_GOBJECT);
1903 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1904 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1905 &value);
1906 g_assert(type == LTTV_TIME);
1907 if(ltt_time_compare(*(value.v_time), t) < 0) {
1908 min_pos = mid_pos;
1909 closest_tree = saved_state_tree;
1910 }
1911 else max_pos = mid_pos - 1;
1912
1913 mid_pos = (min_pos + max_pos + 1) / 2;
1914 }
2a2fa4f0 1915 }
dd025f91 1916
2a2fa4f0 1917 /* restore the closest earlier saved state */
f95bc830 1918 if(min_pos != -1) {
1919 lttv_state_restore(tcs, closest_tree);
728d0c3e 1920 call_rest = 1;
f95bc830 1921 }
dd025f91 1922
2a2fa4f0 1923 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1924 else {
1925 restore_init_state(tcs);
1926 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1927 }
9444deae 1928 }
dd025f91 1929 /* We want to seek quickly without restoring/updating the state */
1930 else {
308711e5 1931 restore_init_state(tcs);
dd025f91 1932 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1933 }
308711e5 1934 }
728d0c3e 1935 if(!call_rest) g_info("NOT Calling restore");
308711e5 1936}
1937
1938
1939static void
1940traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1941{
1942}
1943
1944
1945static void
1946traceset_state_finalize (LttvTracesetState *self)
1947{
1948 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1949 finalize(G_OBJECT(self));
1950}
1951
1952
1953static void
1954traceset_state_class_init (LttvTracesetContextClass *klass)
1955{
1956 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1957
1958 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1959 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1960 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1961 klass->new_traceset_context = new_traceset_context;
1962 klass->new_trace_context = new_trace_context;
1963 klass->new_tracefile_context = new_tracefile_context;
1964}
1965
1966
1967GType
1968lttv_traceset_state_get_type(void)
1969{
1970 static GType type = 0;
1971 if (type == 0) {
1972 static const GTypeInfo info = {
1973 sizeof (LttvTracesetStateClass),
1974 NULL, /* base_init */
1975 NULL, /* base_finalize */
1976 (GClassInitFunc) traceset_state_class_init, /* class_init */
1977 NULL, /* class_finalize */
1978 NULL, /* class_data */
dbb7bb09 1979 sizeof (LttvTracesetState),
308711e5 1980 0, /* n_preallocs */
00e74b69 1981 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1982 NULL /* value handling */
308711e5 1983 };
1984
1985 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1986 &info, 0);
1987 }
1988 return type;
1989}
1990
1991
1992static void
1993trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1994{
1995}
1996
1997
1998static void
1999trace_state_finalize (LttvTraceState *self)
2000{
2001 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2002 finalize(G_OBJECT(self));
2003}
2004
2005
2006static void
2007trace_state_class_init (LttvTraceStateClass *klass)
2008{
2009 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2010
2011 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2012 klass->state_save = state_save;
2013 klass->state_restore = state_restore;
2014 klass->state_saved_free = state_saved_free;
2015}
2016
2017
2018GType
2019lttv_trace_state_get_type(void)
2020{
2021 static GType type = 0;
2022 if (type == 0) {
2023 static const GTypeInfo info = {
2024 sizeof (LttvTraceStateClass),
2025 NULL, /* base_init */
2026 NULL, /* base_finalize */
2027 (GClassInitFunc) trace_state_class_init, /* class_init */
2028 NULL, /* class_finalize */
2029 NULL, /* class_data */
2030 sizeof (LttvTraceState),
2031 0, /* n_preallocs */
00e74b69 2032 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2033 NULL /* value handling */
308711e5 2034 };
2035
2036 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2037 "LttvTraceStateType", &info, 0);
2038 }
2039 return type;
2040}
2041
2042
2043static void
2044tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2045{
2046}
2047
2048
2049static void
2050tracefile_state_finalize (LttvTracefileState *self)
2051{
2052 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2053 finalize(G_OBJECT(self));
2054}
2055
2056
2057static void
2058tracefile_state_class_init (LttvTracefileStateClass *klass)
2059{
2060 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2061
2062 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2063}
2064
2065
2066GType
2067lttv_tracefile_state_get_type(void)
2068{
2069 static GType type = 0;
2070 if (type == 0) {
2071 static const GTypeInfo info = {
2072 sizeof (LttvTracefileStateClass),
2073 NULL, /* base_init */
2074 NULL, /* base_finalize */
2075 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2076 NULL, /* class_finalize */
2077 NULL, /* class_data */
2078 sizeof (LttvTracefileState),
2079 0, /* n_preallocs */
00e74b69 2080 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2081 NULL /* value handling */
308711e5 2082 };
2083
2084 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2085 "LttvTracefileStateType", &info, 0);
2086 }
2087 return type;
2088}
2089
2090
08b1c66e 2091static void module_init()
ffd54a90 2092{
2093 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 2094 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 2095 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2096 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2097 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2098 LTTV_STATE_TRAP = g_quark_from_string("trap");
2099 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 2100 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2101 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 2102 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
dbd243b1 2103 LTTV_STATE_EXIT = g_quark_from_string("exiting");
0828099d 2104 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
ffd54a90 2105 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2106 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 2107 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2108 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2109 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 2110 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 2111 LTTV_STATE_EVENT = g_quark_from_string("event");
2112 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 2113 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 2114 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 2115 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 2116 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2117 LTTV_STATE_TRACE_STATE_USE_COUNT =
2118 g_quark_from_string("trace_state_use_count");
eed2ef37 2119
2120
2121 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2122 LTT_FACILITY_PROCESS = g_quark_from_string("process");
f4b88a7d 2123 LTT_FACILITY_FS = g_quark_from_string("fs");
eed2ef37 2124
2125
2126 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2127 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2128 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2129 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2130 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2131 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2132 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2133 LTT_EVENT_FORK = g_quark_from_string("fork");
2134 LTT_EVENT_EXIT = g_quark_from_string("exit");
2135 LTT_EVENT_FREE = g_quark_from_string("free");
f4b88a7d 2136 LTT_EVENT_EXEC = g_quark_from_string("exec");
eed2ef37 2137
2138
2139 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2140 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2141 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2142 LTT_FIELD_OUT = g_quark_from_string("out");
2143 LTT_FIELD_IN = g_quark_from_string("in");
2144 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2145 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2146 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2147 LTT_FIELD_PID = g_quark_from_string("pid");
f4b88a7d 2148 LTT_FIELD_FILENAME = g_quark_from_string("filename");
eed2ef37 2149
ffd54a90 2150}
dc877563 2151
08b1c66e 2152static void module_destroy()
ffd54a90 2153{
2154}
dc877563 2155
2156
08b1c66e 2157LTTV_MODULE("state", "State computation", \
2158 "Update the system state, possibly saving it at intervals", \
2159 module_init, module_destroy)
2160
dc877563 2161
2162
This page took 0.151676 seconds and 4 git commands to generate.