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