correct process fork and exit in state.c : inversed parent and child
[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);
b56b5fec 451 g_assert(tfcs->parent.t_context != NULL);
452 lttv_process_tracefile_seek_position(LTTV_TRACEFILE_CONTEXT(tfcs), ep);
308711e5 453 }
dc877563 454 }
dc877563 455}
456
457
308711e5 458static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 459{
dbb7bb09 460 guint i, nb_tracefile;
dc877563 461
308711e5 462 LttvTracefileState *tfcs;
dc877563 463
308711e5 464 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 465
308711e5 466 LttvAttributeType type;
dc877563 467
308711e5 468 LttvAttributeValue value;
dc877563 469
308711e5 470 LttvAttributeName name;
dc877563 471
308711e5 472 LttEventPosition *ep;
dc877563 473
308711e5 474 tracefiles_tree = lttv_attribute_find_subdir(container,
475 LTTV_STATE_TRACEFILES);
c47a6dc6 476 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 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 }
c47a6dc6 500 g_object_unref(G_OBJECT(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);
f95bc830 527}
528
529
530static void
531create_max_time(LttvTraceState *tcs)
532{
533 LttvAttributeValue v;
534
535 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
536 LTTV_POINTER, &v);
537 g_assert(*(v.v_pointer) == NULL);
538 *(v.v_pointer) = g_new(LttTime,1);
539 *((LttTime *)*(v.v_pointer)) = time_zero;
540}
541
542
543static void
544get_max_time(LttvTraceState *tcs)
545{
546 LttvAttributeValue v;
547
548 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
549 LTTV_POINTER, &v);
550 g_assert(*(v.v_pointer) != NULL);
551 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
552}
553
554
555static void
556free_max_time(LttvTraceState *tcs)
557{
558 LttvAttributeValue v;
559
560 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
561 LTTV_POINTER, &v);
562 g_free(*(v.v_pointer));
563 *(v.v_pointer) = NULL;
564}
565
566
567typedef struct _LttvNameTables {
568 GQuark *eventtype_names;
569 GQuark *syscall_names;
570 GQuark *trap_names;
571 GQuark *irq_names;
572} LttvNameTables;
573
574
b445142a 575static void
f95bc830 576create_name_tables(LttvTraceState *tcs)
b445142a 577{
578 int i, nb;
dc877563 579
b445142a 580 char *f_name, *e_name;
dc877563 581
b445142a 582 LttvTraceHook h;
583
584 LttEventType *et;
585
586 LttType *t;
587
588 GString *fe_name = g_string_new("");
589
f95bc830 590 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
591
592 LttvAttributeValue v;
593
594 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
595 LTTV_POINTER, &v);
596 g_assert(*(v.v_pointer) == NULL);
597 *(v.v_pointer) = name_tables;
598
b445142a 599 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 600 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 601 for(i = 0 ; i < nb ; i++) {
602 et = ltt_trace_eventtype_get(tcs->parent.t, i);
603 e_name = ltt_eventtype_name(et);
604 f_name = ltt_facility_name(ltt_eventtype_facility(et));
605 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 606 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 607 }
dc877563 608
b445142a 609 lttv_trace_find_hook(tcs->parent.t, "core", "syscall_entry",
610 "syscall_id", NULL, NULL, NULL, &h);
611 t = ltt_field_type(h.f1);
612 nb = ltt_type_element_number(t);
613
614 /* CHECK syscalls should be an emun but currently are not!
f95bc830 615 name_tables->syscall_names = g_new(GQuark, nb);
b445142a 616
617 for(i = 0 ; i < nb ; i++) {
f95bc830 618 name_tables->syscall_names[i] = g_quark_from_string(
619 ltt_enum_string_get(t, i));
b445142a 620 }
621 */
622
f95bc830 623 name_tables->syscall_names = g_new(GQuark, 256);
b445142a 624 for(i = 0 ; i < 256 ; i++) {
625 g_string_printf(fe_name, "syscall %d", i);
f95bc830 626 name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
b445142a 627 }
628
629 lttv_trace_find_hook(tcs->parent.t, "core", "trap_entry",
630 "trap_id", NULL, NULL, NULL, &h);
631 t = ltt_field_type(h.f1);
632 nb = ltt_type_element_number(t);
633
634 /*
f95bc830 635 name_tables->trap_names = g_new(GQuark, nb);
b445142a 636 for(i = 0 ; i < nb ; i++) {
f95bc830 637 name_tables->trap_names[i] = g_quark_from_string(
638 ltt_enum_string_get(t, i));
b445142a 639 }
640 */
641
f95bc830 642 name_tables->trap_names = g_new(GQuark, 256);
b445142a 643 for(i = 0 ; i < 256 ; i++) {
644 g_string_printf(fe_name, "trap %d", i);
f95bc830 645 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
b445142a 646 }
647
648 lttv_trace_find_hook(tcs->parent.t, "core", "irq_entry",
649 "irq_id", NULL, NULL, NULL, &h);
650 t = ltt_field_type(h.f1);
651 nb = ltt_type_element_number(t);
652
653 /*
f95bc830 654 name_tables->irq_names = g_new(GQuark, nb);
b445142a 655 for(i = 0 ; i < nb ; i++) {
f95bc830 656 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
b445142a 657 }
658 */
659
f95bc830 660 name_tables->irq_names = g_new(GQuark, 256);
b445142a 661 for(i = 0 ; i < 256 ; i++) {
662 g_string_printf(fe_name, "irq %d", i);
f95bc830 663 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
b445142a 664 }
665
666 g_string_free(fe_name, TRUE);
667}
668
669
f95bc830 670static void
671get_name_tables(LttvTraceState *tcs)
672{
673 LttvNameTables *name_tables;
674
675 LttvAttributeValue v;
676
677 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
678 LTTV_POINTER, &v);
679 g_assert(*(v.v_pointer) != NULL);
680 name_tables = (LttvNameTables *)*(v.v_pointer);
681 tcs->eventtype_names = name_tables->eventtype_names;
682 tcs->syscall_names = name_tables->syscall_names;
683 tcs->trap_names = name_tables->trap_names;
684 tcs->irq_names = name_tables->irq_names;
685}
686
687
b445142a 688static void
689free_name_tables(LttvTraceState *tcs)
690{
f95bc830 691 LttvNameTables *name_tables;
692
693 LttvAttributeValue v;
694
695 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
696 LTTV_POINTER, &v);
697 name_tables = (LttvNameTables *)*(v.v_pointer);
698 *(v.v_pointer) = NULL;
699
700 g_free(name_tables->eventtype_names);
701 g_free(name_tables->syscall_names);
702 g_free(name_tables->trap_names);
703 g_free(name_tables->irq_names);
704 g_free(name_tables);
b445142a 705}
dc877563 706
b445142a 707
708static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 709 guint state_id)
dc877563 710{
b445142a 711 LttvExecutionState *es;
dc877563 712
713 LttvProcessState *process = tfs->process;
714
b445142a 715 guint depth = process->execution_stack->len;
dc877563 716
b445142a 717 g_array_set_size(process->execution_stack, depth + 1);
718 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
719 es->t = t;
720 es->n = state_id;
721 es->entry = es->change = tfs->parent.timestamp;
722 es->s = process->state->s;
723 process->state = es;
dc877563 724}
725
726
b445142a 727static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 728{
729 LttvProcessState *process = tfs->process;
730
f95bc830 731 guint depth = process->execution_stack->len;
dc877563 732
3d27549e 733 if(process->state->t != t){
08b1c66e 734 g_info("Different execution mode type (%d.%09d): ignore it\n",
b445142a 735 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 736 g_info("process state has %s when pop_int is %s\n",
8e8e6b64 737 g_quark_to_string(process->state->t),
738 g_quark_to_string(t));
08b1c66e 739 g_info("{ %u, %u, %s, %s }\n",
8e8e6b64 740 process->pid,
741 process->ppid,
742 g_quark_to_string(process->name),
743 g_quark_to_string(process->state->s));
3d27549e 744 return;
745 }
b445142a 746
f95bc830 747 if(depth == 1){
08b1c66e 748 g_info("Trying to pop last state on stack (%d.%09d): ignore it\n",
b445142a 749 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
750 return;
751 }
752
f95bc830 753 g_array_set_size(process->execution_stack, depth - 1);
b445142a 754 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 755 depth - 2);
b445142a 756 process->state->change = tfs->parent.timestamp;
dc877563 757}
758
759
2a2fa4f0 760LttvProcessState *
761lttv_state_create_process(LttvTracefileState *tfs, LttvProcessState *parent,
762 guint pid)
dc877563 763{
764 LttvProcessState *process = g_new(LttvProcessState, 1);
765
b445142a 766 LttvExecutionState *es;
dc877563 767
ffd54a90 768 LttvTraceContext *tc;
769
ba576a78 770 LttvTraceState *tcs;
771
b445142a 772 char buffer[128];
ffd54a90 773
a5ba1787 774 tc = tfs->parent.t_context;
775 tcs = (LttvTraceState *)tc;
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
2cdc690b 989static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 990{
2cdc690b 991 LttField *f;
992 guint child_pid;
993
994 /* Child PID */
34871cd8 995 f = trace_hook->f2;
2cdc690b 996 child_pid = ltt_event_get_unsigned(s->parent.e, f);
997
998 lttv_state_create_process(s, s->process, child_pid);
999
1000 return FALSE;
1001#if 0
b445142a 1002 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 1003
ba576a78 1004 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1005
1006 guint child_pid;
1007
3d27549e 1008 child_pid = ltt_event_get_unsigned(s->parent.e, f);
2a2fa4f0 1009 lttv_state_create_process(s, s->process, child_pid);
dc877563 1010 return FALSE;
2cdc690b 1011#endif //0
dc877563 1012}
1013
1014
2cdc690b 1015static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 1016{
2cdc690b 1017 if(s->process != NULL) {
1018 s->process->state->s = LTTV_STATE_EXIT;
1019 }
1020 return FALSE;
1021
1022#if 0
ba576a78 1023 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1024
1025 if(s->process != NULL) {
ffd54a90 1026 s->process->state->s = LTTV_STATE_EXIT;
dc877563 1027 }
1028 return FALSE;
2cdc690b 1029#endif //0
1030}
1031
1032gboolean process(void *hook_data, void *call_data)
1033{
1034 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1035 LttField *f = trace_hook->f1;
1036
1037 LttvTracefileState *s = (LttvTracefileState *)call_data;
1038
1039 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1040
1041 /* CHECK : do not hardcode the sub_id values here ? */
1042 if(sub_id == 2) {
1043 return process_fork(trace_hook, s);
1044 } else if(sub_id == 3) {
1045 return process_exit(trace_hook, s);
1046 }
1047 return 0;
dc877563 1048}
1049
1050
308711e5 1051void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1052{
ba576a78 1053 LttvTraceset *traceset = self->parent.ts;
dc877563 1054
dbb7bb09 1055 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1056
ba576a78 1057 LttvTraceState *ts;
dc877563 1058
ba576a78 1059 LttvTracefileState *tfs;
dc877563 1060
dc877563 1061 GArray *hooks;
1062
b445142a 1063 LttvTraceHook hook;
dc877563 1064
1065 LttvAttributeValue val;
1066
ba576a78 1067 nb_trace = lttv_traceset_number(traceset);
dc877563 1068 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1069 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1070
1071 /* Find the eventtype id for the following events and register the
1072 associated by id hooks. */
1073
b445142a 1074 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
1075 g_array_set_size(hooks, 9);
1076
1077 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1078 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
cbe7c836 1079
b445142a 1080 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1081 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
cbe7c836 1082
b445142a 1083 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1084 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
cbe7c836 1085
b445142a 1086 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1087 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
cbe7c836 1088
b445142a 1089 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1090 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
cbe7c836 1091
b445142a 1092 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1093 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
cbe7c836 1094
b445142a 1095 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1096 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
cbe7c836 1097
2cdc690b 1098 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1099 "event_data1", "event_data2", process,
1100 &g_array_index(hooks, LttvTraceHook, 7));
1101
1102#if 0
b445142a 1103 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1104 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
cbe7c836 1105
b445142a 1106 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1107 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
2cdc690b 1108#endif //0
a5ba1787 1109 /* Add these hooks to each event_by_id hooks list */
dc877563 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);
a5ba1787 1119 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1120 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
ffd54a90 1121 }
dc877563 1122 }
ba576a78 1123 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1124 *(val.v_pointer) = hooks;
dc877563 1125 }
1126}
1127
1128
308711e5 1129void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1130{
ba576a78 1131 LttvTraceset *traceset = self->parent.ts;
dc877563 1132
dbb7bb09 1133 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1134
ba576a78 1135 LttvTraceState *ts;
dc877563 1136
ba576a78 1137 LttvTracefileState *tfs;
dc877563 1138
dc877563 1139 GArray *hooks;
1140
b445142a 1141 LttvTraceHook hook;
dc877563 1142
1143 LttvAttributeValue val;
1144
ba576a78 1145 nb_trace = lttv_traceset_number(traceset);
dc877563 1146 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1147 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1148 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1149 hooks = *(val.v_pointer);
dc877563 1150
a5ba1787 1151 /* Remove these hooks from each event_by_id hooks list */
dc877563 1152
dbb7bb09 1153 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1154 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1155
dc877563 1156 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1157 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1158
1159 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1160 hook = g_array_index(hooks, LttvTraceHook, k);
ba576a78 1161 lttv_hooks_remove_data(
a5ba1787 1162 lttv_hooks_by_id_find(tfs->parent.event_by_id,
b445142a 1163 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1164 }
dc877563 1165 }
1166 g_array_free(hooks, TRUE);
1167 }
1168}
1169
1170
08b1c66e 1171static gboolean block_start(void *hook_data, void *call_data)
308711e5 1172{
dbb7bb09 1173 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1174
dbb7bb09 1175 LttvTracefileState *tfcs;
308711e5 1176
dbb7bb09 1177 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1178
1179 LttEventPosition *ep;
308711e5 1180
dbb7bb09 1181 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1182
1183 LttTracefile *tf;
1184
1185 LttvAttribute *saved_states_tree, *saved_state_tree;
1186
1187 LttvAttributeValue value;
1188
dbb7bb09 1189 ep = ltt_event_position_new();
1190 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1191 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1192
1193 /* Count the number of events added since the last block end in any
1194 tracefile. */
1195
1196 for(i = 0 ; i < nb_tracefile ; i++) {
1197 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1198 ltt_event_position(tfcs->parent.e, ep);
1199 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1200 tcs->nb_event += nb_event - tfcs->saved_position;
1201 tfcs->saved_position = nb_event;
1202 }
1203 g_free(ep);
308711e5 1204
308711e5 1205 if(tcs->nb_event >= tcs->save_interval) {
1206 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1207 LTTV_STATE_SAVED_STATES);
1208 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1209 value = lttv_attribute_add(saved_states_tree,
1210 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1211 *(value.v_gobject) = (GObject *)saved_state_tree;
1212 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1213 *(value.v_time) = self->parent.timestamp;
308711e5 1214 lttv_state_save(tcs, saved_state_tree);
1215 tcs->nb_event = 0;
08b1c66e 1216 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1217 self->parent.timestamp.tv_nsec);
308711e5 1218 }
dbb7bb09 1219 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1220 return FALSE;
1221}
1222
1223
08b1c66e 1224static gboolean block_end(void *hook_data, void *call_data)
1225{
1226 LttvTracefileState *self = (LttvTracefileState *)call_data;
1227
1228 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1229
1230 LttTracefile *tf;
1231
1232 LttEventPosition *ep;
1233
1234 guint nb_block, nb_event;
1235
1236 ep = ltt_event_position_new();
1237 ltt_event_position(self->parent.e, ep);
1238 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1239 tcs->nb_event += nb_event - self->saved_position + 1;
1240 self->saved_position = 0;
1241 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1242 g_free(ep);
1243}
1244
1245
308711e5 1246void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1247{
1248 LttvTraceset *traceset = self->parent.ts;
1249
dbb7bb09 1250 guint i, j, k, nb_trace, nb_tracefile;
308711e5 1251
1252 LttvTraceState *ts;
1253
1254 LttvTracefileState *tfs;
1255
08b1c66e 1256 LttvTraceHook hook_start, hook_end;
308711e5 1257
1258 nb_trace = lttv_traceset_number(traceset);
1259 for(i = 0 ; i < nb_trace ; i++) {
1260 ts = (LttvTraceState *)self->parent.traces[i];
08b1c66e 1261 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1262 NULL, NULL, block_start, &hook_start);
308711e5 1263 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1264 NULL, NULL, block_end, &hook_end);
308711e5 1265
dbb7bb09 1266 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1267 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1268
dbb7bb09 1269 for(j = 0 ; j < nb_tracefile ; j++) {
1270 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
a5ba1787 1271 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1272 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1273 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1274 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
308711e5 1275 }
1276 }
1277}
1278
b56b5fec 1279gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1280{
1281 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1282
1283 lttv_state_save_add_event_hooks(tss);
1284
1285 return 0;
1286}
1287
308711e5 1288
1289void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1290{
1291 LttvTraceset *traceset = self->parent.ts;
1292
dbb7bb09 1293 guint i, j, k, nb_trace, nb_tracefile;
308711e5 1294
1295 LttvTraceState *ts;
1296
1297 LttvTracefileState *tfs;
1298
08b1c66e 1299 LttvTraceHook hook_start, hook_end;
308711e5 1300
1301 nb_trace = lttv_traceset_number(traceset);
1302 for(i = 0 ; i < nb_trace ; i++) {
1303 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
08b1c66e 1304 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1305 NULL, NULL, block_start, &hook_start);
1306
308711e5 1307 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1308 NULL, NULL, block_end, &hook_end);
308711e5 1309
dbb7bb09 1310 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1311 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1312
dbb7bb09 1313 for(j = 0 ; j < nb_tracefile ; j++) {
1314 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1315 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1316 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1317 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1318 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1319 }
1320 }
1321}
1322
b56b5fec 1323gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1324{
1325 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1326
1327 lttv_state_save_remove_event_hooks(tss);
1328
1329 return 0;
1330}
308711e5 1331
dd025f91 1332void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1333{
1334 LttvTraceset *traceset = self->parent.ts;
1335
1336 guint i, j, nb_trace, nb_saved_state;
1337
1338 int min_pos, mid_pos, max_pos;
1339
1340 LttvTraceState *tcs;
1341
1342 LttvAttributeValue value;
1343
1344 LttvAttributeType type;
1345
1346 LttvAttributeName name;
1347
1348 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1349
1350 nb_trace = lttv_traceset_number(traceset);
1351 for(i = 0 ; i < nb_trace ; i++) {
1352 tcs = (LttvTraceState *)self->parent.traces[i];
1353
2a2fa4f0 1354 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1355 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1356 LTTV_STATE_SAVED_STATES);
1357 min_pos = -1;
1358
1359 if(saved_states_tree) {
dd025f91 1360 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1361 mid_pos = max_pos / 2;
1362 while(min_pos < max_pos) {
1363 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1364 g_assert(type == LTTV_GOBJECT);
1365 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1366 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1367 &value);
1368 g_assert(type == LTTV_TIME);
1369 if(ltt_time_compare(*(value.v_time), t) < 0) {
1370 min_pos = mid_pos;
1371 closest_tree = saved_state_tree;
1372 }
1373 else max_pos = mid_pos - 1;
1374
1375 mid_pos = (min_pos + max_pos + 1) / 2;
1376 }
2a2fa4f0 1377 }
dd025f91 1378
2a2fa4f0 1379 /* restore the closest earlier saved state */
f95bc830 1380 if(min_pos != -1) {
1381 lttv_state_restore(tcs, closest_tree);
1382 }
dd025f91 1383
2a2fa4f0 1384 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1385 else {
1386 restore_init_state(tcs);
1387 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1388 }
9444deae 1389 }
dd025f91 1390 /* We want to seek quickly without restoring/updating the state */
1391 else {
308711e5 1392 restore_init_state(tcs);
dd025f91 1393 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1394 }
308711e5 1395 }
1396}
1397
1398
1399static void
1400traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1401{
1402}
1403
1404
1405static void
1406traceset_state_finalize (LttvTracesetState *self)
1407{
1408 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1409 finalize(G_OBJECT(self));
1410}
1411
1412
1413static void
1414traceset_state_class_init (LttvTracesetContextClass *klass)
1415{
1416 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1417
1418 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1419 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1420 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1421 klass->new_traceset_context = new_traceset_context;
1422 klass->new_trace_context = new_trace_context;
1423 klass->new_tracefile_context = new_tracefile_context;
1424}
1425
1426
1427GType
1428lttv_traceset_state_get_type(void)
1429{
1430 static GType type = 0;
1431 if (type == 0) {
1432 static const GTypeInfo info = {
1433 sizeof (LttvTracesetStateClass),
1434 NULL, /* base_init */
1435 NULL, /* base_finalize */
1436 (GClassInitFunc) traceset_state_class_init, /* class_init */
1437 NULL, /* class_finalize */
1438 NULL, /* class_data */
dbb7bb09 1439 sizeof (LttvTracesetState),
308711e5 1440 0, /* n_preallocs */
1441 (GInstanceInitFunc) traceset_state_instance_init /* instance_init */
1442 };
1443
1444 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1445 &info, 0);
1446 }
1447 return type;
1448}
1449
1450
1451static void
1452trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1453{
1454}
1455
1456
1457static void
1458trace_state_finalize (LttvTraceState *self)
1459{
1460 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1461 finalize(G_OBJECT(self));
1462}
1463
1464
1465static void
1466trace_state_class_init (LttvTraceStateClass *klass)
1467{
1468 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1469
1470 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1471 klass->state_save = state_save;
1472 klass->state_restore = state_restore;
1473 klass->state_saved_free = state_saved_free;
1474}
1475
1476
1477GType
1478lttv_trace_state_get_type(void)
1479{
1480 static GType type = 0;
1481 if (type == 0) {
1482 static const GTypeInfo info = {
1483 sizeof (LttvTraceStateClass),
1484 NULL, /* base_init */
1485 NULL, /* base_finalize */
1486 (GClassInitFunc) trace_state_class_init, /* class_init */
1487 NULL, /* class_finalize */
1488 NULL, /* class_data */
1489 sizeof (LttvTraceState),
1490 0, /* n_preallocs */
1491 (GInstanceInitFunc) trace_state_instance_init /* instance_init */
1492 };
1493
1494 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1495 "LttvTraceStateType", &info, 0);
1496 }
1497 return type;
1498}
1499
1500
1501static void
1502tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1503{
1504}
1505
1506
1507static void
1508tracefile_state_finalize (LttvTracefileState *self)
1509{
1510 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1511 finalize(G_OBJECT(self));
1512}
1513
1514
1515static void
1516tracefile_state_class_init (LttvTracefileStateClass *klass)
1517{
1518 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1519
1520 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1521}
1522
1523
1524GType
1525lttv_tracefile_state_get_type(void)
1526{
1527 static GType type = 0;
1528 if (type == 0) {
1529 static const GTypeInfo info = {
1530 sizeof (LttvTracefileStateClass),
1531 NULL, /* base_init */
1532 NULL, /* base_finalize */
1533 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1534 NULL, /* class_finalize */
1535 NULL, /* class_data */
1536 sizeof (LttvTracefileState),
1537 0, /* n_preallocs */
1538 (GInstanceInitFunc) tracefile_state_instance_init /* instance_init */
1539 };
1540
1541 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1542 "LttvTracefileStateType", &info, 0);
1543 }
1544 return type;
1545}
1546
1547
08b1c66e 1548static void module_init()
ffd54a90 1549{
1550 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 1551 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 1552 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1553 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1554 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1555 LTTV_STATE_TRAP = g_quark_from_string("trap");
1556 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 1557 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1558 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 1559 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1560 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1561 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1562 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 1563 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1564 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1565 LTTV_STATE_PROCESS = g_quark_from_string("process");
1566 LTTV_STATE_EVENT = g_quark_from_string("event");
1567 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 1568 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 1569 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 1570 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 1571 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1572 LTTV_STATE_TRACE_STATE_USE_COUNT =
1573 g_quark_from_string("trace_state_use_count");
ffd54a90 1574}
dc877563 1575
08b1c66e 1576static void module_destroy()
ffd54a90 1577{
1578}
dc877563 1579
1580
08b1c66e 1581LTTV_MODULE("state", "State computation", \
1582 "Update the system state, possibly saving it at intervals", \
1583 module_init, module_destroy)
1584
dc877563 1585
1586
This page took 0.102142 seconds and 4 git commands to generate.