desactivate exit_process until we have the release_task event
[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.
846 *
847 * This function is important : it removes the dead PID entry in the hash
848 * table so there is no collision when the OS reuses PID.
849 */
b445142a 850static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 851{
ba576a78 852 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 853 LttvProcessState key;
ba576a78 854
2a2fa4f0 855 key.pid = process->pid;
856 key.last_cpu = process->last_cpu;
857 g_hash_table_remove(ts->processes, &key);
b445142a 858 g_array_free(process->execution_stack, TRUE);
dc877563 859 g_free(process);
860}
861
862
b445142a 863static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 864{
b445142a 865 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
dc877563 866 g_free(value);
867}
868
869
308711e5 870static void lttv_state_free_process_table(GHashTable *processes)
dc877563 871{
872 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 873 g_hash_table_destroy(processes);
dc877563 874}
875
876
b445142a 877static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 878{
b445142a 879 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 880
ba576a78 881 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 882
b445142a 883 LttvExecutionSubmode submode;
884
885 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
886 ltt_event_get_unsigned(s->parent.e, f)];
887 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 888 return FALSE;
889}
890
891
b445142a 892static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 893{
ba576a78 894 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 895
ffd54a90 896 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 897 return FALSE;
898}
899
900
b445142a 901static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 902{
b445142a 903 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 904
ba576a78 905 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 906
b445142a 907 LttvExecutionSubmode submode;
908
909 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[
910 ltt_event_get_unsigned(s->parent.e, f)];
911 push_state(s, LTTV_STATE_TRAP, submode);
dc877563 912 return FALSE;
913}
914
915
b445142a 916static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 917{
ba576a78 918 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 919
ffd54a90 920 pop_state(s, LTTV_STATE_TRAP);
dc877563 921 return FALSE;
922}
923
924
b445142a 925static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 926{
b445142a 927 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 928
ba576a78 929 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 930
b445142a 931 LttvExecutionSubmode submode;
932
933 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[
934 ltt_event_get_unsigned(s->parent.e, f)];
935
dc877563 936 /* Do something with the info about being in user or system mode when int? */
b445142a 937 push_state(s, LTTV_STATE_IRQ, submode);
dc877563 938 return FALSE;
939}
940
941
b445142a 942static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 943{
ba576a78 944 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 945
ffd54a90 946 pop_state(s, LTTV_STATE_IRQ);
dc877563 947 return FALSE;
948}
949
950
b445142a 951static gboolean schedchange(void *hook_data, void *call_data)
dc877563 952{
b445142a 953 LttvTraceHook *h = (LttvTraceHook *)hook_data;
dc877563 954
ba576a78 955 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 956
957 guint pid_in, pid_out, state_out;
958
3d27549e 959 pid_in = ltt_event_get_unsigned(s->parent.e, h->f1);
960 pid_out = ltt_event_get_unsigned(s->parent.e, h->f2);
961 state_out = ltt_event_get_unsigned(s->parent.e, h->f3);
b445142a 962
dc877563 963 if(s->process != NULL) {
b445142a 964
f95bc830 965 /* We could not know but it was not the idle process executing.
966 This should only happen at the beginning, before the first schedule
967 event, and when the initial information (current process for each CPU)
968 is missing. It is not obvious how we could, after the fact, compensate
969 the wrongly attributed statistics. */
970
971 if(s->process->pid != pid_out) {
972 g_assert(s->process->pid == 0);
973 }
974
41c7f803 975 if(s->process->state->s != LTTV_STATE_EXIT) {
976 if(state_out == 0) s->process->state->s = LTTV_STATE_WAIT_CPU;
977 else s->process->state->s = LTTV_STATE_WAIT;
978 } /* FIXME : we do not remove process here, because the kernel
979 * still has them : they may be zombies. We need to know
980 * exactly when release_task is executed on the PID to
981 * know when the zombie is destroyed. We should rename STATE_EXIT
982 * for STATE_ZOMBIE.
983 */
984 //else
985 // exit_process(s, s->process);
3d27549e 986
b445142a 987 s->process->state->change = s->parent.timestamp;
dc877563 988 }
2a2fa4f0 989 s->process = lttv_state_find_process_or_create(s, pid_in);
ffd54a90 990 s->process->state->s = LTTV_STATE_RUN;
2a2fa4f0 991 s->process->last_cpu = s->cpu_name;
b445142a 992 s->process->state->change = s->parent.timestamp;
dc877563 993 return FALSE;
994}
995
996
2cdc690b 997static gboolean process_fork(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 998{
2cdc690b 999 LttField *f;
1000 guint child_pid;
1001
1002 /* Child PID */
34871cd8 1003 f = trace_hook->f2;
2cdc690b 1004 child_pid = ltt_event_get_unsigned(s->parent.e, f);
1005
1006 lttv_state_create_process(s, s->process, child_pid);
1007
1008 return FALSE;
1009#if 0
b445142a 1010 LttField *f = ((LttvTraceHook *)hook_data)->f1;
dc877563 1011
ba576a78 1012 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1013
1014 guint child_pid;
1015
3d27549e 1016 child_pid = ltt_event_get_unsigned(s->parent.e, f);
2a2fa4f0 1017 lttv_state_create_process(s, s->process, child_pid);
dc877563 1018 return FALSE;
2cdc690b 1019#endif //0
dc877563 1020}
1021
1022
2cdc690b 1023static gboolean process_exit(LttvTraceHook *trace_hook, LttvTracefileState *s)
dc877563 1024{
2cdc690b 1025 if(s->process != NULL) {
1026 s->process->state->s = LTTV_STATE_EXIT;
1027 }
1028 return FALSE;
1029
1030#if 0
ba576a78 1031 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 1032
1033 if(s->process != NULL) {
ffd54a90 1034 s->process->state->s = LTTV_STATE_EXIT;
dc877563 1035 }
1036 return FALSE;
2cdc690b 1037#endif //0
1038}
1039
1040gboolean process(void *hook_data, void *call_data)
1041{
1042 LttvTraceHook *trace_hook = (LttvTraceHook *)hook_data;
1043 LttField *f = trace_hook->f1;
1044
1045 LttvTracefileState *s = (LttvTracefileState *)call_data;
1046
1047 guint sub_id = ltt_event_get_unsigned(s->parent.e, f);
1048
1049 /* CHECK : do not hardcode the sub_id values here ? */
1050 if(sub_id == 2) {
1051 return process_fork(trace_hook, s);
1052 } else if(sub_id == 3) {
1053 return process_exit(trace_hook, s);
1054 }
1055 return 0;
dc877563 1056}
1057
58c88a41 1058gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
1059{
1060 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1061
1062 lttv_state_add_event_hooks(tss);
1063
1064 return 0;
1065}
dc877563 1066
308711e5 1067void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 1068{
ba576a78 1069 LttvTraceset *traceset = self->parent.ts;
dc877563 1070
dbb7bb09 1071 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1072
ba576a78 1073 LttvTraceState *ts;
dc877563 1074
ba576a78 1075 LttvTracefileState *tfs;
dc877563 1076
dc877563 1077 GArray *hooks;
1078
b445142a 1079 LttvTraceHook hook;
dc877563 1080
1081 LttvAttributeValue val;
1082
ba576a78 1083 nb_trace = lttv_traceset_number(traceset);
dc877563 1084 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1085 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 1086
1087 /* Find the eventtype id for the following events and register the
1088 associated by id hooks. */
1089
b445142a 1090 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
facab7c2 1091 g_array_set_size(hooks, 8);
b445142a 1092
1093 lttv_trace_find_hook(ts->parent.t, "core","syscall_entry","syscall_id",
1094 NULL, NULL, syscall_entry, &g_array_index(hooks, LttvTraceHook, 0));
cbe7c836 1095
b445142a 1096 lttv_trace_find_hook(ts->parent.t, "core", "syscall_exit", NULL, NULL,
1097 NULL, syscall_exit, &g_array_index(hooks, LttvTraceHook, 1));
cbe7c836 1098
b445142a 1099 lttv_trace_find_hook(ts->parent.t, "core", "trap_entry", "trap_id",
1100 NULL, NULL, trap_entry, &g_array_index(hooks, LttvTraceHook, 2));
cbe7c836 1101
b445142a 1102 lttv_trace_find_hook(ts->parent.t, "core", "trap_exit", NULL, NULL, NULL,
1103 trap_exit, &g_array_index(hooks, LttvTraceHook, 3));
cbe7c836 1104
b445142a 1105 lttv_trace_find_hook(ts->parent.t, "core", "irq_entry", "irq_id", NULL,
1106 NULL, irq_entry, &g_array_index(hooks, LttvTraceHook, 4));
cbe7c836 1107
b445142a 1108 lttv_trace_find_hook(ts->parent.t, "core", "irq_exit", NULL, NULL, NULL,
1109 irq_exit, &g_array_index(hooks, LttvTraceHook, 5));
cbe7c836 1110
b445142a 1111 lttv_trace_find_hook(ts->parent.t, "core", "schedchange", "in", "out",
1112 "out_state", schedchange, &g_array_index(hooks, LttvTraceHook, 6));
cbe7c836 1113
2cdc690b 1114 lttv_trace_find_hook(ts->parent.t, "core", "process", "event_sub_id",
1115 "event_data1", "event_data2", process,
1116 &g_array_index(hooks, LttvTraceHook, 7));
1117
1118#if 0
b445142a 1119 lttv_trace_find_hook(ts->parent.t, "core", "process_fork", "child_pid",
1120 NULL, NULL, process_fork, &g_array_index(hooks, LttvTraceHook, 7));
cbe7c836 1121
b445142a 1122 lttv_trace_find_hook(ts->parent.t, "core", "process_exit", NULL, NULL,
1123 NULL, process_exit, &g_array_index(hooks, LttvTraceHook, 8));
2cdc690b 1124#endif //0
a5ba1787 1125 /* Add these hooks to each event_by_id hooks list */
dc877563 1126
dbb7bb09 1127 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1128 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1129
dc877563 1130 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1131 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1132
1133 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1134 hook = g_array_index(hooks, LttvTraceHook, k);
a5ba1787 1135 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1136 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k), LTTV_PRIO_STATE);
ffd54a90 1137 }
dc877563 1138 }
ba576a78 1139 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1140 *(val.v_pointer) = hooks;
dc877563 1141 }
1142}
1143
58c88a41 1144gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
1145{
1146 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1147
1148 lttv_state_remove_event_hooks(tss);
1149
1150 return 0;
1151}
dc877563 1152
308711e5 1153void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 1154{
ba576a78 1155 LttvTraceset *traceset = self->parent.ts;
dc877563 1156
dbb7bb09 1157 guint i, j, k, nb_trace, nb_tracefile;
dc877563 1158
ba576a78 1159 LttvTraceState *ts;
dc877563 1160
ba576a78 1161 LttvTracefileState *tfs;
dc877563 1162
dc877563 1163 GArray *hooks;
1164
b445142a 1165 LttvTraceHook hook;
dc877563 1166
1167 LttvAttributeValue val;
1168
ba576a78 1169 nb_trace = lttv_traceset_number(traceset);
dc877563 1170 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 1171 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
1172 lttv_attribute_find(self->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
1173 hooks = *(val.v_pointer);
dc877563 1174
a5ba1787 1175 /* Remove these hooks from each event_by_id hooks list */
dc877563 1176
dbb7bb09 1177 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1178 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
1179
dc877563 1180 for(j = 0 ; j < nb_tracefile ; j++) {
dbb7bb09 1181 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
dc877563 1182
1183 for(k = 0 ; k < hooks->len ; k++) {
b445142a 1184 hook = g_array_index(hooks, LttvTraceHook, k);
ba576a78 1185 lttv_hooks_remove_data(
a5ba1787 1186 lttv_hooks_by_id_find(tfs->parent.event_by_id,
b445142a 1187 hook.id), hook.h, &g_array_index(hooks, LttvTraceHook, k));
ffd54a90 1188 }
dc877563 1189 }
1190 g_array_free(hooks, TRUE);
1191 }
1192}
1193
1194
08b1c66e 1195static gboolean block_start(void *hook_data, void *call_data)
308711e5 1196{
dbb7bb09 1197 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 1198
dbb7bb09 1199 LttvTracefileState *tfcs;
308711e5 1200
dbb7bb09 1201 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1202
1203 LttEventPosition *ep;
308711e5 1204
dbb7bb09 1205 guint i, nb_block, nb_event, nb_tracefile;
308711e5 1206
1207 LttTracefile *tf;
1208
1209 LttvAttribute *saved_states_tree, *saved_state_tree;
1210
1211 LttvAttributeValue value;
1212
dbb7bb09 1213 ep = ltt_event_position_new();
1214 nb_tracefile = ltt_trace_control_tracefile_number(tcs->parent.t) +
1215 ltt_trace_per_cpu_tracefile_number(tcs->parent.t);
1216
1217 /* Count the number of events added since the last block end in any
1218 tracefile. */
1219
1220 for(i = 0 ; i < nb_tracefile ; i++) {
1221 tfcs = (LttvTracefileState *)tcs->parent.tracefiles[i];
1222 ltt_event_position(tfcs->parent.e, ep);
1223 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1224 tcs->nb_event += nb_event - tfcs->saved_position;
1225 tfcs->saved_position = nb_event;
1226 }
1227 g_free(ep);
308711e5 1228
308711e5 1229 if(tcs->nb_event >= tcs->save_interval) {
1230 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1231 LTTV_STATE_SAVED_STATES);
1232 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1233 value = lttv_attribute_add(saved_states_tree,
1234 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1235 *(value.v_gobject) = (GObject *)saved_state_tree;
1236 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 1237 *(value.v_time) = self->parent.timestamp;
308711e5 1238 lttv_state_save(tcs, saved_state_tree);
1239 tcs->nb_event = 0;
08b1c66e 1240 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
1241 self->parent.timestamp.tv_nsec);
308711e5 1242 }
dbb7bb09 1243 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 1244 return FALSE;
1245}
1246
1247
08b1c66e 1248static gboolean block_end(void *hook_data, void *call_data)
1249{
1250 LttvTracefileState *self = (LttvTracefileState *)call_data;
1251
1252 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
1253
1254 LttTracefile *tf;
1255
1256 LttEventPosition *ep;
1257
1258 guint nb_block, nb_event;
1259
1260 ep = ltt_event_position_new();
1261 ltt_event_position(self->parent.e, ep);
1262 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
1263 tcs->nb_event += nb_event - self->saved_position + 1;
1264 self->saved_position = 0;
1265 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
1266 g_free(ep);
00e74b69 1267
1268 return FALSE;
08b1c66e 1269}
1270
1271
308711e5 1272void lttv_state_save_add_event_hooks(LttvTracesetState *self)
1273{
1274 LttvTraceset *traceset = self->parent.ts;
1275
00e74b69 1276 guint i, j, nb_trace, nb_tracefile;
308711e5 1277
1278 LttvTraceState *ts;
1279
1280 LttvTracefileState *tfs;
1281
08b1c66e 1282 LttvTraceHook hook_start, hook_end;
308711e5 1283
1284 nb_trace = lttv_traceset_number(traceset);
1285 for(i = 0 ; i < nb_trace ; i++) {
1286 ts = (LttvTraceState *)self->parent.traces[i];
08b1c66e 1287 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1288 NULL, NULL, block_start, &hook_start);
308711e5 1289 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1290 NULL, NULL, block_end, &hook_end);
308711e5 1291
dbb7bb09 1292 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1293 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1294
dbb7bb09 1295 for(j = 0 ; j < nb_tracefile ; j++) {
1296 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
a5ba1787 1297 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1298 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
1299 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
1300 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
308711e5 1301 }
1302 }
1303}
1304
b56b5fec 1305gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
1306{
1307 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1308
1309 lttv_state_save_add_event_hooks(tss);
1310
1311 return 0;
1312}
1313
308711e5 1314
1315void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
1316{
1317 LttvTraceset *traceset = self->parent.ts;
1318
00e74b69 1319 guint i, j, nb_trace, nb_tracefile;
308711e5 1320
1321 LttvTraceState *ts;
1322
1323 LttvTracefileState *tfs;
1324
08b1c66e 1325 LttvTraceHook hook_start, hook_end;
308711e5 1326
1327 nb_trace = lttv_traceset_number(traceset);
1328 for(i = 0 ; i < nb_trace ; i++) {
1329 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
08b1c66e 1330 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
1331 NULL, NULL, block_start, &hook_start);
1332
308711e5 1333 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
08b1c66e 1334 NULL, NULL, block_end, &hook_end);
308711e5 1335
dbb7bb09 1336 nb_tracefile = ltt_trace_control_tracefile_number(ts->parent.t) +
1337 ltt_trace_per_cpu_tracefile_number(ts->parent.t);
308711e5 1338
dbb7bb09 1339 for(j = 0 ; j < nb_tracefile ; j++) {
1340 tfs = LTTV_TRACEFILE_STATE(ts->parent.tracefiles[j]);
308711e5 1341 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1342 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 1343 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 1344 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 1345 }
1346 }
1347}
1348
b56b5fec 1349gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
1350{
1351 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
1352
1353 lttv_state_save_remove_event_hooks(tss);
1354
1355 return 0;
1356}
308711e5 1357
dd025f91 1358void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 1359{
1360 LttvTraceset *traceset = self->parent.ts;
1361
00e74b69 1362 guint i, nb_trace;
308711e5 1363
1364 int min_pos, mid_pos, max_pos;
1365
1366 LttvTraceState *tcs;
1367
1368 LttvAttributeValue value;
1369
1370 LttvAttributeType type;
1371
1372 LttvAttributeName name;
1373
1374 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
1375
1376 nb_trace = lttv_traceset_number(traceset);
1377 for(i = 0 ; i < nb_trace ; i++) {
1378 tcs = (LttvTraceState *)self->parent.traces[i];
1379
2a2fa4f0 1380 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
1381 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
1382 LTTV_STATE_SAVED_STATES);
1383 min_pos = -1;
1384
1385 if(saved_states_tree) {
dd025f91 1386 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
1387 mid_pos = max_pos / 2;
1388 while(min_pos < max_pos) {
1389 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value);
1390 g_assert(type == LTTV_GOBJECT);
1391 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
1392 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
1393 &value);
1394 g_assert(type == LTTV_TIME);
1395 if(ltt_time_compare(*(value.v_time), t) < 0) {
1396 min_pos = mid_pos;
1397 closest_tree = saved_state_tree;
1398 }
1399 else max_pos = mid_pos - 1;
1400
1401 mid_pos = (min_pos + max_pos + 1) / 2;
1402 }
2a2fa4f0 1403 }
dd025f91 1404
2a2fa4f0 1405 /* restore the closest earlier saved state */
f95bc830 1406 if(min_pos != -1) {
1407 lttv_state_restore(tcs, closest_tree);
1408 }
dd025f91 1409
2a2fa4f0 1410 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 1411 else {
1412 restore_init_state(tcs);
1413 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 1414 }
9444deae 1415 }
dd025f91 1416 /* We want to seek quickly without restoring/updating the state */
1417 else {
308711e5 1418 restore_init_state(tcs);
dd025f91 1419 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 1420 }
308711e5 1421 }
1422}
1423
1424
1425static void
1426traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
1427{
1428}
1429
1430
1431static void
1432traceset_state_finalize (LttvTracesetState *self)
1433{
1434 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
1435 finalize(G_OBJECT(self));
1436}
1437
1438
1439static void
1440traceset_state_class_init (LttvTracesetContextClass *klass)
1441{
1442 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1443
1444 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
1445 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
1446 klass->fini = (void (*)(LttvTracesetContext *self))fini;
1447 klass->new_traceset_context = new_traceset_context;
1448 klass->new_trace_context = new_trace_context;
1449 klass->new_tracefile_context = new_tracefile_context;
1450}
1451
1452
1453GType
1454lttv_traceset_state_get_type(void)
1455{
1456 static GType type = 0;
1457 if (type == 0) {
1458 static const GTypeInfo info = {
1459 sizeof (LttvTracesetStateClass),
1460 NULL, /* base_init */
1461 NULL, /* base_finalize */
1462 (GClassInitFunc) traceset_state_class_init, /* class_init */
1463 NULL, /* class_finalize */
1464 NULL, /* class_data */
dbb7bb09 1465 sizeof (LttvTracesetState),
308711e5 1466 0, /* n_preallocs */
00e74b69 1467 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
1468 NULL /* value handling */
308711e5 1469 };
1470
1471 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
1472 &info, 0);
1473 }
1474 return type;
1475}
1476
1477
1478static void
1479trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
1480{
1481}
1482
1483
1484static void
1485trace_state_finalize (LttvTraceState *self)
1486{
1487 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
1488 finalize(G_OBJECT(self));
1489}
1490
1491
1492static void
1493trace_state_class_init (LttvTraceStateClass *klass)
1494{
1495 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1496
1497 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
1498 klass->state_save = state_save;
1499 klass->state_restore = state_restore;
1500 klass->state_saved_free = state_saved_free;
1501}
1502
1503
1504GType
1505lttv_trace_state_get_type(void)
1506{
1507 static GType type = 0;
1508 if (type == 0) {
1509 static const GTypeInfo info = {
1510 sizeof (LttvTraceStateClass),
1511 NULL, /* base_init */
1512 NULL, /* base_finalize */
1513 (GClassInitFunc) trace_state_class_init, /* class_init */
1514 NULL, /* class_finalize */
1515 NULL, /* class_data */
1516 sizeof (LttvTraceState),
1517 0, /* n_preallocs */
00e74b69 1518 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
1519 NULL /* value handling */
308711e5 1520 };
1521
1522 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
1523 "LttvTraceStateType", &info, 0);
1524 }
1525 return type;
1526}
1527
1528
1529static void
1530tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
1531{
1532}
1533
1534
1535static void
1536tracefile_state_finalize (LttvTracefileState *self)
1537{
1538 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
1539 finalize(G_OBJECT(self));
1540}
1541
1542
1543static void
1544tracefile_state_class_init (LttvTracefileStateClass *klass)
1545{
1546 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1547
1548 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
1549}
1550
1551
1552GType
1553lttv_tracefile_state_get_type(void)
1554{
1555 static GType type = 0;
1556 if (type == 0) {
1557 static const GTypeInfo info = {
1558 sizeof (LttvTracefileStateClass),
1559 NULL, /* base_init */
1560 NULL, /* base_finalize */
1561 (GClassInitFunc) tracefile_state_class_init, /* class_init */
1562 NULL, /* class_finalize */
1563 NULL, /* class_data */
1564 sizeof (LttvTracefileState),
1565 0, /* n_preallocs */
00e74b69 1566 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
1567 NULL /* value handling */
308711e5 1568 };
1569
1570 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
1571 "LttvTracefileStateType", &info, 0);
1572 }
1573 return type;
1574}
1575
1576
08b1c66e 1577static void module_init()
ffd54a90 1578{
1579 LTTV_STATE_UNNAMED = g_quark_from_string("unnamed");
b445142a 1580 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("unknown execution mode");
ffd54a90 1581 LTTV_STATE_USER_MODE = g_quark_from_string("user mode");
1582 LTTV_STATE_WAIT_FORK = g_quark_from_string("wait fork");
1583 LTTV_STATE_SYSCALL = g_quark_from_string("system call");
1584 LTTV_STATE_TRAP = g_quark_from_string("trap");
1585 LTTV_STATE_IRQ = g_quark_from_string("irq");
b445142a 1586 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("unknown submode");
1587 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("(no submode)");
ffd54a90 1588 LTTV_STATE_WAIT_CPU = g_quark_from_string("wait for cpu");
1589 LTTV_STATE_EXIT = g_quark_from_string("exiting");
1590 LTTV_STATE_WAIT = g_quark_from_string("wait for I/O");
1591 LTTV_STATE_RUN = g_quark_from_string("running");
308711e5 1592 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
1593 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
1594 LTTV_STATE_PROCESS = g_quark_from_string("process");
1595 LTTV_STATE_EVENT = g_quark_from_string("event");
1596 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 1597 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 1598 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 1599 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 1600 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
1601 LTTV_STATE_TRACE_STATE_USE_COUNT =
1602 g_quark_from_string("trace_state_use_count");
ffd54a90 1603}
dc877563 1604
08b1c66e 1605static void module_destroy()
ffd54a90 1606{
1607}
dc877563 1608
1609
08b1c66e 1610LTTV_MODULE("state", "State computation", \
1611 "Update the system state, possibly saving it at intervals", \
1612 module_init, module_destroy)
1613
dc877563 1614
1615
This page took 0.10698 seconds and 4 git commands to generate.