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