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