no more end event to p t middle
[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
f95bc830 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);
451 ltt_tracefile_seek_position(tfcs->parent.tf, ep);
452 tfcs->parent.e = ltt_tracefile_read(tfcs->parent.tf);
453 tfcs->parent.timestamp = ltt_event_time(tfcs->parent.e);
454 }
dc877563 455 }
dc877563 456}
457
458
308711e5 459static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 460{
dbb7bb09 461 guint i, nb_tracefile;
dc877563 462
308711e5 463 LttvTracefileState *tfcs;
dc877563 464
308711e5 465 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 466
308711e5 467 LttvAttributeType type;
dc877563 468
308711e5 469 LttvAttributeValue value;
dc877563 470
308711e5 471 LttvAttributeName name;
dc877563 472
308711e5 473 LttEventPosition *ep;
dc877563 474
308711e5 475 tracefiles_tree = lttv_attribute_find_subdir(container,
476 LTTV_STATE_TRACEFILES);
477 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 478
308711e5 479 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
480 &value);
481 g_assert(type == LTTV_POINTER);
482 lttv_state_free_process_table(*(value.v_pointer));
483 *(value.v_pointer) = NULL;
484 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
485
dbb7bb09 486 nb_tracefile = ltt_trace_control_tracefile_number(self->parent.t) +
487 ltt_trace_per_cpu_tracefile_number(self->parent.t);
308711e5 488
489 for(i = 0 ; i < nb_tracefile ; i++) {
dbb7bb09 490 tfcs = (LttvTracefileState *)self->parent.tracefiles[i];
308711e5 491 type = lttv_attribute_get(tracefiles_tree, i, &name, &value);
492 g_assert(type == LTTV_GOBJECT);
493 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
494
495 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
496 &value);
497 g_assert(type == LTTV_POINTER);
498 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 499 }
308711e5 500 lttv_attribute_recursive_free(tracefiles_tree);
dc877563 501}
502
503
f95bc830 504static void free_saved_state(LttvTraceState *self)
505{
506 guint i, nb;
507
508 LttvAttributeType type;
509
510 LttvAttributeValue value;
511
512 LttvAttributeName name;
513
514 LttvAttribute *saved_states;
515
516 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
517 LTTV_STATE_SAVED_STATES);
518
519 nb = lttv_attribute_get_number(saved_states);
520 for(i = 0 ; i < nb ; i++) {
521 type = lttv_attribute_get(saved_states, i, &name, &value);
522 g_assert(type == LTTV_GOBJECT);
523 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
524 }
525
526 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
527 lttv_attribute_recursive_free(saved_states);
528}
529
530
531static void
532create_max_time(LttvTraceState *tcs)
533{
534 LttvAttributeValue v;
535
536 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
537 LTTV_POINTER, &v);
538 g_assert(*(v.v_pointer) == NULL);
539 *(v.v_pointer) = g_new(LttTime,1);
540 *((LttTime *)*(v.v_pointer)) = time_zero;
541}
542
543
544static void
545get_max_time(LttvTraceState *tcs)
546{
547 LttvAttributeValue v;
548
549 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
550 LTTV_POINTER, &v);
551 g_assert(*(v.v_pointer) != NULL);
552 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
553}
554
555
556static void
557free_max_time(LttvTraceState *tcs)
558{
559 LttvAttributeValue v;
560
561 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
562 LTTV_POINTER, &v);
563 g_free(*(v.v_pointer));
564 *(v.v_pointer) = NULL;
565}
566
567
568typedef struct _LttvNameTables {
569 GQuark *eventtype_names;
570 GQuark *syscall_names;
571 GQuark *trap_names;
572 GQuark *irq_names;
573} LttvNameTables;
574
575
b445142a 576static void
f95bc830 577create_name_tables(LttvTraceState *tcs)
b445142a 578{
579 int i, nb;
dc877563 580
b445142a 581 char *f_name, *e_name;
dc877563 582
b445142a 583 LttvTraceHook h;
584
585 LttEventType *et;
586
587 LttType *t;
588
589 GString *fe_name = g_string_new("");
590
f95bc830 591 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
592
593 LttvAttributeValue v;
594
595 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
596 LTTV_POINTER, &v);
597 g_assert(*(v.v_pointer) == NULL);
598 *(v.v_pointer) = name_tables;
599
b445142a 600 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 601 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 602 for(i = 0 ; i < nb ; i++) {
603 et = ltt_trace_eventtype_get(tcs->parent.t, i);
604 e_name = ltt_eventtype_name(et);
605 f_name = ltt_facility_name(ltt_eventtype_facility(et));
606 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 607 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 608 }
dc877563 609
b445142a 610 lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry",
611 "syscall_id", NULL, NULL, NULL, &h);
612 t = ltt_field_type(h.f1);
613 nb = ltt_type_element_number(t);
614
615 /* CHECK syscalls should be an emun but currently are not!
f95bc830 616 name_tables->syscall_names = g_new(GQuark, nb);
b445142a 617
618 for(i = 0 ; i < nb ; i++) {
f95bc830 619 name_tables->syscall_names[i] = g_quark_from_string(
620 ltt_enum_string_get(t, i));
b445142a 621 }
622 */
623
f95bc830 624 name_tables->syscall_names = g_new(GQuark, 256);
b445142a 625 for(i = 0 ; i < 256 ; i++) {
626 g_string_printf(fe_name, "syscall %d", i);
f95bc830 627 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
b445142a 628 }
629
630 lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry",
631 "trap_id", NULL, NULL, NULL, &h);
632 t = ltt_field_type(h.f1);
633 nb = ltt_type_element_number(t);
634
635 /*
f95bc830 636 name_tables->trap_names = g_new(GQuark, nb);
b445142a 637 for(i = 0 ; i < nb ; i++) {
f95bc830 638 name_tables->trap_names[i] = g_quark_from_string(
639 ltt_enum_string_get(t, i));
b445142a 640 }
641 */
642
f95bc830 643 name_tables->trap_names = g_new(GQuark, 256);
b445142a 644 for(i = 0 ; i < 256 ; i++) {
645 g_string_printf(fe_name, "trap %d", i);
f95bc830 646 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
b445142a 647 }
648
649 lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry",
650 "irq_id", NULL, NULL, NULL, &h);
651 t = ltt_field_type(h.f1);
652 nb = ltt_type_element_number(t);
653
654 /*
f95bc830 655 name_tables->irq_names = g_new(GQuark, nb);
b445142a 656 for(i = 0 ; i < nb ; i++) {
f95bc830 657 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
b445142a 658 }
659 */
660
f95bc830 661 name_tables->irq_names = g_new(GQuark, 256);
b445142a 662 for(i = 0 ; i < 256 ; i++) {
663 g_string_printf(fe_name, "irq %d", i);
f95bc830 664 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
b445142a 665 }
666
667 g_string_free(fe_name, TRUE);
668}
669
670
f95bc830 671static void
672get_name_tables(LttvTraceState *tcs)
673{
674 LttvNameTables *name_tables;
675
676 LttvAttributeValue v;
677
678 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
679 LTTV_POINTER, &v);
680 g_assert(*(v.v_pointer) != NULL);
681 name_tables = (LttvNameTables *)*(v.v_pointer);
682 tcs->eventtype_names = name_tables->eventtype_names;
683 tcs->syscall_names = name_tables->syscall_names;
684 tcs->trap_names = name_tables->trap_names;
685 tcs->irq_names = name_tables->irq_names;
686}
687
688
b445142a 689static void
690free_name_tables(LttvTraceState *tcs)
691{
f95bc830 692 LttvNameTables *name_tables;
693
694 LttvAttributeValue v;
695
696 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
697 LTTV_POINTER, &v);
698 name_tables = (LttvNameTables *)*(v.v_pointer);
699 *(v.v_pointer) = NULL;
700
701 g_free(name_tables->eventtype_names);
702 g_free(name_tables->syscall_names);
703 g_free(name_tables->trap_names);
704 g_free(name_tables->irq_names);
705 g_free(name_tables);
b445142a 706}
dc877563 707
b445142a 708
709static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 710 guint state_id)
dc877563 711{
b445142a 712 LttvExecutionState *es;
dc877563 713
714 LttvProcessState *process = tfs->process;
715
b445142a 716 guint depth = process->execution_stack->len;
dc877563 717
b445142a 718 g_array_set_size(process->execution_stack, depth + 1);
719 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
720 es->t = t;
721 es->n = state_id;
722 es->entry = es->change = tfs->parent.timestamp;
723 es->s = process->state->s;
724 process->state = es;
dc877563 725}
726
727
b445142a 728static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 729{
730 LttvProcessState *process = tfs->process;
731
f95bc830 732 guint depth = process->execution_stack->len;
dc877563 733
3d27549e 734 if(process->state->t != t){
08b1c66e 735 g_info("Different execution mode type (%d.%09d): ignore it\n",
b445142a 736 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 737 g_info("process state has %s when pop_int is %s\n",
8e8e6b64 738 g_quark_to_string(process->state->t),
739 g_quark_to_string(t));
08b1c66e 740 g_info("{ %u, %u, %s, %s }\n",
8e8e6b64 741 process->pid,
742 process->ppid,
743 g_quark_to_string(process->name),
744 g_quark_to_string(process->state->s));
3d27549e 745 return;
746 }
b445142a 747
f95bc830 748 if(depth == 1){
08b1c66e 749 g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
b445142a 750 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
751 return;
752 }
753
f95bc830 754 g_array_set_size(process->execution_stack, depth - 1);
b445142a 755 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 756 depth - 2);
b445142a 757 process->state->change = tfs->parent.timestamp;
dc877563 758}
759
760
2a2fa4f0 761LttvProcessState *
762lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
763 guint pid)
dc877563 764{
765 LttvProcessState *process = g_new(LttvProcessState, 1);
766
b445142a 767 LttvExecutionState *es;
dc877563 768
ffd54a90 769 LttvTraceContext *tc;
770
ba576a78 771 LttvTraceState *tcs;
772
b445142a 773 char buffer[128];
ffd54a90 774
f95bc830 775 tcs = ((LttvTraceState *)tc = tfs->parent.t_context);
60b53e4f 776
dc877563 777 process->pid = pid;
2a2fa4f0 778 process->last_cpu = tfs->cpu_name;
f95bc830 779 g_warning("Process %u, core %p", process->pid, process);
2a2fa4f0 780 g_hash_table_insert(tcs->processes, process, process);
b445142a 781
782 if(parent) {
783 process->ppid = parent->pid;
784 process->name = parent->name;
2a2fa4f0 785 process->creation_time = tfs->parent.timestamp;
b445142a 786 }
2a2fa4f0 787
788 /* No parent. This process exists but we are missing all information about
789 its creation. The birth time is set to zero but we remember the time of
790 insertion */
791
b445142a 792 else {
793 process->ppid = 0;
794 process->name = LTTV_STATE_UNNAMED;
2a2fa4f0 795 process->creation_time = ltt_time_zero;
b445142a 796 }
797
2a2fa4f0 798 process->insertion_time = tfs->parent.timestamp;
b445142a 799 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
800 process->creation_time.tv_nsec);
801 process->pid_time = g_quark_from_string(buffer);
2a2fa4f0 802 process->last_cpu = tfs->cpu_name;
b445142a 803 process->execution_stack = g_array_new(FALSE, FALSE,
804 sizeof(LttvExecutionState));
805 g_array_set_size(process->execution_stack, 1);
806 es = process->state = &g_array_index(process->execution_stack,
807 LttvExecutionState, 0);
808 es->t = LTTV_STATE_USER_MODE;
809 es->n = LTTV_STATE_SUBMODE_NONE;
810 es->entry = tfs->parent.timestamp;
811 es->change = tfs->parent.timestamp;
812 es->s = LTTV_STATE_WAIT_FORK;
cbe7c836 813
814 return process;
dc877563 815}
816
2a2fa4f0 817
818LttvProcessState *
819lttv_state_find_process_from_trace(LttvTraceState *ts, GQuark cpu, guint pid)
dc877563 820{
2a2fa4f0 821 LttvProcessState key;
822 LttvProcessState *process;
823
824 key.pid = pid;
825 key.last_cpu = cpu;
826 process = g_hash_table_lookup(ts->processes, &key);
dc877563 827 return process;
828}
829
2a2fa4f0 830
831LttvProcessState *lttv_state_find_process(LttvTracefileState *tfs,
d0cd7f09 832 guint pid)
833{
2a2fa4f0 834 LttvTraceState *ts =(LttvTraceState *)tfs->parent.t_context;
835 return lttv_state_find_process_from_trace(ts, tfs->cpu_name, pid);
d0cd7f09 836}
837
838
2a2fa4f0 839LttvProcessState *
840lttv_state_find_process_or_create(LttvTracefileState *tfs, guint pid)
841{
842 LttvProcessState *process = lttv_state_find_process(tfs, pid);
843
844 if(process == NULL) process = lttv_state_create_process(tfs, NULL, pid);
845 return process;
846}
847
dc877563 848
b445142a 849static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 850{
ba576a78 851 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 852 LttvProcessState key;
ba576a78 853
2a2fa4f0 854 key.pid = process->pid;
855 key.last_cpu = process->last_cpu;
856 g_hash_table_remove(ts->processes, &key);
b445142a 857 g_array_free(process->execution_stack, TRUE);
dc877563 858 g_free(process);
859}
860
861
b445142a 862static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 863{
b445142a 864 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 865 g_free(value);
866}
867
868
308711e5 869static void lttv_state_free_process_table(GHashTable *processes)
dc877563 870{
871 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 872 g_hash_table_destroy(processes);
dc877563 873}
874
875
b445142a 876static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 877{
b445142a 878 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 879
ba576a78 880 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 881
b445142a 882 LttvExecutionSubmode submode;
883
884 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
885 ltt_event_get_unsigned(s->parent.e, f)];
886 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 887 return FALSE;
888}
889
890
b445142a 891static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 892{
ba576a78 893 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 894
ffd54a90 895 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 896 return FALSE;
897}
898
899
b445142a 900static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 901{
b445142a 902 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 903
ba576a78 904 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 905
b445142a 906 LttvExecutionSubmode submode;
907
908 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
909 ltt_event_get_unsigned(s->parent.e, f)];
910 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 911 return FALSE;
912}
913
914
b445142a 915static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 916{
ba576a78 917 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 918
ffd54a90 919 pop_state(s, LTTV_STATE_TRAP);
dc877563 920 return FALSE;
921}
922
923
b445142a 924static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 925{
b445142a 926 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 927
ba576a78 928 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 929
b445142a 930 LttvExecutionSubmode submode;
931
932 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
933 ltt_event_get_unsigned(s->parent.e, f)];
934
dc877563 935 /* Do something with the info about being in user or system mode when int? */
b445142a 936 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 937 return FALSE;
938}
939
940
b445142a 941static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 942{
ba576a78 943 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 944
ffd54a90 945 pop_state(s, LTTV_STATE_IRQ);
dc877563 946 return FALSE;
947}
948
949
b445142a 950static gboolean schedchange(void *hook_data, void *call_data)
dc877563 951{
b445142a 952 LttvTraceHook *h = (LttvTraceHook *)hook_data;
dc877563 953
ba576a78 954 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 955
956 guint pid_in, pid_out, state_out;
957
3d27549e 958 pid_in = ltt_event_get_unsigned(s->parent.e, h->f1);
959 pid_out = ltt_event_get_unsigned(s->parent.e, h->f2);
960 state_out = ltt_event_get_unsigned(s->parent.e, h->f3);
b445142a 961
dc877563 962 if(s->process != NULL) {
b445142a 963
f95bc830 964 /* We could not know but it was not the idle process executing.
965 This should only happen at the beginning, before the first schedule
966 event, and when the initial information (current process for each CPU)
967 is missing. It is not obvious how we could, after the fact, compensate
968 the wrongly attributed statistics. */
969
970 if(s->process->pid != pid_out) {
971 g_assert(s->process->pid == 0);
972 }
973
ffd54a90 974 if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
975 else if(s->process->state->s == LTTV_STATE_EXIT)
ba576a78 976 exit_process(s, s->process);
ffd54a90 977 else s->process->state->s = LTTV_STATE_WAIT;
3d27549e 978
b445142a 979 s->process->state->change = s->parent.timestamp;
dc877563 980 }
2a2fa4f0 981 s->process = lttv_state_find_process_or_create(s, pid_in);
ffd54a90 982 s->process->state->s = LTTV_STATE_RUN;
2a2fa4f0 983 s->process->last_cpu = s->cpu_name;
b445142a 984 s->process->state->change = s->parent.timestamp;
dc877563 985 return FALSE;
986}
987
988
b445142a 989static gboolean process_fork(void *hook_data, void *call_data)
dc877563 990{
b445142a 991 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 992
ba576a78 993 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 994
995 guint child_pid;
996
3d27549e 997 child_pid = ltt_event_get_unsigned(s->parent.e, f);
2a2fa4f0 998 lttv_state_create_process(s, s->process, child_pid);
dc877563 999 return FALSE;
1000}
1001
1002
b445142a 1003static gboolean process_exit(void *hook_data, void *call_data)
dc877563 1004{
ba576a78 1005 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1006
1007 if(s->process != NULL) {
ffd54a90 1008 s->process->state->s = LTTV_STATE_EXIT;
dc877563 1009 }
1010 return FALSE;
1011}
1012
1013
308711e5 1014void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1015{
ba576a78 1016 LttvTraceset *traceset = self->parent.ts;
dc877563 1017
dbb7bb09 1018 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1019
ba576a78 1020 LttvTraceState *ts;
dc877563 1021
ba576a78 1022 LttvTracefileState *tfs;
dc877563 1023
dc877563 1024 GArray *hooks;
1025
b445142a 1026 LttvTraceHook hook;
dc877563 1027
1028 LttvAttributeValue val;
1029
ba576a78 1030 nb_trace = lttv_traceset_number(traceset);
dc877563 1031 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1032 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1033
1034 /* Find the eventtype id for the following events and register the
1035 associated by id hooks. */
1036
b445142a 1037 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1038 g_array_set_size(hooks, 9);
1039
1040 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1041 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
cbe7c836 1042
b445142a 1043 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1044 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
cbe7c836 1045
b445142a 1046 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1047 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
cbe7c836 1048
b445142a 1049 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1050 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
cbe7c836 1051
b445142a 1052 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1053 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
cbe7c836 1054
b445142a 1055 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1056 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
cbe7c836 1057
b445142a 1058 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1059 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
cbe7c836 1060
b445142a 1061 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1062 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
cbe7c836 1063
b445142a 1064 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1065 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
dc877563 1066
1067 /* Add these hooks to each before_event_by_id hooks list */
1068
dbb7bb09 1069 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1070 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1071
dc877563 1072 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1073 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1074
1075 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1076 hook = g_array_index(hooks, LttvTraceHook, k);
1077 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1078 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1079 }
dc877563 1080 }
ba576a78 1081 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1082 *(val.v_pointer) = hooks;
dc877563 1083 }
1084}
1085
1086
308711e5 1087void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1088{
ba576a78 1089 LttvTraceset *traceset = self->parent.ts;
dc877563 1090
dbb7bb09 1091 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1092
ba576a78 1093 LttvTraceState *ts;
dc877563 1094
ba576a78 1095 LttvTracefileState *tfs;
dc877563 1096
dc877563 1097 GArray *hooks;
1098
b445142a 1099 LttvTraceHook hook;
dc877563 1100
1101 LttvAttributeValue val;
1102
ba576a78 1103 nb_trace = lttv_traceset_number(traceset);
dc877563 1104 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1105 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1106 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1107 hooks = *(val.v_pointer);
dc877563 1108
1109 /* Add these hooks to each before_event_by_id hooks list */
1110
dbb7bb09 1111 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1112 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1113
dc877563 1114 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1115 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1116
1117 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1118 hook = g_array_index(hooks, LttvTraceHook, k);
ba576a78 1119 lttv_hooks_remove_data(
b445142a 1120 lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1121 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1122 }
dc877563 1123 }
1124 g_array_free(hooks, TRUE);
1125 }
1126}
1127
1128
08b1c66e 1129static gboolean block_start(void *hook_data, void *call_data)
308711e5 1130{
dbb7bb09 1131 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1132
dbb7bb09 1133 LttvTracefileState *tfcs;
308711e5 1134
dbb7bb09 1135 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1136
1137 LttEventPosition *ep;
308711e5 1138
dbb7bb09 1139 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1140
1141 LttTracefile *tf;
1142
1143 LttvAttribute *saved_states_tree, *saved_state_tree;
1144
1145 LttvAttributeValue value;
1146
dbb7bb09 1147 ep = ltt_event_position_new();
1148 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1149 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1150
1151 /* Count the number of events added since the last block end in any
1152 tracefile. */
1153
1154 for(i = 0 ; i < nb_tracefile ; i++) {
1155 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1156 ltt_event_position(tfcs->parent.e, ep);
1157 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1158 tcs->nb_event += nb_event - tfcs->saved_position;
1159 tfcs->saved_position = nb_event;
1160 }
1161 g_free(ep);
308711e5 1162
308711e5 1163 if(tcs->nb_event >= tcs->save_interval) {
1164 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1165 LTTV_STATE_SAVED_STATES);
1166 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1167 value = lttv_attribute_add(saved_states_tree,
1168 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1169 *(value.v_gobject) = (GObject *)saved_state_tree;
1170 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1171 *(value.v_time) = self->parent.timestamp;
308711e5 1172 lttv_state_save(tcs, saved_state_tree);
1173 tcs->nb_event = 0;
08b1c66e 1174 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1175 self->parent.timestamp.tv_nsec);
308711e5 1176 }
dbb7bb09 1177 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1178 return FALSE;
1179}
1180
1181
08b1c66e 1182static gboolean block_end(void *hook_data, void *call_data)
1183{
1184 LttvTracefileState *self = (LttvTracefileState *)call_data;
1185
1186 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1187
1188 LttTracefile *tf;
1189
1190 LttEventPosition *ep;
1191
1192 guint nb_block, nb_event;
1193
1194 ep = ltt_event_position_new();
1195 ltt_event_position(self->parent.e, ep);
1196 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1197 tcs->nb_event += nb_event - self->saved_position + 1;
1198 self->saved_position = 0;
1199 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1200 g_free(ep);
1201}
1202
1203
308711e5 1204void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1205{
1206 LttvTraceset *traceset = self->parent.ts;
1207
dbb7bb09 1208 guint i, j, k, nb_trace, nb_tracefile;
308711e5 1209
1210 LttvTraceState *ts;
1211
1212 LttvTracefileState *tfs;
1213
08b1c66e 1214 LttvTraceHook hook_start, hook_end;
308711e5 1215
1216 nb_trace = lttv_traceset_number(traceset);
1217 for(i = 0 ; i < nb_trace ; i++) {
1218 ts = (LttvTraceState *)self->parent.traces[i];
08b1c66e 1219 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1220 NULL, NULL, block_start, &hook_start);
308711e5 1221 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1222 NULL, NULL, block_end, &hook_end);
308711e5 1223
dbb7bb09 1224 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1225 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1226
dbb7bb09 1227 for(j = 0 ; j < nb_tracefile ; j++) {
1228 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1229 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
08b1c66e 1230 hook_start.id), hook_start.h, NULL);
1231 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.after_event_by_id,
1232 hook_end.id), hook_end.h, NULL);
308711e5 1233 }
1234 }
1235}
1236
1237
1238void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1239{
1240 LttvTraceset *traceset = self->parent.ts;
1241
dbb7bb09 1242 guint i, j, k, nb_trace, nb_tracefile;
308711e5 1243
1244 LttvTraceState *ts;
1245
1246 LttvTracefileState *tfs;
1247
08b1c66e 1248 LttvTraceHook hook_start, hook_end;
308711e5 1249
1250 nb_trace = lttv_traceset_number(traceset);
1251 for(i = 0 ; i < nb_trace ; i++) {
1252 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
08b1c66e 1253 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1254 NULL, NULL, block_start, &hook_start);
1255
308711e5 1256 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1257 NULL, NULL, block_end, &hook_end);
308711e5 1258
dbb7bb09 1259 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1260 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1261
dbb7bb09 1262 for(j = 0 ; j < nb_tracefile ; j++) {
1263 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1264 lttv_hooks_remove_data(lttv_hooks_by_id_find(
08b1c66e 1265 tfs->parent.after_event_by_id, hook_start.id), hook_start.h, NULL);
1266 lttv_hooks_remove_data(lttv_hooks_by_id_find(
1267 tfs->parent.after_event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1268 }
1269 }
1270}
1271
1272
dd025f91 1273void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1274{
1275 LttvTraceset *traceset = self->parent.ts;
1276
1277 guint i, j, nb_trace, nb_saved_state;
1278
1279 int min_pos, mid_pos, max_pos;
1280
1281 LttvTraceState *tcs;
1282
1283 LttvAttributeValue value;
1284
1285 LttvAttributeType type;
1286
1287 LttvAttributeName name;
1288
1289 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1290
1291 nb_trace = lttv_traceset_number(traceset);
1292 for(i = 0 ; i < nb_trace ; i++) {
1293 tcs = (LttvTraceState *)self->parent.traces[i];
1294
2a2fa4f0 1295 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1296 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1297 LTTV_STATE_SAVED_STATES);
1298 min_pos = -1;
1299
1300 if(saved_states_tree) {
dd025f91 1301 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1302 mid_pos = max_pos / 2;
1303 while(min_pos < max_pos) {
1304 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1305 g_assert(type == LTTV_GOBJECT);
1306 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1307 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1308 &value);
1309 g_assert(type == LTTV_TIME);
1310 if(ltt_time_compare(*(value.v_time), t) < 0) {
1311 min_pos = mid_pos;
1312 closest_tree = saved_state_tree;
1313 }
1314 else max_pos = mid_pos - 1;
1315
1316 mid_pos = (min_pos + max_pos + 1) / 2;
1317 }
2a2fa4f0 1318 }
dd025f91 1319
2a2fa4f0 1320 /* restore the closest earlier saved state */
f95bc830 1321 if(min_pos != -1) {
1322 lttv_state_restore(tcs, closest_tree);
1323 }
dd025f91 1324
2a2fa4f0 1325 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1326 else {
1327 restore_init_state(tcs);
1328 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1329 }
9444deae 1330 }
dd025f91 1331 /* We want to seek quickly without restoring/updating the state */
1332 else {
308711e5 1333 restore_init_state(tcs);
dd025f91 1334 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1335 }
308711e5 1336 }
1337}
1338
1339
1340static void
1341traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1342{
1343}
1344
1345
1346static void
1347traceset_state_finalize (LttvTracesetState *self)
1348{
1349 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1350 finalize(G_OBJECT(self));
1351}
1352
1353
1354static void
1355traceset_state_class_init (LttvTracesetContextClass *klass)
1356{
1357 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1358
1359 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1360 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1361 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1362 klass->new_traceset_context = new_traceset_context;
1363 klass->new_trace_context = new_trace_context;
1364 klass->new_tracefile_context = new_tracefile_context;
1365}
1366
1367
1368GType
1369lttv_traceset_state_get_type(void)
1370{
1371 static GType type = 0;
1372 if (type == 0) {
1373 static const GTypeInfo info = {
1374 sizeof (LttvTracesetStateClass),
1375 NULL, /* base_init */
1376 NULL, /* base_finalize */
1377 (GClassInitFunc) traceset_state_class_init, /* class_init */
1378 NULL, /* class_finalize */
1379 NULL, /* class_data */
dbb7bb09 1380 sizeof (LttvTracesetState),
308711e5 1381 0, /* n_preallocs */
1382 (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
1383 };
1384
1385 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1386 &info, 0);
1387 }
1388 return type;
1389}
1390
1391
1392static void
1393trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1394{
1395}
1396
1397
1398static void
1399trace_state_finalize (LttvTraceState *self)
1400{
1401 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1402 finalize(G_OBJECT(self));
1403}
1404
1405
1406static void
1407trace_state_class_init (LttvTraceStateClass *klass)
1408{
1409 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1410
1411 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1412 klass->state_save = state_save;
1413 klass->state_restore = state_restore;
1414 klass->state_saved_free = state_saved_free;
1415}
1416
1417
1418GType
1419lttv_trace_state_get_type(void)
1420{
1421 static GType type = 0;
1422 if (type == 0) {
1423 static const GTypeInfo info = {
1424 sizeof (LttvTraceStateClass),
1425 NULL, /* base_init */
1426 NULL, /* base_finalize */
1427 (GClassInitFunc) trace_state_class_init, /* class_init */
1428 NULL, /* class_finalize */
1429 NULL, /* class_data */
1430 sizeof (LttvTraceState),
1431 0, /* n_preallocs */
1432 (GInstanceInitFunc) trace_state_instance_init /* instance_init */
1433 };
1434
1435 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1436 "LttvTraceStateType", &info, 0);
1437 }
1438 return type;
1439}
1440
1441
1442static void
1443tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1444{
1445}
1446
1447
1448static void
1449tracefile_state_finalize (LttvTracefileState *self)
1450{
1451 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1452 finalize(G_OBJECT(self));
1453}
1454
1455
1456static void
1457tracefile_state_class_init (LttvTracefileStateClass *klass)
1458{
1459 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1460
1461 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1462}
1463
1464
1465GType
1466lttv_tracefile_state_get_type(void)
1467{
1468 static GType type = 0;
1469 if (type == 0) {
1470 static const GTypeInfo info = {
1471 sizeof (LttvTracefileStateClass),
1472 NULL, /* base_init */
1473 NULL, /* base_finalize */
1474 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1475 NULL, /* class_finalize */
1476 NULL, /* class_data */
1477 sizeof (LttvTracefileState),
1478 0, /* n_preallocs */
1479 (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
1480 };
1481
1482 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1483 "LttvTracefileStateType", &info, 0);
1484 }
1485 return type;
1486}
1487
1488
08b1c66e 1489static void module_init()
ffd54a90 1490{
1491 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 1492 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 1493 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1494 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1495 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1496 LTTV_STATE_TRAP = g_quark_from_string("trap");
1497 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 1498 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1499 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 1500 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1501 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1502 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1503 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 1504 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1505 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1506 LTTV_STATE_PROCESS = g_quark_from_string("process");
1507 LTTV_STATE_EVENT = g_quark_from_string("event");
1508 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 1509 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 1510 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 1511 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 1512 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1513 LTTV_STATE_TRACE_STATE_USE_COUNT =
1514 g_quark_from_string("trace_state_use_count");
ffd54a90 1515}
dc877563 1516
08b1c66e 1517static void module_destroy()
ffd54a90 1518{
1519}
dc877563 1520
1521
08b1c66e 1522LTTV_MODULE("state", "State computation", \
1523 "Update the system state, possibly saving it at intervals", \
1524 module_init, module_destroy)
1525
dc877563 1526
1527
This page took 0.095238 seconds and 4 git commands to generate.