header missing
[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
2da61677 1040static gboolean process_release(LttvTraceHook *trace_hook,
1041 LttvTracefileState *s)
1042{
1043 LttField *f;
1044 guint release_pid;
1045 LttvProcessState *process;
1046
1047 /* PID of the process to release */
1048 f = trace_hook->f2;
1049 release_pid = ltt_event_get_unsigned(s->parent.e, f);
1050
1051 process = lttv_state_find_process(s, release_pid);
1052
1053 if(likely(process != NULL)) {
1054 /* release_task is happening at kernel level : we can now safely release
1055 * the data structure of the process */
1056 exit_process(s, process);
1057 }
1058
1059 return FALSE;
1060}
1061
2cdc690b 1062gboolean process(void *hook_data, void *call_data)
1063{
1064 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1065 LttField *f = trace_hook->f1;
1066
1067 LttvTracefileState *s = (LttvTracefileState *)call_data;
1068
1069 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1070
1071 /* CHECK : do not hardcode the sub_id values here ? */
1072 if(sub_id == 2) {
1073 return process_fork(trace_hook, s);
1074 } else if(sub_id == 3) {
1075 return process_exit(trace_hook, s);
2da61677 1076 } else if(sub_id == 7) {
1077 return process_release(trace_hook, s);
2cdc690b 1078 }
1079 return 0;
dc877563 1080}
1081
58c88a41 1082gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1083{
1084 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1085
1086 lttv_state_add_event_hooks(tss);
1087
1088 return 0;
1089}
dc877563 1090
308711e5 1091void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1092{
ba576a78 1093 LttvTraceset *traceset = self->parent.ts;
dc877563 1094
dbb7bb09 1095 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1096
ba576a78 1097 LttvTraceState *ts;
dc877563 1098
ba576a78 1099 LttvTracefileState *tfs;
dc877563 1100
dc877563 1101 GArray *hooks;
1102
b445142a 1103 LttvTraceHook hook;
dc877563 1104
1105 LttvAttributeValue val;
1106
ba576a78 1107 nb_trace = lttv_traceset_number(traceset);
dc877563 1108 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1109 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1110
1111 /* Find the eventtype id for the following events and register the
1112 associated by id hooks. */
1113
b445142a 1114 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
facab7c2 1115 g_array_set_size(hooks, 8);
b445142a 1116
1117 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1118 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
cbe7c836 1119
b445142a 1120 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1121 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
cbe7c836 1122
b445142a 1123 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1124 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
cbe7c836 1125
b445142a 1126 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1127 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
cbe7c836 1128
b445142a 1129 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1130 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
cbe7c836 1131
b445142a 1132 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1133 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
cbe7c836 1134
b445142a 1135 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1136 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
cbe7c836 1137
2cdc690b 1138 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1139 "event_data1", "event_data2", process,
1140 &g_array_index(hooks, LttvTraceHook, 7));
1141
1142#if 0
b445142a 1143 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1144 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
cbe7c836 1145
b445142a 1146 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1147 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
2cdc690b 1148#endif //0
a5ba1787 1149 /* Add these hooks to each event_by_id hooks list */
dc877563 1150
dbb7bb09 1151 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1152 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1153
dc877563 1154 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1155 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1156
1157 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1158 hook = g_array_index(hooks, LttvTraceHook, k);
a5ba1787 1159 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1160 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
ffd54a90 1161 }
dc877563 1162 }
ba576a78 1163 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1164 *(val.v_pointer) = hooks;
dc877563 1165 }
1166}
1167
58c88a41 1168gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1169{
1170 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1171
1172 lttv_state_remove_event_hooks(tss);
1173
1174 return 0;
1175}
dc877563 1176
308711e5 1177void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1178{
ba576a78 1179 LttvTraceset *traceset = self->parent.ts;
dc877563 1180
dbb7bb09 1181 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1182
ba576a78 1183 LttvTraceState *ts;
dc877563 1184
ba576a78 1185 LttvTracefileState *tfs;
dc877563 1186
dc877563 1187 GArray *hooks;
1188
b445142a 1189 LttvTraceHook hook;
dc877563 1190
1191 LttvAttributeValue val;
1192
ba576a78 1193 nb_trace = lttv_traceset_number(traceset);
dc877563 1194 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1195 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1196 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1197 hooks = *(val.v_pointer);
dc877563 1198
a5ba1787 1199 /* Remove these hooks from each event_by_id hooks list */
dc877563 1200
dbb7bb09 1201 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1202 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1203
dc877563 1204 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1205 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1206
1207 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1208 hook = g_array_index(hooks, LttvTraceHook, k);
ba576a78 1209 lttv_hooks_remove_data(
a5ba1787 1210 lttv_hooks_by_id_find(tfs->parent.event_by_id,
b445142a 1211 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1212 }
dc877563 1213 }
1214 g_array_free(hooks, TRUE);
1215 }
1216}
1217
1218
08b1c66e 1219static gboolean block_start(void *hook_data, void *call_data)
308711e5 1220{
dbb7bb09 1221 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1222
dbb7bb09 1223 LttvTracefileState *tfcs;
308711e5 1224
dbb7bb09 1225 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1226
1227 LttEventPosition *ep;
308711e5 1228
dbb7bb09 1229 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1230
1231 LttTracefile *tf;
1232
1233 LttvAttribute *saved_states_tree, *saved_state_tree;
1234
1235 LttvAttributeValue value;
1236
dbb7bb09 1237 ep = ltt_event_position_new();
1238 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1239 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1240
1241 /* Count the number of events added since the last block end in any
1242 tracefile. */
1243
1244 for(i = 0 ; i < nb_tracefile ; i++) {
1245 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1246 ltt_event_position(tfcs->parent.e, ep);
1247 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1248 tcs->nb_event += nb_event - tfcs->saved_position;
1249 tfcs->saved_position = nb_event;
1250 }
1251 g_free(ep);
308711e5 1252
308711e5 1253 if(tcs->nb_event >= tcs->save_interval) {
1254 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1255 LTTV_STATE_SAVED_STATES);
1256 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1257 value = lttv_attribute_add(saved_states_tree,
1258 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1259 *(value.v_gobject) = (GObject *)saved_state_tree;
1260 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1261 *(value.v_time) = self->parent.timestamp;
308711e5 1262 lttv_state_save(tcs, saved_state_tree);
1263 tcs->nb_event = 0;
08b1c66e 1264 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1265 self->parent.timestamp.tv_nsec);
308711e5 1266 }
dbb7bb09 1267 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1268 return FALSE;
1269}
1270
1271
08b1c66e 1272static gboolean block_end(void *hook_data, void *call_data)
1273{
1274 LttvTracefileState *self = (LttvTracefileState *)call_data;
1275
1276 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1277
1278 LttTracefile *tf;
1279
1280 LttEventPosition *ep;
1281
1282 guint nb_block, nb_event;
1283
1284 ep = ltt_event_position_new();
1285 ltt_event_position(self->parent.e, ep);
1286 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1287 tcs->nb_event += nb_event - self->saved_position + 1;
1288 self->saved_position = 0;
1289 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1290 g_free(ep);
00e74b69 1291
1292 return FALSE;
08b1c66e 1293}
1294
1295
308711e5 1296void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1297{
1298 LttvTraceset *traceset = self->parent.ts;
1299
00e74b69 1300 guint i, j, nb_trace, nb_tracefile;
308711e5 1301
1302 LttvTraceState *ts;
1303
1304 LttvTracefileState *tfs;
1305
08b1c66e 1306 LttvTraceHook hook_start, hook_end;
308711e5 1307
1308 nb_trace = lttv_traceset_number(traceset);
1309 for(i = 0 ; i < nb_trace ; i++) {
1310 ts = (LttvTraceState *)self->parent.traces[i];
08b1c66e 1311 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1312 NULL, NULL, block_start, &hook_start);
308711e5 1313 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1314 NULL, NULL, block_end, &hook_end);
308711e5 1315
dbb7bb09 1316 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1317 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1318
dbb7bb09 1319 for(j = 0 ; j < nb_tracefile ; j++) {
1320 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
a5ba1787 1321 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1322 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1323 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1324 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
308711e5 1325 }
1326 }
1327}
1328
b56b5fec 1329gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1330{
1331 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1332
1333 lttv_state_save_add_event_hooks(tss);
1334
1335 return 0;
1336}
1337
308711e5 1338
1339void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1340{
1341 LttvTraceset *traceset = self->parent.ts;
1342
00e74b69 1343 guint i, j, nb_trace, nb_tracefile;
308711e5 1344
1345 LttvTraceState *ts;
1346
1347 LttvTracefileState *tfs;
1348
08b1c66e 1349 LttvTraceHook hook_start, hook_end;
308711e5 1350
1351 nb_trace = lttv_traceset_number(traceset);
1352 for(i = 0 ; i < nb_trace ; i++) {
1353 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
08b1c66e 1354 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1355 NULL, NULL, block_start, &hook_start);
1356
308711e5 1357 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1358 NULL, NULL, block_end, &hook_end);
308711e5 1359
dbb7bb09 1360 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1361 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1362
dbb7bb09 1363 for(j = 0 ; j < nb_tracefile ; j++) {
1364 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1365 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1366 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1367 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1368 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1369 }
1370 }
1371}
1372
b56b5fec 1373gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1374{
1375 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1376
1377 lttv_state_save_remove_event_hooks(tss);
1378
1379 return 0;
1380}
308711e5 1381
dd025f91 1382void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1383{
1384 LttvTraceset *traceset = self->parent.ts;
1385
00e74b69 1386 guint i, nb_trace;
308711e5 1387
1388 int min_pos, mid_pos, max_pos;
1389
1390 LttvTraceState *tcs;
1391
1392 LttvAttributeValue value;
1393
1394 LttvAttributeType type;
1395
1396 LttvAttributeName name;
1397
1398 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1399
1400 nb_trace = lttv_traceset_number(traceset);
1401 for(i = 0 ; i < nb_trace ; i++) {
1402 tcs = (LttvTraceState *)self->parent.traces[i];
1403
2a2fa4f0 1404 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1405 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1406 LTTV_STATE_SAVED_STATES);
1407 min_pos = -1;
1408
1409 if(saved_states_tree) {
dd025f91 1410 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1411 mid_pos = max_pos / 2;
1412 while(min_pos < max_pos) {
1413 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1414 g_assert(type == LTTV_GOBJECT);
1415 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1416 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1417 &value);
1418 g_assert(type == LTTV_TIME);
1419 if(ltt_time_compare(*(value.v_time), t) < 0) {
1420 min_pos = mid_pos;
1421 closest_tree = saved_state_tree;
1422 }
1423 else max_pos = mid_pos - 1;
1424
1425 mid_pos = (min_pos + max_pos + 1) / 2;
1426 }
2a2fa4f0 1427 }
dd025f91 1428
2a2fa4f0 1429 /* restore the closest earlier saved state */
f95bc830 1430 if(min_pos != -1) {
1431 lttv_state_restore(tcs, closest_tree);
1432 }
dd025f91 1433
2a2fa4f0 1434 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1435 else {
1436 restore_init_state(tcs);
1437 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1438 }
9444deae 1439 }
dd025f91 1440 /* We want to seek quickly without restoring/updating the state */
1441 else {
308711e5 1442 restore_init_state(tcs);
dd025f91 1443 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1444 }
308711e5 1445 }
1446}
1447
1448
1449static void
1450traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1451{
1452}
1453
1454
1455static void
1456traceset_state_finalize (LttvTracesetState *self)
1457{
1458 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1459 finalize(G_OBJECT(self));
1460}
1461
1462
1463static void
1464traceset_state_class_init (LttvTracesetContextClass *klass)
1465{
1466 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1467
1468 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1469 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1470 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1471 klass->new_traceset_context = new_traceset_context;
1472 klass->new_trace_context = new_trace_context;
1473 klass->new_tracefile_context = new_tracefile_context;
1474}
1475
1476
1477GType
1478lttv_traceset_state_get_type(void)
1479{
1480 static GType type = 0;
1481 if (type == 0) {
1482 static const GTypeInfo info = {
1483 sizeof (LttvTracesetStateClass),
1484 NULL, /* base_init */
1485 NULL, /* base_finalize */
1486 (GClassInitFunc) traceset_state_class_init, /* class_init */
1487 NULL, /* class_finalize */
1488 NULL, /* class_data */
dbb7bb09 1489 sizeof (LttvTracesetState),
308711e5 1490 0, /* n_preallocs */
00e74b69 1491 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1492 NULL /* value handling */
308711e5 1493 };
1494
1495 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1496 &info, 0);
1497 }
1498 return type;
1499}
1500
1501
1502static void
1503trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1504{
1505}
1506
1507
1508static void
1509trace_state_finalize (LttvTraceState *self)
1510{
1511 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1512 finalize(G_OBJECT(self));
1513}
1514
1515
1516static void
1517trace_state_class_init (LttvTraceStateClass *klass)
1518{
1519 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1520
1521 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1522 klass->state_save = state_save;
1523 klass->state_restore = state_restore;
1524 klass->state_saved_free = state_saved_free;
1525}
1526
1527
1528GType
1529lttv_trace_state_get_type(void)
1530{
1531 static GType type = 0;
1532 if (type == 0) {
1533 static const GTypeInfo info = {
1534 sizeof (LttvTraceStateClass),
1535 NULL, /* base_init */
1536 NULL, /* base_finalize */
1537 (GClassInitFunc) trace_state_class_init, /* class_init */
1538 NULL, /* class_finalize */
1539 NULL, /* class_data */
1540 sizeof (LttvTraceState),
1541 0, /* n_preallocs */
00e74b69 1542 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1543 NULL /* value handling */
308711e5 1544 };
1545
1546 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1547 "LttvTraceStateType", &info, 0);
1548 }
1549 return type;
1550}
1551
1552
1553static void
1554tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1555{
1556}
1557
1558
1559static void
1560tracefile_state_finalize (LttvTracefileState *self)
1561{
1562 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1563 finalize(G_OBJECT(self));
1564}
1565
1566
1567static void
1568tracefile_state_class_init (LttvTracefileStateClass *klass)
1569{
1570 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1571
1572 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1573}
1574
1575
1576GType
1577lttv_tracefile_state_get_type(void)
1578{
1579 static GType type = 0;
1580 if (type == 0) {
1581 static const GTypeInfo info = {
1582 sizeof (LttvTracefileStateClass),
1583 NULL, /* base_init */
1584 NULL, /* base_finalize */
1585 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1586 NULL, /* class_finalize */
1587 NULL, /* class_data */
1588 sizeof (LttvTracefileState),
1589 0, /* n_preallocs */
00e74b69 1590 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1591 NULL /* value handling */
308711e5 1592 };
1593
1594 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1595 "LttvTracefileStateType", &info, 0);
1596 }
1597 return type;
1598}
1599
1600
08b1c66e 1601static void module_init()
ffd54a90 1602{
1603 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 1604 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 1605 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1606 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1607 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1608 LTTV_STATE_TRAP = g_quark_from_string("trap");
1609 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 1610 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1611 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 1612 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
dbd243b1 1613 LTTV_STATE_EXIT = g_quark_from_string("exiting");
0828099d 1614 LTTV_STATE_ZOMBIE = g_quark_from_string("zombie");
ffd54a90 1615 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1616 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 1617 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1618 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1619 LTTV_STATE_PROCESS = g_quark_from_string("process");
1620 LTTV_STATE_EVENT = g_quark_from_string("event");
1621 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 1622 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 1623 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 1624 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 1625 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1626 LTTV_STATE_TRACE_STATE_USE_COUNT =
1627 g_quark_from_string("trace_state_use_count");
ffd54a90 1628}
dc877563 1629
08b1c66e 1630static void module_destroy()
ffd54a90 1631{
1632}
dc877563 1633
1634
08b1c66e 1635LTTV_MODULE("state", "State computation", \
1636 "Update the system state, possibly saving it at intervals", \
1637 module_init, module_destroy)
1638
dc877563 1639
1640
This page took 0.110226 seconds and 4 git commands to generate.