change window name
[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
dc877563 19
08b1c66e 20#include <lttv/lttv.h>
21#include <lttv/module.h>
dc877563 22#include <lttv/state.h>
ba576a78 23#include <ltt/facility.h>
24#include <ltt/trace.h>
308711e5 25#include <ltt/event.h>
a5dcde2f 26#include <ltt/type.h>
f95bc830 27#include <stdio.h>
dc877563 28
e8f2280c 29#define PREALLOCATED_EXECUTION_STACK 10
30
b445142a 31LttvExecutionMode
32 LTTV_STATE_MODE_UNKNOWN,
ffd54a90 33 LTTV_STATE_USER_MODE,
34 LTTV_STATE_SYSCALL,
35 LTTV_STATE_TRAP,
36 LTTV_STATE_IRQ;
37
b445142a 38LttvExecutionSubmode
39 LTTV_STATE_SUBMODE_UNKNOWN,
40 LTTV_STATE_SUBMODE_NONE;
ffd54a90 41
42LttvProcessStatus
43 LTTV_STATE_UNNAMED,
44 LTTV_STATE_WAIT_FORK,
45 LTTV_STATE_WAIT_CPU,
dbd243b1 46 LTTV_STATE_EXIT,
0828099d 47 LTTV_STATE_ZOMBIE,
ffd54a90 48 LTTV_STATE_WAIT,
49 LTTV_STATE_RUN;
50
ba576a78 51static GQuark
308711e5 52 LTTV_STATE_TRACEFILES,
53 LTTV_STATE_PROCESSES,
54 LTTV_STATE_PROCESS,
55 LTTV_STATE_EVENT,
56 LTTV_STATE_SAVED_STATES,
dbb7bb09 57 LTTV_STATE_SAVED_STATES_TIME,
308711e5 58 LTTV_STATE_TIME,
f95bc830 59 LTTV_STATE_HOOKS,
60 LTTV_STATE_NAME_TABLES,
61 LTTV_STATE_TRACE_STATE_USE_COUNT;
ba576a78 62
b445142a 63
f95bc830 64static void create_max_time(LttvTraceState *tcs);
65
66static void get_max_time(LttvTraceState *tcs);
67
68static void free_max_time(LttvTraceState *tcs);
69
70static void create_name_tables(LttvTraceState *tcs);
71
72static void get_name_tables(LttvTraceState *tcs);
b445142a 73
74static void free_name_tables(LttvTraceState *tcs);
75
f95bc830 76static void free_saved_state(LttvTraceState *tcs);
77
308711e5 78static void lttv_state_free_process_table(GHashTable *processes);
ba576a78 79
dc877563 80
308711e5 81void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
82{
83 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
84}
85
86
87void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
88{
89 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
90}
91
92
2d262115 93void lttv_state_state_saved_free(LttvTraceState *self,
308711e5 94 LttvAttribute *container)
95{
f95bc830 96 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
308711e5 97}
98
99
2a2fa4f0 100guint process_hash(gconstpointer key)
101{
7893f726 102 guint pid = ((const LttvProcessState *)key)->pid;
103 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
2a2fa4f0 104}
105
106
1d1df11d 107/* If the hash table hash function is well distributed,
108 * the process_equal should compare different pid */
2a2fa4f0 109gboolean process_equal(gconstpointer a, gconstpointer b)
110{
00e74b69 111 const LttvProcessState *process_a, *process_b;
1d1df11d 112 gboolean ret = TRUE;
113
00e74b69 114 process_a = (const LttvProcessState *)a;
115 process_b = (const LttvProcessState *)b;
1d1df11d 116
117 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
118 else if(likely(process_a->pid == 0 &&
119 process_a->last_cpu != process_b->last_cpu)) ret = FALSE;
2a2fa4f0 120
1d1df11d 121 return ret;
2a2fa4f0 122}
123
124
308711e5 125static void
126restore_init_state(LttvTraceState *self)
127{
dbb7bb09 128 guint i, nb_tracefile;
308711e5 129
130 LttvTracefileState *tfcs;
131
308711e5 132 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
2a2fa4f0 133 self->processes = g_hash_table_new(process_hash, process_equal);
308711e5 134 self->nb_event = 0;
135
dbb7bb09 136 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
137 ltt_trace_per_cpu_tracefile_number(self->parent.t);
308711e5 138
dbb7bb09 139 for(i = 0 ; i < nb_tracefile ; i++) {
140 tfcs = LTTV_TRACEFILE_STATE(self->parent.tracefiles[i]);
d3e01c7a 141 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
308711e5 142 tfcs->saved_position = 0;
2a2fa4f0 143 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
144 tfcs->process->state->s = LTTV_STATE_RUN;
145 tfcs->process->last_cpu = tfcs->cpu_name;
ac4e21cf 146 tfcs->process->last_cpu_index = ((LttvTracefileContext*)tfcs)->index;
308711e5 147 }
148}
149
2a2fa4f0 150static LttTime time_zero = {0,0};
308711e5 151
dc877563 152static void
153init(LttvTracesetState *self, LttvTraceset *ts)
154{
dbb7bb09 155 guint i, j, nb_trace, nb_tracefile;
dc877563 156
ffd54a90 157 LttvTraceContext *tc;
dc877563 158
ffd54a90 159 LttvTraceState *tcs;
160
ffd54a90 161 LttvTracefileState *tfcs;
3d27549e 162
dbb7bb09 163 LttvAttributeValue v;
164
b445142a 165 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
166 init((LttvTracesetContext *)self, ts);
dc877563 167
168 nb_trace = lttv_traceset_number(ts);
169 for(i = 0 ; i < nb_trace ; i++) {
b445142a 170 tc = self->parent.traces[i];
171 tcs = (LttvTraceState *)tc;
dbb7bb09 172 tcs->save_interval = 50000;
f95bc830 173 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
174 LTTV_UINT, &v);
175 (*v.v_uint)++;
dbb7bb09 176
f95bc830 177 if(*(v.v_uint) == 1) {
178 create_name_tables(tcs);
179 create_max_time(tcs);
180 }
181 get_name_tables(tcs);
182 get_max_time(tcs);
dc877563 183
dbb7bb09 184 nb_tracefile = ltt_trace_control_tracefile_number(tc->t) +
185 ltt_trace_per_cpu_tracefile_number(tc->t);
186
dc877563 187 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 188 tfcs = LTTV_TRACEFILE_STATE(tc->tracefiles[j]);
b445142a 189 tfcs->cpu_name= g_quark_from_string(ltt_tracefile_name(tfcs->parent.tf));
dc877563 190 }
308711e5 191 tcs->processes = NULL;
192 restore_init_state(tcs);
dc877563 193 }
194}
195
196
197static void
198fini(LttvTracesetState *self)
199{
00e74b69 200 guint i, nb_trace;
dc877563 201
ffd54a90 202 LttvTraceState *tcs;
dc877563 203
ffd54a90 204 LttvTracefileState *tfcs;
dc877563 205
f95bc830 206 LttvAttributeValue v;
207
ffd54a90 208 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
dc877563 209 for(i = 0 ; i < nb_trace ; i++) {
ffd54a90 210 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
f95bc830 211 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
212 LTTV_UINT, &v);
00e74b69 213
214 g_assert(*(v.v_uint) != 0);
f95bc830 215 (*v.v_uint)--;
216
f95bc830 217 if(*(v.v_uint) == 0) {
218 free_name_tables(tcs);
219 free_max_time(tcs);
220 free_saved_state(tcs);
221 }
308711e5 222 lttv_state_free_process_table(tcs->processes);
223 tcs->processes = NULL;
dc877563 224 }
b445142a 225 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
226 fini((LttvTracesetContext *)self);
dc877563 227}
228
229
c432246e 230static LttvTracesetContext *
dc877563 231new_traceset_context(LttvTracesetContext *self)
232{
ffd54a90 233 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
dc877563 234}
235
236
c432246e 237static LttvTraceContext *
dc877563 238new_trace_context(LttvTracesetContext *self)
239{
ffd54a90 240 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
dc877563 241}
242
243
c432246e 244static LttvTracefileContext *
dc877563 245new_tracefile_context(LttvTracesetContext *self)
246{
ffd54a90 247 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
248}
249
250
dbb7bb09 251/* Write the process state of the trace */
252
253static void write_process_state(gpointer key, gpointer value,
254 gpointer user_data)
255{
256 LttvProcessState *process;
257
258 LttvExecutionState *es;
259
260 FILE *fp = (FILE *)user_data;
261
262 guint i;
263
264 process = (LttvProcessState *)value;
265 fprintf(fp,
f95bc830 266" <PROCESS CORE=%p PID=%u PPID=%u CTIME_S=%lu CTIME_NS=%lu NAME=\"%s\" CPU=\"%s\">\n",
267 process, process->pid, process->ppid, process->creation_time.tv_sec,
dbb7bb09 268 process->creation_time.tv_nsec, g_quark_to_string(process->name),
269 g_quark_to_string(process->last_cpu));
270
271 for(i = 0 ; i < process->execution_stack->len; i++) {
272 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
273 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
274 g_quark_to_string(es->t), g_quark_to_string(es->n),
275 es->entry.tv_sec, es->entry.tv_nsec);
276 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
277 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
278 }
279 fprintf(fp, " </PROCESS>\n");
280}
281
282
283void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
284{
285 guint i, nb_tracefile, nb_block, nb_event;
286
287 LttvTracefileState *tfcs;
288
289 LttTracefile *tf;
290
291 LttEventPosition *ep;
292
293 ep = ltt_event_position_new();
294
295 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
296
297 g_hash_table_foreach(self->processes, write_process_state, fp);
298
299 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
300 ltt_trace_per_cpu_tracefile_number(self->parent.t);
301
302 for(i = 0 ; i < nb_tracefile ; i++) {
303 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
08b1c66e 304 fprintf(fp, " <TRACEFILE PID=%u TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
305 tfcs->process->pid, tfcs->parent.timestamp.tv_sec,
306 tfcs->parent.timestamp.tv_nsec);
dbb7bb09 307 if(tfcs->parent.e == NULL) fprintf(fp,"/>\n");
308 else {
309 ltt_event_position(tfcs->parent.e, ep);
310 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
311 fprintf(fp, " BLOCK=%u EVENT=%u/>\n", nb_block, nb_event);
312 }
313 }
314 g_free(ep);
315 fprintf(fp,"</PROCESS_STATE>");
316}
317
318
319/* Copy each process from an existing hash table to a new one */
320
308711e5 321static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
ffd54a90 322{
308711e5 323 LttvProcessState *process, *new_process;
ffd54a90 324
308711e5 325 GHashTable *new_processes = (GHashTable *)user_data;
ffd54a90 326
308711e5 327 guint i;
328
329 process = (LttvProcessState *)value;
330 new_process = g_new(LttvProcessState, 1);
331 *new_process = *process;
e8f2280c 332 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
333 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
308711e5 334 g_array_set_size(new_process->execution_stack,process->execution_stack->len);
335 for(i = 0 ; i < process->execution_stack->len; i++) {
336 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
337 g_array_index(process->execution_stack, LttvExecutionState, i);
338 }
339 new_process->state = &g_array_index(new_process->execution_stack,
340 LttvExecutionState, new_process->execution_stack->len - 1);
2a2fa4f0 341 g_hash_table_insert(new_processes, new_process, new_process);
ffd54a90 342}
343
344
308711e5 345static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
ffd54a90 346{
2a2fa4f0 347 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
ffd54a90 348
308711e5 349 g_hash_table_foreach(processes, copy_process_state, new_processes);
350 return new_processes;
dc877563 351}
352
353
308711e5 354/* The saved state for each trace contains a member "processes", which
355 stores a copy of the process table, and a member "tracefiles" with
356 one entry per tracefile. Each tracefile has a "process" member pointing
357 to the current process and a "position" member storing the tracefile
358 position (needed to seek to the current "next" event. */
359
360static void state_save(LttvTraceState *self, LttvAttribute *container)
dc877563 361{
dbb7bb09 362 guint i, nb_tracefile;
dc877563 363
308711e5 364 LttvTracefileState *tfcs;
365
366 LttvAttribute *tracefiles_tree, *tracefile_tree;
367
368 LttvAttributeType type;
369
370 LttvAttributeValue value;
371
372 LttvAttributeName name;
373
374 LttEventPosition *ep;
375
376 tracefiles_tree = lttv_attribute_find_subdir(container,
377 LTTV_STATE_TRACEFILES);
378
379 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
380 LTTV_POINTER);
381 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
382
dbb7bb09 383 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
384 ltt_trace_per_cpu_tracefile_number(self->parent.t);
308711e5 385
386 for(i = 0 ; i < nb_tracefile ; i++) {
dbb7bb09 387 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
308711e5 388 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
389 value = lttv_attribute_add(tracefiles_tree, i,
390 LTTV_GOBJECT);
391 *(value.v_gobject) = (GObject *)tracefile_tree;
392 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
393 LTTV_UINT);
394 *(value.v_uint) = tfcs->process->pid;
395 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
396 LTTV_POINTER);
397 if(tfcs->parent.e == NULL) *(value.v_pointer) = NULL;
398 else {
a5dcde2f 399 ep = ltt_event_position_new();
308711e5 400 ltt_event_position(tfcs->parent.e, ep);
401 *(value.v_pointer) = ep;
08b1c66e 402
403 guint nb_block, nb_event;
404 LttTracefile *tf;
405 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
406 g_debug("Block %u event %u time %lu.%lu", nb_block, nb_event,
407 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
308711e5 408 }
dc877563 409 }
dc877563 410}
411
412
308711e5 413static void state_restore(LttvTraceState *self, LttvAttribute *container)
dc877563 414{
dbb7bb09 415 guint i, nb_tracefile, pid;
dc877563 416
308711e5 417 LttvTracefileState *tfcs;
dc877563 418
308711e5 419 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 420
308711e5 421 LttvAttributeType type;
dc877563 422
308711e5 423 LttvAttributeValue value;
dc877563 424
308711e5 425 LttvAttributeName name;
dc877563 426
308711e5 427 LttEventPosition *ep;
dc877563 428
308711e5 429 tracefiles_tree = lttv_attribute_find_subdir(container,
430 LTTV_STATE_TRACEFILES);
dc877563 431
308711e5 432 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
433 &value);
434 g_assert(type == LTTV_POINTER);
435 lttv_state_free_process_table(self->processes);
436 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
437
dbb7bb09 438 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
439 ltt_trace_per_cpu_tracefile_number(self->parent.t);
308711e5 440
441 for(i = 0 ; i < nb_tracefile ; i++) {
dbb7bb09 442 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
308711e5 443 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
444 g_assert(type == LTTV_GOBJECT);
445 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
446
447 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
448 &value);
449 g_assert(type == LTTV_UINT);
2a2fa4f0 450 pid = *(value.v_uint);
451 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
452
308711e5 453 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
454 &value);
455 g_assert(type == LTTV_POINTER);
456 if(*(value.v_pointer) == NULL) tfcs->parent.e = NULL;
457 else {
458 ep = *(value.v_pointer);
b56b5fec 459 g_assert(tfcs->parent.t_context != NULL);
460 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep);
308711e5 461 }
dc877563 462 }
dc877563 463}
464
465
308711e5 466static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 467{
dbb7bb09 468 guint i, nb_tracefile;
dc877563 469
308711e5 470 LttvTracefileState *tfcs;
dc877563 471
308711e5 472 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 473
308711e5 474 LttvAttributeType type;
dc877563 475
308711e5 476 LttvAttributeValue value;
dc877563 477
308711e5 478 LttvAttributeName name;
dc877563 479
308711e5 480 LttEventPosition *ep;
dc877563 481
308711e5 482 tracefiles_tree = lttv_attribute_find_subdir(container,
483 LTTV_STATE_TRACEFILES);
c47a6dc6 484 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 485 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 486
308711e5 487 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
488 &value);
489 g_assert(type == LTTV_POINTER);
490 lttv_state_free_process_table(*(value.v_pointer));
491 *(value.v_pointer) = NULL;
492 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
493
dbb7bb09 494 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
495 ltt_trace_per_cpu_tracefile_number(self->parent.t);
308711e5 496
497 for(i = 0 ; i < nb_tracefile ; i++) {
dbb7bb09 498 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
308711e5 499 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
500 g_assert(type == LTTV_GOBJECT);
501 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
502
503 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
504 &value);
505 g_assert(type == LTTV_POINTER);
506 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 507 }
c47a6dc6 508 g_object_unref(G_OBJECT(tracefiles_tree));
dc877563 509}
510
511
f95bc830 512static void free_saved_state(LttvTraceState *self)
513{
514 guint i, nb;
515
516 LttvAttributeType type;
517
518 LttvAttributeValue value;
519
520 LttvAttributeName name;
521
522 LttvAttribute *saved_states;
523
524 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
525 LTTV_STATE_SAVED_STATES);
526
527 nb = lttv_attribute_get_number(saved_states);
528 for(i = 0 ; i < nb ; i++) {
529 type = lttv_attribute_get(saved_states, i, &name, &value);
530 g_assert(type == LTTV_GOBJECT);
531 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
532 }
533
534 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
f95bc830 535}
536
537
538static void
539create_max_time(LttvTraceState *tcs)
540{
541 LttvAttributeValue v;
542
543 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
544 LTTV_POINTER, &v);
545 g_assert(*(v.v_pointer) == NULL);
546 *(v.v_pointer) = g_new(LttTime,1);
547 *((LttTime *)*(v.v_pointer)) = time_zero;
548}
549
550
551static void
552get_max_time(LttvTraceState *tcs)
553{
554 LttvAttributeValue v;
555
556 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
557 LTTV_POINTER, &v);
558 g_assert(*(v.v_pointer) != NULL);
559 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
560}
561
562
563static void
564free_max_time(LttvTraceState *tcs)
565{
566 LttvAttributeValue v;
567
568 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
569 LTTV_POINTER, &v);
570 g_free(*(v.v_pointer));
571 *(v.v_pointer) = NULL;
572}
573
574
575typedef struct _LttvNameTables {
576 GQuark *eventtype_names;
577 GQuark *syscall_names;
578 GQuark *trap_names;
579 GQuark *irq_names;
580} LttvNameTables;
581
582
b445142a 583static void
f95bc830 584create_name_tables(LttvTraceState *tcs)
b445142a 585{
586 int i, nb;
dc877563 587
b445142a 588 char *f_name, *e_name;
dc877563 589
b445142a 590 LttvTraceHook h;
591
592 LttEventType *et;
593
594 LttType *t;
595
596 GString *fe_name = g_string_new("");
597
f95bc830 598 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
599
600 LttvAttributeValue v;
601
602 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
603 LTTV_POINTER, &v);
604 g_assert(*(v.v_pointer) == NULL);
605 *(v.v_pointer) = name_tables;
606
b445142a 607 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 608 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 609 for(i = 0 ; i < nb ; i++) {
610 et = ltt_trace_eventtype_get(tcs->parent.t, i);
611 e_name = ltt_eventtype_name(et);
612 f_name = ltt_facility_name(ltt_eventtype_facility(et));
613 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 614 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 615 }
dc877563 616
b445142a 617 lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry",
618 "syscall_id", NULL, NULL, NULL, &h);
619 t = ltt_field_type(h.f1);
620 nb = ltt_type_element_number(t);
621
622 /* CHECK syscalls should be an emun but currently are not!
f95bc830 623 name_tables->syscall_names = g_new(GQuark, nb);
b445142a 624
625 for(i = 0 ; i < nb ; i++) {
f95bc830 626 name_tables->syscall_names[i] = g_quark_from_string(
627 ltt_enum_string_get(t, i));
b445142a 628 }
629 */
630
f95bc830 631 name_tables->syscall_names = g_new(GQuark, 256);
b445142a 632 for(i = 0 ; i < 256 ; i++) {
633 g_string_printf(fe_name, "syscall %d", i);
f95bc830 634 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
b445142a 635 }
636
637 lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry",
638 "trap_id", NULL, NULL, NULL, &h);
639 t = ltt_field_type(h.f1);
640 nb = ltt_type_element_number(t);
641
642 /*
f95bc830 643 name_tables->trap_names = g_new(GQuark, nb);
b445142a 644 for(i = 0 ; i < nb ; i++) {
f95bc830 645 name_tables->trap_names[i] = g_quark_from_string(
646 ltt_enum_string_get(t, i));
b445142a 647 }
648 */
649
f95bc830 650 name_tables->trap_names = g_new(GQuark, 256);
b445142a 651 for(i = 0 ; i < 256 ; i++) {
652 g_string_printf(fe_name, "trap %d", i);
f95bc830 653 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
b445142a 654 }
655
656 lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry",
657 "irq_id", NULL, NULL, NULL, &h);
658 t = ltt_field_type(h.f1);
659 nb = ltt_type_element_number(t);
660
661 /*
f95bc830 662 name_tables->irq_names = g_new(GQuark, nb);
b445142a 663 for(i = 0 ; i < nb ; i++) {
f95bc830 664 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
b445142a 665 }
666 */
667
f95bc830 668 name_tables->irq_names = g_new(GQuark, 256);
b445142a 669 for(i = 0 ; i < 256 ; i++) {
670 g_string_printf(fe_name, "irq %d", i);
f95bc830 671 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
b445142a 672 }
673
674 g_string_free(fe_name, TRUE);
675}
676
677
f95bc830 678static void
679get_name_tables(LttvTraceState *tcs)
680{
681 LttvNameTables *name_tables;
682
683 LttvAttributeValue v;
684
685 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
686 LTTV_POINTER, &v);
687 g_assert(*(v.v_pointer) != NULL);
688 name_tables = (LttvNameTables *)*(v.v_pointer);
689 tcs->eventtype_names = name_tables->eventtype_names;
690 tcs->syscall_names = name_tables->syscall_names;
691 tcs->trap_names = name_tables->trap_names;
692 tcs->irq_names = name_tables->irq_names;
693}
694
695
b445142a 696static void
697free_name_tables(LttvTraceState *tcs)
698{
f95bc830 699 LttvNameTables *name_tables;
700
701 LttvAttributeValue v;
702
703 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
704 LTTV_POINTER, &v);
705 name_tables = (LttvNameTables *)*(v.v_pointer);
706 *(v.v_pointer) = NULL;
707
708 g_free(name_tables->eventtype_names);
709 g_free(name_tables->syscall_names);
710 g_free(name_tables->trap_names);
711 g_free(name_tables->irq_names);
712 g_free(name_tables);
b445142a 713}
dc877563 714
b445142a 715
716static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 717 guint state_id)
dc877563 718{
b445142a 719 LttvExecutionState *es;
dc877563 720
721 LttvProcessState *process = tfs->process;
722
b445142a 723 guint depth = process->execution_stack->len;
dc877563 724
b445142a 725 g_array_set_size(process->execution_stack, depth + 1);
726 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
727 es->t = t;
728 es->n = state_id;
729 es->entry = es->change = tfs->parent.timestamp;
730 es->s = process->state->s;
731 process->state = es;
dc877563 732}
733
734
b445142a 735static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 736{
737 LttvProcessState *process = tfs->process;
738
f95bc830 739 guint depth = process->execution_stack->len;
dc877563 740
3d27549e 741 if(process->state->t != t){
00e74b69 742 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 743 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 744 g_info("process state has %s when pop_int is %s\n",
8e8e6b64 745 g_quark_to_string(process->state->t),
746 g_quark_to_string(t));
08b1c66e 747 g_info("{ %u, %u, %s, %s }\n",
8e8e6b64 748 process->pid,
749 process->ppid,
750 g_quark_to_string(process->name),
751 g_quark_to_string(process->state->s));
3d27549e 752 return;
753 }
b445142a 754
f95bc830 755 if(depth == 1){
00e74b69 756 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 757 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
758 return;
759 }
760
f95bc830 761 g_array_set_size(process->execution_stack, depth - 1);
b445142a 762 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 763 depth - 2);
b445142a 764 process->state->change = tfs->parent.timestamp;
dc877563 765}
766
767
2a2fa4f0 768LttvProcessState *
769lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
770 guint pid)
dc877563 771{
772 LttvProcessState *process = g_new(LttvProcessState, 1);
773
b445142a 774 LttvExecutionState *es;
dc877563 775
ffd54a90 776 LttvTraceContext *tc;
777
ba576a78 778 LttvTraceState *tcs;
779
b445142a 780 char buffer[128];
ffd54a90 781
a5ba1787 782 tc = tfs->parent.t_context;
783 tcs = (LttvTraceState *)tc;
60b53e4f 784
dc877563 785 process->pid = pid;
2a2fa4f0 786 process->last_cpu = tfs->cpu_name;
ac4e21cf 787 process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
f95bc830 788 g_warning("Process %u, core %p", process->pid, process);
2a2fa4f0 789 g_hash_table_insert(tcs->processes, process, process);
b445142a 790
791 if(parent) {
792 process->ppid = parent->pid;
793 process->name = parent->name;
2a2fa4f0 794 process->creation_time = tfs->parent.timestamp;
b445142a 795 }
2a2fa4f0 796
797 /* No parent. This process exists but we are missing all information about
798 its creation. The birth time is set to zero but we remember the time of
799 insertion */
800
b445142a 801 else {
802 process->ppid = 0;
803 process->name = LTTV_STATE_UNNAMED;
2a2fa4f0 804 process->creation_time = ltt_time_zero;
b445142a 805 }
806
2a2fa4f0 807 process->insertion_time = tfs->parent.timestamp;
b445142a 808 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
809 process->creation_time.tv_nsec);
810 process->pid_time = g_quark_from_string(buffer);
2a2fa4f0 811 process->last_cpu = tfs->cpu_name;
ac4e21cf 812 process->last_cpu_index = ((LttvTracefileContext*)tfs)->index;
e8f2280c 813 process->execution_stack = g_array_sized_new(FALSE, FALSE,
814 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
b445142a 815 g_array_set_size(process->execution_stack, 1);
816 es = process->state = &g_array_index(process->execution_stack,
817 LttvExecutionState, 0);
818 es->t = LTTV_STATE_USER_MODE;
819 es->n = LTTV_STATE_SUBMODE_NONE;
820 es->entry = tfs->parent.timestamp;
d3e01c7a 821 g_assert(tfs->parent.timestamp.tv_sec != 0);
b445142a 822 es->change = tfs->parent.timestamp;
823 es->s = LTTV_STATE_WAIT_FORK;
cbe7c836 824
825 return process;
dc877563 826}
827
41c7f803 828LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
829 guint pid)
dc877563 830{
2a2fa4f0 831 LttvProcessState key;
832 LttvProcessState *process;
833
41c7f803 834 LttvTraceState* ts = (LttvTraceState*)tfs->parent.t_context;
835
2a2fa4f0 836 key.pid = pid;
41c7f803 837 key.last_cpu = tfs->cpu_name;
2a2fa4f0 838 process = g_hash_table_lookup(ts->processes, &key);
dc877563 839 return process;
840}
841
2a2fa4f0 842LttvProcessState *
843lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
844{
845 LttvProcessState *process = lttv_state_find_process(tfs, pid);
846
1d1df11d 847 if(unlikely(process == NULL)) process = lttv_state_create_process(tfs, NULL, pid);
2a2fa4f0 848 return process;
849}
850
41c7f803 851/* FIXME : this function should be called when we receive an event telling that
852 * release_task has been called in the kernel. In happens generally when
853 * the parent waits for its child terminaison, but may also happen in special
854 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
855 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
856 * of a killed thread ground, but isn't the leader.
41c7f803 857 */
b445142a 858static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 859{
ba576a78 860 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 861 LttvProcessState key;
ba576a78 862
2a2fa4f0 863 key.pid = process->pid;
864 key.last_cpu = process->last_cpu;
865 g_hash_table_remove(ts->processes, &key);
b445142a 866 g_array_free(process->execution_stack, TRUE);
dc877563 867 g_free(process);
868}
869
870
b445142a 871static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 872{
b445142a 873 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 874 g_free(value);
875}
876
877
308711e5 878static void lttv_state_free_process_table(GHashTable *processes)
dc877563 879{
880 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 881 g_hash_table_destroy(processes);
dc877563 882}
883
884
b445142a 885static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 886{
b445142a 887 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 888
ba576a78 889 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 890
b445142a 891 LttvExecutionSubmode submode;
892
893 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
894 ltt_event_get_unsigned(s->parent.e, f)];
895 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 896 return FALSE;
897}
898
899
b445142a 900static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 901{
ba576a78 902 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 903
ffd54a90 904 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 905 return FALSE;
906}
907
908
b445142a 909static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 910{
b445142a 911 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 912
ba576a78 913 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 914
b445142a 915 LttvExecutionSubmode submode;
916
917 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
918 ltt_event_get_unsigned(s->parent.e, f)];
919 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 920 return FALSE;
921}
922
923
b445142a 924static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 925{
ba576a78 926 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 927
ffd54a90 928 pop_state(s, LTTV_STATE_TRAP);
dc877563 929 return FALSE;
930}
931
932
b445142a 933static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 934{
b445142a 935 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 936
ba576a78 937 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 938
b445142a 939 LttvExecutionSubmode submode;
940
941 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
942 ltt_event_get_unsigned(s->parent.e, f)];
943
dc877563 944 /* Do something with the info about being in user or system mode when int? */
b445142a 945 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 946 return FALSE;
947}
948
949
b445142a 950static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 951{
ba576a78 952 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 953
ffd54a90 954 pop_state(s, LTTV_STATE_IRQ);
dc877563 955 return FALSE;
956}
957
958
b445142a 959static gboolean schedchange(void *hook_data, void *call_data)
dc877563 960{
b445142a 961 LttvTraceHook *h = (LttvTraceHook *)hook_data;
dc877563 962
ba576a78 963 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 964
965 guint pid_in, pid_out, state_out;
966
3d27549e 967 pid_in = ltt_event_get_unsigned(s->parent.e, h->f1);
968 pid_out = ltt_event_get_unsigned(s->parent.e, h->f2);
969 state_out = ltt_event_get_unsigned(s->parent.e, h->f3);
b445142a 970
1d1df11d 971 if(likely(s->process != NULL)) {
b445142a 972
f95bc830 973 /* We could not know but it was not the idle process executing.
974 This should only happen at the beginning, before the first schedule
975 event, and when the initial information (current process for each CPU)
976 is missing. It is not obvious how we could, after the fact, compensate
977 the wrongly attributed statistics. */
978
1d1df11d 979 if(unlikely(s->process->pid != pid_out)) {
f95bc830 980 g_assert(s->process->pid == 0);
981 }
982
1d1df11d 983 if(unlikely(s->process->state->s == LTTV_STATE_EXIT)) {
dbd243b1 984 s->process->state->s = LTTV_STATE_ZOMBIE;
985 } else {
1d1df11d 986 if(unlikely(state_out == 0)) s->process->state->s = LTTV_STATE_WAIT_CPU;
41c7f803 987 else s->process->state->s = LTTV_STATE_WAIT;
988 } /* FIXME : we do not remove process here, because the kernel
989 * still has them : they may be zombies. We need to know
990 * exactly when release_task is executed on the PID to
0828099d 991 * know when the zombie is destroyed.
41c7f803 992 */
993 //else
994 // exit_process(s, s->process);
3d27549e 995
b445142a 996 s->process->state->change = s->parent.timestamp;
dc877563 997 }
2a2fa4f0 998 s->process = lttv_state_find_process_or_create(s, pid_in);
ffd54a90 999 s->process->state->s = LTTV_STATE_RUN;
2a2fa4f0 1000 s->process->last_cpu = s->cpu_name;
ac4e21cf 1001 s->process->last_cpu_index = ((LttvTracefileContext*)s)->index;
b445142a 1002 s->process->state->change = s->parent.timestamp;
dc877563 1003 return FALSE;
1004}
1005
1006
2cdc690b 1007static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 1008{
2cdc690b 1009 LttField *f;
1010 guint child_pid;
4ad73431 1011 LttvProcessState *zombie_process;
2cdc690b 1012
1013 /* Child PID */
34871cd8 1014 f = trace_hook->f2;
2cdc690b 1015 child_pid = ltt_event_get_unsigned(s->parent.e, f);
1016
4ad73431 1017 zombie_process = lttv_state_find_process(s, child_pid);
dc877563 1018
1d1df11d 1019 if(unlikely(zombie_process != NULL)) {
4ad73431 1020 /* Reutilisation of PID. Only now we are sure that the old PID
1021 * has been released. FIXME : sould know when release_task happens instead.
1022 */
1023 exit_process(s, zombie_process);
1024 }
dbd243b1 1025 g_assert(s->process->pid != child_pid);
2a2fa4f0 1026 lttv_state_create_process(s, s->process, child_pid);
4ad73431 1027
dc877563 1028 return FALSE;
1029}
1030
1031
2cdc690b 1032static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 1033{
1d1df11d 1034 if(likely(s->process != NULL)) {
dbd243b1 1035 s->process->state->s = LTTV_STATE_EXIT;
2cdc690b 1036 }
1037 return FALSE;
2cdc690b 1038}
1039
1040gboolean process(void *hook_data, void *call_data)
1041{
1042 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1043 LttField *f = trace_hook->f1;
1044
1045 LttvTracefileState *s = (LttvTracefileState *)call_data;
1046
1047 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1048
1049 /* CHECK : do not hardcode the sub_id values here ? */
1050 if(sub_id == 2) {
1051 return process_fork(trace_hook, s);
1052 } else if(sub_id == 3) {
1053 return process_exit(trace_hook, s);
1054 }
1055 return 0;
dc877563 1056}
1057
58c88a41 1058gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1059{
1060 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1061
1062 lttv_state_add_event_hooks(tss);
1063
1064 return 0;
1065}
dc877563 1066
308711e5 1067void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1068{
ba576a78 1069 LttvTraceset *traceset = self->parent.ts;
dc877563 1070
dbb7bb09 1071 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1072
ba576a78 1073 LttvTraceState *ts;
dc877563 1074
ba576a78 1075 LttvTracefileState *tfs;
dc877563 1076
dc877563 1077 GArray *hooks;
1078
b445142a 1079 LttvTraceHook hook;
dc877563 1080
1081 LttvAttributeValue val;
1082
ba576a78 1083 nb_trace = lttv_traceset_number(traceset);
dc877563 1084 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1085 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1086
1087 /* Find the eventtype id for the following events and register the
1088 associated by id hooks. */
1089
b445142a 1090 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
facab7c2 1091 g_array_set_size(hooks, 8);
b445142a 1092
1093 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1094 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
cbe7c836 1095
b445142a 1096 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1097 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
cbe7c836 1098
b445142a 1099 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1100 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
cbe7c836 1101
b445142a 1102 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1103 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
cbe7c836 1104
b445142a 1105 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1106 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
cbe7c836 1107
b445142a 1108 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1109 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
cbe7c836 1110
b445142a 1111 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1112 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
cbe7c836 1113
2cdc690b 1114 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1115 "event_data1", "event_data2", process,
1116 &g_array_index(hooks, LttvTraceHook, 7));
1117
1118#if 0
b445142a 1119 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1120 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
cbe7c836 1121
b445142a 1122 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1123 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
2cdc690b 1124#endif //0
a5ba1787 1125 /* Add these hooks to each event_by_id hooks list */
dc877563 1126
dbb7bb09 1127 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1128 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1129
dc877563 1130 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1131 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1132
1133 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1134 hook = g_array_index(hooks, LttvTraceHook, k);
a5ba1787 1135 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1136 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
ffd54a90 1137 }
dc877563 1138 }
ba576a78 1139 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1140 *(val.v_pointer) = hooks;
dc877563 1141 }
1142}
1143
58c88a41 1144gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1145{
1146 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1147
1148 lttv_state_remove_event_hooks(tss);
1149
1150 return 0;
1151}
dc877563 1152
308711e5 1153void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1154{
ba576a78 1155 LttvTraceset *traceset = self->parent.ts;
dc877563 1156
dbb7bb09 1157 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1158
ba576a78 1159 LttvTraceState *ts;
dc877563 1160
ba576a78 1161 LttvTracefileState *tfs;
dc877563 1162
dc877563 1163 GArray *hooks;
1164
b445142a 1165 LttvTraceHook hook;
dc877563 1166
1167 LttvAttributeValue val;
1168
ba576a78 1169 nb_trace = lttv_traceset_number(traceset);
dc877563 1170 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1171 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1172 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1173 hooks = *(val.v_pointer);
dc877563 1174
a5ba1787 1175 /* Remove these hooks from each event_by_id hooks list */
dc877563 1176
dbb7bb09 1177 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1178 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1179
dc877563 1180 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1181 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1182
1183 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1184 hook = g_array_index(hooks, LttvTraceHook, k);
ba576a78 1185 lttv_hooks_remove_data(
a5ba1787 1186 lttv_hooks_by_id_find(tfs->parent.event_by_id,
b445142a 1187 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1188 }
dc877563 1189 }
1190 g_array_free(hooks, TRUE);
1191 }
1192}
1193
1194
08b1c66e 1195static gboolean block_start(void *hook_data, void *call_data)
308711e5 1196{
dbb7bb09 1197 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1198
dbb7bb09 1199 LttvTracefileState *tfcs;
308711e5 1200
dbb7bb09 1201 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1202
1203 LttEventPosition *ep;
308711e5 1204
dbb7bb09 1205 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1206
1207 LttTracefile *tf;
1208
1209 LttvAttribute *saved_states_tree, *saved_state_tree;
1210
1211 LttvAttributeValue value;
1212
dbb7bb09 1213 ep = ltt_event_position_new();
1214 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1215 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1216
1217 /* Count the number of events added since the last block end in any
1218 tracefile. */
1219
1220 for(i = 0 ; i < nb_tracefile ; i++) {
1221 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1222 ltt_event_position(tfcs->parent.e, ep);
1223 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1224 tcs->nb_event += nb_event - tfcs->saved_position;
1225 tfcs->saved_position = nb_event;
1226 }
1227 g_free(ep);
308711e5 1228
308711e5 1229 if(tcs->nb_event >= tcs->save_interval) {
1230 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1231 LTTV_STATE_SAVED_STATES);
1232 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1233 value = lttv_attribute_add(saved_states_tree,
1234 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1235 *(value.v_gobject) = (GObject *)saved_state_tree;
1236 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1237 *(value.v_time) = self->parent.timestamp;
308711e5 1238 lttv_state_save(tcs, saved_state_tree);
1239 tcs->nb_event = 0;
08b1c66e 1240 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1241 self->parent.timestamp.tv_nsec);
308711e5 1242 }
dbb7bb09 1243 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1244 return FALSE;
1245}
1246
1247
08b1c66e 1248static gboolean block_end(void *hook_data, void *call_data)
1249{
1250 LttvTracefileState *self = (LttvTracefileState *)call_data;
1251
1252 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1253
1254 LttTracefile *tf;
1255
1256 LttEventPosition *ep;
1257
1258 guint nb_block, nb_event;
1259
1260 ep = ltt_event_position_new();
1261 ltt_event_position(self->parent.e, ep);
1262 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1263 tcs->nb_event += nb_event - self->saved_position + 1;
1264 self->saved_position = 0;
1265 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1266 g_free(ep);
00e74b69 1267
1268 return FALSE;
08b1c66e 1269}
1270
1271
308711e5 1272void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1273{
1274 LttvTraceset *traceset = self->parent.ts;
1275
00e74b69 1276 guint i, j, nb_trace, nb_tracefile;
308711e5 1277
1278 LttvTraceState *ts;
1279
1280 LttvTracefileState *tfs;
1281
08b1c66e 1282 LttvTraceHook hook_start, hook_end;
308711e5 1283
1284 nb_trace = lttv_traceset_number(traceset);
1285 for(i = 0 ; i < nb_trace ; i++) {
1286 ts = (LttvTraceState *)self->parent.traces[i];
08b1c66e 1287 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1288 NULL, NULL, block_start, &hook_start);
308711e5 1289 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1290 NULL, NULL, block_end, &hook_end);
308711e5 1291
dbb7bb09 1292 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1293 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1294
dbb7bb09 1295 for(j = 0 ; j < nb_tracefile ; j++) {
1296 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
a5ba1787 1297 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1298 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1299 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1300 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
308711e5 1301 }
1302 }
1303}
1304
b56b5fec 1305gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1306{
1307 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1308
1309 lttv_state_save_add_event_hooks(tss);
1310
1311 return 0;
1312}
1313
308711e5 1314
1315void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1316{
1317 LttvTraceset *traceset = self->parent.ts;
1318
00e74b69 1319 guint i, j, nb_trace, nb_tracefile;
308711e5 1320
1321 LttvTraceState *ts;
1322
1323 LttvTracefileState *tfs;
1324
08b1c66e 1325 LttvTraceHook hook_start, hook_end;
308711e5 1326
1327 nb_trace = lttv_traceset_number(traceset);
1328 for(i = 0 ; i < nb_trace ; i++) {
1329 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
08b1c66e 1330 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1331 NULL, NULL, block_start, &hook_start);
1332
308711e5 1333 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1334 NULL, NULL, block_end, &hook_end);
308711e5 1335
dbb7bb09 1336 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1337 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1338
dbb7bb09 1339 for(j = 0 ; j < nb_tracefile ; j++) {
1340 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1341 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1342 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1343 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1344 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1345 }
1346 }
1347}
1348
b56b5fec 1349gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1350{
1351 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1352
1353 lttv_state_save_remove_event_hooks(tss);
1354
1355 return 0;
1356}
308711e5 1357
dd025f91 1358void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1359{
1360 LttvTraceset *traceset = self->parent.ts;
1361
00e74b69 1362 guint i, nb_trace;
308711e5 1363
1364 int min_pos, mid_pos, max_pos;
1365
1366 LttvTraceState *tcs;
1367
1368 LttvAttributeValue value;
1369
1370 LttvAttributeType type;
1371
1372 LttvAttributeName name;
1373
1374 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1375
1376 nb_trace = lttv_traceset_number(traceset);
1377 for(i = 0 ; i < nb_trace ; i++) {
1378 tcs = (LttvTraceState *)self->parent.traces[i];
1379
2a2fa4f0 1380 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1381 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1382 LTTV_STATE_SAVED_STATES);
1383 min_pos = -1;
1384
1385 if(saved_states_tree) {
dd025f91 1386 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1387 mid_pos = max_pos / 2;
1388 while(min_pos < max_pos) {
1389 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1390 g_assert(type == LTTV_GOBJECT);
1391 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1392 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1393 &value);
1394 g_assert(type == LTTV_TIME);
1395 if(ltt_time_compare(*(value.v_time), t) < 0) {
1396 min_pos = mid_pos;
1397 closest_tree = saved_state_tree;
1398 }
1399 else max_pos = mid_pos - 1;
1400
1401 mid_pos = (min_pos + max_pos + 1) / 2;
1402 }
2a2fa4f0 1403 }
dd025f91 1404
2a2fa4f0 1405 /* restore the closest earlier saved state */
f95bc830 1406 if(min_pos != -1) {
1407 lttv_state_restore(tcs, closest_tree);
1408 }
dd025f91 1409
2a2fa4f0 1410 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1411 else {
1412 restore_init_state(tcs);
1413 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1414 }
9444deae 1415 }
dd025f91 1416 /* We want to seek quickly without restoring/updating the state */
1417 else {
308711e5 1418 restore_init_state(tcs);
dd025f91 1419 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1420 }
308711e5 1421 }
1422}
1423
1424
1425static void
1426traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1427{
1428}
1429
1430
1431static void
1432traceset_state_finalize (LttvTracesetState *self)
1433{
1434 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1435 finalize(G_OBJECT(self));
1436}
1437
1438
1439static void
1440traceset_state_class_init (LttvTracesetContextClass *klass)
1441{
1442 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1443
1444 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1445 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1446 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1447 klass->new_traceset_context = new_traceset_context;
1448 klass->new_trace_context = new_trace_context;
1449 klass->new_tracefile_context = new_tracefile_context;
1450}
1451
1452
1453GType
1454lttv_traceset_state_get_type(void)
1455{
1456 static GType type = 0;
1457 if (type == 0) {
1458 static const GTypeInfo info = {
1459 sizeof (LttvTracesetStateClass),
1460 NULL, /* base_init */
1461 NULL, /* base_finalize */
1462 (GClassInitFunc) traceset_state_class_init, /* class_init */
1463 NULL, /* class_finalize */
1464 NULL, /* class_data */
dbb7bb09 1465 sizeof (LttvTracesetState),
308711e5 1466 0, /* n_preallocs */
00e74b69 1467 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1468 NULL /* value handling */
308711e5 1469 };
1470
1471 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1472 &info, 0);
1473 }
1474 return type;
1475}
1476
1477
1478static void
1479trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1480{
1481}
1482
1483
1484static void
1485trace_state_finalize (LttvTraceState *self)
1486{
1487 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1488 finalize(G_OBJECT(self));
1489}
1490
1491
1492static void
1493trace_state_class_init (LttvTraceStateClass *klass)
1494{
1495 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1496
1497 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1498 klass->state_save = state_save;
1499 klass->state_restore = state_restore;
1500 klass->state_saved_free = state_saved_free;
1501}
1502
1503
1504GType
1505lttv_trace_state_get_type(void)
1506{
1507 static GType type = 0;
1508 if (type == 0) {
1509 static const GTypeInfo info = {
1510 sizeof (LttvTraceStateClass),
1511 NULL, /* base_init */
1512 NULL, /* base_finalize */
1513 (GClassInitFunc) trace_state_class_init, /* class_init */
1514 NULL, /* class_finalize */
1515 NULL, /* class_data */
1516 sizeof (LttvTraceState),
1517 0, /* n_preallocs */
00e74b69 1518 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1519 NULL /* value handling */
308711e5 1520 };
1521
1522 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1523 "LttvTraceStateType", &info, 0);
1524 }
1525 return type;
1526}
1527
1528
1529static void
1530tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1531{
1532}
1533
1534
1535static void
1536tracefile_state_finalize (LttvTracefileState *self)
1537{
1538 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1539 finalize(G_OBJECT(self));
1540}
1541
1542
1543static void
1544tracefile_state_class_init (LttvTracefileStateClass *klass)
1545{
1546 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1547
1548 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1549}
1550
1551
1552GType
1553lttv_tracefile_state_get_type(void)
1554{
1555 static GType type = 0;
1556 if (type == 0) {
1557 static const GTypeInfo info = {
1558 sizeof (LttvTracefileStateClass),
1559 NULL, /* base_init */
1560 NULL, /* base_finalize */
1561 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1562 NULL, /* class_finalize */
1563 NULL, /* class_data */
1564 sizeof (LttvTracefileState),
1565 0, /* n_preallocs */
00e74b69 1566 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1567 NULL /* value handling */
308711e5 1568 };
1569
1570 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1571 "LttvTracefileStateType", &info, 0);
1572 }
1573 return type;
1574}
1575
1576
08b1c66e 1577static void module_init()
ffd54a90 1578{
1579 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 1580 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 1581 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1582 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1583 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1584 LTTV_STATE_TRAP = g_quark_from_string("trap");
1585 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 1586 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1587 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 1588 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
dbd243b1 1589 LTTV_STATE_EXIT = g_quark_from_string("exiting");
0828099d 1590 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
ffd54a90 1591 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1592 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 1593 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1594 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1595 LTTV_STATE_PROCESS = g_quark_from_string("process");
1596 LTTV_STATE_EVENT = g_quark_from_string("event");
1597 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 1598 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 1599 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 1600 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 1601 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1602 LTTV_STATE_TRACE_STATE_USE_COUNT =
1603 g_quark_from_string("trace_state_use_count");
ffd54a90 1604}
dc877563 1605
08b1c66e 1606static void module_destroy()
ffd54a90 1607{
1608}
dc877563 1609
1610
08b1c66e 1611LTTV_MODULE("state", "State computation", \
1612 "Update the system state, possibly saving it at intervals", \
1613 module_init, module_destroy)
1614
dc877563 1615
1616
This page took 0.109116 seconds and 4 git commands to generate.