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