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