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