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