fork fix
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
CommitLineData
9c312311 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
4e4d11b3 19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
dc877563 22
08b1c66e 23#include <lttv/lttv.h>
24#include <lttv/module.h>
dc877563 25#include <lttv/state.h>
ba576a78 26#include <ltt/facility.h>
27#include <ltt/trace.h>
308711e5 28#include <ltt/event.h>
a5dcde2f 29#include <ltt/type.h>
f95bc830 30#include <stdio.h>
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);
c607371b 1020 process->execution_stack = g_array_set_size(process->execution_stack, 2);
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;
c607371b 1028 es->s = LTTV_STATE_RUN;
1029
1030 es = process->state = &g_array_index(process->execution_stack,
1031 LttvExecutionState, 1);
1032 es->t = LTTV_STATE_SYSCALL;
1033 es->n = LTTV_STATE_SUBMODE_NONE;
1034 es->entry = *timestamp;
1035 //g_assert(timestamp->tv_sec != 0);
1036 es->change = *timestamp;
b445142a 1037 es->s = LTTV_STATE_WAIT_FORK;
cbe7c836 1038
1039 return process;
dc877563 1040}
1041
348c6ba8 1042LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 1043 guint pid)
dc877563 1044{
2a2fa4f0 1045 LttvProcessState key;
1046 LttvProcessState *process;
1047
1048 key.pid = pid;
348c6ba8 1049 key.cpu = cpu;
2a2fa4f0 1050 process = g_hash_table_lookup(ts->processes, &key);
dc877563 1051 return process;
1052}
1053
2a2fa4f0 1054LttvProcessState *
348c6ba8 1055lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1056 LttTime *timestamp)
2a2fa4f0 1057{
348c6ba8 1058 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1059
1060 /* Put ltt_time_zero creation time for unexisting processes */
1061 if(unlikely(process == NULL)) process = lttv_state_create_process(ts,
1062 NULL, cpu, pid, timestamp);
2a2fa4f0 1063 return process;
1064}
1065
41c7f803 1066/* FIXME : this function should be called when we receive an event telling that
1067 * release_task has been called in the kernel. In happens generally when
1068 * the parent waits for its child terminaison, but may also happen in special
1069 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1070 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1071 * of a killed thread ground, but isn't the leader.
41c7f803 1072 */
b445142a 1073static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 1074{
ba576a78 1075 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 1076 LttvProcessState key;
ba576a78 1077
2a2fa4f0 1078 key.pid = process->pid;
348c6ba8 1079 key.cpu = process->cpu;
2a2fa4f0 1080 g_hash_table_remove(ts->processes, &key);
b445142a 1081 g_array_free(process->execution_stack, TRUE);
dc877563 1082 g_free(process);
1083}
1084
1085
b445142a 1086static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 1087{
b445142a 1088 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 1089 g_free(value);
1090}
1091
1092
308711e5 1093static void lttv_state_free_process_table(GHashTable *processes)
dc877563 1094{
1095 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 1096 g_hash_table_destroy(processes);
dc877563 1097}
1098
1099
b445142a 1100static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 1101{
ba576a78 1102 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1103 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1104 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1105 LttField *f = thf->f1;
dc877563 1106
b445142a 1107 LttvExecutionSubmode submode;
1108
1109 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
eed2ef37 1110 ltt_event_get_unsigned(e, f)];
b445142a 1111 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 1112 return FALSE;
1113}
1114
1115
b445142a 1116static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 1117{
ba576a78 1118 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1119
ffd54a90 1120 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 1121 return FALSE;
1122}
1123
1124
b445142a 1125static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 1126{
ba576a78 1127 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1128 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1129 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1130 LttField *f = thf->f1;
dc877563 1131
b445142a 1132 LttvExecutionSubmode submode;
1133
1134 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
eed2ef37 1135 ltt_event_get_unsigned(e, f)];
b445142a 1136 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 1137 return FALSE;
1138}
1139
1140
b445142a 1141static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 1142{
ba576a78 1143 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1144
ffd54a90 1145 pop_state(s, LTTV_STATE_TRAP);
dc877563 1146 return FALSE;
1147}
1148
1149
b445142a 1150static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 1151{
ba576a78 1152 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 1153 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 1154 guint8 fac_id = ltt_event_facility_id(e);
1155 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 1156 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 1157 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1158 g_assert(thf->f1 != NULL);
1159 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 1160 LttField *f = thf->f1;
dc877563 1161
b445142a 1162 LttvExecutionSubmode submode;
1163
1164 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
eed2ef37 1165 ltt_event_get_unsigned(e, f)];
b445142a 1166
dc877563 1167 /* Do something with the info about being in user or system mode when int? */
b445142a 1168 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 1169 return FALSE;
1170}
1171
1172
b445142a 1173static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 1174{
ba576a78 1175 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1176
ffd54a90 1177 pop_state(s, LTTV_STATE_IRQ);
dc877563 1178 return FALSE;
1179}
1180
1181
b445142a 1182static gboolean schedchange(void *hook_data, void *call_data)
dc877563 1183{
ba576a78 1184 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1185 guint cpu = ltt_tracefile_num(s->parent.tf);
1186 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1187 LttvProcessState *process = ts->running_process[cpu];
1188
eed2ef37 1189 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1190 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 1191 guint pid_in, pid_out;
1192 gint state_out;
dc877563 1193
eed2ef37 1194 pid_out = ltt_event_get_unsigned(e, thf->f1);
1195 pid_in = ltt_event_get_unsigned(e, thf->f2);
73394fd3 1196 state_out = ltt_event_get_int(e, thf->f3);
348c6ba8 1197
1198 if(likely(process != NULL)) {
b445142a 1199
f95bc830 1200 /* We could not know but it was not the idle process executing.
1201 This should only happen at the beginning, before the first schedule
1202 event, and when the initial information (current process for each CPU)
1203 is missing. It is not obvious how we could, after the fact, compensate
1204 the wrongly attributed statistics. */
1205
240f1fea 1206 //This test only makes sense once the state is known and if there is no
1207 //missing events.
348c6ba8 1208 //if(unlikely(process->pid != pid_out)) {
1209 // g_assert(process->pid == 0);
240f1fea 1210 //}
f95bc830 1211
348c6ba8 1212 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
1213 process->state->s = LTTV_STATE_ZOMBIE;
dbd243b1 1214 } else {
348c6ba8 1215 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
1216 else process->state->s = LTTV_STATE_WAIT;
41c7f803 1217 } /* FIXME : we do not remove process here, because the kernel
1218 * still has them : they may be zombies. We need to know
1219 * exactly when release_task is executed on the PID to
0828099d 1220 * know when the zombie is destroyed.
41c7f803 1221 */
1222 //else
348c6ba8 1223 // exit_process(s, process);
3d27549e 1224
348c6ba8 1225 process->state->change = s->parent.timestamp;
dc877563 1226 }
348c6ba8 1227 process = ts->running_process[cpu] =
1228 lttv_state_find_process_or_create(
1229 (LttvTraceState*)s->parent.t_context,
1230 cpu, pid_in,
1231 &s->parent.timestamp);
1232 process->state->s = LTTV_STATE_RUN;
1233 process->cpu = cpu;
1234 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
1235 process->state->change = s->parent.timestamp;
dc877563 1236 return FALSE;
1237}
1238
eed2ef37 1239static gboolean process_fork(void *hook_data, void *call_data)
dc877563 1240{
eed2ef37 1241 LttvTracefileState *s = (LttvTracefileState *)call_data;
1242 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1243 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2cdc690b 1244 LttField *f;
eed2ef37 1245 guint parent_pid;
2cdc690b 1246 guint child_pid;
4ad73431 1247 LttvProcessState *zombie_process;
348c6ba8 1248 guint cpu = ltt_tracefile_num(s->parent.tf);
1249 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1250 LttvProcessState *process = ts->running_process[cpu];
26275aa2 1251 LttvProcessState *child_process;
2cdc690b 1252
eed2ef37 1253 /* Parent PID */
1254 f = thf->f1;
1255 parent_pid = ltt_event_get_unsigned(e, f);
1256
2cdc690b 1257 /* Child PID */
eed2ef37 1258 f = thf->f2;
1259 child_pid = ltt_event_get_unsigned(e, f);
2cdc690b 1260
15b3d537 1261 /* Mathieu : it seems like the process might have been scheduled in before the
1262 * fork, and, in a rare case, might be the current process. This might happen
1263 * in a SMP case where we don't have enough precision on the clocks */
1264#if 0
348c6ba8 1265 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 1266
1d1df11d 1267 if(unlikely(zombie_process != NULL)) {
4ad73431 1268 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 1269 * has been released. FIXME : should know when release_task happens instead.
4ad73431 1270 */
15b3d537 1271 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1272 guint i;
1273 for(i=0; i< num_cpus; i++) {
1274 g_assert(process != ts->running_process[i]);
1275 }
1276
4ad73431 1277 exit_process(s, zombie_process);
1278 }
15b3d537 1279#endif //0
348c6ba8 1280 g_assert(process->pid != child_pid);
eed2ef37 1281 // FIXME : Add this test in the "known state" section
348c6ba8 1282 // g_assert(process->pid == parent_pid);
26275aa2 1283 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1284 if(child_process == NULL) {
1285 lttv_state_create_process(ts, process, cpu,
1286 child_pid, &s->parent.timestamp);
1287 } else {
1288 /* The process has already been created : due to time imprecision between
1289 * multiple CPUs : it has been scheduled in before creation.
1290 *
1291 * Simply put a correct parent.
1292 */
1293 child_process->ppid = process->pid;
1294 }
4ad73431 1295
dc877563 1296 return FALSE;
1297}
1298
1299
eed2ef37 1300static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1301{
eed2ef37 1302 LttvTracefileState *s = (LttvTracefileState *)call_data;
1303 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1304 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1305 LttField *f;
1306 guint pid;
348c6ba8 1307 guint cpu = ltt_tracefile_num(s->parent.tf);
1308 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1309 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1310
1311 pid = ltt_event_get_unsigned(e, thf->f1);
1312
1313 // FIXME : Add this test in the "known state" section
348c6ba8 1314 // g_assert(process->pid == pid);
eed2ef37 1315
348c6ba8 1316 if(likely(process != NULL)) {
1317 process->state->s = LTTV_STATE_EXIT;
2cdc690b 1318 }
1319 return FALSE;
2cdc690b 1320}
1321
eed2ef37 1322static gboolean process_free(void *hook_data, void *call_data)
2da61677 1323{
eed2ef37 1324 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1325 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 1326 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1327 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 1328 guint release_pid;
1329 LttvProcessState *process;
1330
1331 /* PID of the process to release */
eed2ef37 1332 release_pid = ltt_event_get_unsigned(e, thf->f1);
15b3d537 1333
1334 g_assert(release_pid != 0);
2da61677 1335
348c6ba8 1336 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 1337
1338 if(likely(process != NULL)) {
1339 /* release_task is happening at kernel level : we can now safely release
1340 * the data structure of the process */
0bd2f89c 1341 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1342 guint i;
1343 for(i=0; i< num_cpus; i++) {
1344 g_assert(process != ts->running_process[i]);
1345 }
2da61677 1346 exit_process(s, process);
1347 }
1348
1349 return FALSE;
1350}
1351
f4b88a7d 1352
1353static gboolean process_exec(void *hook_data, void *call_data)
1354{
1355 LttvTracefileState *s = (LttvTracefileState *)call_data;
1356 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1357 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1358 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1359 gchar *name;
1360 guint cpu = ltt_tracefile_num(s->parent.tf);
1361 LttvProcessState *process = ts->running_process[cpu];
1362
1363 /* PID of the process to release */
1364 name = ltt_event_get_string(e, thf->f1);
1365
1366 process->name = g_quark_from_string(name);
1367
1368 return FALSE;
1369}
1370
1371
1372
1373
58c88a41 1374gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1375{
1376 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1377
1378 lttv_state_add_event_hooks(tss);
1379
1380 return 0;
1381}
dc877563 1382
308711e5 1383void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1384{
ba576a78 1385 LttvTraceset *traceset = self->parent.ts;
dc877563 1386
eed2ef37 1387 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1388
ba576a78 1389 LttvTraceState *ts;
dc877563 1390
ba576a78 1391 LttvTracefileState *tfs;
dc877563 1392
dc877563 1393 GArray *hooks;
1394
eed2ef37 1395 LttvTraceHookByFacility *thf;
1396
1397 LttvTraceHook *hook;
dc877563 1398
1399 LttvAttributeValue val;
1400
9d239bd9 1401 gint ret;
1402
ba576a78 1403 nb_trace = lttv_traceset_number(traceset);
dc877563 1404 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1405 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1406
1407 /* Find the eventtype id for the following events and register the
1408 associated by id hooks. */
1409
f4b88a7d 1410 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1411 hooks = g_array_set_size(hooks, 11);
b445142a 1412
9d239bd9 1413 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1414 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1415 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 1416 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
9d239bd9 1417 g_assert(!ret);
cbe7c836 1418
9d239bd9 1419 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1420 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1421 0, 0, 0,
2c82c4dc 1422 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
9d239bd9 1423 g_assert(!ret);
cbe7c836 1424
9d239bd9 1425 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1426 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1427 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 1428 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
9d239bd9 1429 g_assert(!ret);
cbe7c836 1430
9d239bd9 1431 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1432 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1433 0, 0, 0,
2c82c4dc 1434 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
9d239bd9 1435 g_assert(!ret);
cbe7c836 1436
9d239bd9 1437 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1438 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1439 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 1440 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
9d239bd9 1441 g_assert(!ret);
cbe7c836 1442
9d239bd9 1443 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1444 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1445 0, 0, 0,
2c82c4dc 1446 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
9d239bd9 1447 g_assert(!ret);
cbe7c836 1448
9d239bd9 1449 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1450 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1451 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
2c82c4dc 1452 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
9d239bd9 1453 g_assert(!ret);
cbe7c836 1454
9d239bd9 1455 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1456 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1457 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
2c82c4dc 1458 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
9d239bd9 1459 g_assert(!ret);
eed2ef37 1460
9d239bd9 1461 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1462 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1463 LTT_FIELD_PID, 0, 0,
2c82c4dc 1464 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
9d239bd9 1465 g_assert(!ret);
eed2ef37 1466
9d239bd9 1467 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1468 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1469 LTT_FIELD_PID, 0, 0,
2c82c4dc 1470 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
9d239bd9 1471 g_assert(!ret);
2cdc690b 1472
f4b88a7d 1473 ret = lttv_trace_find_hook(ts->parent.t,
1474 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1475 LTT_FIELD_FILENAME, 0, 0,
1476 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1477 g_assert(!ret);
1478
1479
cbe7c836 1480
a5ba1787 1481 /* Add these hooks to each event_by_id hooks list */
dc877563 1482
eed2ef37 1483 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1484
dc877563 1485 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1486 tfs =
9d239bd9 1487 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1488 LttvTracefileContext*, j));
dc877563 1489
1490 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1491 hook = &g_array_index(hooks, LttvTraceHook, k);
1492 for(l=0;l<hook->fac_list->len;l++) {
1493 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1494 lttv_hooks_add(
1495 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1496 thf->h,
d052ffc3 1497 thf,
eed2ef37 1498 LTTV_PRIO_STATE);
1499 }
ffd54a90 1500 }
dc877563 1501 }
ba576a78 1502 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1503 *(val.v_pointer) = hooks;
dc877563 1504 }
1505}
1506
58c88a41 1507gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1508{
1509 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1510
1511 lttv_state_remove_event_hooks(tss);
1512
1513 return 0;
1514}
dc877563 1515
308711e5 1516void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1517{
ba576a78 1518 LttvTraceset *traceset = self->parent.ts;
dc877563 1519
eed2ef37 1520 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1521
ba576a78 1522 LttvTraceState *ts;
dc877563 1523
ba576a78 1524 LttvTracefileState *tfs;
dc877563 1525
dc877563 1526 GArray *hooks;
1527
eed2ef37 1528 LttvTraceHook *hook;
1529
1530 LttvTraceHookByFacility *thf;
dc877563 1531
1532 LttvAttributeValue val;
1533
ba576a78 1534 nb_trace = lttv_traceset_number(traceset);
dc877563 1535 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 1536 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
ba576a78 1537 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1538 hooks = *(val.v_pointer);
dc877563 1539
a5ba1787 1540 /* Remove these hooks from each event_by_id hooks list */
dc877563 1541
eed2ef37 1542 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1543
dc877563 1544 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1545 tfs =
cb03932a 1546 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1547 LttvTracefileContext*, j));
dc877563 1548
1549 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1550 hook = &g_array_index(hooks, LttvTraceHook, k);
1551 for(l=0;l<hook->fac_list->len;l++) {
1552 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1553
1554 lttv_hooks_remove_data(
1555 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1556 thf->h,
d052ffc3 1557 thf);
eed2ef37 1558 }
ffd54a90 1559 }
dc877563 1560 }
1986f254 1561 for(k = 0 ; k < hooks->len ; k++)
1562 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 1563 g_array_free(hooks, TRUE);
1564 }
1565}
1566
eed2ef37 1567static gboolean state_save_event_hook(void *hook_data, void *call_data)
1568{
1569 guint *event_count = (guint*)hook_data;
1570
1571 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1572 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1573 return FALSE;
1574 else
18c87975 1575 *event_count = 0;
eed2ef37 1576
1577 LttvTracefileState *self = (LttvTracefileState *)call_data;
1578
1579 LttvTracefileState *tfcs;
1580
1581 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1582
1583 LttEventPosition *ep;
1584
1585 guint i;
1586
1587 LttTracefile *tf;
1588
1589 LttvAttribute *saved_states_tree, *saved_state_tree;
1590
1591 LttvAttributeValue value;
1592
1593 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1594 LTTV_STATE_SAVED_STATES);
1595 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1596 value = lttv_attribute_add(saved_states_tree,
1597 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1598 *(value.v_gobject) = (GObject *)saved_state_tree;
1599 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1600 *(value.v_time) = self->parent.timestamp;
1601 lttv_state_save(tcs, saved_state_tree);
1602 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1603 self->parent.timestamp.tv_nsec);
1604
1605 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1606
1607 return FALSE;
1608}
1609
14aecf75 1610static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1611{
1612 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1613
1614 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1615
1616 return FALSE;
1617}
1618
eed2ef37 1619#if 0
08b1c66e 1620static gboolean block_start(void *hook_data, void *call_data)
308711e5 1621{
dbb7bb09 1622 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1623
dbb7bb09 1624 LttvTracefileState *tfcs;
308711e5 1625
dbb7bb09 1626 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1627
1628 LttEventPosition *ep;
308711e5 1629
dbb7bb09 1630 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1631
1632 LttTracefile *tf;
1633
1634 LttvAttribute *saved_states_tree, *saved_state_tree;
1635
1636 LttvAttributeValue value;
1637
dbb7bb09 1638 ep = ltt_event_position_new();
eed2ef37 1639
1640 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 1641
1642 /* Count the number of events added since the last block end in any
1643 tracefile. */
1644
1645 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1646 tfcs =
1647 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1648 LttvTracefileContext, i));
dbb7bb09 1649 ltt_event_position(tfcs->parent.e, ep);
1650 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1651 tcs->nb_event += nb_event - tfcs->saved_position;
1652 tfcs->saved_position = nb_event;
1653 }
1654 g_free(ep);
308711e5 1655
308711e5 1656 if(tcs->nb_event >= tcs->save_interval) {
1657 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1658 LTTV_STATE_SAVED_STATES);
1659 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1660 value = lttv_attribute_add(saved_states_tree,
1661 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1662 *(value.v_gobject) = (GObject *)saved_state_tree;
1663 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1664 *(value.v_time) = self->parent.timestamp;
308711e5 1665 lttv_state_save(tcs, saved_state_tree);
1666 tcs->nb_event = 0;
08b1c66e 1667 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1668 self->parent.timestamp.tv_nsec);
308711e5 1669 }
dbb7bb09 1670 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1671 return FALSE;
1672}
eed2ef37 1673#endif //0
308711e5 1674
eed2ef37 1675#if 0
08b1c66e 1676static gboolean block_end(void *hook_data, void *call_data)
1677{
1678 LttvTracefileState *self = (LttvTracefileState *)call_data;
1679
1680 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1681
1682 LttTracefile *tf;
1683
1684 LttEventPosition *ep;
1685
1686 guint nb_block, nb_event;
1687
1688 ep = ltt_event_position_new();
1689 ltt_event_position(self->parent.e, ep);
1690 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1691 tcs->nb_event += nb_event - self->saved_position + 1;
1692 self->saved_position = 0;
1693 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1694 g_free(ep);
00e74b69 1695
1696 return FALSE;
08b1c66e 1697}
eed2ef37 1698#endif //0
1699#if 0
308711e5 1700void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1701{
1702 LttvTraceset *traceset = self->parent.ts;
1703
00e74b69 1704 guint i, j, nb_trace, nb_tracefile;
308711e5 1705
1706 LttvTraceState *ts;
1707
1708 LttvTracefileState *tfs;
1709
08b1c66e 1710 LttvTraceHook hook_start, hook_end;
308711e5 1711
1712 nb_trace = lttv_traceset_number(traceset);
1713 for(i = 0 ; i < nb_trace ; i++) {
1714 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 1715
08b1c66e 1716 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1717 NULL, NULL, block_start, &hook_start);
308711e5 1718 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1719 NULL, NULL, block_end, &hook_end);
308711e5 1720
eed2ef37 1721 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1722
dbb7bb09 1723 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1724 tfs =
1725 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1726 LttvTracefileContext, j));
a5ba1787 1727 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1728 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 1729 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1730 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1731 }
1732 }
1733}
1734#endif //0
1735
1736void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1737{
1738 LttvTraceset *traceset = self->parent.ts;
1739
1740 guint i, j, nb_trace, nb_tracefile;
1741
1742 LttvTraceState *ts;
1743
1744 LttvTracefileState *tfs;
1745
1746
1747 nb_trace = lttv_traceset_number(traceset);
1748 for(i = 0 ; i < nb_trace ; i++) {
1749
1750 ts = (LttvTraceState *)self->parent.traces[i];
1751 nb_tracefile = ts->parent.tracefiles->len;
1752
3054461a 1753 guint *event_count = g_new(guint, 1);
1754 *event_count = 0;
1755
eed2ef37 1756 for(j = 0 ; j < nb_tracefile ; j++) {
1757 tfs =
cb03932a 1758 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1759 LttvTracefileContext*, j));
eed2ef37 1760 lttv_hooks_add(tfs->parent.event,
1761 state_save_event_hook,
1762 event_count,
1763 LTTV_PRIO_STATE);
1764
308711e5 1765 }
1766 }
14aecf75 1767
1768 lttv_process_traceset_begin(&self->parent,
1769 NULL, NULL, NULL, NULL, NULL);
1770
308711e5 1771}
1772
b56b5fec 1773gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1774{
1775 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1776
1777 lttv_state_save_add_event_hooks(tss);
1778
1779 return 0;
1780}
1781
308711e5 1782
eed2ef37 1783#if 0
308711e5 1784void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1785{
1786 LttvTraceset *traceset = self->parent.ts;
1787
00e74b69 1788 guint i, j, nb_trace, nb_tracefile;
308711e5 1789
1790 LttvTraceState *ts;
1791
1792 LttvTracefileState *tfs;
1793
08b1c66e 1794 LttvTraceHook hook_start, hook_end;
308711e5 1795
1796 nb_trace = lttv_traceset_number(traceset);
1797 for(i = 0 ; i < nb_trace ; i++) {
1798 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 1799
08b1c66e 1800 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1801 NULL, NULL, block_start, &hook_start);
1802
308711e5 1803 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1804 NULL, NULL, block_end, &hook_end);
308711e5 1805
eed2ef37 1806 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1807
dbb7bb09 1808 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1809 tfs =
1810 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1811 LttvTracefileContext, j));
308711e5 1812 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1813 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1814 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1815 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1816 }
1817 }
1818}
eed2ef37 1819#endif //0
1820
1821void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1822{
1823 LttvTraceset *traceset = self->parent.ts;
1824
1825 guint i, j, nb_trace, nb_tracefile;
1826
1827 LttvTraceState *ts;
1828
1829 LttvTracefileState *tfs;
1830
14aecf75 1831 LttvHooks *after_trace = lttv_hooks_new();
1832
1833 lttv_hooks_add(after_trace,
1834 state_save_after_trace_hook,
1835 NULL,
1836 LTTV_PRIO_STATE);
1837
1838
1839 lttv_process_traceset_end(&self->parent,
1840 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 1841
14aecf75 1842 lttv_hooks_destroy(after_trace);
1843
eed2ef37 1844 nb_trace = lttv_traceset_number(traceset);
1845 for(i = 0 ; i < nb_trace ; i++) {
1846
1847 ts = (LttvTraceState *)self->parent.traces[i];
1848 nb_tracefile = ts->parent.tracefiles->len;
1849
1850 guint *event_count;
1851
1852 for(j = 0 ; j < nb_tracefile ; j++) {
1853 tfs =
cb03932a 1854 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1855 LttvTracefileContext*, j));
eed2ef37 1856 event_count = lttv_hooks_remove(tfs->parent.event,
1857 state_save_event_hook);
eed2ef37 1858 }
3054461a 1859 g_free(event_count);
eed2ef37 1860 }
1861}
308711e5 1862
b56b5fec 1863gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1864{
1865 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1866
1867 lttv_state_save_remove_event_hooks(tss);
1868
1869 return 0;
1870}
308711e5 1871
dd025f91 1872void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1873{
1874 LttvTraceset *traceset = self->parent.ts;
1875
00e74b69 1876 guint i, nb_trace;
308711e5 1877
1878 int min_pos, mid_pos, max_pos;
1879
728d0c3e 1880 guint call_rest = 0;
1881
308711e5 1882 LttvTraceState *tcs;
1883
1884 LttvAttributeValue value;
1885
1886 LttvAttributeType type;
1887
1888 LttvAttributeName name;
1889
1890 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1891
d448fce2 1892 //g_tree_destroy(self->parent.pqueue);
1893 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 1894
728d0c3e 1895 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1896
308711e5 1897 nb_trace = lttv_traceset_number(traceset);
1898 for(i = 0 ; i < nb_trace ; i++) {
1899 tcs = (LttvTraceState *)self->parent.traces[i];
1900
2a2fa4f0 1901 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1902 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1903 LTTV_STATE_SAVED_STATES);
1904 min_pos = -1;
1905
1906 if(saved_states_tree) {
dd025f91 1907 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1908 mid_pos = max_pos / 2;
1909 while(min_pos < max_pos) {
1910 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1911 g_assert(type == LTTV_GOBJECT);
1912 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1913 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1914 &value);
1915 g_assert(type == LTTV_TIME);
1916 if(ltt_time_compare(*(value.v_time), t) < 0) {
1917 min_pos = mid_pos;
1918 closest_tree = saved_state_tree;
1919 }
1920 else max_pos = mid_pos - 1;
1921
1922 mid_pos = (min_pos + max_pos + 1) / 2;
1923 }
2a2fa4f0 1924 }
dd025f91 1925
2a2fa4f0 1926 /* restore the closest earlier saved state */
f95bc830 1927 if(min_pos != -1) {
1928 lttv_state_restore(tcs, closest_tree);
728d0c3e 1929 call_rest = 1;
f95bc830 1930 }
dd025f91 1931
2a2fa4f0 1932 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1933 else {
1934 restore_init_state(tcs);
1935 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1936 }
9444deae 1937 }
dd025f91 1938 /* We want to seek quickly without restoring/updating the state */
1939 else {
308711e5 1940 restore_init_state(tcs);
dd025f91 1941 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1942 }
308711e5 1943 }
728d0c3e 1944 if(!call_rest) g_info("NOT Calling restore");
308711e5 1945}
1946
1947
1948static void
1949traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1950{
1951}
1952
1953
1954static void
1955traceset_state_finalize (LttvTracesetState *self)
1956{
1957 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1958 finalize(G_OBJECT(self));
1959}
1960
1961
1962static void
1963traceset_state_class_init (LttvTracesetContextClass *klass)
1964{
1965 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1966
1967 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1968 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1969 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1970 klass->new_traceset_context = new_traceset_context;
1971 klass->new_trace_context = new_trace_context;
1972 klass->new_tracefile_context = new_tracefile_context;
1973}
1974
1975
1976GType
1977lttv_traceset_state_get_type(void)
1978{
1979 static GType type = 0;
1980 if (type == 0) {
1981 static const GTypeInfo info = {
1982 sizeof (LttvTracesetStateClass),
1983 NULL, /* base_init */
1984 NULL, /* base_finalize */
1985 (GClassInitFunc) traceset_state_class_init, /* class_init */
1986 NULL, /* class_finalize */
1987 NULL, /* class_data */
dbb7bb09 1988 sizeof (LttvTracesetState),
308711e5 1989 0, /* n_preallocs */
00e74b69 1990 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1991 NULL /* value handling */
308711e5 1992 };
1993
1994 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1995 &info, 0);
1996 }
1997 return type;
1998}
1999
2000
2001static void
2002trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2003{
2004}
2005
2006
2007static void
2008trace_state_finalize (LttvTraceState *self)
2009{
2010 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2011 finalize(G_OBJECT(self));
2012}
2013
2014
2015static void
2016trace_state_class_init (LttvTraceStateClass *klass)
2017{
2018 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2019
2020 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2021 klass->state_save = state_save;
2022 klass->state_restore = state_restore;
2023 klass->state_saved_free = state_saved_free;
2024}
2025
2026
2027GType
2028lttv_trace_state_get_type(void)
2029{
2030 static GType type = 0;
2031 if (type == 0) {
2032 static const GTypeInfo info = {
2033 sizeof (LttvTraceStateClass),
2034 NULL, /* base_init */
2035 NULL, /* base_finalize */
2036 (GClassInitFunc) trace_state_class_init, /* class_init */
2037 NULL, /* class_finalize */
2038 NULL, /* class_data */
2039 sizeof (LttvTraceState),
2040 0, /* n_preallocs */
00e74b69 2041 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2042 NULL /* value handling */
308711e5 2043 };
2044
2045 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2046 "LttvTraceStateType", &info, 0);
2047 }
2048 return type;
2049}
2050
2051
2052static void
2053tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2054{
2055}
2056
2057
2058static void
2059tracefile_state_finalize (LttvTracefileState *self)
2060{
2061 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2062 finalize(G_OBJECT(self));
2063}
2064
2065
2066static void
2067tracefile_state_class_init (LttvTracefileStateClass *klass)
2068{
2069 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2070
2071 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2072}
2073
2074
2075GType
2076lttv_tracefile_state_get_type(void)
2077{
2078 static GType type = 0;
2079 if (type == 0) {
2080 static const GTypeInfo info = {
2081 sizeof (LttvTracefileStateClass),
2082 NULL, /* base_init */
2083 NULL, /* base_finalize */
2084 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2085 NULL, /* class_finalize */
2086 NULL, /* class_data */
2087 sizeof (LttvTracefileState),
2088 0, /* n_preallocs */
00e74b69 2089 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2090 NULL /* value handling */
308711e5 2091 };
2092
2093 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2094 "LttvTracefileStateType", &info, 0);
2095 }
2096 return type;
2097}
2098
2099
08b1c66e 2100static void module_init()
ffd54a90 2101{
2102 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 2103 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 2104 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2105 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2106 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2107 LTTV_STATE_TRAP = g_quark_from_string("trap");
2108 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 2109 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2110 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 2111 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
dbd243b1 2112 LTTV_STATE_EXIT = g_quark_from_string("exiting");
0828099d 2113 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
ffd54a90 2114 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2115 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 2116 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2117 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2118 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 2119 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 2120 LTTV_STATE_EVENT = g_quark_from_string("event");
2121 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 2122 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 2123 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 2124 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 2125 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2126 LTTV_STATE_TRACE_STATE_USE_COUNT =
2127 g_quark_from_string("trace_state_use_count");
eed2ef37 2128
2129
2130 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2131 LTT_FACILITY_PROCESS = g_quark_from_string("process");
f4b88a7d 2132 LTT_FACILITY_FS = g_quark_from_string("fs");
eed2ef37 2133
2134
2135 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2136 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2137 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2138 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2139 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2140 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2141 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2142 LTT_EVENT_FORK = g_quark_from_string("fork");
2143 LTT_EVENT_EXIT = g_quark_from_string("exit");
2144 LTT_EVENT_FREE = g_quark_from_string("free");
f4b88a7d 2145 LTT_EVENT_EXEC = g_quark_from_string("exec");
eed2ef37 2146
2147
2148 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2149 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2150 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2151 LTT_FIELD_OUT = g_quark_from_string("out");
2152 LTT_FIELD_IN = g_quark_from_string("in");
2153 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2154 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2155 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2156 LTT_FIELD_PID = g_quark_from_string("pid");
f4b88a7d 2157 LTT_FIELD_FILENAME = g_quark_from_string("filename");
eed2ef37 2158
ffd54a90 2159}
dc877563 2160
08b1c66e 2161static void module_destroy()
ffd54a90 2162{
2163}
dc877563 2164
2165
08b1c66e 2166LTTV_MODULE("state", "State computation", \
2167 "Update the system state, possibly saving it at intervals", \
2168 module_init, module_destroy)
2169
dc877563 2170
2171
This page took 0.182679 seconds and 4 git commands to generate.