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