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