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