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