add missing Makefile.am in facilities
[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
d4942a23 1263 * in a SMP case where we don't have enough precision on the clocks.
1264 *
1265 * Test reenabled after precision fixes on time. (Mathieu) */
1266
348c6ba8 1267 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 1268
1d1df11d 1269 if(unlikely(zombie_process != NULL)) {
4ad73431 1270 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 1271 * has been released. FIXME : should know when release_task happens instead.
4ad73431 1272 */
15b3d537 1273 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1274 guint i;
1275 for(i=0; i< num_cpus; i++) {
5ac05980 1276 g_assert(zombie_process != ts->running_process[i]);
15b3d537 1277 }
1278
4ad73431 1279 exit_process(s, zombie_process);
1280 }
d4942a23 1281
348c6ba8 1282 g_assert(process->pid != child_pid);
eed2ef37 1283 // FIXME : Add this test in the "known state" section
348c6ba8 1284 // g_assert(process->pid == parent_pid);
26275aa2 1285 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
1286 if(child_process == NULL) {
1287 lttv_state_create_process(ts, process, cpu,
1288 child_pid, &s->parent.timestamp);
1289 } else {
1290 /* The process has already been created : due to time imprecision between
1291 * multiple CPUs : it has been scheduled in before creation.
1292 *
1293 * Simply put a correct parent.
1294 */
1295 child_process->ppid = process->pid;
1296 }
4ad73431 1297
dc877563 1298 return FALSE;
1299}
1300
1301
eed2ef37 1302static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1303{
eed2ef37 1304 LttvTracefileState *s = (LttvTracefileState *)call_data;
1305 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1306 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 1307 LttField *f;
1308 guint pid;
348c6ba8 1309 guint cpu = ltt_tracefile_num(s->parent.tf);
1310 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1311 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 1312
1313 pid = ltt_event_get_unsigned(e, thf->f1);
1314
1315 // FIXME : Add this test in the "known state" section
348c6ba8 1316 // g_assert(process->pid == pid);
eed2ef37 1317
348c6ba8 1318 if(likely(process != NULL)) {
1319 process->state->s = LTTV_STATE_EXIT;
2cdc690b 1320 }
1321 return FALSE;
2cdc690b 1322}
1323
eed2ef37 1324static gboolean process_free(void *hook_data, void *call_data)
2da61677 1325{
eed2ef37 1326 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 1327 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 1328 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 1329 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 1330 guint release_pid;
1331 LttvProcessState *process;
1332
1333 /* PID of the process to release */
eed2ef37 1334 release_pid = ltt_event_get_unsigned(e, thf->f1);
15b3d537 1335
1336 g_assert(release_pid != 0);
2da61677 1337
348c6ba8 1338 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 1339
1340 if(likely(process != NULL)) {
1341 /* release_task is happening at kernel level : we can now safely release
1342 * the data structure of the process */
5562ddce 1343 //This test is fun, though, as it may happen that
1344 //at time t : CPU 0 : process_free
1345 //at time t+150ns : CPU 1 : schedule out
1346 //Clearly due to time imprecision, we disable it. (Mathieu)
1347 //If this weird case happen, we have no choice but to put the
1348 //Currently running process on the cpu to 0.
0bd2f89c 1349 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1350 guint i;
1351 for(i=0; i< num_cpus; i++) {
5562ddce 1352 //g_assert(process != ts->running_process[i]);
1353 if(process == ts->running_process[i]) {
1354 ts->running_process[i] = lttv_state_find_process(ts, i, 0);
1355 }
0bd2f89c 1356 }
2da61677 1357 exit_process(s, process);
1358 }
1359
1360 return FALSE;
1361}
1362
f4b88a7d 1363
1364static gboolean process_exec(void *hook_data, void *call_data)
1365{
1366 LttvTracefileState *s = (LttvTracefileState *)call_data;
1367 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1368 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1369 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1370 gchar *name;
1371 guint cpu = ltt_tracefile_num(s->parent.tf);
1372 LttvProcessState *process = ts->running_process[cpu];
1373
1374 /* PID of the process to release */
1375 name = ltt_event_get_string(e, thf->f1);
1376
1377 process->name = g_quark_from_string(name);
1378
1379 return FALSE;
1380}
1381
1382
1383
1384
58c88a41 1385gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1386{
1387 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1388
1389 lttv_state_add_event_hooks(tss);
1390
1391 return 0;
1392}
dc877563 1393
308711e5 1394void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1395{
ba576a78 1396 LttvTraceset *traceset = self->parent.ts;
dc877563 1397
eed2ef37 1398 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1399
ba576a78 1400 LttvTraceState *ts;
dc877563 1401
ba576a78 1402 LttvTracefileState *tfs;
dc877563 1403
dc877563 1404 GArray *hooks;
1405
eed2ef37 1406 LttvTraceHookByFacility *thf;
1407
1408 LttvTraceHook *hook;
dc877563 1409
1410 LttvAttributeValue val;
1411
9d239bd9 1412 gint ret;
1413
ba576a78 1414 nb_trace = lttv_traceset_number(traceset);
dc877563 1415 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1416 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1417
1418 /* Find the eventtype id for the following events and register the
1419 associated by id hooks. */
1420
f4b88a7d 1421 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 11);
1422 hooks = g_array_set_size(hooks, 11);
b445142a 1423
9d239bd9 1424 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1425 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_ENTRY,
1426 LTT_FIELD_SYSCALL_ID, 0, 0,
2c82c4dc 1427 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, 0));
9d239bd9 1428 g_assert(!ret);
cbe7c836 1429
9d239bd9 1430 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1431 LTT_FACILITY_KERNEL, LTT_EVENT_SYSCALL_EXIT,
1432 0, 0, 0,
2c82c4dc 1433 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, 1));
9d239bd9 1434 g_assert(!ret);
cbe7c836 1435
9d239bd9 1436 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1437 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_ENTRY,
1438 LTT_FIELD_TRAP_ID, 0, 0,
2c82c4dc 1439 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, 2));
9d239bd9 1440 g_assert(!ret);
cbe7c836 1441
9d239bd9 1442 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1443 LTT_FACILITY_KERNEL, LTT_EVENT_TRAP_EXIT,
1444 0, 0, 0,
2c82c4dc 1445 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, 3));
9d239bd9 1446 g_assert(!ret);
cbe7c836 1447
9d239bd9 1448 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1449 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1450 LTT_FIELD_IRQ_ID, 0, 0,
2c82c4dc 1451 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, 4));
9d239bd9 1452 g_assert(!ret);
cbe7c836 1453
9d239bd9 1454 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1455 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
1456 0, 0, 0,
2c82c4dc 1457 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, 5));
9d239bd9 1458 g_assert(!ret);
cbe7c836 1459
9d239bd9 1460 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1461 LTT_FACILITY_PROCESS, LTT_EVENT_SCHEDCHANGE,
1462 LTT_FIELD_OUT, LTT_FIELD_IN, LTT_FIELD_OUT_STATE,
2c82c4dc 1463 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, 6));
9d239bd9 1464 g_assert(!ret);
cbe7c836 1465
9d239bd9 1466 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1467 LTT_FACILITY_PROCESS, LTT_EVENT_FORK,
1468 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, 0,
2c82c4dc 1469 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, 7));
9d239bd9 1470 g_assert(!ret);
eed2ef37 1471
9d239bd9 1472 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1473 LTT_FACILITY_PROCESS, LTT_EVENT_EXIT,
1474 LTT_FIELD_PID, 0, 0,
2c82c4dc 1475 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, 8));
9d239bd9 1476 g_assert(!ret);
eed2ef37 1477
9d239bd9 1478 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 1479 LTT_FACILITY_PROCESS, LTT_EVENT_FREE,
1480 LTT_FIELD_PID, 0, 0,
2c82c4dc 1481 process_free, NULL, &g_array_index(hooks, LttvTraceHook, 9));
9d239bd9 1482 g_assert(!ret);
2cdc690b 1483
f4b88a7d 1484 ret = lttv_trace_find_hook(ts->parent.t,
1485 LTT_FACILITY_FS, LTT_EVENT_EXEC,
1486 LTT_FIELD_FILENAME, 0, 0,
1487 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, 10));
1488 g_assert(!ret);
1489
1490
cbe7c836 1491
a5ba1787 1492 /* Add these hooks to each event_by_id hooks list */
dc877563 1493
eed2ef37 1494 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1495
dc877563 1496 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1497 tfs =
9d239bd9 1498 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1499 LttvTracefileContext*, j));
dc877563 1500
1501 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1502 hook = &g_array_index(hooks, LttvTraceHook, k);
1503 for(l=0;l<hook->fac_list->len;l++) {
1504 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1505 lttv_hooks_add(
1506 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1507 thf->h,
d052ffc3 1508 thf,
eed2ef37 1509 LTTV_PRIO_STATE);
1510 }
ffd54a90 1511 }
dc877563 1512 }
ba576a78 1513 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1514 *(val.v_pointer) = hooks;
dc877563 1515 }
1516}
1517
58c88a41 1518gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1519{
1520 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1521
1522 lttv_state_remove_event_hooks(tss);
1523
1524 return 0;
1525}
dc877563 1526
308711e5 1527void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1528{
ba576a78 1529 LttvTraceset *traceset = self->parent.ts;
dc877563 1530
eed2ef37 1531 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 1532
ba576a78 1533 LttvTraceState *ts;
dc877563 1534
ba576a78 1535 LttvTracefileState *tfs;
dc877563 1536
dc877563 1537 GArray *hooks;
1538
eed2ef37 1539 LttvTraceHook *hook;
1540
1541 LttvTraceHookByFacility *thf;
dc877563 1542
1543 LttvAttributeValue val;
1544
ba576a78 1545 nb_trace = lttv_traceset_number(traceset);
dc877563 1546 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 1547 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
ba576a78 1548 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1549 hooks = *(val.v_pointer);
dc877563 1550
a5ba1787 1551 /* Remove these hooks from each event_by_id hooks list */
dc877563 1552
eed2ef37 1553 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 1554
dc877563 1555 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1556 tfs =
cb03932a 1557 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1558 LttvTracefileContext*, j));
dc877563 1559
1560 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 1561 hook = &g_array_index(hooks, LttvTraceHook, k);
1562 for(l=0;l<hook->fac_list->len;l++) {
1563 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
1564
1565 lttv_hooks_remove_data(
1566 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
1567 thf->h,
d052ffc3 1568 thf);
eed2ef37 1569 }
ffd54a90 1570 }
dc877563 1571 }
1986f254 1572 for(k = 0 ; k < hooks->len ; k++)
1573 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 1574 g_array_free(hooks, TRUE);
1575 }
1576}
1577
eed2ef37 1578static gboolean state_save_event_hook(void *hook_data, void *call_data)
1579{
1580 guint *event_count = (guint*)hook_data;
1581
1582 /* Only save at LTTV_STATE_SAVE_INTERVAL */
1583 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
1584 return FALSE;
1585 else
18c87975 1586 *event_count = 0;
eed2ef37 1587
1588 LttvTracefileState *self = (LttvTracefileState *)call_data;
1589
1590 LttvTracefileState *tfcs;
1591
1592 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1593
1594 LttEventPosition *ep;
1595
1596 guint i;
1597
1598 LttTracefile *tf;
1599
1600 LttvAttribute *saved_states_tree, *saved_state_tree;
1601
1602 LttvAttributeValue value;
1603
1604 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1605 LTTV_STATE_SAVED_STATES);
1606 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1607 value = lttv_attribute_add(saved_states_tree,
1608 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1609 *(value.v_gobject) = (GObject *)saved_state_tree;
1610 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1611 *(value.v_time) = self->parent.timestamp;
1612 lttv_state_save(tcs, saved_state_tree);
1613 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1614 self->parent.timestamp.tv_nsec);
1615
1616 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1617
1618 return FALSE;
1619}
1620
14aecf75 1621static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
1622{
1623 LttvTraceState *tcs = (LttvTraceState *)(call_data);
1624
1625 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1626
1627 return FALSE;
1628}
1629
eed2ef37 1630#if 0
08b1c66e 1631static gboolean block_start(void *hook_data, void *call_data)
308711e5 1632{
dbb7bb09 1633 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1634
dbb7bb09 1635 LttvTracefileState *tfcs;
308711e5 1636
dbb7bb09 1637 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1638
1639 LttEventPosition *ep;
308711e5 1640
dbb7bb09 1641 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1642
1643 LttTracefile *tf;
1644
1645 LttvAttribute *saved_states_tree, *saved_state_tree;
1646
1647 LttvAttributeValue value;
1648
dbb7bb09 1649 ep = ltt_event_position_new();
eed2ef37 1650
1651 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 1652
1653 /* Count the number of events added since the last block end in any
1654 tracefile. */
1655
1656 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1657 tfcs =
1658 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
1659 LttvTracefileContext, i));
dbb7bb09 1660 ltt_event_position(tfcs->parent.e, ep);
1661 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1662 tcs->nb_event += nb_event - tfcs->saved_position;
1663 tfcs->saved_position = nb_event;
1664 }
1665 g_free(ep);
308711e5 1666
308711e5 1667 if(tcs->nb_event >= tcs->save_interval) {
1668 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1669 LTTV_STATE_SAVED_STATES);
1670 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1671 value = lttv_attribute_add(saved_states_tree,
1672 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1673 *(value.v_gobject) = (GObject *)saved_state_tree;
1674 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1675 *(value.v_time) = self->parent.timestamp;
308711e5 1676 lttv_state_save(tcs, saved_state_tree);
1677 tcs->nb_event = 0;
08b1c66e 1678 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1679 self->parent.timestamp.tv_nsec);
308711e5 1680 }
dbb7bb09 1681 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1682 return FALSE;
1683}
eed2ef37 1684#endif //0
308711e5 1685
eed2ef37 1686#if 0
08b1c66e 1687static gboolean block_end(void *hook_data, void *call_data)
1688{
1689 LttvTracefileState *self = (LttvTracefileState *)call_data;
1690
1691 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1692
1693 LttTracefile *tf;
1694
1695 LttEventPosition *ep;
1696
1697 guint nb_block, nb_event;
1698
1699 ep = ltt_event_position_new();
1700 ltt_event_position(self->parent.e, ep);
1701 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1702 tcs->nb_event += nb_event - self->saved_position + 1;
1703 self->saved_position = 0;
1704 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1705 g_free(ep);
00e74b69 1706
1707 return FALSE;
08b1c66e 1708}
eed2ef37 1709#endif //0
1710#if 0
308711e5 1711void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1712{
1713 LttvTraceset *traceset = self->parent.ts;
1714
00e74b69 1715 guint i, j, nb_trace, nb_tracefile;
308711e5 1716
1717 LttvTraceState *ts;
1718
1719 LttvTracefileState *tfs;
1720
08b1c66e 1721 LttvTraceHook hook_start, hook_end;
308711e5 1722
1723 nb_trace = lttv_traceset_number(traceset);
1724 for(i = 0 ; i < nb_trace ; i++) {
1725 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 1726
08b1c66e 1727 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1728 NULL, NULL, block_start, &hook_start);
308711e5 1729 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1730 NULL, NULL, block_end, &hook_end);
308711e5 1731
eed2ef37 1732 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1733
dbb7bb09 1734 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1735 tfs =
1736 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1737 LttvTracefileContext, j));
a5ba1787 1738 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1739 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 1740 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
eed2ef37 1741 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
1742 }
1743 }
1744}
1745#endif //0
1746
1747void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1748{
1749 LttvTraceset *traceset = self->parent.ts;
1750
1751 guint i, j, nb_trace, nb_tracefile;
1752
1753 LttvTraceState *ts;
1754
1755 LttvTracefileState *tfs;
1756
1757
1758 nb_trace = lttv_traceset_number(traceset);
1759 for(i = 0 ; i < nb_trace ; i++) {
1760
1761 ts = (LttvTraceState *)self->parent.traces[i];
1762 nb_tracefile = ts->parent.tracefiles->len;
1763
3054461a 1764 guint *event_count = g_new(guint, 1);
1765 *event_count = 0;
1766
eed2ef37 1767 for(j = 0 ; j < nb_tracefile ; j++) {
1768 tfs =
cb03932a 1769 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1770 LttvTracefileContext*, j));
eed2ef37 1771 lttv_hooks_add(tfs->parent.event,
1772 state_save_event_hook,
1773 event_count,
1774 LTTV_PRIO_STATE);
1775
308711e5 1776 }
1777 }
14aecf75 1778
1779 lttv_process_traceset_begin(&self->parent,
1780 NULL, NULL, NULL, NULL, NULL);
1781
308711e5 1782}
1783
b56b5fec 1784gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1785{
1786 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1787
1788 lttv_state_save_add_event_hooks(tss);
1789
1790 return 0;
1791}
1792
308711e5 1793
eed2ef37 1794#if 0
308711e5 1795void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1796{
1797 LttvTraceset *traceset = self->parent.ts;
1798
00e74b69 1799 guint i, j, nb_trace, nb_tracefile;
308711e5 1800
1801 LttvTraceState *ts;
1802
1803 LttvTracefileState *tfs;
1804
08b1c66e 1805 LttvTraceHook hook_start, hook_end;
308711e5 1806
1807 nb_trace = lttv_traceset_number(traceset);
1808 for(i = 0 ; i < nb_trace ; i++) {
1809 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 1810
08b1c66e 1811 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1812 NULL, NULL, block_start, &hook_start);
1813
308711e5 1814 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1815 NULL, NULL, block_end, &hook_end);
308711e5 1816
eed2ef37 1817 nb_tracefile = ts->parent.tracefiles->len;
308711e5 1818
dbb7bb09 1819 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 1820 tfs =
1821 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
1822 LttvTracefileContext, j));
308711e5 1823 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1824 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1825 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1826 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1827 }
1828 }
1829}
eed2ef37 1830#endif //0
1831
1832void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1833{
1834 LttvTraceset *traceset = self->parent.ts;
1835
1836 guint i, j, nb_trace, nb_tracefile;
1837
1838 LttvTraceState *ts;
1839
1840 LttvTracefileState *tfs;
1841
14aecf75 1842 LttvHooks *after_trace = lttv_hooks_new();
1843
1844 lttv_hooks_add(after_trace,
1845 state_save_after_trace_hook,
1846 NULL,
1847 LTTV_PRIO_STATE);
1848
1849
1850 lttv_process_traceset_end(&self->parent,
1851 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 1852
14aecf75 1853 lttv_hooks_destroy(after_trace);
1854
eed2ef37 1855 nb_trace = lttv_traceset_number(traceset);
1856 for(i = 0 ; i < nb_trace ; i++) {
1857
1858 ts = (LttvTraceState *)self->parent.traces[i];
1859 nb_tracefile = ts->parent.tracefiles->len;
1860
1861 guint *event_count;
1862
1863 for(j = 0 ; j < nb_tracefile ; j++) {
1864 tfs =
cb03932a 1865 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
1866 LttvTracefileContext*, j));
eed2ef37 1867 event_count = lttv_hooks_remove(tfs->parent.event,
1868 state_save_event_hook);
eed2ef37 1869 }
3054461a 1870 g_free(event_count);
eed2ef37 1871 }
1872}
308711e5 1873
b56b5fec 1874gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1875{
1876 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1877
1878 lttv_state_save_remove_event_hooks(tss);
1879
1880 return 0;
1881}
308711e5 1882
dd025f91 1883void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1884{
1885 LttvTraceset *traceset = self->parent.ts;
1886
00e74b69 1887 guint i, nb_trace;
308711e5 1888
1889 int min_pos, mid_pos, max_pos;
1890
728d0c3e 1891 guint call_rest = 0;
1892
308711e5 1893 LttvTraceState *tcs;
1894
1895 LttvAttributeValue value;
1896
1897 LttvAttributeType type;
1898
1899 LttvAttributeName name;
1900
1901 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1902
d448fce2 1903 //g_tree_destroy(self->parent.pqueue);
1904 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 1905
728d0c3e 1906 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
1907
308711e5 1908 nb_trace = lttv_traceset_number(traceset);
1909 for(i = 0 ; i < nb_trace ; i++) {
1910 tcs = (LttvTraceState *)self->parent.traces[i];
1911
2a2fa4f0 1912 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1913 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1914 LTTV_STATE_SAVED_STATES);
1915 min_pos = -1;
1916
1917 if(saved_states_tree) {
dd025f91 1918 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1919 mid_pos = max_pos / 2;
1920 while(min_pos < max_pos) {
1921 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1922 g_assert(type == LTTV_GOBJECT);
1923 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1924 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1925 &value);
1926 g_assert(type == LTTV_TIME);
1927 if(ltt_time_compare(*(value.v_time), t) < 0) {
1928 min_pos = mid_pos;
1929 closest_tree = saved_state_tree;
1930 }
1931 else max_pos = mid_pos - 1;
1932
1933 mid_pos = (min_pos + max_pos + 1) / 2;
1934 }
2a2fa4f0 1935 }
dd025f91 1936
2a2fa4f0 1937 /* restore the closest earlier saved state */
f95bc830 1938 if(min_pos != -1) {
1939 lttv_state_restore(tcs, closest_tree);
728d0c3e 1940 call_rest = 1;
f95bc830 1941 }
dd025f91 1942
2a2fa4f0 1943 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1944 else {
1945 restore_init_state(tcs);
1946 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1947 }
9444deae 1948 }
dd025f91 1949 /* We want to seek quickly without restoring/updating the state */
1950 else {
308711e5 1951 restore_init_state(tcs);
dd025f91 1952 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1953 }
308711e5 1954 }
728d0c3e 1955 if(!call_rest) g_info("NOT Calling restore");
308711e5 1956}
1957
1958
1959static void
1960traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1961{
1962}
1963
1964
1965static void
1966traceset_state_finalize (LttvTracesetState *self)
1967{
1968 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1969 finalize(G_OBJECT(self));
1970}
1971
1972
1973static void
1974traceset_state_class_init (LttvTracesetContextClass *klass)
1975{
1976 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1977
1978 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1979 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1980 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1981 klass->new_traceset_context = new_traceset_context;
1982 klass->new_trace_context = new_trace_context;
1983 klass->new_tracefile_context = new_tracefile_context;
1984}
1985
1986
1987GType
1988lttv_traceset_state_get_type(void)
1989{
1990 static GType type = 0;
1991 if (type == 0) {
1992 static const GTypeInfo info = {
1993 sizeof (LttvTracesetStateClass),
1994 NULL, /* base_init */
1995 NULL, /* base_finalize */
1996 (GClassInitFunc) traceset_state_class_init, /* class_init */
1997 NULL, /* class_finalize */
1998 NULL, /* class_data */
dbb7bb09 1999 sizeof (LttvTracesetState),
308711e5 2000 0, /* n_preallocs */
00e74b69 2001 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
2002 NULL /* value handling */
308711e5 2003 };
2004
2005 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
2006 &info, 0);
2007 }
2008 return type;
2009}
2010
2011
2012static void
2013trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
2014{
2015}
2016
2017
2018static void
2019trace_state_finalize (LttvTraceState *self)
2020{
2021 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
2022 finalize(G_OBJECT(self));
2023}
2024
2025
2026static void
2027trace_state_class_init (LttvTraceStateClass *klass)
2028{
2029 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2030
2031 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
2032 klass->state_save = state_save;
2033 klass->state_restore = state_restore;
2034 klass->state_saved_free = state_saved_free;
2035}
2036
2037
2038GType
2039lttv_trace_state_get_type(void)
2040{
2041 static GType type = 0;
2042 if (type == 0) {
2043 static const GTypeInfo info = {
2044 sizeof (LttvTraceStateClass),
2045 NULL, /* base_init */
2046 NULL, /* base_finalize */
2047 (GClassInitFunc) trace_state_class_init, /* class_init */
2048 NULL, /* class_finalize */
2049 NULL, /* class_data */
2050 sizeof (LttvTraceState),
2051 0, /* n_preallocs */
00e74b69 2052 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
2053 NULL /* value handling */
308711e5 2054 };
2055
2056 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
2057 "LttvTraceStateType", &info, 0);
2058 }
2059 return type;
2060}
2061
2062
2063static void
2064tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
2065{
2066}
2067
2068
2069static void
2070tracefile_state_finalize (LttvTracefileState *self)
2071{
2072 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
2073 finalize(G_OBJECT(self));
2074}
2075
2076
2077static void
2078tracefile_state_class_init (LttvTracefileStateClass *klass)
2079{
2080 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
2081
2082 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
2083}
2084
2085
2086GType
2087lttv_tracefile_state_get_type(void)
2088{
2089 static GType type = 0;
2090 if (type == 0) {
2091 static const GTypeInfo info = {
2092 sizeof (LttvTracefileStateClass),
2093 NULL, /* base_init */
2094 NULL, /* base_finalize */
2095 (GClassInitFunc) tracefile_state_class_init, /* class_init */
2096 NULL, /* class_finalize */
2097 NULL, /* class_data */
2098 sizeof (LttvTracefileState),
2099 0, /* n_preallocs */
00e74b69 2100 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
2101 NULL /* value handling */
308711e5 2102 };
2103
2104 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
2105 "LttvTracefileStateType", &info, 0);
2106 }
2107 return type;
2108}
2109
2110
08b1c66e 2111static void module_init()
ffd54a90 2112{
2113 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 2114 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 2115 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
2116 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
2117 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
2118 LTTV_STATE_TRAP = g_quark_from_string("trap");
2119 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 2120 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
2121 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 2122 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
dbd243b1 2123 LTTV_STATE_EXIT = g_quark_from_string("exiting");
0828099d 2124 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
ffd54a90 2125 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
2126 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 2127 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
2128 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
2129 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 2130 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 2131 LTTV_STATE_EVENT = g_quark_from_string("event");
2132 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 2133 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 2134 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 2135 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 2136 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
2137 LTTV_STATE_TRACE_STATE_USE_COUNT =
2138 g_quark_from_string("trace_state_use_count");
eed2ef37 2139
2140
2141 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
2142 LTT_FACILITY_PROCESS = g_quark_from_string("process");
f4b88a7d 2143 LTT_FACILITY_FS = g_quark_from_string("fs");
eed2ef37 2144
2145
2146 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
2147 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
2148 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
2149 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
2150 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
2151 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
2152 LTT_EVENT_SCHEDCHANGE = g_quark_from_string("schedchange");
2153 LTT_EVENT_FORK = g_quark_from_string("fork");
2154 LTT_EVENT_EXIT = g_quark_from_string("exit");
2155 LTT_EVENT_FREE = g_quark_from_string("free");
f4b88a7d 2156 LTT_EVENT_EXEC = g_quark_from_string("exec");
eed2ef37 2157
2158
2159 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
2160 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
2161 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
2162 LTT_FIELD_OUT = g_quark_from_string("out");
2163 LTT_FIELD_IN = g_quark_from_string("in");
2164 LTT_FIELD_OUT_STATE = g_quark_from_string("out_state");
2165 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
2166 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
2167 LTT_FIELD_PID = g_quark_from_string("pid");
f4b88a7d 2168 LTT_FIELD_FILENAME = g_quark_from_string("filename");
eed2ef37 2169
ffd54a90 2170}
dc877563 2171
08b1c66e 2172static void module_destroy()
ffd54a90 2173{
2174}
dc877563 2175
2176
08b1c66e 2177LTTV_MODULE("state", "State computation", \
2178 "Update the system state, possibly saving it at intervals", \
2179 module_init, module_destroy)
2180
dc877563 2181
2182
This page took 0.150144 seconds and 4 git commands to generate.