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