add support for block devices in restore_init_state()
[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
4e4d11b3 19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
dc877563 22
08b1c66e 23#include <lttv/lttv.h>
24#include <lttv/module.h>
dc877563 25#include <lttv/state.h>
ba576a78 26#include <ltt/facility.h>
27#include <ltt/trace.h>
308711e5 28#include <ltt/event.h>
a5dcde2f 29#include <ltt/type.h>
f95bc830 30#include <stdio.h>
b3fd4c02 31#include <string.h>
dc877563 32
7df20ca4 33/* Comment :
34 * Mathieu Desnoyers
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
38 *
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
41 */
42
e8f2280c 43#define PREALLOCATED_EXECUTION_STACK 10
44
eed2ef37 45/* Facilities Quarks */
46
47GQuark
48 LTT_FACILITY_KERNEL,
f5d7967f 49 LTT_FACILITY_KERNEL_ARCH,
86c32a8f 50 LTT_FACILITY_LIST,
b3fd4c02 51 LTT_FACILITY_FS,
27811799 52 LTT_FACILITY_USER_GENERIC,
53 LTT_FACILITY_BLOCK;
eed2ef37 54
55/* Events Quarks */
56
57GQuark
58 LTT_EVENT_SYSCALL_ENTRY,
59 LTT_EVENT_SYSCALL_EXIT,
60 LTT_EVENT_TRAP_ENTRY,
61 LTT_EVENT_TRAP_EXIT,
62 LTT_EVENT_IRQ_ENTRY,
63 LTT_EVENT_IRQ_EXIT,
faf074a3 64 LTT_EVENT_SOFT_IRQ_ENTRY,
65 LTT_EVENT_SOFT_IRQ_EXIT,
86c32a8f 66 LTT_EVENT_SCHED_SCHEDULE,
67 LTT_EVENT_PROCESS_FORK,
68 LTT_EVENT_KTHREAD_CREATE,
69 LTT_EVENT_PROCESS_EXIT,
70 LTT_EVENT_PROCESS_FREE,
b3fd4c02 71 LTT_EVENT_EXEC,
86c32a8f 72 LTT_EVENT_PROCESS_STATE,
c3b3b60b 73 LTT_EVENT_STATEDUMP_END,
80e0221b 74 LTT_EVENT_FUNCTION_ENTRY,
75 LTT_EVENT_FUNCTION_EXIT,
27811799 76 LTT_EVENT_THREAD_BRAND,
77 LTT_EVENT_REQUEST_ISSUE,
78 LTT_EVENT_REQUEST_COMPLETE;
eed2ef37 79
80/* Fields Quarks */
81
82GQuark
83 LTT_FIELD_SYSCALL_ID,
84 LTT_FIELD_TRAP_ID,
85 LTT_FIELD_IRQ_ID,
faf074a3 86 LTT_FIELD_SOFT_IRQ_ID,
f63ebe51 87 LTT_FIELD_PREV_PID,
88 LTT_FIELD_NEXT_PID,
89 LTT_FIELD_PREV_STATE,
eed2ef37 90 LTT_FIELD_PARENT_PID,
91 LTT_FIELD_CHILD_PID,
f4b88a7d 92 LTT_FIELD_PID,
fcc08e1e 93 LTT_FIELD_TGID,
f63ebe51 94 LTT_FIELD_CHILD_TGID,
b3fd4c02 95 LTT_FIELD_FILENAME,
96 LTT_FIELD_NAME,
e62e7f3a 97 LTT_FIELD_TYPE,
b3fd4c02 98 LTT_FIELD_MODE,
99 LTT_FIELD_SUBMODE,
302efbad 100 LTT_FIELD_STATUS,
80e0221b 101 LTT_FIELD_THIS_FN,
27811799 102 LTT_FIELD_CALL_SITE,
103 LTT_FIELD_MINOR,
104 LTT_FIELD_MAJOR,
105 LTT_FIELD_OPERATION;
eed2ef37 106
b445142a 107LttvExecutionMode
108 LTTV_STATE_MODE_UNKNOWN,
ffd54a90 109 LTTV_STATE_USER_MODE,
110 LTTV_STATE_SYSCALL,
111 LTTV_STATE_TRAP,
faf074a3 112 LTTV_STATE_IRQ,
113 LTTV_STATE_SOFT_IRQ;
ffd54a90 114
b445142a 115LttvExecutionSubmode
116 LTTV_STATE_SUBMODE_UNKNOWN,
117 LTTV_STATE_SUBMODE_NONE;
ffd54a90 118
119LttvProcessStatus
120 LTTV_STATE_UNNAMED,
121 LTTV_STATE_WAIT_FORK,
122 LTTV_STATE_WAIT_CPU,
dbd243b1 123 LTTV_STATE_EXIT,
0828099d 124 LTTV_STATE_ZOMBIE,
ffd54a90 125 LTTV_STATE_WAIT,
791dffa6 126 LTTV_STATE_RUN,
127 LTTV_STATE_DEAD;
ffd54a90 128
c4a72569 129GQuark
130 LTTV_STATE_UNBRANDED;
131
e62e7f3a 132LttvProcessType
133 LTTV_STATE_USER_THREAD,
80e0221b 134 LTTV_STATE_KERNEL_THREAD;
e62e7f3a 135
44ffb95f 136LttvCPUMode
137 LTTV_CPU_UNKNOWN,
138 LTTV_CPU_IDLE,
598026ba 139 LTTV_CPU_BUSY,
d3d99fde 140 LTTV_CPU_IRQ,
141 LTTV_CPU_TRAP;
44ffb95f 142
5e563da0 143LttvIRQMode
144 LTTV_IRQ_UNKNOWN,
145 LTTV_IRQ_IDLE,
146 LTTV_IRQ_BUSY;
147
27811799 148LttvBdevMode
149 LTTV_BDEV_UNKNOWN,
150 LTTV_BDEV_IDLE,
151 LTTV_BDEV_BUSY_READING,
152 LTTV_BDEV_BUSY_WRITING;
153
ba576a78 154static GQuark
308711e5 155 LTTV_STATE_TRACEFILES,
156 LTTV_STATE_PROCESSES,
157 LTTV_STATE_PROCESS,
348c6ba8 158 LTTV_STATE_RUNNING_PROCESS,
308711e5 159 LTTV_STATE_EVENT,
160 LTTV_STATE_SAVED_STATES,
dbb7bb09 161 LTTV_STATE_SAVED_STATES_TIME,
308711e5 162 LTTV_STATE_TIME,
f95bc830 163 LTTV_STATE_HOOKS,
164 LTTV_STATE_NAME_TABLES,
fbfbd4db 165 LTTV_STATE_TRACE_STATE_USE_COUNT,
fc6a87b2 166 LTTV_STATE_RESOURCE_CPUS,
167 LTTV_STATE_RESOURCE_IRQS;
ba576a78 168
f95bc830 169static void create_max_time(LttvTraceState *tcs);
170
171static void get_max_time(LttvTraceState *tcs);
172
173static void free_max_time(LttvTraceState *tcs);
174
175static void create_name_tables(LttvTraceState *tcs);
176
177static void get_name_tables(LttvTraceState *tcs);
b445142a 178
179static void free_name_tables(LttvTraceState *tcs);
180
f95bc830 181static void free_saved_state(LttvTraceState *tcs);
182
308711e5 183static void lttv_state_free_process_table(GHashTable *processes);
ba576a78 184
7df20ca4 185static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
186 GPtrArray *quarktable);
dc877563 187
44c0619e 188/* Resource function prototypes */
189static void bdev_state_free(gpointer key, gpointer value, gpointer user_data);
190static LttvBdevState *bdev_state_get(LttvTraceState *ts, guint16 devcode);
191
192
308711e5 193void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
194{
195 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
196}
197
198
199void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
200{
201 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
202}
203
204
2d262115 205void lttv_state_state_saved_free(LttvTraceState *self,
308711e5 206 LttvAttribute *container)
207{
f95bc830 208 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
308711e5 209}
210
211
2a2fa4f0 212guint process_hash(gconstpointer key)
213{
7893f726 214 guint pid = ((const LttvProcessState *)key)->pid;
215 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
2a2fa4f0 216}
217
218
1d1df11d 219/* If the hash table hash function is well distributed,
220 * the process_equal should compare different pid */
2a2fa4f0 221gboolean process_equal(gconstpointer a, gconstpointer b)
222{
00e74b69 223 const LttvProcessState *process_a, *process_b;
1d1df11d 224 gboolean ret = TRUE;
225
00e74b69 226 process_a = (const LttvProcessState *)a;
227 process_b = (const LttvProcessState *)b;
1d1df11d 228
229 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
230 else if(likely(process_a->pid == 0 &&
348c6ba8 231 process_a->cpu != process_b->cpu)) ret = FALSE;
2a2fa4f0 232
1d1df11d 233 return ret;
2a2fa4f0 234}
235
6806b3c6 236static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
237{
80e0221b 238 g_tree_destroy((GTree*)value);
6806b3c6 239}
240
241static void lttv_state_free_usertraces(GHashTable *usertraces)
242{
80e0221b 243 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
244 g_hash_table_destroy(usertraces);
6806b3c6 245}
246
247
2a2fa4f0 248
308711e5 249static void
250restore_init_state(LttvTraceState *self)
251{
311b8e39 252 guint i, nb_cpus, nb_irqs;
308711e5 253
254 LttvTracefileState *tfcs;
954417fa 255
256 LttTime start_time, end_time;
308711e5 257
348c6ba8 258 /* Free the process tables */
308711e5 259 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
80e0221b 260 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
2a2fa4f0 261 self->processes = g_hash_table_new(process_hash, process_equal);
80e0221b 262 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
308711e5 263 self->nb_event = 0;
264
348c6ba8 265 /* Seek time to beginning */
9ba3aaaf 266 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
267 // closest. It's the tracecontext job to seek the trace to the beginning
268 // anyway : the init state might be used at the middle of the trace as well...
269 //g_tree_destroy(self->parent.ts_context->pqueue);
270 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
348c6ba8 271
954417fa 272 ltt_trace_time_span_get(self->parent.t, &start_time, &end_time);
9ba3aaaf 273
274 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
348c6ba8 275
276 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
311b8e39 277 nb_irqs = self->nb_irqs;
348c6ba8 278
279 /* Put the per cpu running_process to beginning state : process 0. */
280 for(i=0; i< nb_cpus; i++) {
1e304fa1 281 LttvExecutionState *es;
fcc08e1e 282 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
954417fa 283 LTTV_STATE_UNNAMED, &start_time);
1e304fa1 284 /* We are not sure is it's a kernel thread or normal thread, put the
285 * bottom stack state to unknown */
286 self->running_process[i]->execution_stack =
287 g_array_set_size(self->running_process[i]->execution_stack, 1);
288 es = self->running_process[i]->state =
289 &g_array_index(self->running_process[i]->execution_stack,
290 LttvExecutionState, 0);
291 es->t = LTTV_STATE_MODE_UNKNOWN;
c4a72569 292 es->s = LTTV_STATE_UNNAMED;
1e304fa1 293
c4a72569 294 //self->running_process[i]->state->s = LTTV_STATE_RUN;
348c6ba8 295 self->running_process[i]->cpu = i;
311b8e39 296
297 /* reset cpu states */
298 if(self->cpu_states[i].mode_stack->len > 0)
299 g_array_remove_range(self->cpu_states[i].mode_stack, 0, self->cpu_states[i].mode_stack->len);
300 }
301
302 for(i=0; i<nb_irqs; i++) {
303 if(self->irq_states[i].mode_stack->len > 0)
304 g_array_remove_range(self->irq_states[i].mode_stack, 0, self->irq_states[i].mode_stack->len);
348c6ba8 305 }
44c0619e 306
307 g_hash_table_foreach(self->bdev_states, bdev_state_free, NULL);
308 g_hash_table_steal_all(self->bdev_states);
348c6ba8 309
310#if 0
eed2ef37 311 nb_tracefile = self->parent.tracefiles->len;
308711e5 312
dbb7bb09 313 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 314 tfcs =
cb03932a 315 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
316 LttvTracefileContext*, i));
d3e01c7a 317 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
eed2ef37 318// tfcs->saved_position = 0;
2a2fa4f0 319 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
320 tfcs->process->state->s = LTTV_STATE_RUN;
321 tfcs->process->last_cpu = tfcs->cpu_name;
2c82c4dc 322 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
308711e5 323 }
348c6ba8 324#endif //0
308711e5 325}
326
348c6ba8 327//static LttTime time_zero = {0,0};
308711e5 328
6806b3c6 329static gint compare_usertraces(gconstpointer a, gconstpointer b,
80e0221b 330 gpointer user_data)
6806b3c6 331{
80e0221b 332 const LttTime *t1 = (const LttTime *)a;
333 const LttTime *t2 = (const LttTime *)b;
6806b3c6 334
80e0221b 335 return ltt_time_compare(*t1, *t2);
6806b3c6 336}
337
338static void free_usertrace_key(gpointer data)
339{
80e0221b 340 g_free(data);
6806b3c6 341}
342
7df20ca4 343#define MAX_STRING_LEN 4096
344
345static void
346state_load_saved_states(LttvTraceState *tcs)
347{
348 FILE *fp;
349 GPtrArray *quarktable;
350 char *trace_path;
351 char path[PATH_MAX];
352 guint count;
353 guint i;
354 tcs->has_precomputed_states = FALSE;
355 GQuark q;
356 gchar *string;
357 gint hdr;
358 gchar buf[MAX_STRING_LEN];
359 guint len;
360
361 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
362 strncpy(path, trace_path, PATH_MAX-1);
363 count = strnlen(trace_path, PATH_MAX-1);
364 // quarktable : open, test
365 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
366 fp = fopen(path, "r");
367 if(!fp) return;
368 quarktable = g_ptr_array_sized_new(4096);
369
370 /* Index 0 is null */
371 hdr = fgetc(fp);
372 if(hdr == EOF) return;
373 g_assert(hdr == HDR_QUARKS);
374 q = 1;
375 do {
376 hdr = fgetc(fp);
377 if(hdr == EOF) break;
378 g_assert(hdr == HDR_QUARK);
379 g_ptr_array_set_size(quarktable, q+1);
380 i=0;
381 while(1) {
382 fread(&buf[i], sizeof(gchar), 1, fp);
383 if(buf[i] == '\0' || feof(fp)) break;
384 i++;
385 }
386 len = strnlen(buf, MAX_STRING_LEN-1);
387 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
388 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
389 q++;
390 } while(1);
391
392 fclose(fp);
ce05e187 393
7df20ca4 394 // saved_states : open, test
395 strncpy(path, trace_path, PATH_MAX-1);
396 count = strnlen(trace_path, PATH_MAX-1);
397 strncat(path, "/precomputed/states", PATH_MAX-count-1);
398 fp = fopen(path, "r");
399 if(!fp) return;
400
401 hdr = fgetc(fp);
402 if(hdr != HDR_TRACE) goto end;
403
404 lttv_trace_states_read_raw(tcs, fp, quarktable);
405
406 tcs->has_precomputed_states = TRUE;
407
408end:
409 fclose(fp);
410
411 /* Free the quarktable */
412 for(i=0; i<quarktable->len; i++) {
413 string = g_ptr_array_index (quarktable, i);
414 g_free(string);
415 }
416 g_ptr_array_free(quarktable, TRUE);
417 return;
418}
419
dc877563 420static void
421init(LttvTracesetState *self, LttvTraceset *ts)
422{
d3d99fde 423 guint i, j, nb_trace, nb_tracefile, nb_cpu;
5e563da0 424 guint64 nb_irq;
dc877563 425
ffd54a90 426 LttvTraceContext *tc;
dc877563 427
ffd54a90 428 LttvTraceState *tcs;
429
ffd54a90 430 LttvTracefileState *tfcs;
3d27549e 431
dbb7bb09 432 LttvAttributeValue v;
433
b445142a 434 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
435 init((LttvTracesetContext *)self, ts);
dc877563 436
437 nb_trace = lttv_traceset_number(ts);
438 for(i = 0 ; i < nb_trace ; i++) {
b445142a 439 tc = self->parent.traces[i];
021eeb41 440 tcs = LTTV_TRACE_STATE(tc);
eed2ef37 441 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
f95bc830 442 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
443 LTTV_UINT, &v);
444 (*v.v_uint)++;
dbb7bb09 445
f95bc830 446 if(*(v.v_uint) == 1) {
447 create_name_tables(tcs);
448 create_max_time(tcs);
449 }
450 get_name_tables(tcs);
451 get_max_time(tcs);
dc877563 452
eed2ef37 453 nb_tracefile = tc->tracefiles->len;
d3d99fde 454 nb_cpu = ltt_trace_get_num_cpu(tc->t);
5e563da0 455 nb_irq = tcs->nb_irqs;
ae3d0f50 456 tcs->processes = NULL;
6806b3c6 457 tcs->usertraces = NULL;
d3d99fde 458 tcs->running_process = g_new(LttvProcessState*, nb_cpu);
5e563da0 459
d3d99fde 460 /* init cpu resource stuff */
461 tcs->cpu_states = g_new(LttvCPUState, nb_cpu);
462 for(j = 0; j<nb_cpu; j++) {
463 tcs->cpu_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
464 g_assert(tcs->cpu_states[j].mode_stack != NULL);
465 }
466
5e563da0 467 /* init irq resource stuff */
468 tcs->irq_states = g_new(LttvIRQState, nb_irq);
469 for(j = 0; j<nb_irq; j++) {
470 tcs->irq_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
471 g_assert(tcs->irq_states[j].mode_stack != NULL);
472 }
473
27811799 474 /* init bdev resource stuff */
475 tcs->bdev_states = g_hash_table_new(g_int_hash, g_int_equal);
476
ae3d0f50 477 restore_init_state(tcs);
dc877563 478 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 479 tfcs =
cb03932a 480 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
481 LttvTracefileContext*, j));
348c6ba8 482 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
80e0221b 483 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
44ffb95f 484 tfcs->cpu_state = &(tcs->cpu_states[tfcs->cpu]);
80e0221b 485 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
486 /* It's a Usertrace */
487 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
488 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
489 (gconstpointer)tid);
490 if(!usertrace_tree) {
491 usertrace_tree = g_tree_new_full(compare_usertraces,
492 NULL, free_usertrace_key, NULL);
493 g_hash_table_insert(tcs->usertraces,
494 (gpointer)tid, usertrace_tree);
495 }
496 LttTime *timestamp = g_new(LttTime, 1);
497 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
498 ltt_tracefile_creation(tfcs->parent.tf));
499 g_tree_insert(usertrace_tree, timestamp, tfcs);
500 }
6806b3c6 501 }
502
7df20ca4 503 /* See if the trace has saved states */
504 state_load_saved_states(tcs);
dc877563 505 }
506}
507
dc877563 508static void
509fini(LttvTracesetState *self)
510{
00e74b69 511 guint i, nb_trace;
dc877563 512
ffd54a90 513 LttvTraceState *tcs;
dc877563 514
ffd54a90 515 LttvTracefileState *tfcs;
dc877563 516
f95bc830 517 LttvAttributeValue v;
518
ffd54a90 519 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
dc877563 520 for(i = 0 ; i < nb_trace ; i++) {
ffd54a90 521 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
f95bc830 522 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
523 LTTV_UINT, &v);
00e74b69 524
525 g_assert(*(v.v_uint) != 0);
f95bc830 526 (*v.v_uint)--;
527
f95bc830 528 if(*(v.v_uint) == 0) {
529 free_name_tables(tcs);
530 free_max_time(tcs);
531 free_saved_state(tcs);
532 }
348c6ba8 533 g_free(tcs->running_process);
534 tcs->running_process = NULL;
308711e5 535 lttv_state_free_process_table(tcs->processes);
80e0221b 536 lttv_state_free_usertraces(tcs->usertraces);
308711e5 537 tcs->processes = NULL;
6806b3c6 538 tcs->usertraces = NULL;
dc877563 539 }
b445142a 540 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
541 fini((LttvTracesetContext *)self);
dc877563 542}
543
544
c432246e 545static LttvTracesetContext *
dc877563 546new_traceset_context(LttvTracesetContext *self)
547{
ffd54a90 548 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
dc877563 549}
550
551
c432246e 552static LttvTraceContext *
dc877563 553new_trace_context(LttvTracesetContext *self)
554{
ffd54a90 555 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
dc877563 556}
557
558
c432246e 559static LttvTracefileContext *
dc877563 560new_tracefile_context(LttvTracesetContext *self)
561{
ffd54a90 562 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
563}
564
565
dbb7bb09 566/* Write the process state of the trace */
567
568static void write_process_state(gpointer key, gpointer value,
569 gpointer user_data)
570{
571 LttvProcessState *process;
572
573 LttvExecutionState *es;
574
575 FILE *fp = (FILE *)user_data;
576
577 guint i;
d4dd4885 578 guint64 address;
dbb7bb09 579
580 process = (LttvProcessState *)value;
581 fprintf(fp,
d41c66bf 582" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
d4dd4885 583 process, process->pid, process->tgid, process->ppid,
584 g_quark_to_string(process->type),
80e0221b 585 process->creation_time.tv_sec,
d4dd4885 586 process->creation_time.tv_nsec,
587 process->insertion_time.tv_sec,
588 process->insertion_time.tv_nsec,
589 g_quark_to_string(process->name),
7b5f6cf1 590 g_quark_to_string(process->brand),
6d0cdf22 591 process->cpu);
dbb7bb09 592
593 for(i = 0 ; i < process->execution_stack->len; i++) {
594 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
595 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
80e0221b 596 g_quark_to_string(es->t), g_quark_to_string(es->n),
dbb7bb09 597 es->entry.tv_sec, es->entry.tv_nsec);
598 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
599 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
600 }
d4dd4885 601
6d0cdf22 602 for(i = 0 ; i < process->user_stack->len; i++) {
d4dd4885 603 address = &g_array_index(process->user_stack, guint64, i);
604 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
605 address);
606 }
607
608 if(process->usertrace) {
609 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
6d0cdf22 610 g_quark_to_string(process->usertrace->tracefile_name),
d4dd4885 611 process->usertrace->cpu);
612 }
613
614
dbb7bb09 615 fprintf(fp, " </PROCESS>\n");
616}
617
618
619void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
620{
eed2ef37 621 guint i, nb_tracefile, nb_block, offset;
622 guint64 tsc;
dbb7bb09 623
624 LttvTracefileState *tfcs;
625
626 LttTracefile *tf;
627
628 LttEventPosition *ep;
629
348c6ba8 630 guint nb_cpus;
631
dbb7bb09 632 ep = ltt_event_position_new();
633
634 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
635
636 g_hash_table_foreach(self->processes, write_process_state, fp);
348c6ba8 637
638 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
639 for(i=0;i<nb_cpus;i++) {
6d0cdf22 640 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
348c6ba8 641 i, self->running_process[i]->pid);
642 }
dbb7bb09 643
eed2ef37 644 nb_tracefile = self->parent.tracefiles->len;
dbb7bb09 645
646 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 647 tfcs =
cb03932a 648 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
649 LttvTracefileContext*, i));
348c6ba8 650 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
651 tfcs->parent.timestamp.tv_sec,
08b1c66e 652 tfcs->parent.timestamp.tv_nsec);
eed2ef37 653 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
654 if(e == NULL) fprintf(fp,"/>\n");
dbb7bb09 655 else {
eed2ef37 656 ltt_event_position(e, ep);
657 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
27304273 658 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
eed2ef37 659 tsc);
dbb7bb09 660 }
661 }
662 g_free(ep);
6d0cdf22 663 fprintf(fp,"</PROCESS_STATE>\n");
664}
665
666
667static void write_process_state_raw(gpointer key, gpointer value,
668 gpointer user_data)
669{
670 LttvProcessState *process;
671
672 LttvExecutionState *es;
673
674 FILE *fp = (FILE *)user_data;
675
676 guint i;
677 guint64 address;
678
679 process = (LttvProcessState *)value;
680 fputc(HDR_PROCESS, fp);
681 //fwrite(&header, sizeof(header), 1, fp);
682 //fprintf(fp, "%s", g_quark_to_string(process->type));
683 //fputc('\0', fp);
684 fwrite(&process->type, sizeof(process->type), 1, fp);
685 //fprintf(fp, "%s", g_quark_to_string(process->name));
686 //fputc('\0', fp);
687 fwrite(&process->name, sizeof(process->name), 1, fp);
688 //fprintf(fp, "%s", g_quark_to_string(process->brand));
689 //fputc('\0', fp);
690 fwrite(&process->brand, sizeof(process->brand), 1, fp);
691 fwrite(&process->pid, sizeof(process->pid), 1, fp);
692 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
693 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
694 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
695 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
696 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
697
698#if 0
699 fprintf(fp,
700" <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
701 process, process->pid, process->tgid, process->ppid,
702 g_quark_to_string(process->type),
703 process->creation_time.tv_sec,
704 process->creation_time.tv_nsec,
705 process->insertion_time.tv_sec,
706 process->insertion_time.tv_nsec,
707 g_quark_to_string(process->name),
708 g_quark_to_string(process->brand),
709 process->cpu);
710#endif //0
711
712 for(i = 0 ; i < process->execution_stack->len; i++) {
713 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
714
715 fputc(HDR_ES, fp);
716 //fprintf(fp, "%s", g_quark_to_string(es->t));
717 //fputc('\0', fp);
718 fwrite(&es->t, sizeof(es->t), 1, fp);
719 //fprintf(fp, "%s", g_quark_to_string(es->n));
720 //fputc('\0', fp);
721 fwrite(&es->n, sizeof(es->n), 1, fp);
722 //fprintf(fp, "%s", g_quark_to_string(es->s));
723 //fputc('\0', fp);
724 fwrite(&es->s, sizeof(es->s), 1, fp);
725 fwrite(&es->entry, sizeof(es->entry), 1, fp);
726 fwrite(&es->change, sizeof(es->change), 1, fp);
7df20ca4 727 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
6d0cdf22 728#if 0
729 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
730 g_quark_to_string(es->t), g_quark_to_string(es->n),
731 es->entry.tv_sec, es->entry.tv_nsec);
732 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
733 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
734#endif //0
735 }
736
737 for(i = 0 ; i < process->user_stack->len; i++) {
738 address = &g_array_index(process->user_stack, guint64, i);
739 fputc(HDR_USER_STACK, fp);
740 fwrite(&address, sizeof(address), 1, fp);
741#if 0
742 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
743 address);
744#endif //0
745 }
746
747 if(process->usertrace) {
748 fputc(HDR_USERTRACE, fp);
749 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
750 //fputc('\0', fp);
751 fwrite(&process->usertrace->tracefile_name,
752 sizeof(process->usertrace->tracefile_name), 1, fp);
753 fwrite(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
754#if 0
755 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
756 g_quark_to_string(process->usertrace->tracefile_name),
757 process->usertrace->cpu);
758#endif //0
759 }
760
dbb7bb09 761}
762
763
6d0cdf22 764void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
765{
766 guint i, nb_tracefile, nb_block, offset;
767 guint64 tsc;
768
769 LttvTracefileState *tfcs;
770
771 LttTracefile *tf;
772
773 LttEventPosition *ep;
774
775 guint nb_cpus;
776
777 ep = ltt_event_position_new();
778
779 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
780 fputc(HDR_PROCESS_STATE, fp);
781 fwrite(&t, sizeof(t), 1, fp);
782
783 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
784
785 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
786 for(i=0;i<nb_cpus;i++) {
787 fputc(HDR_CPU, fp);
788 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
789 fwrite(&self->running_process[i]->pid,
790 sizeof(self->running_process[i]->pid), 1, fp);
791 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
792 // i, self->running_process[i]->pid);
793 }
794
795 nb_tracefile = self->parent.tracefiles->len;
796
797 for(i = 0 ; i < nb_tracefile ; i++) {
798 tfcs =
799 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
800 LttvTracefileContext*, i));
801 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
802 // tfcs->parent.timestamp.tv_sec,
803 // tfcs->parent.timestamp.tv_nsec);
804 fputc(HDR_TRACEFILE, fp);
805 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
806 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
807 * position following : end of trace */
808 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
809 if(e != NULL) {
810 ltt_event_position(e, ep);
811 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
812 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
813 // tsc);
814 fwrite(&nb_block, sizeof(nb_block), 1, fp);
815 fwrite(&offset, sizeof(offset), 1, fp);
816 fwrite(&tsc, sizeof(tsc), 1, fp);
817 }
818 }
819 g_free(ep);
820}
821
822
823/* Read process state from a file */
824
825/* Called because a HDR_PROCESS was found */
7df20ca4 826static void read_process_state_raw(LttvTraceState *self, FILE *fp,
827 GPtrArray *quarktable)
6d0cdf22 828{
829 LttvExecutionState *es;
830 LttvProcessState *process, *parent_process;
831 LttvProcessState tmp;
7df20ca4 832 GQuark tmpq;
6d0cdf22 833
6d0cdf22 834 guint i;
7df20ca4 835 guint64 *address;
6d0cdf22 836 guint cpu;
837
7df20ca4 838 /* TODO : check return value */
6d0cdf22 839 fread(&tmp.type, sizeof(tmp.type), 1, fp);
840 fread(&tmp.name, sizeof(tmp.name), 1, fp);
841 fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
842 fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
843 fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
844 fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
845 fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
846 fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
847 fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
848
849 if(tmp.pid == 0) {
d41c66bf 850 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
6d0cdf22 851 } else {
852 /* We must link to the parent */
853 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
d41c66bf 854 &ltt_time_zero);
ce05e187 855 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
856 if(process == NULL) {
857 process = lttv_state_create_process(self, parent_process, tmp.cpu,
858 tmp.pid, tmp.tgid,
859 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
860 &tmp.creation_time);
861 }
6d0cdf22 862 }
7df20ca4 863 process->insertion_time = tmp.insertion_time;
6d0cdf22 864 process->creation_time = tmp.creation_time;
7df20ca4 865 process->type = g_quark_from_string(
866 (gchar*)g_ptr_array_index(quarktable, tmp.type));
6d0cdf22 867 process->tgid = tmp.tgid;
7df20ca4 868 process->ppid = tmp.ppid;
869 process->brand = g_quark_from_string(
870 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
871 process->name =
872 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
6d0cdf22 873
ce05e187 874
6d0cdf22 875 do {
876 if(feof(fp) || ferror(fp)) goto end_loop;
877
d41c66bf 878 gint hdr = fgetc(fp);
7df20ca4 879 if(hdr == EOF) goto end_loop;
6d0cdf22 880
881 switch(hdr) {
882 case HDR_ES:
7df20ca4 883 process->execution_stack =
884 g_array_set_size(process->execution_stack,
885 process->execution_stack->len + 1);
886 es = &g_array_index(process->execution_stack, LttvExecutionState,
887 process->execution_stack->len-1);
ce05e187 888 process->state = es;
7df20ca4 889
890 fread(&es->t, sizeof(es->t), 1, fp);
891 es->t = g_quark_from_string(
892 (gchar*)g_ptr_array_index(quarktable, es->t));
893 fread(&es->n, sizeof(es->n), 1, fp);
894 es->n = g_quark_from_string(
895 (gchar*)g_ptr_array_index(quarktable, es->n));
896 fread(&es->s, sizeof(es->s), 1, fp);
897 es->s = g_quark_from_string(
898 (gchar*)g_ptr_array_index(quarktable, es->s));
899 fread(&es->entry, sizeof(es->entry), 1, fp);
900 fread(&es->change, sizeof(es->change), 1, fp);
901 fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
6d0cdf22 902 break;
903 case HDR_USER_STACK:
7df20ca4 904 process->user_stack = g_array_set_size(process->user_stack,
905 process->user_stack->len + 1);
906 address = &g_array_index(process->user_stack, guint64,
907 process->user_stack->len-1);
908 fread(address, sizeof(address), 1, fp);
909 process->current_function = *address;
6d0cdf22 910 break;
911 case HDR_USERTRACE:
7df20ca4 912 fread(&tmpq, sizeof(tmpq), 1, fp);
913 fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
6d0cdf22 914 break;
915 default:
916 ungetc(hdr, fp);
917 goto end_loop;
918 };
919 } while(1);
920end_loop:
d41c66bf 921 return;
6d0cdf22 922}
923
924
925/* Called because a HDR_PROCESS_STATE was found */
926/* Append a saved state to the trace states */
7df20ca4 927void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
6d0cdf22 928{
929 guint i, nb_tracefile, nb_block, offset;
930 guint64 tsc;
d41c66bf 931 LttvTracefileState *tfcs;
6d0cdf22 932
933 LttEventPosition *ep;
934
935 guint nb_cpus;
936
937 int hdr;
938
939 LttTime t;
940
941 LttvAttribute *saved_states_tree, *saved_state_tree;
942
943 LttvAttributeValue value;
ce05e187 944 GTree *pqueue = self->parent.ts_context->pqueue;
6d0cdf22 945 ep = ltt_event_position_new();
946
947 restore_init_state(self);
948
949 fread(&t, sizeof(t), 1, fp);
950
951 do {
952 if(feof(fp) || ferror(fp)) goto end_loop;
953 hdr = fgetc(fp);
7df20ca4 954 if(hdr == EOF) goto end_loop;
6d0cdf22 955
956 switch(hdr) {
957 case HDR_PROCESS:
958 /* Call read_process_state_raw */
7df20ca4 959 read_process_state_raw(self, fp, quarktable);
6d0cdf22 960 break;
961 case HDR_TRACEFILE:
962 case HDR_TRACESET:
963 case HDR_TRACE:
964 case HDR_QUARKS:
965 case HDR_QUARK:
966 case HDR_ES:
967 case HDR_USER_STACK:
968 case HDR_USERTRACE:
969 case HDR_PROCESS_STATE:
970 case HDR_CPU:
7df20ca4 971 ungetc(hdr, fp);
972 goto end_loop;
6d0cdf22 973 break;
974 default:
975 g_error("Error while parsing saved state file : unknown data header %d",
976 hdr);
977 };
978 } while(1);
979end_loop:
980
981 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
982 for(i=0;i<nb_cpus;i++) {
983 int cpu_num;
984 hdr = fgetc(fp);
985 g_assert(hdr == HDR_CPU);
986 fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
987 g_assert(i == cpu_num);
988 fread(&self->running_process[i]->pid,
989 sizeof(self->running_process[i]->pid), 1, fp);
990 }
991
992 nb_tracefile = self->parent.tracefiles->len;
993
994 for(i = 0 ; i < nb_tracefile ; i++) {
995 tfcs =
996 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
997 LttvTracefileContext*, i));
998 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
999 // tfcs->parent.timestamp.tv_sec,
1000 // tfcs->parent.timestamp.tv_nsec);
ce05e187 1001 g_tree_remove(pqueue, &tfcs->parent);
6d0cdf22 1002 hdr = fgetc(fp);
1003 g_assert(hdr == HDR_TRACEFILE);
1004 fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
1005 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
1006 * position following : end of trace */
d41c66bf 1007 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
6d0cdf22 1008 fread(&nb_block, sizeof(nb_block), 1, fp);
1009 fread(&offset, sizeof(offset), 1, fp);
1010 fread(&tsc, sizeof(tsc), 1, fp);
7df20ca4 1011 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
d41c66bf 1012 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
1013 g_assert(ret == 0);
ce05e187 1014 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
6d0cdf22 1015 }
1016 }
1017 g_free(ep);
1018
d41c66bf 1019 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
6d0cdf22 1020 LTTV_STATE_SAVED_STATES);
1021 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1022 value = lttv_attribute_add(saved_states_tree,
1023 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
1024 *(value.v_gobject) = (GObject *)saved_state_tree;
1025 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
1026 *(value.v_time) = t;
d41c66bf 1027 lttv_state_save(self, saved_state_tree);
6d0cdf22 1028 g_debug("Saving state at time %lu.%lu", t.tv_sec,
d41c66bf 1029 t.tv_nsec);
6d0cdf22 1030
1031 *(self->max_time_state_recomputed_in_seek) = t;
ce05e187 1032
6d0cdf22 1033}
1034
1035/* Called when a HDR_TRACE is found */
7df20ca4 1036void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
1037 GPtrArray *quarktable)
6d0cdf22 1038{
1039 int hdr;
1040
1041 do {
1042 if(feof(fp) || ferror(fp)) goto end_loop;
1043 hdr = fgetc(fp);
7df20ca4 1044 if(hdr == EOF) goto end_loop;
6d0cdf22 1045
1046 switch(hdr) {
1047 case HDR_PROCESS_STATE:
1048 /* Call read_process_state_raw */
7df20ca4 1049 lttv_state_read_raw(tcs, fp, quarktable);
6d0cdf22 1050 break;
1051 case HDR_TRACEFILE:
1052 case HDR_TRACESET:
1053 case HDR_TRACE:
1054 case HDR_QUARKS:
1055 case HDR_QUARK:
1056 case HDR_ES:
1057 case HDR_USER_STACK:
1058 case HDR_USERTRACE:
1059 case HDR_PROCESS:
1060 case HDR_CPU:
1061 g_error("Error while parsing saved state file :"
1062 " unexpected data header %d",
1063 hdr);
1064 break;
1065 default:
1066 g_error("Error while parsing saved state file : unknown data header %d",
1067 hdr);
1068 };
1069 } while(1);
1070end_loop:
6d0cdf22 1071 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
ce05e187 1072 restore_init_state(tcs);
1073 lttv_process_trace_seek_time(tcs, ltt_time_zero);
1074 return;
6d0cdf22 1075}
1076
1077
1078
dbb7bb09 1079/* Copy each process from an existing hash table to a new one */
1080
308711e5 1081static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
ffd54a90 1082{
308711e5 1083 LttvProcessState *process, *new_process;
ffd54a90 1084
308711e5 1085 GHashTable *new_processes = (GHashTable *)user_data;
ffd54a90 1086
308711e5 1087 guint i;
1088
1089 process = (LttvProcessState *)value;
1090 new_process = g_new(LttvProcessState, 1);
1091 *new_process = *process;
e8f2280c 1092 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1093 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
e05fc742 1094 new_process->execution_stack =
1095 g_array_set_size(new_process->execution_stack,
1096 process->execution_stack->len);
308711e5 1097 for(i = 0 ; i < process->execution_stack->len; i++) {
1098 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1099 g_array_index(process->execution_stack, LttvExecutionState, i);
1100 }
1101 new_process->state = &g_array_index(new_process->execution_stack,
1102 LttvExecutionState, new_process->execution_stack->len - 1);
302efbad 1103 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1104 sizeof(guint64), 0);
1105 new_process->user_stack =
1106 g_array_set_size(new_process->user_stack,
1107 process->user_stack->len);
1108 for(i = 0 ; i < process->user_stack->len; i++) {
1109 g_array_index(new_process->user_stack, guint64, i) =
1110 g_array_index(process->user_stack, guint64, i);
1111 }
052a984f 1112 new_process->current_function = process->current_function;
2a2fa4f0 1113 g_hash_table_insert(new_processes, new_process, new_process);
ffd54a90 1114}
1115
1116
308711e5 1117static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
ffd54a90 1118{
2a2fa4f0 1119 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
ffd54a90 1120
308711e5 1121 g_hash_table_foreach(processes, copy_process_state, new_processes);
1122 return new_processes;
dc877563 1123}
1124
fbfbd4db 1125static LttvCPUState *lttv_state_copy_cpu_states(LttvCPUState *states, guint n)
1126{
1127 guint i,j;
1128 LttvCPUState *retval;
1129
1130 retval = g_malloc(n*sizeof(LttvCPUState));
1131
1132 for(i=0; i<n; i++) {
1133 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
1134 retval[i].last_irq = states[i].last_irq;
1135 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1136 for(j=0; j<states[i].mode_stack->len; j++) {
1137 g_array_index(retval[i].mode_stack, GQuark, j) = g_array_index(states[i].mode_stack, GQuark, j);
1138 }
1139 }
1140
1141 return retval;
1142}
1143
1144static void lttv_state_free_cpu_states(LttvCPUState *states, guint n)
1145{
1146 guint i;
1147
1148 for(i=0; i<n; i++) {
1149 g_array_free(states[i].mode_stack, FALSE);
1150 }
1151
1152 g_free(states);
1153}
dc877563 1154
fc6a87b2 1155static LttvIRQState *lttv_state_copy_irq_states(LttvIRQState *states, guint n)
1156{
1157 guint i,j;
1158 LttvIRQState *retval;
1159
1160 retval = g_malloc(n*sizeof(LttvIRQState));
1161
1162 for(i=0; i<n; i++) {
1163 retval[i].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvIRQMode));
1164 g_array_set_size(retval[i].mode_stack, states[i].mode_stack->len);
1165 for(j=0; j<states[i].mode_stack->len; j++) {
1166 g_array_index(retval[i].mode_stack, GQuark, j) = g_array_index(states[i].mode_stack, GQuark, j);
1167 }
1168 }
1169
1170 return retval;
1171}
1172
1173static void lttv_state_free_irq_states(LttvIRQState *states, guint n)
1174{
1175 guint i;
1176
1177 for(i=0; i<n; i++) {
1178 g_array_free(states[i].mode_stack, FALSE);
1179 }
1180
1181 g_free(states);
1182}
1183
308711e5 1184/* The saved state for each trace contains a member "processes", which
1185 stores a copy of the process table, and a member "tracefiles" with
1186 one entry per tracefile. Each tracefile has a "process" member pointing
1187 to the current process and a "position" member storing the tracefile
1188 position (needed to seek to the current "next" event. */
1189
1190static void state_save(LttvTraceState *self, LttvAttribute *container)
dc877563 1191{
fc6a87b2 1192 guint i, nb_tracefile, nb_cpus, nb_irqs;
dc877563 1193
308711e5 1194 LttvTracefileState *tfcs;
1195
1196 LttvAttribute *tracefiles_tree, *tracefile_tree;
348c6ba8 1197
1198 guint *running_process;
308711e5 1199
1200 LttvAttributeType type;
1201
1202 LttvAttributeValue value;
1203
1204 LttvAttributeName name;
1205
1206 LttEventPosition *ep;
1207
1208 tracefiles_tree = lttv_attribute_find_subdir(container,
1209 LTTV_STATE_TRACEFILES);
1210
1211 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1212 LTTV_POINTER);
1213 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1214
348c6ba8 1215 /* Add the currently running processes array */
1216 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1217 running_process = g_new(guint, nb_cpus);
1218 for(i=0;i<nb_cpus;i++) {
1219 running_process[i] = self->running_process[i]->pid;
1220 }
1221 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1222 LTTV_POINTER);
1223 *(value.v_pointer) = running_process;
728d0c3e 1224
1225 g_info("State save");
348c6ba8 1226
eed2ef37 1227 nb_tracefile = self->parent.tracefiles->len;
308711e5 1228
1229 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1230 tfcs =
cb03932a 1231 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1232 LttvTracefileContext*, i));
308711e5 1233 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1234 value = lttv_attribute_add(tracefiles_tree, i,
1235 LTTV_GOBJECT);
1236 *(value.v_gobject) = (GObject *)tracefile_tree;
348c6ba8 1237#if 0
308711e5 1238 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1239 LTTV_UINT);
1240 *(value.v_uint) = tfcs->process->pid;
348c6ba8 1241#endif //0
308711e5 1242 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1243 LTTV_POINTER);
3054461a 1244 /* Only save the position if the tfs has not infinite time. */
1245 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1246 // && current_tfcs != tfcs) {
1247 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1986f254 1248 *(value.v_pointer) = NULL;
1249 } else {
1250 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
a5dcde2f 1251 ep = ltt_event_position_new();
eed2ef37 1252 ltt_event_position(e, ep);
308711e5 1253 *(value.v_pointer) = ep;
08b1c66e 1254
eed2ef37 1255 guint nb_block, offset;
1256 guint64 tsc;
08b1c66e 1257 LttTracefile *tf;
eed2ef37 1258 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
728d0c3e 1259 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
eed2ef37 1260 tsc,
08b1c66e 1261 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
308711e5 1262 }
dc877563 1263 }
fbfbd4db 1264
fc6a87b2 1265 /* save the cpu state */
1266 {
1267 guint size = sizeof(LttvCPUState)*nb_cpus;
1268 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_CPUS,
1269 LTTV_POINTER);
1270 *(value.v_pointer) = lttv_state_copy_cpu_states(self->cpu_states, nb_cpus);
1271 }
1272
1273 /* save the irq state */
1274 nb_irqs = self->nb_irqs;
1275 {
1276 guint size = sizeof(LttvCPUState)*nb_irqs;
1277 value = lttv_attribute_add(container, LTTV_STATE_RESOURCE_IRQS,
1278 LTTV_POINTER);
1279 *(value.v_pointer) = lttv_state_copy_irq_states(self->irq_states, nb_irqs);
1280 }
dc877563 1281}
1282
1283
308711e5 1284static void state_restore(LttvTraceState *self, LttvAttribute *container)
dc877563 1285{
fc6a87b2 1286 guint i, nb_tracefile, pid, nb_cpus, nb_irqs;
dc877563 1287
308711e5 1288 LttvTracefileState *tfcs;
dc877563 1289
308711e5 1290 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 1291
348c6ba8 1292 guint *running_process;
1293
308711e5 1294 LttvAttributeType type;
dc877563 1295
308711e5 1296 LttvAttributeValue value;
dc877563 1297
308711e5 1298 LttvAttributeName name;
dc877563 1299
80e0221b 1300 gboolean is_named;
c0cb4d12 1301
308711e5 1302 LttEventPosition *ep;
dc877563 1303
27304273 1304 LttvTracesetContext *tsc = self->parent.ts_context;
1305
308711e5 1306 tracefiles_tree = lttv_attribute_find_subdir(container,
1307 LTTV_STATE_TRACEFILES);
dc877563 1308
308711e5 1309 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1310 &value);
1311 g_assert(type == LTTV_POINTER);
1312 lttv_state_free_process_table(self->processes);
1313 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1314
348c6ba8 1315 /* Add the currently running processes array */
1316 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1317 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1318 &value);
1319 g_assert(type == LTTV_POINTER);
1320 running_process = *(value.v_pointer);
1321 for(i=0;i<nb_cpus;i++) {
1322 pid = running_process[i];
1323 self->running_process[i] = lttv_state_find_process(self, i, pid);
1324 g_assert(self->running_process[i] != NULL);
1325 }
1326
eed2ef37 1327 nb_tracefile = self->parent.tracefiles->len;
308711e5 1328
d448fce2 1329 //g_tree_destroy(tsc->pqueue);
1330 //tsc->pqueue = g_tree_new(compare_tracefile);
fbfbd4db 1331
1332 /* restore cpu resource states */
1333 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_CPUS, &value);
1334 g_assert(type == LTTV_POINTER);
1335 lttv_state_free_cpu_states(self->cpu_states, nb_cpus);
1336 self->cpu_states = lttv_state_copy_cpu_states(*(value.v_pointer), nb_cpus);
e7f5e89d 1337
fc6a87b2 1338 /* restore irq resource states */
1339 nb_irqs = self->nb_irqs;
1340 type = lttv_attribute_get_by_name(container, LTTV_STATE_RESOURCE_IRQS, &value);
1341 g_assert(type == LTTV_POINTER);
1342 lttv_state_free_irq_states(self->irq_states, nb_irqs);
1343 self->irq_states = lttv_state_copy_irq_states(*(value.v_pointer), nb_irqs);
1344
308711e5 1345 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1346 tfcs =
cb03932a 1347 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1348 LttvTracefileContext*, i));
c0cb4d12 1349 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
308711e5 1350 g_assert(type == LTTV_GOBJECT);
1351 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
348c6ba8 1352#if 0
308711e5 1353 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1354 &value);
1355 g_assert(type == LTTV_UINT);
2a2fa4f0 1356 pid = *(value.v_uint);
1357 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
348c6ba8 1358#endif //0
308711e5 1359 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1360 &value);
1361 g_assert(type == LTTV_POINTER);
e7f5e89d 1362 //g_assert(*(value.v_pointer) != NULL);
eed2ef37 1363 ep = *(value.v_pointer);
1364 g_assert(tfcs->parent.t_context != NULL);
fbfbd4db 1365
1366 tfcs->cpu_state = &self->cpu_states[tfcs->cpu];
27304273 1367
27304273 1368 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
d448fce2 1369 g_tree_remove(tsc->pqueue, tfc);
27304273 1370
1986f254 1371 if(ep != NULL) {
1372 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
1373 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
e7f5e89d 1374 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1986f254 1375 g_tree_insert(tsc->pqueue, tfc, tfc);
728d0c3e 1376 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1986f254 1377 } else {
1378 tfc->timestamp = ltt_time_infinite;
1379 }
dc877563 1380 }
dc877563 1381}
1382
1383
308711e5 1384static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
dc877563 1385{
348c6ba8 1386 guint i, nb_tracefile, nb_cpus;
dc877563 1387
308711e5 1388 LttvTracefileState *tfcs;
dc877563 1389
308711e5 1390 LttvAttribute *tracefiles_tree, *tracefile_tree;
dc877563 1391
348c6ba8 1392 guint *running_process;
1393
308711e5 1394 LttvAttributeType type;
dc877563 1395
308711e5 1396 LttvAttributeValue value;
dc877563 1397
308711e5 1398 LttvAttributeName name;
dc877563 1399
80e0221b 1400 gboolean is_named;
c0cb4d12 1401
308711e5 1402 LttEventPosition *ep;
dc877563 1403
308711e5 1404 tracefiles_tree = lttv_attribute_find_subdir(container,
1405 LTTV_STATE_TRACEFILES);
c47a6dc6 1406 g_object_ref(G_OBJECT(tracefiles_tree));
308711e5 1407 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
dc877563 1408
308711e5 1409 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1410 &value);
1411 g_assert(type == LTTV_POINTER);
1412 lttv_state_free_process_table(*(value.v_pointer));
1413 *(value.v_pointer) = NULL;
1414 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1415
348c6ba8 1416 /* Free running processes array */
1417 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
728d0c3e 1418 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
348c6ba8 1419 &value);
1420 g_assert(type == LTTV_POINTER);
1421 running_process = *(value.v_pointer);
1422 g_free(running_process);
1423
eed2ef37 1424 nb_tracefile = self->parent.tracefiles->len;
308711e5 1425
1426 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 1427 tfcs =
cb03932a 1428 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1429 LttvTracefileContext*, i));
c0cb4d12 1430 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
308711e5 1431 g_assert(type == LTTV_GOBJECT);
1432 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1433
1434 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1435 &value);
1436 g_assert(type == LTTV_POINTER);
1437 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
dc877563 1438 }
c47a6dc6 1439 g_object_unref(G_OBJECT(tracefiles_tree));
dc877563 1440}
1441
1442
f95bc830 1443static void free_saved_state(LttvTraceState *self)
1444{
1445 guint i, nb;
1446
1447 LttvAttributeType type;
1448
1449 LttvAttributeValue value;
1450
1451 LttvAttributeName name;
1452
80e0221b 1453 gboolean is_named;
c0cb4d12 1454
f95bc830 1455 LttvAttribute *saved_states;
1456
1457 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1458 LTTV_STATE_SAVED_STATES);
1459
1460 nb = lttv_attribute_get_number(saved_states);
1461 for(i = 0 ; i < nb ; i++) {
c0cb4d12 1462 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
f95bc830 1463 g_assert(type == LTTV_GOBJECT);
1464 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1465 }
1466
1467 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
f95bc830 1468}
1469
1470
1471static void
1472create_max_time(LttvTraceState *tcs)
1473{
1474 LttvAttributeValue v;
1475
1476 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1477 LTTV_POINTER, &v);
1478 g_assert(*(v.v_pointer) == NULL);
1479 *(v.v_pointer) = g_new(LttTime,1);
348c6ba8 1480 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
f95bc830 1481}
1482
1483
1484static void
1485get_max_time(LttvTraceState *tcs)
1486{
1487 LttvAttributeValue v;
1488
1489 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1490 LTTV_POINTER, &v);
1491 g_assert(*(v.v_pointer) != NULL);
1492 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1493}
1494
1495
1496static void
1497free_max_time(LttvTraceState *tcs)
1498{
1499 LttvAttributeValue v;
1500
1501 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1502 LTTV_POINTER, &v);
1503 g_free(*(v.v_pointer));
1504 *(v.v_pointer) = NULL;
1505}
1506
1507
1508typedef struct _LttvNameTables {
eed2ef37 1509 // FIXME GQuark *eventtype_names;
f95bc830 1510 GQuark *syscall_names;
5e96e7e3 1511 guint nb_syscalls;
f95bc830 1512 GQuark *trap_names;
5e96e7e3 1513 guint nb_traps;
f95bc830 1514 GQuark *irq_names;
6214c229 1515 guint nb_irqs;
faf074a3 1516 GQuark *soft_irq_names;
6214c229 1517 guint nb_softirqs;
f95bc830 1518} LttvNameTables;
1519
1520
b445142a 1521static void
f95bc830 1522create_name_tables(LttvTraceState *tcs)
b445142a 1523{
1524 int i, nb;
dc877563 1525
eed2ef37 1526 GQuark f_name, e_name;
1527
021eeb41 1528 LttvTraceHook h;
dc877563 1529
eed2ef37 1530 LttvTraceHookByFacility *thf;
b445142a 1531
1532 LttEventType *et;
1533
1534 LttType *t;
1535
1536 GString *fe_name = g_string_new("");
1537
f95bc830 1538 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1539
1540 LttvAttributeValue v;
1541
1542 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1543 LTTV_POINTER, &v);
1544 g_assert(*(v.v_pointer) == NULL);
1545 *(v.v_pointer) = name_tables;
eed2ef37 1546#if 0 // Use iteration over the facilities_by_name and then list all event
1547 // types of each facility
b445142a 1548 nb = ltt_trace_eventtype_number(tcs->parent.t);
f95bc830 1549 name_tables->eventtype_names = g_new(GQuark, nb);
b445142a 1550 for(i = 0 ; i < nb ; i++) {
1551 et = ltt_trace_eventtype_get(tcs->parent.t, i);
1552 e_name = ltt_eventtype_name(et);
1553 f_name = ltt_facility_name(ltt_eventtype_facility(et));
1554 g_string_printf(fe_name, "%s.%s", f_name, e_name);
f95bc830 1555 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
b445142a 1556 }
eed2ef37 1557#endif //0
285468d4 1558 if(!lttv_trace_find_hook(tcs->parent.t,
f5d7967f 1559 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 1560 LTT_FIELD_SYSCALL_ID, 0, 0,
285468d4 1561 NULL, NULL, &h)) {
80e0221b 1562
1563 thf = lttv_trace_hook_get_first(&h);
1564
1565 t = ltt_field_type(thf->f1);
1566 nb = ltt_type_element_number(t);
1567
1568 lttv_trace_hook_destroy(&h);
1569
1570 name_tables->syscall_names = g_new(GQuark, nb);
1571 name_tables->nb_syscalls = nb;
1572
1573 for(i = 0 ; i < nb ; i++) {
1574 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
da5d36a5 1575 if(!name_tables->syscall_names[i]) {
1576 GString *string = g_string_new("");
1577 g_string_printf(string, "syscall %u", i);
1578 name_tables->syscall_names[i] = g_quark_from_string(string->str);
1579 g_string_free(string, TRUE);
1580 }
80e0221b 1581 }
1582
1583 //name_tables->syscall_names = g_new(GQuark, 256);
1584 //for(i = 0 ; i < 256 ; i++) {
1585 // g_string_printf(fe_name, "syscall %d", i);
1586 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1587 //}
1588 } else {
1589 name_tables->syscall_names = NULL;
1590 name_tables->nb_syscalls = 0;
1591 }
285468d4 1592
86c32a8f 1593 if(!lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL_ARCH,
eed2ef37 1594 LTT_EVENT_TRAP_ENTRY,
1595 LTT_FIELD_TRAP_ID, 0, 0,
285468d4 1596 NULL, NULL, &h)) {
eed2ef37 1597
80e0221b 1598 thf = lttv_trace_hook_get_first(&h);
1599
1600 t = ltt_field_type(thf->f1);
1601 //nb = ltt_type_element_number(t);
1602
1603 lttv_trace_hook_destroy(&h);
1604
1605 /*
1606 name_tables->trap_names = g_new(GQuark, nb);
1607 for(i = 0 ; i < nb ; i++) {
1608 name_tables->trap_names[i] = g_quark_from_string(
1609 ltt_enum_string_get(t, i));
1610 }
1611 */
1612 name_tables->nb_traps = 256;
1613 name_tables->trap_names = g_new(GQuark, 256);
1614 for(i = 0 ; i < 256 ; i++) {
1615 g_string_printf(fe_name, "trap %d", i);
1616 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1617 }
1618 } else {
1619 name_tables->trap_names = NULL;
1620 name_tables->nb_traps = 0;
1621 }
b445142a 1622
285468d4 1623 if(!lttv_trace_find_hook(tcs->parent.t,
eed2ef37 1624 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1625 LTT_FIELD_IRQ_ID, 0, 0,
285468d4 1626 NULL, NULL, &h)) {
80e0221b 1627
1628 thf = lttv_trace_hook_get_first(&h);
1629
1630 t = ltt_field_type(thf->f1);
1631 //nb = ltt_type_element_number(t);
1632
1633 lttv_trace_hook_destroy(&h);
1634
1635 /*
1636 name_tables->irq_names = g_new(GQuark, nb);
1637 for(i = 0 ; i < nb ; i++) {
1638 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1639 }
1640 */
1641
6214c229 1642 name_tables->nb_irqs = 256;
80e0221b 1643 name_tables->irq_names = g_new(GQuark, 256);
1644 for(i = 0 ; i < 256 ; i++) {
1645 g_string_printf(fe_name, "irq %d", i);
1646 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1647 }
1648 } else {
6214c229 1649 name_tables->nb_irqs = 0;
80e0221b 1650 name_tables->irq_names = NULL;
1651 }
faf074a3 1652 /*
1653 name_tables->soft_irq_names = g_new(GQuark, nb);
1654 for(i = 0 ; i < nb ; i++) {
1655 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1656 }
1657 */
1658
6214c229 1659 name_tables->nb_softirqs = 256;
faf074a3 1660 name_tables->soft_irq_names = g_new(GQuark, 256);
1661 for(i = 0 ; i < 256 ; i++) {
1662 g_string_printf(fe_name, "softirq %d", i);
1663 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1664 }
1665
1666
b445142a 1667 g_string_free(fe_name, TRUE);
1668}
1669
1670
f95bc830 1671static void
1672get_name_tables(LttvTraceState *tcs)
1673{
1674 LttvNameTables *name_tables;
1675
1676 LttvAttributeValue v;
1677
1678 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1679 LTTV_POINTER, &v);
1680 g_assert(*(v.v_pointer) != NULL);
1681 name_tables = (LttvNameTables *)*(v.v_pointer);
eed2ef37 1682 //tcs->eventtype_names = name_tables->eventtype_names;
f95bc830 1683 tcs->syscall_names = name_tables->syscall_names;
7cd289b0 1684 tcs->nb_syscalls = name_tables->nb_syscalls;
f95bc830 1685 tcs->trap_names = name_tables->trap_names;
5e96e7e3 1686 tcs->nb_traps = name_tables->nb_traps;
f95bc830 1687 tcs->irq_names = name_tables->irq_names;
faf074a3 1688 tcs->soft_irq_names = name_tables->soft_irq_names;
6214c229 1689 tcs->nb_irqs = name_tables->nb_irqs;
1690 tcs->nb_softirqs = name_tables->nb_softirqs;
f95bc830 1691}
1692
1693
b445142a 1694static void
1695free_name_tables(LttvTraceState *tcs)
1696{
f95bc830 1697 LttvNameTables *name_tables;
1698
1699 LttvAttributeValue v;
1700
1701 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1702 LTTV_POINTER, &v);
1703 name_tables = (LttvNameTables *)*(v.v_pointer);
1704 *(v.v_pointer) = NULL;
1705
eed2ef37 1706 // g_free(name_tables->eventtype_names);
285468d4 1707 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1708 if(name_tables->trap_names) g_free(name_tables->trap_names);
1709 if(name_tables->irq_names) g_free(name_tables->irq_names);
1710 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1711 if(name_tables) g_free(name_tables);
b445142a 1712}
dc877563 1713
15b3d537 1714#ifdef HASH_TABLE_DEBUG
1715
1716static void test_process(gpointer key, gpointer value, gpointer user_data)
1717{
1718 LttvProcessState *process = (LttvProcessState *)value;
1719
1720 /* Test for process corruption */
1721 guint stack_len = process->execution_stack->len;
1722}
1723
1724static void hash_table_check(GHashTable *table)
1725{
1726 g_hash_table_foreach(table, test_process, NULL);
1727}
1728
1729
1730#endif
1731
d3d99fde 1732/* clears the stack and sets the state passed as argument */
1733static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1734{
1735 g_array_set_size(cpust->mode_stack, 1);
1736 ((GQuark *)cpust->mode_stack->data)[0] = state;
1737}
1738
1739static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1740{
1741 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1742 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1743}
1744
1745static void cpu_pop_mode(LttvCPUState *cpust)
1746{
0c0168a8 1747 if(cpust->mode_stack->len <= 1)
d3d99fde 1748 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1749 else
1750 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1751}
15b3d537 1752
5e563da0 1753/* clears the stack and sets the state passed as argument */
27811799 1754static void bdev_set_base_mode(LttvBdevState *bdevst, LttvBdevMode state)
1755{
1756 g_array_set_size(bdevst->mode_stack, 1);
1757 ((GQuark *)bdevst->mode_stack->data)[0] = state;
1758}
1759
1760static void bdev_push_mode(LttvBdevState *bdevst, LttvBdevMode state)
1761{
1762 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len + 1);
1763 ((GQuark *)bdevst->mode_stack->data)[bdevst->mode_stack->len - 1] = state;
1764}
1765
1766static void bdev_pop_mode(LttvBdevState *bdevst)
1767{
0c0168a8 1768 if(bdevst->mode_stack->len <= 1)
27811799 1769 bdev_set_base_mode(bdevst, LTTV_BDEV_UNKNOWN);
1770 else
1771 g_array_set_size(bdevst->mode_stack, bdevst->mode_stack->len - 1);
1772}
1773
5e563da0 1774static void irq_set_base_mode(LttvIRQState *irqst, LttvIRQMode state)
1775{
1776 g_array_set_size(irqst->mode_stack, 1);
1777 ((GQuark *)irqst->mode_stack->data)[0] = state;
1778}
1779
1780static void irq_push_mode(LttvIRQState *irqst, LttvIRQMode state)
1781{
1782 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len + 1);
1783 ((GQuark *)irqst->mode_stack->data)[irqst->mode_stack->len - 1] = state;
1784}
1785
1786static void irq_pop_mode(LttvIRQState *irqst)
1787{
0c0168a8 1788 if(irqst->mode_stack->len <= 1)
5e563da0 1789 irq_set_base_mode(irqst, LTTV_IRQ_UNKNOWN);
1790 else
1791 g_array_set_size(irqst->mode_stack, irqst->mode_stack->len - 1);
1792}
1793
b445142a 1794static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
ffd54a90 1795 guint state_id)
dc877563 1796{
b445142a 1797 LttvExecutionState *es;
348c6ba8 1798
348c6ba8 1799 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
ae3d0f50 1800 guint cpu = tfs->cpu;
15b3d537 1801
1802#ifdef HASH_TABLE_DEBUG
1803 hash_table_check(ts->processes);
1804#endif
348c6ba8 1805 LttvProcessState *process = ts->running_process[cpu];
dc877563 1806
b445142a 1807 guint depth = process->execution_stack->len;
dc877563 1808
e05fc742 1809 process->execution_stack =
1810 g_array_set_size(process->execution_stack, depth + 1);
1811 /* Keep in sync */
1812 process->state =
1813 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1814
b445142a 1815 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1816 es->t = t;
1817 es->n = state_id;
1818 es->entry = es->change = tfs->parent.timestamp;
80e0221b 1819 es->cum_cpu_time = ltt_time_zero;
b445142a 1820 es->s = process->state->s;
1821 process->state = es;
dc877563 1822}
1823
b49e54b4 1824/* pop state
1825 * return 1 when empty, else 0 */
1826int lttv_state_pop_state_cleanup(LttvProcessState *process,
80e0221b 1827 LttvTracefileState *tfs)
b49e54b4 1828{
80e0221b 1829 guint cpu = tfs->cpu;
b49e54b4 1830 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1831
1832 guint depth = process->execution_stack->len;
1833
1834 if(depth == 1){
1835 return 1;
1836 }
1837
1838 process->execution_stack =
1839 g_array_set_size(process->execution_stack, depth - 1);
1840 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1841 depth - 2);
1842 process->state->change = tfs->parent.timestamp;
80e0221b 1843
1844 return 0;
b49e54b4 1845}
dc877563 1846
b445142a 1847static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
dc877563 1848{
ae3d0f50 1849 guint cpu = tfs->cpu;
348c6ba8 1850 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1851 LttvProcessState *process = ts->running_process[cpu];
dc877563 1852
f95bc830 1853 guint depth = process->execution_stack->len;
dc877563 1854
3d27549e 1855 if(process->state->t != t){
00e74b69 1856 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
b445142a 1857 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
08b1c66e 1858 g_info("process state has %s when pop_int is %s\n",
80e0221b 1859 g_quark_to_string(process->state->t),
1860 g_quark_to_string(t));
7b5f6cf1 1861 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 1862 process->pid,
1863 process->ppid,
1864 g_quark_to_string(process->name),
1865 g_quark_to_string(process->brand),
1866 g_quark_to_string(process->state->s));
3d27549e 1867 return;
1868 }
b445142a 1869
f95bc830 1870 if(depth == 1){
00e74b69 1871 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
b445142a 1872 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1873 return;
1874 }
1875
e05fc742 1876 process->execution_stack =
1877 g_array_set_size(process->execution_stack, depth - 1);
b445142a 1878 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
f95bc830 1879 depth - 2);
b445142a 1880 process->state->change = tfs->parent.timestamp;
dc877563 1881}
1882
6806b3c6 1883struct search_result {
80e0221b 1884 const LttTime *time; /* Requested time */
1885 LttTime *best; /* Best result */
6806b3c6 1886};
1887
1888static gint search_usertrace(gconstpointer a, gconstpointer b)
1889{
80e0221b 1890 const LttTime *elem_time = (const LttTime*)a;
1891 /* Explicit non const cast */
1892 struct search_result *res = (struct search_result *)b;
1893
1894 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1895 /* The usertrace was created before the schedchange */
1896 /* Get larger keys */
1897 return 1;
1898 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1899 /* The usertrace was created after the schedchange time */
1900 /* Get smaller keys */
1901 if(res->best) {
1902 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1903 res->best = elem_time;
1904 }
1905 } else {
1906 res->best = elem_time;
1907 }
1908 return -1;
1909 }
1910 return 0;
6806b3c6 1911}
1912
1913static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
80e0221b 1914 guint pid, const LttTime *timestamp)
1915{
1916 LttvTracefileState *tfs = NULL;
1917 struct search_result res;
1918 /* Find the usertrace associated with a pid and time interval.
1919 * Search in the usertraces by PID (within a hash) and then, for each
1920 * corresponding element of the array, find the first one with creation
1921 * timestamp the lowest, but higher or equal to "timestamp". */
1922 res.time = timestamp;
1923 res.best = NULL;
1924 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1925 if(usertrace_tree) {
1926 g_tree_search(usertrace_tree, search_usertrace, &res);
1927 if(res.best)
1928 tfs = g_tree_lookup(usertrace_tree, res.best);
1929 }
6806b3c6 1930
80e0221b 1931 return tfs;
6806b3c6 1932}
1933
dc877563 1934
2a2fa4f0 1935LttvProcessState *
348c6ba8 1936lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
fcc08e1e 1937 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
dc877563 1938{
1939 LttvProcessState *process = g_new(LttvProcessState, 1);
1940
b445142a 1941 LttvExecutionState *es;
dc877563 1942
348c6ba8 1943 LttvTraceContext *tc = (LttvTraceContext*)tcs;
ba576a78 1944
b445142a 1945 char buffer[128];
ffd54a90 1946
dc877563 1947 process->pid = pid;
fcc08e1e 1948 process->tgid = tgid;
348c6ba8 1949 process->cpu = cpu;
b3fd4c02 1950 process->name = name;
7b5f6cf1 1951 process->brand = LTTV_STATE_UNBRANDED;
348c6ba8 1952 //process->last_cpu = tfs->cpu_name;
1953 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
80e0221b 1954 process->type = LTTV_STATE_USER_THREAD;
1955 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1956 process->current_function = 0; //function 0x0 by default.
7bfd7820 1957
cb03932a 1958 g_info("Process %u, core %p", process->pid, process);
2a2fa4f0 1959 g_hash_table_insert(tcs->processes, process, process);
b445142a 1960
1961 if(parent) {
1962 process->ppid = parent->pid;
348c6ba8 1963 process->creation_time = *timestamp;
b445142a 1964 }
2a2fa4f0 1965
1966 /* No parent. This process exists but we are missing all information about
1967 its creation. The birth time is set to zero but we remember the time of
1968 insertion */
1969
b445142a 1970 else {
1971 process->ppid = 0;
2a2fa4f0 1972 process->creation_time = ltt_time_zero;
b445142a 1973 }
1974
348c6ba8 1975 process->insertion_time = *timestamp;
b445142a 1976 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
80e0221b 1977 process->creation_time.tv_nsec);
b445142a 1978 process->pid_time = g_quark_from_string(buffer);
348c6ba8 1979 process->cpu = cpu;
1980 //process->last_cpu = tfs->cpu_name;
1981 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
e8f2280c 1982 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1983 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
c607371b 1984 process->execution_stack = g_array_set_size(process->execution_stack, 2);
b445142a 1985 es = process->state = &g_array_index(process->execution_stack,
1986 LttvExecutionState, 0);
1987 es->t = LTTV_STATE_USER_MODE;
1988 es->n = LTTV_STATE_SUBMODE_NONE;
348c6ba8 1989 es->entry = *timestamp;
1990 //g_assert(timestamp->tv_sec != 0);
1991 es->change = *timestamp;
80e0221b 1992 es->cum_cpu_time = ltt_time_zero;
c607371b 1993 es->s = LTTV_STATE_RUN;
1994
1995 es = process->state = &g_array_index(process->execution_stack,
1996 LttvExecutionState, 1);
1997 es->t = LTTV_STATE_SYSCALL;
1998 es->n = LTTV_STATE_SUBMODE_NONE;
1999 es->entry = *timestamp;
2000 //g_assert(timestamp->tv_sec != 0);
2001 es->change = *timestamp;
80e0221b 2002 es->cum_cpu_time = ltt_time_zero;
c3b3b60b 2003 es->s = LTTV_STATE_WAIT_FORK;
80e0221b 2004
2005 /* Allocate an empty function call stack. If it's empty, use 0x0. */
2006 process->user_stack = g_array_sized_new(FALSE, FALSE,
2007 sizeof(guint64), 0);
2008
cbe7c836 2009 return process;
dc877563 2010}
2011
348c6ba8 2012LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
41c7f803 2013 guint pid)
dc877563 2014{
2a2fa4f0 2015 LttvProcessState key;
2016 LttvProcessState *process;
2017
2018 key.pid = pid;
348c6ba8 2019 key.cpu = cpu;
2a2fa4f0 2020 process = g_hash_table_lookup(ts->processes, &key);
dc877563 2021 return process;
2022}
2023
2a2fa4f0 2024LttvProcessState *
348c6ba8 2025lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
d41c66bf 2026 const LttTime *timestamp)
2a2fa4f0 2027{
348c6ba8 2028 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
7bfd7820 2029 LttvExecutionState *es;
348c6ba8 2030
2031 /* Put ltt_time_zero creation time for unexisting processes */
7bfd7820 2032 if(unlikely(process == NULL)) {
80e0221b 2033 process = lttv_state_create_process(ts,
fcc08e1e 2034 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
80e0221b 2035 /* We are not sure is it's a kernel thread or normal thread, put the
2036 * bottom stack state to unknown */
c3b3b60b 2037 process->execution_stack =
2038 g_array_set_size(process->execution_stack, 1);
2039 process->state = es =
2040 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2041 es->t = LTTV_STATE_MODE_UNKNOWN;
c4a72569 2042 es->s = LTTV_STATE_UNNAMED;
80e0221b 2043 }
2a2fa4f0 2044 return process;
2045}
2046
41c7f803 2047/* FIXME : this function should be called when we receive an event telling that
2048 * release_task has been called in the kernel. In happens generally when
2049 * the parent waits for its child terminaison, but may also happen in special
2050 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
2051 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
2052 * of a killed thread ground, but isn't the leader.
41c7f803 2053 */
b445142a 2054static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
dc877563 2055{
ba576a78 2056 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
2a2fa4f0 2057 LttvProcessState key;
ba576a78 2058
2a2fa4f0 2059 key.pid = process->pid;
348c6ba8 2060 key.cpu = process->cpu;
2a2fa4f0 2061 g_hash_table_remove(ts->processes, &key);
b445142a 2062 g_array_free(process->execution_stack, TRUE);
302efbad 2063 g_array_free(process->user_stack, TRUE);
dc877563 2064 g_free(process);
2065}
2066
2067
b445142a 2068static void free_process_state(gpointer key, gpointer value,gpointer user_data)
dc877563 2069{
b445142a 2070 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
302efbad 2071 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
dc877563 2072 g_free(value);
2073}
2074
2075
308711e5 2076static void lttv_state_free_process_table(GHashTable *processes)
dc877563 2077{
2078 g_hash_table_foreach(processes, free_process_state, NULL);
308711e5 2079 g_hash_table_destroy(processes);
dc877563 2080}
2081
2082
b445142a 2083static gboolean syscall_entry(void *hook_data, void *call_data)
dc877563 2084{
ba576a78 2085 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2086 guint cpu = s->cpu;
2087 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2088 LttvProcessState *process = ts->running_process[cpu];
eed2ef37 2089 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2090 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2091 LttField *f = thf->f1;
dc877563 2092
b445142a 2093 LttvExecutionSubmode submode;
2094
80e0221b 2095 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
2096 guint syscall = ltt_event_get_unsigned(e, f);
2097
2098 if(syscall < nb_syscalls) {
2099 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
2100 syscall];
2101 } else {
2102 /* Fixup an incomplete syscall table */
2103 GString *string = g_string_new("");
7cd289b0 2104 g_string_printf(string, "syscall %u", syscall);
80e0221b 2105 submode = g_quark_from_string(string->str);
2106 g_string_free(string, TRUE);
2107 }
1e304fa1 2108 /* There can be no system call from PID 0 : unknown state */
2109 if(process->pid != 0)
2110 push_state(s, LTTV_STATE_SYSCALL, submode);
dc877563 2111 return FALSE;
2112}
2113
2114
b445142a 2115static gboolean syscall_exit(void *hook_data, void *call_data)
dc877563 2116{
ba576a78 2117 LttvTracefileState *s = (LttvTracefileState *)call_data;
1e304fa1 2118 guint cpu = s->cpu;
2119 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2120 LttvProcessState *process = ts->running_process[cpu];
dc877563 2121
1e304fa1 2122 /* There can be no system call from PID 0 : unknown state */
2123 if(process->pid != 0)
2124 pop_state(s, LTTV_STATE_SYSCALL);
dc877563 2125 return FALSE;
2126}
2127
2128
b445142a 2129static gboolean trap_entry(void *hook_data, void *call_data)
dc877563 2130{
ba576a78 2131 LttvTracefileState *s = (LttvTracefileState *)call_data;
eed2ef37 2132 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2133 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2134 LttField *f = thf->f1;
dc877563 2135
b445142a 2136 LttvExecutionSubmode submode;
2137
17ddd1f2 2138 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
2139 guint64 trap = ltt_event_get_long_unsigned(e, f);
5e96e7e3 2140
2141 if(trap < nb_traps) {
2142 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
2143 } else {
2144 /* Fixup an incomplete trap table */
2145 GString *string = g_string_new("");
fcc08e1e 2146 g_string_printf(string, "trap %llu", trap);
5e96e7e3 2147 submode = g_quark_from_string(string->str);
2148 g_string_free(string, TRUE);
2149 }
2150
b445142a 2151 push_state(s, LTTV_STATE_TRAP, submode);
d3d99fde 2152
2153 /* update cpu status */
2154 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
2155
dc877563 2156 return FALSE;
2157}
2158
b445142a 2159static gboolean trap_exit(void *hook_data, void *call_data)
dc877563 2160{
ba576a78 2161 LttvTracefileState *s = (LttvTracefileState *)call_data;
dc877563 2162
ffd54a90 2163 pop_state(s, LTTV_STATE_TRAP);
d3d99fde 2164
2165 /* update cpu status */
2166 cpu_pop_mode(s->cpu_state);
2167
dc877563 2168 return FALSE;
2169}
2170
b445142a 2171static gboolean irq_entry(void *hook_data, void *call_data)
dc877563 2172{
ba576a78 2173 LttvTracefileState *s = (LttvTracefileState *)call_data;
5e563da0 2174 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
eed2ef37 2175 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
9d239bd9 2176 guint8 fac_id = ltt_event_facility_id(e);
2177 guint8 ev_id = ltt_event_eventtype_id(e);
d052ffc3 2178 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
9d239bd9 2179 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2180 g_assert(thf->f1 != NULL);
2181 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
eed2ef37 2182 LttField *f = thf->f1;
dc877563 2183
b445142a 2184 LttvExecutionSubmode submode;
1bb8d3a5 2185 guint64 irq = ltt_event_get_long_unsigned(e, f);
6214c229 2186 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
2187 GString *string;
b445142a 2188
6214c229 2189 if(irq < nb_irqs) {
2190 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2191 } else {
2192 /* Fixup an incomplete irq table */
2193 GString *string = g_string_new("");
2194 g_string_printf(string, "irq %llu", irq);
2195 submode = g_quark_from_string(string->str);
2196 g_string_free(string, TRUE);
2197 }
b445142a 2198
dc877563 2199 /* Do something with the info about being in user or system mode when int? */
b445142a 2200 push_state(s, LTTV_STATE_IRQ, submode);
598026ba 2201
2202 /* update cpu status */
d3d99fde 2203 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
598026ba 2204
5e563da0 2205 /* update irq status */
8743690d 2206 s->cpu_state->last_irq = irq;
5e563da0 2207 irq_push_mode(&ts->irq_states[irq], LTTV_IRQ_BUSY);
2208
dc877563 2209 return FALSE;
2210}
2211
302efbad 2212static gboolean soft_irq_exit(void *hook_data, void *call_data)
2213{
2214 LttvTracefileState *s = (LttvTracefileState *)call_data;
2215
2216 pop_state(s, LTTV_STATE_SOFT_IRQ);
2217 return FALSE;
2218}
2219
2220
dc877563 2221
b445142a 2222static gboolean irq_exit(void *hook_data, void *call_data)
dc877563 2223{
ba576a78 2224 LttvTracefileState *s = (LttvTracefileState *)call_data;
8743690d 2225 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
dc877563 2226
ffd54a90 2227 pop_state(s, LTTV_STATE_IRQ);
598026ba 2228
2229 /* update cpu status */
d3d99fde 2230 cpu_pop_mode(s->cpu_state);
598026ba 2231
8743690d 2232 /* update irq status */
2233 irq_pop_mode(&ts->irq_states[s->cpu_state->last_irq]);
2234
dc877563 2235 return FALSE;
2236}
2237
faf074a3 2238static gboolean soft_irq_entry(void *hook_data, void *call_data)
2239{
2240 LttvTracefileState *s = (LttvTracefileState *)call_data;
2241 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2242 guint8 fac_id = ltt_event_facility_id(e);
2243 guint8 ev_id = ltt_event_eventtype_id(e);
2244 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2245 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2246 g_assert(thf->f1 != NULL);
2247 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2248 LttField *f = thf->f1;
2249
2250 LttvExecutionSubmode submode;
1bb8d3a5 2251 guint64 softirq = ltt_event_get_long_unsigned(e, f);
6214c229 2252 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
2253 GString *string;
faf074a3 2254
6214c229 2255 if(softirq < nb_softirqs) {
2256 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2257 } else {
2258 /* Fixup an incomplete irq table */
2259 GString *string = g_string_new("");
2260 g_string_printf(string, "softirq %llu", softirq);
2261 submode = g_quark_from_string(string->str);
2262 g_string_free(string, TRUE);
2263 }
faf074a3 2264
2265 /* Do something with the info about being in user or system mode when int? */
2266 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2267 return FALSE;
2268}
2269
44c0619e 2270static LttvBdevState *bdev_state_get(LttvTraceState *ts, guint16 devcode)
27811799 2271{
2272 gint devcode_gint = devcode;
2273 gpointer bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
2274 if(bdev == NULL) {
2275 LttvBdevState *bdevstate = g_malloc(sizeof(LttvBdevState));
2276 bdevstate->mode_stack = g_array_new(FALSE, FALSE, sizeof(GQuark));
2277
2278 gint * key = g_malloc(sizeof(gint));
2279 *key = devcode;
2280 g_hash_table_insert(ts->bdev_states, key, bdevstate);
2281 printf("adding key %u to hash table\n", *key);
2282
2283 bdev = bdevstate;
2284 }
2285
2286 return bdev;
2287}
2288
44c0619e 2289static void bdev_state_free(gpointer key, gpointer value, gpointer user_data)
2290{
2291 LttvBdevState *bds = (LttvBdevState *) value;
2292
2293 g_array_free(bds->mode_stack, FALSE);
2294 g_free(bds);
2295}
2296
27811799 2297static gboolean bdev_request_issue(void *hook_data, void *call_data)
2298{
2299 LttvTracefileState *s = (LttvTracefileState *)call_data;
2300 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2301 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2302 guint8 fac_id = ltt_event_facility_id(e);
2303 guint8 ev_id = ltt_event_eventtype_id(e);
2304 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2305
2306 guint major = ltt_event_get_long_unsigned(e, thf->f1);
2307 guint minor = ltt_event_get_long_unsigned(e, thf->f2);
2308 guint oper = ltt_event_get_long_unsigned(e, thf->f3);
2309 guint16 devcode = MKDEV(major,minor);
2310
2311 /* have we seen this block device before? */
2312 gpointer bdev = bdev_state_get(ts, devcode);
2313
2314 if(oper == 0)
2315 bdev_push_mode(bdev, LTTV_BDEV_BUSY_READING);
2316 else
2317 bdev_push_mode(bdev, LTTV_BDEV_BUSY_WRITING);
2318
2319 return FALSE;
2320}
2321
2322static gboolean bdev_request_complete(void *hook_data, void *call_data)
2323{
2324 LttvTracefileState *s = (LttvTracefileState *)call_data;
2325 LttvTraceState *ts = (LttvTraceState *)s->parent.t_context;
2326 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2327 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2328
2329 guint major = ltt_event_get_long_unsigned(e, thf->f1);
2330 guint minor = ltt_event_get_long_unsigned(e, thf->f2);
2331 guint oper = ltt_event_get_long_unsigned(e, thf->f3);
2332 guint16 devcode = MKDEV(major,minor);
2333
2334 /* have we seen this block device before? */
2335 gpointer bdev = bdev_state_get(ts, devcode);
2336
2337 /* update block device */
2338 bdev_pop_mode(bdev);
2339
2340 return FALSE;
2341}
2342
302efbad 2343static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2344{
2345 guint64 *new_func;
2346
2347 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2348 guint cpu = tfs->cpu;
2349 LttvProcessState *process = ts->running_process[cpu];
faf074a3 2350
302efbad 2351 guint depth = process->user_stack->len;
2352
2353 process->user_stack =
2354 g_array_set_size(process->user_stack, depth + 1);
2355
2356 new_func = &g_array_index(process->user_stack, guint64, depth);
80e0221b 2357 *new_func = funcptr;
9bff13df 2358 process->current_function = funcptr;
302efbad 2359}
2360
2361static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2362{
2363 guint cpu = tfs->cpu;
2364 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2365 LttvProcessState *process = ts->running_process[cpu];
2366
302efbad 2367 if(process->current_function != funcptr){
2368 g_info("Different functions (%lu.%09lu): ignore it\n",
2369 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2370 g_info("process state has %llu when pop_function is %llu\n",
80e0221b 2371 process->current_function, funcptr);
7b5f6cf1 2372 g_info("{ %u, %u, %s, %s, %s }\n",
80e0221b 2373 process->pid,
2374 process->ppid,
2375 g_quark_to_string(process->name),
2376 g_quark_to_string(process->brand),
2377 g_quark_to_string(process->state->s));
302efbad 2378 return;
2379 }
9bff13df 2380 guint depth = process->user_stack->len;
302efbad 2381
2382 if(depth == 0){
2383 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2384 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2385 return;
2386 }
2387
2388 process->user_stack =
2389 g_array_set_size(process->user_stack, depth - 1);
2390 process->current_function =
80e0221b 2391 g_array_index(process->user_stack, guint64, depth - 2);
302efbad 2392}
2393
2394
2395static gboolean function_entry(void *hook_data, void *call_data)
faf074a3 2396{
2397 LttvTracefileState *s = (LttvTracefileState *)call_data;
302efbad 2398 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2399 guint8 fac_id = ltt_event_facility_id(e);
2400 guint8 ev_id = ltt_event_eventtype_id(e);
2401 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2402 g_assert(thf->f1 != NULL);
2403 LttField *f = thf->f1;
80e0221b 2404 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
faf074a3 2405
302efbad 2406 push_function(s, funcptr);
faf074a3 2407 return FALSE;
2408}
2409
302efbad 2410static gboolean function_exit(void *hook_data, void *call_data)
2411{
2412 LttvTracefileState *s = (LttvTracefileState *)call_data;
2413 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2414 guint8 fac_id = ltt_event_facility_id(e);
2415 guint8 ev_id = ltt_event_eventtype_id(e);
2416 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2417 g_assert(thf->f1 != NULL);
2418 LttField *f = thf->f1;
80e0221b 2419 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
302efbad 2420
2421 LttvExecutionSubmode submode;
2422
2423 pop_function(s, funcptr);
2424 return FALSE;
2425}
dc877563 2426
b445142a 2427static gboolean schedchange(void *hook_data, void *call_data)
dc877563 2428{
ba576a78 2429 LttvTracefileState *s = (LttvTracefileState *)call_data;
ae3d0f50 2430 guint cpu = s->cpu;
348c6ba8 2431 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2432 LttvProcessState *process = ts->running_process[cpu];
48b002b8 2433 LttvProcessState *old_process = ts->running_process[cpu];
348c6ba8 2434
eed2ef37 2435 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2436 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
73394fd3 2437 guint pid_in, pid_out;
7092fb86 2438 gint64 state_out;
dc877563 2439
eed2ef37 2440 pid_out = ltt_event_get_unsigned(e, thf->f1);
2441 pid_in = ltt_event_get_unsigned(e, thf->f2);
7092fb86 2442 state_out = ltt_event_get_long_int(e, thf->f3);
348c6ba8 2443
2444 if(likely(process != NULL)) {
b445142a 2445
f95bc830 2446 /* We could not know but it was not the idle process executing.
2447 This should only happen at the beginning, before the first schedule
2448 event, and when the initial information (current process for each CPU)
2449 is missing. It is not obvious how we could, after the fact, compensate
2450 the wrongly attributed statistics. */
2451
240f1fea 2452 //This test only makes sense once the state is known and if there is no
48b002b8 2453 //missing events. We need to silently ignore schedchange coming after a
80e0221b 2454 //process_free, or it causes glitches. (FIXME)
348c6ba8 2455 //if(unlikely(process->pid != pid_out)) {
2456 // g_assert(process->pid == 0);
240f1fea 2457 //}
c4a72569 2458 if(process->pid == 0
2459 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2460 if(pid_out == 0) {
2461 /* Scheduling out of pid 0 at beginning of the trace :
2462 * we know for sure it is in syscall mode at this point. */
2463 g_assert(process->execution_stack->len == 1);
2464 process->state->t = LTTV_STATE_SYSCALL;
2465 process->state->s = LTTV_STATE_WAIT;
2466 process->state->change = s->parent.timestamp;
d3670e3d 2467 process->state->entry = s->parent.timestamp;
c4a72569 2468 }
dbd243b1 2469 } else {
c4a72569 2470 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2471 process->state->s = LTTV_STATE_ZOMBIE;
2472 process->state->change = s->parent.timestamp;
2473 } else {
2474 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2475 else process->state->s = LTTV_STATE_WAIT;
2476 process->state->change = s->parent.timestamp;
2477 }
2478
5fe0b9ca 2479 if(state_out == 32 || state_out == 128)
2480 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
c4a72569 2481 /* see sched.h for states */
791dffa6 2482 }
dc877563 2483 }
348c6ba8 2484 process = ts->running_process[cpu] =
2485 lttv_state_find_process_or_create(
2486 (LttvTraceState*)s->parent.t_context,
2487 cpu, pid_in,
2488 &s->parent.timestamp);
2489 process->state->s = LTTV_STATE_RUN;
2490 process->cpu = cpu;
80e0221b 2491 if(process->usertrace)
2492 process->usertrace->cpu = cpu;
348c6ba8 2493 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2494 process->state->change = s->parent.timestamp;
44ffb95f 2495
2496 /* update cpu status */
2497 if(pid_in == 0)
d3d99fde 2498 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
44ffb95f 2499 else
d3d99fde 2500 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
44ffb95f 2501
dc877563 2502 return FALSE;
2503}
2504
eed2ef37 2505static gboolean process_fork(void *hook_data, void *call_data)
dc877563 2506{
eed2ef37 2507 LttvTracefileState *s = (LttvTracefileState *)call_data;
2508 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2509 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2510 guint parent_pid;
fcc08e1e 2511 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2512 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
4ad73431 2513 LttvProcessState *zombie_process;
ae3d0f50 2514 guint cpu = s->cpu;
348c6ba8 2515 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2516 LttvProcessState *process = ts->running_process[cpu];
26275aa2 2517 LttvProcessState *child_process;
2cdc690b 2518
eed2ef37 2519 /* Parent PID */
b3fd4c02 2520 parent_pid = ltt_event_get_unsigned(e, thf->f1);
eed2ef37 2521
2cdc690b 2522 /* Child PID */
b3fd4c02 2523 child_pid = ltt_event_get_unsigned(e, thf->f2);
33bdc8dd 2524 s->parent.target_pid = child_pid;
2cdc690b 2525
fcc08e1e 2526 /* Child TGID */
2527 if(thf->f3) child_tgid = ltt_event_get_unsigned(e, thf->f3);
2528 else child_tgid = 0;
2529
15b3d537 2530 /* Mathieu : it seems like the process might have been scheduled in before the
2531 * fork, and, in a rare case, might be the current process. This might happen
d4942a23 2532 * in a SMP case where we don't have enough precision on the clocks.
2533 *
2534 * Test reenabled after precision fixes on time. (Mathieu) */
791dffa6 2535#if 0
348c6ba8 2536 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
dc877563 2537
1d1df11d 2538 if(unlikely(zombie_process != NULL)) {
4ad73431 2539 /* Reutilisation of PID. Only now we are sure that the old PID
eed2ef37 2540 * has been released. FIXME : should know when release_task happens instead.
4ad73431 2541 */
15b3d537 2542 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2543 guint i;
2544 for(i=0; i< num_cpus; i++) {
5ac05980 2545 g_assert(zombie_process != ts->running_process[i]);
15b3d537 2546 }
2547
4ad73431 2548 exit_process(s, zombie_process);
2549 }
791dffa6 2550#endif //0
348c6ba8 2551 g_assert(process->pid != child_pid);
eed2ef37 2552 // FIXME : Add this test in the "known state" section
348c6ba8 2553 // g_assert(process->pid == parent_pid);
26275aa2 2554 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2555 if(child_process == NULL) {
ab893fb1 2556 child_process = lttv_state_create_process(ts, process, cpu,
fcc08e1e 2557 child_pid, child_tgid,
2558 LTTV_STATE_UNNAMED, &s->parent.timestamp);
26275aa2 2559 } else {
2560 /* The process has already been created : due to time imprecision between
791dffa6 2561 * multiple CPUs : it has been scheduled in before creation. Note that we
2562 * shouldn't have this kind of imprecision.
26275aa2 2563 *
2564 * Simply put a correct parent.
2565 */
6806b3c6 2566 g_assert(0); /* This is a problematic case : the process has been created
2567 before the fork event */
26275aa2 2568 child_process->ppid = process->pid;
fcc08e1e 2569 child_process->tgid = child_tgid;
26275aa2 2570 }
0292757b 2571 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2572 child_process->name = process->name;
2573 child_process->brand = process->brand;
4ad73431 2574
dc877563 2575 return FALSE;
2576}
2577
89f8741a 2578/* We stamp a newly created process as kernel_thread.
2579 * The thread should not be running yet. */
7bfd7820 2580static gboolean process_kernel_thread(void *hook_data, void *call_data)
2581{
2582 LttvTracefileState *s = (LttvTracefileState *)call_data;
2583 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2584 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2585 guint pid;
ae3d0f50 2586 guint cpu = s->cpu;
7bfd7820 2587 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2588 LttvProcessState *process;
2589 LttvExecutionState *es;
2590
2591 /* PID */
61c8808e 2592 pid = (guint)ltt_event_get_long_unsigned(e, thf->f1);
33bdc8dd 2593 s->parent.target_pid = pid;
7bfd7820 2594
61c8808e 2595 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2596 &ltt_time_zero);
15f3a340 2597 process->execution_stack =
2598 g_array_set_size(process->execution_stack, 1);
2599 es = process->state =
2600 &g_array_index(process->execution_stack, LttvExecutionState, 0);
80e0221b 2601 es->t = LTTV_STATE_SYSCALL;
2602 process->type = LTTV_STATE_KERNEL_THREAD;
7bfd7820 2603
80e0221b 2604 return FALSE;
7bfd7820 2605}
dc877563 2606
eed2ef37 2607static gboolean process_exit(void *hook_data, void *call_data)
dc877563 2608{
eed2ef37 2609 LttvTracefileState *s = (LttvTracefileState *)call_data;
2610 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2611 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
eed2ef37 2612 LttField *f;
2613 guint pid;
ae3d0f50 2614 guint cpu = s->cpu;
348c6ba8 2615 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
6f54e0f4 2616 LttvProcessState *process; // = ts->running_process[cpu];
eed2ef37 2617
2618 pid = ltt_event_get_unsigned(e, thf->f1);
33bdc8dd 2619 s->parent.target_pid = pid;
eed2ef37 2620
2621 // FIXME : Add this test in the "known state" section
348c6ba8 2622 // g_assert(process->pid == pid);
eed2ef37 2623
6f54e0f4 2624 process = lttv_state_find_process(ts, ANY_CPU, pid);
348c6ba8 2625 if(likely(process != NULL)) {
2626 process->state->s = LTTV_STATE_EXIT;
2cdc690b 2627 }
2628 return FALSE;
2cdc690b 2629}
2630
eed2ef37 2631static gboolean process_free(void *hook_data, void *call_data)
2da61677 2632{
eed2ef37 2633 LttvTracefileState *s = (LttvTracefileState *)call_data;
348c6ba8 2634 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
eed2ef37 2635 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
d052ffc3 2636 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2da61677 2637 guint release_pid;
2638 LttvProcessState *process;
2639
2640 /* PID of the process to release */
eed2ef37 2641 release_pid = ltt_event_get_unsigned(e, thf->f1);
33bdc8dd 2642 s->parent.target_pid = release_pid;
15b3d537 2643
2644 g_assert(release_pid != 0);
2da61677 2645
348c6ba8 2646 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2da61677 2647
2648 if(likely(process != NULL)) {
2649 /* release_task is happening at kernel level : we can now safely release
2650 * the data structure of the process */
5562ddce 2651 //This test is fun, though, as it may happen that
2652 //at time t : CPU 0 : process_free
2653 //at time t+150ns : CPU 1 : schedule out
2654 //Clearly due to time imprecision, we disable it. (Mathieu)
2655 //If this weird case happen, we have no choice but to put the
2656 //Currently running process on the cpu to 0.
791dffa6 2657 //I re-enable it following time precision fixes. (Mathieu)
2658 //Well, in the case where an process is freed by a process on another CPU
2659 //and still scheduled, it happens that this is the schedchange that will
2660 //drop the last reference count. Do not free it here!
0bd2f89c 2661 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2662 guint i;
2663 for(i=0; i< num_cpus; i++) {
5562ddce 2664 //g_assert(process != ts->running_process[i]);
2665 if(process == ts->running_process[i]) {
791dffa6 2666 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2667 break;
5562ddce 2668 }
0bd2f89c 2669 }
6f54e0f4 2670 if(i == num_cpus) /* process is not scheduled */
2671 exit_process(s, process);
2da61677 2672 }
2673
2674 return FALSE;
2675}
2676
f4b88a7d 2677
2678static gboolean process_exec(void *hook_data, void *call_data)
2679{
2680 LttvTracefileState *s = (LttvTracefileState *)call_data;
2681 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2682 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2683 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
743e50fd 2684 //gchar *name;
ae3d0f50 2685 guint cpu = s->cpu;
f4b88a7d 2686 LttvProcessState *process = ts->running_process[cpu];
2687
f63ebe51 2688#if 0//how to use a sequence that must be transformed in a string
f4b88a7d 2689 /* PID of the process to release */
743e50fd 2690 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
2691 //name = ltt_event_get_string(e, thf->f1);
f2923fb2 2692 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
2693 gchar *name_begin =
2694 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
743e50fd 2695 gchar *null_term_name = g_new(gchar, name_len+1);
2696 memcpy(null_term_name, name_begin, name_len);
2697 null_term_name[name_len] = '\0';
743e50fd 2698 process->name = g_quark_from_string(null_term_name);
f63ebe51 2699#endif //0
2700
7092fb86 2701 process->name = g_quark_from_string(ltt_event_get_string(e, thf->f1));
0292757b 2702 process->brand = LTTV_STATE_UNBRANDED;
f63ebe51 2703 //g_free(null_term_name);
f4b88a7d 2704 return FALSE;
2705}
2706
7b5f6cf1 2707static gboolean thread_brand(void *hook_data, void *call_data)
2708{
2709 LttvTracefileState *s = (LttvTracefileState *)call_data;
2710 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2711 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2712 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2713 gchar *name;
2714 guint cpu = s->cpu;
2715 LttvProcessState *process = ts->running_process[cpu];
2716
2717 name = ltt_event_get_string(e, thf->f1);
2718 process->brand = g_quark_from_string(name);
2719
2720 return FALSE;
2721}
2722
c3b3b60b 2723static void fix_process(gpointer key, gpointer value,
2724 gpointer user_data)
2725{
2726 LttvProcessState *process;
2727 LttvExecutionState *es;
2728 process = (LttvProcessState *)value;
2729 LttvTracefileContext *tfc = (LttvTracefileContext *)user_data;
2730 LttTime *timestamp = (LttTime*)user_data;
2731
c3b3b60b 2732 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2b25224d 2733 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2734 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2735 es->t = LTTV_STATE_SYSCALL;
2b25224d 2736 es->n = LTTV_STATE_SUBMODE_NONE;
2737 es->entry = *timestamp;
2738 es->change = *timestamp;
2739 es->cum_cpu_time = ltt_time_zero;
c4a72569 2740 if(es->s == LTTV_STATE_UNNAMED)
2741 es->s = LTTV_STATE_WAIT;
c3b3b60b 2742 }
2743 } else {
2b25224d 2744 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2745 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
c3b3b60b 2746 es->t = LTTV_STATE_USER_MODE;
2747 es->n = LTTV_STATE_SUBMODE_NONE;
2748 es->entry = *timestamp;
2749 //g_assert(timestamp->tv_sec != 0);
2750 es->change = *timestamp;
2751 es->cum_cpu_time = ltt_time_zero;
c4a72569 2752 if(es->s == LTTV_STATE_UNNAMED)
2753 es->s = LTTV_STATE_RUN;
c3b3b60b 2754
2b25224d 2755 if(process->execution_stack->len == 1) {
89f8741a 2756 /* Still in bottom unknown mode, means never did a system call
2757 * May be either in user mode, syscall mode, running or waiting.*/
2758 /* FIXME : we may be tagging syscall mode when being user mode */
2b25224d 2759 process->execution_stack =
2760 g_array_set_size(process->execution_stack, 2);
2761 es = process->state = &g_array_index(process->execution_stack,
c3b3b60b 2762 LttvExecutionState, 1);
2b25224d 2763 es->t = LTTV_STATE_SYSCALL;
2764 es->n = LTTV_STATE_SUBMODE_NONE;
2765 es->entry = *timestamp;
2766 //g_assert(timestamp->tv_sec != 0);
2767 es->change = *timestamp;
2768 es->cum_cpu_time = ltt_time_zero;
b59b7222 2769 if(es->s == LTTV_STATE_WAIT_FORK)
2770 es->s = LTTV_STATE_WAIT;
2b25224d 2771 }
c3b3b60b 2772 }
2773 }
2774}
2775
2776static gboolean statedump_end(void *hook_data, void *call_data)
2777{
2778 LttvTracefileState *s = (LttvTracefileState *)call_data;
2779 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2780 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2781 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2782 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2783
2784 /* For all processes */
2785 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2786 /* else, if stack[0] is unknown, set to user mode, running */
2787
2788 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
2789}
2790
b3fd4c02 2791static gboolean enum_process_state(void *hook_data, void *call_data)
2792{
2793 LttvTracefileState *s = (LttvTracefileState *)call_data;
2794 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
80e0221b 2795 //It's slow : optimise later by doing this before reading trace.
2796 LttEventType *et = ltt_event_eventtype(e);
2797 //
b3fd4c02 2798 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2799 guint parent_pid;
2800 guint pid;
fcc08e1e 2801 guint tgid;
b3fd4c02 2802 gchar * command;
ae3d0f50 2803 guint cpu = s->cpu;
b3fd4c02 2804 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2805 LttvProcessState *process = ts->running_process[cpu];
2806 LttvProcessState *parent_process;
fcc08e1e 2807 LttField *f4, *f5, *f6, *f7, *f8;
80e0221b 2808 GQuark type, mode, submode, status;
2809 LttvExecutionState *es;
c4a72569 2810 guint i, nb_cpus;
f4b88a7d 2811
b3fd4c02 2812 /* PID */
2813 pid = ltt_event_get_unsigned(e, thf->f1);
e38d9ea0 2814 s->parent.target_pid = pid;
2815
b3fd4c02 2816 /* Parent PID */
2817 parent_pid = ltt_event_get_unsigned(e, thf->f2);
2818
2819 /* Command name */
2820 command = ltt_event_get_string(e, thf->f3);
2821
80e0221b 2822 /* type */
2823 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
2824 type = ltt_enum_string_get(ltt_field_type(f4),
2825 ltt_event_get_unsigned(e, f4));
b3fd4c02 2826
80e0221b 2827 /* mode */
2828 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
2829 mode = ltt_enum_string_get(ltt_field_type(f5),
2830 ltt_event_get_unsigned(e, f5));
b3fd4c02 2831
80e0221b 2832 /* submode */
2833 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
2834 submode = ltt_enum_string_get(ltt_field_type(f6),
2835 ltt_event_get_unsigned(e, f6));
b3fd4c02 2836
80e0221b 2837 /* status */
2838 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
2839 status = ltt_enum_string_get(ltt_field_type(f7),
2840 ltt_event_get_unsigned(e, f7));
e62e7f3a 2841
fcc08e1e 2842 /* TGID */
2843 f8 = ltt_eventtype_field_by_name(et, LTT_FIELD_TGID);
2844 if(f8) tgid = ltt_event_get_unsigned(e, f8);
2845 else tgid = 0;
2846
c4a72569 2847
2848 if(pid == 0) {
2849 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2850 for(i=0; i<nb_cpus; i++) {
2851 process = lttv_state_find_process(ts, i, pid);
2852 g_assert(process != NULL);
2853
2854 process->ppid = parent_pid;
2855 process->tgid = tgid;
2856 process->name = g_quark_from_string(command);
2857 es =
2858 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2859 process->type = LTTV_STATE_KERNEL_THREAD;
c4a72569 2860 }
2861
2862 } else {
2863 /* The process might exist if a process was forked while performing the
2864 * state dump. */
2865 process = lttv_state_find_process(ts, ANY_CPU, pid);
2866 if(process == NULL) {
2867 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2868 process = lttv_state_create_process(ts, parent_process, cpu,
2869 pid, tgid, g_quark_from_string(command),
2870 &s->parent.timestamp);
2871
2872 /* Keep the stack bottom : a running user mode */
2873 /* Disabled because of inconsistencies in the current statedump states. */
2874 if(type == LTTV_STATE_KERNEL_THREAD) {
2875 /* Only keep the bottom
2876 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2877 /* Will cause expected trap when in fact being syscall (even after end of
2878 * statedump event)
2879 * Will cause expected interrupt when being syscall. (only before end of
2880 * statedump event) */
2881 // This will cause a "popping last state on stack, ignoring it."
2882 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2883 es = process->state = &g_array_index(process->execution_stack,
2884 LttvExecutionState, 0);
2885 process->type = LTTV_STATE_KERNEL_THREAD;
2886 es->t = LTTV_STATE_MODE_UNKNOWN;
2887 es->s = LTTV_STATE_UNNAMED;
2888 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2889 #if 0
2890 es->t = LTTV_STATE_SYSCALL;
2891 es->s = status;
2892 es->n = submode;
2893 #endif //0
2894 } else {
2895 /* User space process :
2896 * bottom : user mode
2897 * either currently running or scheduled out.
2898 * can be scheduled out because interrupted in (user mode or in syscall)
2899 * or because of an explicit call to the scheduler in syscall. Note that
2900 * the scheduler call comes after the irq_exit, so never in interrupt
2901 * context. */
2902 // temp workaround : set size to 1 : only have user mode bottom of stack.
2903 // will cause g_info message of expected syscall mode when in fact being
2904 // in user mode. Can also cause expected trap when in fact being user
2905 // mode in the event of a page fault reenabling interrupts in the handler.
2906 // Expected syscall and trap can also happen after the end of statedump
2907 // This will cause a "popping last state on stack, ignoring it."
2908 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2909 es = process->state = &g_array_index(process->execution_stack,
2910 LttvExecutionState, 0);
2911 es->t = LTTV_STATE_MODE_UNKNOWN;
2912 es->s = LTTV_STATE_UNNAMED;
2913 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2914 #if 0
2915 es->t = LTTV_STATE_USER_MODE;
2916 es->s = status;
2917 es->n = submode;
2918 #endif //0
2919 }
2920 #if 0
2921 /* UNKNOWN STATE */
2922 {
2923 es = process->state = &g_array_index(process->execution_stack,
2924 LttvExecutionState, 1);
2925 es->t = LTTV_STATE_MODE_UNKNOWN;
2926 es->s = LTTV_STATE_UNNAMED;
2927 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2928 }
2929 #endif //0
80e0221b 2930 } else {
c4a72569 2931 /* The process has already been created :
2932 * Probably was forked while dumping the process state or
2933 * was simply scheduled in prior to get the state dump event.
2934 */
2935 process->ppid = parent_pid;
2936 process->tgid = tgid;
2937 process->name = g_quark_from_string(command);
2938 process->type = type;
2939 es =
2940 &g_array_index(process->execution_stack, LttvExecutionState, 0);
c3b3b60b 2941#if 0
c4a72569 2942 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2943 if(type == LTTV_STATE_KERNEL_THREAD)
2944 es->t = LTTV_STATE_SYSCALL;
2945 else
2946 es->t = LTTV_STATE_USER_MODE;
2947 }
cab321cf 2948#endif //0
c4a72569 2949 /* Don't mess around with the stack, it will eventually become
2950 * ok after the end of state dump. */
80e0221b 2951 }
b3fd4c02 2952 }
2953
2954 return FALSE;
2955}
f4b88a7d 2956
58c88a41 2957gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
2958{
2959 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2960
2961 lttv_state_add_event_hooks(tss);
2962
2963 return 0;
2964}
dc877563 2965
308711e5 2966void lttv_state_add_event_hooks(LttvTracesetState *self)
dc877563 2967{
ba576a78 2968 LttvTraceset *traceset = self->parent.ts;
dc877563 2969
eed2ef37 2970 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 2971
ba576a78 2972 LttvTraceState *ts;
dc877563 2973
ba576a78 2974 LttvTracefileState *tfs;
dc877563 2975
dc877563 2976 GArray *hooks;
2977
eed2ef37 2978 LttvTraceHookByFacility *thf;
2979
2980 LttvTraceHook *hook;
dc877563 2981
2982 LttvAttributeValue val;
2983
9d239bd9 2984 gint ret;
80e0221b 2985 gint hn;
9d239bd9 2986
ba576a78 2987 nb_trace = lttv_traceset_number(traceset);
dc877563 2988 for(i = 0 ; i < nb_trace ; i++) {
ba576a78 2989 ts = (LttvTraceState *)self->parent.traces[i];
dc877563 2990
2991 /* Find the eventtype id for the following events and register the
2992 associated by id hooks. */
2993
c3b3b60b 2994 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
2995 hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
80e0221b 2996 hn = 0;
b445142a 2997
9d239bd9 2998 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 2999 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
eed2ef37 3000 LTT_FIELD_SYSCALL_ID, 0, 0,
302efbad 3001 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3002 if(ret) hn--;
cbe7c836 3003
9d239bd9 3004 ret = lttv_trace_find_hook(ts->parent.t,
f5d7967f 3005 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
eed2ef37 3006 0, 0, 0,
302efbad 3007 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3008 if(ret) hn--;
cbe7c836 3009
9d239bd9 3010 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3011 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
eed2ef37 3012 LTT_FIELD_TRAP_ID, 0, 0,
302efbad 3013 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3014 if(ret) hn--;
cbe7c836 3015
9d239bd9 3016 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3017 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
eed2ef37 3018 0, 0, 0,
302efbad 3019 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3020 if(ret) hn--;
cbe7c836 3021
9d239bd9 3022 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 3023 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
3024 LTT_FIELD_IRQ_ID, 0, 0,
302efbad 3025 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3026 if(ret) hn--;
cbe7c836 3027
9d239bd9 3028 ret = lttv_trace_find_hook(ts->parent.t,
eed2ef37 3029 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
3030 0, 0, 0,
302efbad 3031 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3032 if(ret) hn--;
cbe7c836 3033
faf074a3 3034 ret = lttv_trace_find_hook(ts->parent.t,
3035 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
3036 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
302efbad 3037 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3038 if(ret) hn--;
faf074a3 3039
3040 ret = lttv_trace_find_hook(ts->parent.t,
3041 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
3042 0, 0, 0,
302efbad 3043 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3044 if(ret) hn--;
faf074a3 3045
9d239bd9 3046 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3047 LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
f63ebe51 3048 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
302efbad 3049 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3050 if(ret) hn--;
cbe7c836 3051
9d239bd9 3052 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3053 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FORK,
f63ebe51 3054 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, LTT_FIELD_CHILD_TGID,
302efbad 3055 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3056 if(ret) hn--;
eed2ef37 3057
7bfd7820 3058 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3059 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_KTHREAD_CREATE,
7bfd7820 3060 LTT_FIELD_PID, 0, 0,
302efbad 3061 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
80e0221b 3062 hn++));
3063 if(ret) hn--;
7bfd7820 3064
9d239bd9 3065 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3066 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
eed2ef37 3067 LTT_FIELD_PID, 0, 0,
302efbad 3068 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3069 if(ret) hn--;
eed2ef37 3070
9d239bd9 3071 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3072 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FREE,
eed2ef37 3073 LTT_FIELD_PID, 0, 0,
302efbad 3074 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3075 if(ret) hn--;
2cdc690b 3076
f4b88a7d 3077 ret = lttv_trace_find_hook(ts->parent.t,
3078 LTT_FACILITY_FS, LTT_EVENT_EXEC,
3079 LTT_FIELD_FILENAME, 0, 0,
302efbad 3080 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3081 if(ret) hn--;
f4b88a7d 3082
7b5f6cf1 3083 ret = lttv_trace_find_hook(ts->parent.t,
3084 LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
3085 LTT_FIELD_NAME, 0, 0,
3086 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3087 if(ret) hn--;
7b5f6cf1 3088
b3fd4c02 3089 /* statedump-related hooks */
3090 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3091 LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
b3fd4c02 3092 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
302efbad 3093 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3094 if(ret) hn--;
f4b88a7d 3095
c3b3b60b 3096 ret = lttv_trace_find_hook(ts->parent.t,
86c32a8f 3097 LTT_FACILITY_LIST, LTT_EVENT_STATEDUMP_END,
c3b3b60b 3098 0, 0, 0,
3099 statedump_end, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3100 if(ret) hn--;
3101
27811799 3102 ret = lttv_trace_find_hook(ts->parent.t,
3103 LTT_FACILITY_BLOCK, LTT_EVENT_REQUEST_ISSUE,
3104 LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION,
3105 bdev_request_issue, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3106 if(ret) hn--;
3107
3108 ret = lttv_trace_find_hook(ts->parent.t,
3109 LTT_FACILITY_BLOCK, LTT_EVENT_REQUEST_COMPLETE,
3110 LTT_FIELD_MAJOR, LTT_FIELD_MINOR, LTT_FIELD_OPERATION,
3111 bdev_request_complete, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
3112 if(ret) hn--;
3113
302efbad 3114 ret = lttv_trace_find_hook(ts->parent.t,
3115 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
3116 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
3117 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3118 if(ret) hn--;
302efbad 3119
3120 ret = lttv_trace_find_hook(ts->parent.t,
3121 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
3122 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
3123 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
80e0221b 3124 if(ret) hn--;
302efbad 3125
3126 hooks = g_array_set_size(hooks, hn);
3127
a5ba1787 3128 /* Add these hooks to each event_by_id hooks list */
dc877563 3129
eed2ef37 3130 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3131
dc877563 3132 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3133 tfs =
9d239bd9 3134 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3135 LttvTracefileContext*, j));
dc877563 3136
3137 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 3138 hook = &g_array_index(hooks, LttvTraceHook, k);
3139 for(l=0;l<hook->fac_list->len;l++) {
3140 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
3141 lttv_hooks_add(
3142 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
3143 thf->h,
d052ffc3 3144 thf,
eed2ef37 3145 LTTV_PRIO_STATE);
3146 }
ffd54a90 3147 }
dc877563 3148 }
f0b795e0 3149 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3150 *(val.v_pointer) = hooks;
dc877563 3151 }
3152}
3153
58c88a41 3154gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
3155{
3156 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3157
3158 lttv_state_remove_event_hooks(tss);
3159
3160 return 0;
3161}
dc877563 3162
308711e5 3163void lttv_state_remove_event_hooks(LttvTracesetState *self)
dc877563 3164{
ba576a78 3165 LttvTraceset *traceset = self->parent.ts;
dc877563 3166
eed2ef37 3167 guint i, j, k, l, nb_trace, nb_tracefile;
dc877563 3168
ba576a78 3169 LttvTraceState *ts;
dc877563 3170
ba576a78 3171 LttvTracefileState *tfs;
dc877563 3172
dc877563 3173 GArray *hooks;
3174
eed2ef37 3175 LttvTraceHook *hook;
3176
3177 LttvTraceHookByFacility *thf;
dc877563 3178
3179 LttvAttributeValue val;
3180
ba576a78 3181 nb_trace = lttv_traceset_number(traceset);
dc877563 3182 for(i = 0 ; i < nb_trace ; i++) {
021eeb41 3183 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
7df20ca4 3184
f0b795e0 3185 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
ba576a78 3186 hooks = *(val.v_pointer);
dc877563 3187
a5ba1787 3188 /* Remove these hooks from each event_by_id hooks list */
dc877563 3189
eed2ef37 3190 nb_tracefile = ts->parent.tracefiles->len;
dbb7bb09 3191
dc877563 3192 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3193 tfs =
cb03932a 3194 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3195 LttvTracefileContext*, j));
dc877563 3196
3197 for(k = 0 ; k < hooks->len ; k++) {
eed2ef37 3198 hook = &g_array_index(hooks, LttvTraceHook, k);
3199 for(l=0;l<hook->fac_list->len;l++) {
3200 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
3201
3202 lttv_hooks_remove_data(
3203 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
3204 thf->h,
d052ffc3 3205 thf);
eed2ef37 3206 }
ffd54a90 3207 }
dc877563 3208 }
1986f254 3209 for(k = 0 ; k < hooks->len ; k++)
3210 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
dc877563 3211 g_array_free(hooks, TRUE);
3212 }
3213}
3214
eed2ef37 3215static gboolean state_save_event_hook(void *hook_data, void *call_data)
3216{
3217 guint *event_count = (guint*)hook_data;
3218
3219 /* Only save at LTTV_STATE_SAVE_INTERVAL */
3220 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
3221 return FALSE;
3222 else
18c87975 3223 *event_count = 0;
eed2ef37 3224
3225 LttvTracefileState *self = (LttvTracefileState *)call_data;
3226
3227 LttvTracefileState *tfcs;
3228
3229 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3230
3231 LttEventPosition *ep;
3232
3233 guint i;
3234
3235 LttTracefile *tf;
3236
3237 LttvAttribute *saved_states_tree, *saved_state_tree;
3238
3239 LttvAttributeValue value;
3240
3241 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3242 LTTV_STATE_SAVED_STATES);
3243 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3244 value = lttv_attribute_add(saved_states_tree,
3245 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3246 *(value.v_gobject) = (GObject *)saved_state_tree;
3247 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3248 *(value.v_time) = self->parent.timestamp;
3249 lttv_state_save(tcs, saved_state_tree);
3250 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3251 self->parent.timestamp.tv_nsec);
3252
3253 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3254
3255 return FALSE;
3256}
3257
14aecf75 3258static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
3259{
3260 LttvTraceState *tcs = (LttvTraceState *)(call_data);
3261
3262 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
3263
3264 return FALSE;
3265}
3266
ae3d0f50 3267guint lttv_state_current_cpu(LttvTracefileState *tfs)
3268{
80e0221b 3269 return tfs->cpu;
ae3d0f50 3270}
3271
3272
3273
eed2ef37 3274#if 0
08b1c66e 3275static gboolean block_start(void *hook_data, void *call_data)
308711e5 3276{
dbb7bb09 3277 LttvTracefileState *self = (LttvTracefileState *)call_data;
308711e5 3278
dbb7bb09 3279 LttvTracefileState *tfcs;
308711e5 3280
dbb7bb09 3281 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3282
3283 LttEventPosition *ep;
308711e5 3284
dbb7bb09 3285 guint i, nb_block, nb_event, nb_tracefile;
308711e5 3286
3287 LttTracefile *tf;
3288
3289 LttvAttribute *saved_states_tree, *saved_state_tree;
3290
3291 LttvAttributeValue value;
3292
dbb7bb09 3293 ep = ltt_event_position_new();
eed2ef37 3294
3295 nb_tracefile = tcs->parent.tracefiles->len;
dbb7bb09 3296
3297 /* Count the number of events added since the last block end in any
3298 tracefile. */
3299
3300 for(i = 0 ; i < nb_tracefile ; i++) {
eed2ef37 3301 tfcs =
3302 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3303 LttvTracefileContext, i));
dbb7bb09 3304 ltt_event_position(tfcs->parent.e, ep);
3305 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3306 tcs->nb_event += nb_event - tfcs->saved_position;
3307 tfcs->saved_position = nb_event;
3308 }
3309 g_free(ep);
308711e5 3310
308711e5 3311 if(tcs->nb_event >= tcs->save_interval) {
3312 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3313 LTTV_STATE_SAVED_STATES);
3314 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3315 value = lttv_attribute_add(saved_states_tree,
3316 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3317 *(value.v_gobject) = (GObject *)saved_state_tree;
3318 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
dbb7bb09 3319 *(value.v_time) = self->parent.timestamp;
308711e5 3320 lttv_state_save(tcs, saved_state_tree);
3321 tcs->nb_event = 0;
08b1c66e 3322 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
80e0221b 3323 self->parent.timestamp.tv_nsec);
308711e5 3324 }
dbb7bb09 3325 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
308711e5 3326 return FALSE;
3327}
eed2ef37 3328#endif //0
308711e5 3329
eed2ef37 3330#if 0
08b1c66e 3331static gboolean block_end(void *hook_data, void *call_data)
3332{
3333 LttvTracefileState *self = (LttvTracefileState *)call_data;
3334
3335 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3336
3337 LttTracefile *tf;
3338
3339 LttEventPosition *ep;
3340
3341 guint nb_block, nb_event;
3342
3343 ep = ltt_event_position_new();
3344 ltt_event_position(self->parent.e, ep);
3345 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3346 tcs->nb_event += nb_event - self->saved_position + 1;
3347 self->saved_position = 0;
3348 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3349 g_free(ep);
00e74b69 3350
3351 return FALSE;
08b1c66e 3352}
eed2ef37 3353#endif //0
3354#if 0
308711e5 3355void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3356{
3357 LttvTraceset *traceset = self->parent.ts;
3358
00e74b69 3359 guint i, j, nb_trace, nb_tracefile;
308711e5 3360
3361 LttvTraceState *ts;
3362
3363 LttvTracefileState *tfs;
3364
08b1c66e 3365 LttvTraceHook hook_start, hook_end;
308711e5 3366
3367 nb_trace = lttv_traceset_number(traceset);
3368 for(i = 0 ; i < nb_trace ; i++) {
3369 ts = (LttvTraceState *)self->parent.traces[i];
eed2ef37 3370
08b1c66e 3371 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3372 NULL, NULL, block_start, &hook_start);
308711e5 3373 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3374 NULL, NULL, block_end, &hook_end);
308711e5 3375
eed2ef37 3376 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3377
dbb7bb09 3378 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3379 tfs =
3380 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3381 LttvTracefileContext, j));
a5ba1787 3382 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3383 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
a5ba1787 3384 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
80e0221b 3385 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
eed2ef37 3386 }
3387 }
3388}
3389#endif //0
3390
3391void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3392{
3393 LttvTraceset *traceset = self->parent.ts;
3394
3395 guint i, j, nb_trace, nb_tracefile;
3396
3397 LttvTraceState *ts;
3398
3399 LttvTracefileState *tfs;
3400
3401
3402 nb_trace = lttv_traceset_number(traceset);
3403 for(i = 0 ; i < nb_trace ; i++) {
3404
3405 ts = (LttvTraceState *)self->parent.traces[i];
3406 nb_tracefile = ts->parent.tracefiles->len;
3407
ce05e187 3408 if(ts->has_precomputed_states) continue;
3409
3054461a 3410 guint *event_count = g_new(guint, 1);
3411 *event_count = 0;
3412
eed2ef37 3413 for(j = 0 ; j < nb_tracefile ; j++) {
3414 tfs =
cb03932a 3415 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3416 LttvTracefileContext*, j));
eed2ef37 3417 lttv_hooks_add(tfs->parent.event,
3418 state_save_event_hook,
3419 event_count,
3420 LTTV_PRIO_STATE);
3421
308711e5 3422 }
3423 }
14aecf75 3424
3425 lttv_process_traceset_begin(&self->parent,
3426 NULL, NULL, NULL, NULL, NULL);
3427
308711e5 3428}
3429
b56b5fec 3430gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3431{
3432 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3433
3434 lttv_state_save_add_event_hooks(tss);
3435
3436 return 0;
3437}
3438
308711e5 3439
eed2ef37 3440#if 0
308711e5 3441void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3442{
3443 LttvTraceset *traceset = self->parent.ts;
3444
00e74b69 3445 guint i, j, nb_trace, nb_tracefile;
308711e5 3446
3447 LttvTraceState *ts;
3448
3449 LttvTracefileState *tfs;
3450
08b1c66e 3451 LttvTraceHook hook_start, hook_end;
308711e5 3452
3453 nb_trace = lttv_traceset_number(traceset);
3454 for(i = 0 ; i < nb_trace ; i++) {
3455 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
eed2ef37 3456
08b1c66e 3457 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
80e0221b 3458 NULL, NULL, block_start, &hook_start);
08b1c66e 3459
308711e5 3460 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
80e0221b 3461 NULL, NULL, block_end, &hook_end);
308711e5 3462
eed2ef37 3463 nb_tracefile = ts->parent.tracefiles->len;
308711e5 3464
dbb7bb09 3465 for(j = 0 ; j < nb_tracefile ; j++) {
eed2ef37 3466 tfs =
3467 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3468 LttvTracefileContext, j));
308711e5 3469 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3470 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
08b1c66e 3471 lttv_hooks_remove_data(lttv_hooks_by_id_find(
a5ba1787 3472 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
308711e5 3473 }
3474 }
3475}
eed2ef37 3476#endif //0
3477
3478void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3479{
3480 LttvTraceset *traceset = self->parent.ts;
3481
3482 guint i, j, nb_trace, nb_tracefile;
3483
3484 LttvTraceState *ts;
3485
3486 LttvTracefileState *tfs;
3487
14aecf75 3488 LttvHooks *after_trace = lttv_hooks_new();
3489
3490 lttv_hooks_add(after_trace,
3491 state_save_after_trace_hook,
3492 NULL,
3493 LTTV_PRIO_STATE);
3494
3495
3496 lttv_process_traceset_end(&self->parent,
3497 NULL, after_trace, NULL, NULL, NULL);
eed2ef37 3498
14aecf75 3499 lttv_hooks_destroy(after_trace);
3500
eed2ef37 3501 nb_trace = lttv_traceset_number(traceset);
3502 for(i = 0 ; i < nb_trace ; i++) {
3503
3504 ts = (LttvTraceState *)self->parent.traces[i];
3505 nb_tracefile = ts->parent.tracefiles->len;
3506
ce05e187 3507 if(ts->has_precomputed_states) continue;
3508
22b165e9 3509 guint *event_count = NULL;
eed2ef37 3510
3511 for(j = 0 ; j < nb_tracefile ; j++) {
3512 tfs =
cb03932a 3513 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3514 LttvTracefileContext*, j));
eed2ef37 3515 event_count = lttv_hooks_remove(tfs->parent.event,
3516 state_save_event_hook);
eed2ef37 3517 }
22b165e9 3518 if(event_count) g_free(event_count);
eed2ef37 3519 }
3520}
308711e5 3521
b56b5fec 3522gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3523{
3524 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3525
3526 lttv_state_save_remove_event_hooks(tss);
3527
3528 return 0;
3529}
308711e5 3530
dd025f91 3531void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
308711e5 3532{
3533 LttvTraceset *traceset = self->parent.ts;
3534
00e74b69 3535 guint i, nb_trace;
308711e5 3536
3537 int min_pos, mid_pos, max_pos;
3538
728d0c3e 3539 guint call_rest = 0;
3540
308711e5 3541 LttvTraceState *tcs;
3542
3543 LttvAttributeValue value;
3544
3545 LttvAttributeType type;
3546
3547 LttvAttributeName name;
3548
80e0221b 3549 gboolean is_named;
c0cb4d12 3550
308711e5 3551 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3552
d448fce2 3553 //g_tree_destroy(self->parent.pqueue);
3554 //self->parent.pqueue = g_tree_new(compare_tracefile);
348c6ba8 3555
728d0c3e 3556 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3557
308711e5 3558 nb_trace = lttv_traceset_number(traceset);
3559 for(i = 0 ; i < nb_trace ; i++) {
3560 tcs = (LttvTraceState *)self->parent.traces[i];
3561
2a2fa4f0 3562 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3563 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3564 LTTV_STATE_SAVED_STATES);
3565 min_pos = -1;
3566
3567 if(saved_states_tree) {
dd025f91 3568 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3569 mid_pos = max_pos / 2;
3570 while(min_pos < max_pos) {
c0cb4d12 3571 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
80e0221b 3572 &is_named);
dd025f91 3573 g_assert(type == LTTV_GOBJECT);
3574 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3575 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3576 &value);
3577 g_assert(type == LTTV_TIME);
3578 if(ltt_time_compare(*(value.v_time), t) < 0) {
3579 min_pos = mid_pos;
3580 closest_tree = saved_state_tree;
3581 }
3582 else max_pos = mid_pos - 1;
3583
3584 mid_pos = (min_pos + max_pos + 1) / 2;
3585 }
2a2fa4f0 3586 }
dd025f91 3587
2a2fa4f0 3588 /* restore the closest earlier saved state */
f95bc830 3589 if(min_pos != -1) {
3590 lttv_state_restore(tcs, closest_tree);
728d0c3e 3591 call_rest = 1;
f95bc830 3592 }
dd025f91 3593
2a2fa4f0 3594 /* There is no saved state, yet we want to have it. Restart at T0 */
dd025f91 3595 else {
3596 restore_init_state(tcs);
3597 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
308711e5 3598 }
9444deae 3599 }
dd025f91 3600 /* We want to seek quickly without restoring/updating the state */
3601 else {
308711e5 3602 restore_init_state(tcs);
dd025f91 3603 lttv_process_trace_seek_time(&(tcs->parent), t);
308711e5 3604 }
308711e5 3605 }
728d0c3e 3606 if(!call_rest) g_info("NOT Calling restore");
308711e5 3607}
3608
3609
3610static void
3611traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3612{
3613}
3614
3615
3616static void
3617traceset_state_finalize (LttvTracesetState *self)
3618{
3619 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3620 finalize(G_OBJECT(self));
3621}
3622
3623
3624static void
3625traceset_state_class_init (LttvTracesetContextClass *klass)
3626{
3627 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3628
3629 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3630 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3631 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3632 klass->new_traceset_context = new_traceset_context;
3633 klass->new_trace_context = new_trace_context;
3634 klass->new_tracefile_context = new_tracefile_context;
3635}
3636
3637
3638GType
3639lttv_traceset_state_get_type(void)
3640{
3641 static GType type = 0;
3642 if (type == 0) {
3643 static const GTypeInfo info = {
3644 sizeof (LttvTracesetStateClass),
3645 NULL, /* base_init */
3646 NULL, /* base_finalize */
3647 (GClassInitFunc) traceset_state_class_init, /* class_init */
3648 NULL, /* class_finalize */
3649 NULL, /* class_data */
dbb7bb09 3650 sizeof (LttvTracesetState),
308711e5 3651 0, /* n_preallocs */
00e74b69 3652 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3653 NULL /* value handling */
308711e5 3654 };
3655
3656 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3657 &info, 0);
3658 }
3659 return type;
3660}
3661
3662
3663static void
3664trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3665{
3666}
3667
3668
3669static void
3670trace_state_finalize (LttvTraceState *self)
3671{
3672 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3673 finalize(G_OBJECT(self));
3674}
3675
3676
3677static void
3678trace_state_class_init (LttvTraceStateClass *klass)
3679{
3680 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3681
3682 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3683 klass->state_save = state_save;
3684 klass->state_restore = state_restore;
3685 klass->state_saved_free = state_saved_free;
3686}
3687
3688
3689GType
3690lttv_trace_state_get_type(void)
3691{
3692 static GType type = 0;
3693 if (type == 0) {
3694 static const GTypeInfo info = {
3695 sizeof (LttvTraceStateClass),
3696 NULL, /* base_init */
3697 NULL, /* base_finalize */
3698 (GClassInitFunc) trace_state_class_init, /* class_init */
3699 NULL, /* class_finalize */
3700 NULL, /* class_data */
3701 sizeof (LttvTraceState),
3702 0, /* n_preallocs */
00e74b69 3703 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3704 NULL /* value handling */
308711e5 3705 };
3706
3707 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3708 "LttvTraceStateType", &info, 0);
3709 }
3710 return type;
3711}
3712
3713
3714static void
3715tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3716{
3717}
3718
3719
3720static void
3721tracefile_state_finalize (LttvTracefileState *self)
3722{
3723 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3724 finalize(G_OBJECT(self));
3725}
3726
3727
3728static void
3729tracefile_state_class_init (LttvTracefileStateClass *klass)
3730{
3731 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3732
3733 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3734}
3735
3736
3737GType
3738lttv_tracefile_state_get_type(void)
3739{
3740 static GType type = 0;
3741 if (type == 0) {
3742 static const GTypeInfo info = {
3743 sizeof (LttvTracefileStateClass),
3744 NULL, /* base_init */
3745 NULL, /* base_finalize */
3746 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3747 NULL, /* class_finalize */
3748 NULL, /* class_data */
3749 sizeof (LttvTracefileState),
3750 0, /* n_preallocs */
00e74b69 3751 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3752 NULL /* value handling */
308711e5 3753 };
3754
3755 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3756 "LttvTracefileStateType", &info, 0);
3757 }
3758 return type;
3759}
3760
3761
08b1c66e 3762static void module_init()
ffd54a90 3763{
83e160f2 3764 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
7b5f6cf1 3765 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
b3fd4c02 3766 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3767 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3768 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3769 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3770 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3771 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3772 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3773 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3774 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3775 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3776 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3777 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3778 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3779 LTTV_STATE_RUN = g_quark_from_string("RUN");
3780 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
80e0221b 3781 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3782 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
308711e5 3783 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3784 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3785 LTTV_STATE_PROCESS = g_quark_from_string("process");
348c6ba8 3786 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
308711e5 3787 LTTV_STATE_EVENT = g_quark_from_string("event");
3788 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
dbb7bb09 3789 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
308711e5 3790 LTTV_STATE_TIME = g_quark_from_string("time");
ffd54a90 3791 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
f95bc830 3792 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3793 LTTV_STATE_TRACE_STATE_USE_COUNT =
3794 g_quark_from_string("trace_state_use_count");
fbfbd4db 3795 LTTV_STATE_RESOURCE_CPUS = g_quark_from_string("cpu resource states");
eed2ef37 3796
3797
3798 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
f5d7967f 3799 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
f4b88a7d 3800 LTT_FACILITY_FS = g_quark_from_string("fs");
86c32a8f 3801 LTT_FACILITY_LIST = g_quark_from_string("list");
302efbad 3802 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
27811799 3803 LTT_FACILITY_BLOCK = g_quark_from_string("block");
eed2ef37 3804
3805
3806 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3807 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3808 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3809 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3810 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3811 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
faf074a3 3812 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
3813 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
86c32a8f 3814 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3815 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3816 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3817 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
f63ebe51 3818 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
f4b88a7d 3819 LTT_EVENT_EXEC = g_quark_from_string("exec");
86c32a8f 3820 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
c3b3b60b 3821 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
302efbad 3822 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3823 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
7b5f6cf1 3824 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
27811799 3825 LTT_EVENT_REQUEST_ISSUE = g_quark_from_string("_blk_request_issue");
3826 LTT_EVENT_REQUEST_COMPLETE = g_quark_from_string("_blk_request_complete");
eed2ef37 3827
3828
3829 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3830 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3831 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
faf074a3 3832 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
f63ebe51 3833 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3834 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3835 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
eed2ef37 3836 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3837 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3838 LTT_FIELD_PID = g_quark_from_string("pid");
fcc08e1e 3839 LTT_FIELD_TGID = g_quark_from_string("tgid");
f63ebe51 3840 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
f4b88a7d 3841 LTT_FIELD_FILENAME = g_quark_from_string("filename");
b3fd4c02 3842 LTT_FIELD_NAME = g_quark_from_string("name");
e62e7f3a 3843 LTT_FIELD_TYPE = g_quark_from_string("type");
b3fd4c02 3844 LTT_FIELD_MODE = g_quark_from_string("mode");
3845 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3846 LTT_FIELD_STATUS = g_quark_from_string("status");
302efbad 3847 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3848 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
27811799 3849 LTT_FIELD_MAJOR = g_quark_from_string("major");
3850 LTT_FIELD_MINOR = g_quark_from_string("minor");
3851 LTT_FIELD_OPERATION = g_quark_from_string("direction");
eed2ef37 3852
44ffb95f 3853 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3854 LTTV_CPU_IDLE = g_quark_from_string("idle");
3855 LTTV_CPU_BUSY = g_quark_from_string("busy");
598026ba 3856 LTTV_CPU_IRQ = g_quark_from_string("irq");
d3d99fde 3857 LTTV_CPU_TRAP = g_quark_from_string("trap");
5e563da0 3858
3859 LTTV_IRQ_UNKNOWN = g_quark_from_string("unknown");
3860 LTTV_IRQ_IDLE = g_quark_from_string("idle");
3861 LTTV_IRQ_BUSY = g_quark_from_string("busy");
27811799 3862
3863 LTTV_BDEV_UNKNOWN = g_quark_from_string("unknown");
3864 LTTV_BDEV_IDLE = g_quark_from_string("idle");
3865 LTTV_BDEV_BUSY_READING = g_quark_from_string("busy_reading");
3866 LTTV_BDEV_BUSY_WRITING = g_quark_from_string("busy_writing");
ffd54a90 3867}
dc877563 3868
08b1c66e 3869static void module_destroy()
ffd54a90 3870{
3871}
dc877563 3872
3873
08b1c66e 3874LTTV_MODULE("state", "State computation", \
3875 "Update the system state, possibly saving it at intervals", \
3876 module_init, module_destroy)
3877
dc877563 3878
3879
This page took 0.266717 seconds and 4 git commands to generate.