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